From f953fc2b69658a032fa7b476b4ed0303ab45c041 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Sun, 20 Sep 2015 02:26:41 -0400 Subject: [PATCH 01/29] Bug 1195951 - fix heap type on stack error in MediaUtils' Pledge class. r=jesup --HG-- extra : commitid : 7vVVqOmBW1W extra : rebase_source : 186c56708e579f2734a1a9db8acebcb69c9f5af2 --- dom/media/MediaManager.cpp | 8 +- dom/media/MediaManager.h | 2 +- dom/media/systemservices/MediaUtils.h | 105 ++------------------------ 3 files changed, 12 insertions(+), 103 deletions(-) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 9ace320c50c9..843b3373982e 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -2031,8 +2031,8 @@ MediaManager::GetUserMedia(nsPIDOMWindow* aWindow, #ifdef MOZ_WEBRTC EnableWebRtcLog(); #endif - }, [onFailure](MediaStreamError& reason) mutable { - onFailure->OnError(&reason); + }, [onFailure](MediaStreamError*& reason) mutable { + onFailure->OnError(reason); }); return NS_OK; } @@ -2212,10 +2212,10 @@ MediaManager::EnumerateDevices(nsPIDOMWindow* aWindow, mgr->RemoveFromWindowList(windowId, listener); nsCOMPtr array = MediaManager_ToJSArray(*devices); onSuccess->OnSuccess(array); - }, [onFailure, windowId, listener](MediaStreamError& reason) mutable { + }, [onFailure, windowId, listener](MediaStreamError*& reason) mutable { nsRefPtr mgr = MediaManager_GetInstance(); mgr->RemoveFromWindowList(windowId, listener); - onFailure->OnError(&reason); + onFailure->OnError(reason); }); return NS_OK; } diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index d35f4bf40ece..d15d32726676 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -586,7 +586,7 @@ public: typedef nsTArray> SourceSet; static bool IsPrivateBrowsing(nsPIDOMWindow *window); private: - typedef media::Pledge PledgeSourceSet; + typedef media::Pledge PledgeSourceSet; static bool IsPrivileged(); static bool IsLoop(nsIURI* aDocURI); diff --git a/dom/media/systemservices/MediaUtils.h b/dom/media/systemservices/MediaUtils.h index 1851f3ac83fb..a89316b6d3ee 100644 --- a/dom/media/systemservices/MediaUtils.h +++ b/dom/media/systemservices/MediaUtils.h @@ -63,7 +63,7 @@ class Pledge : public PledgeBase }; public: - explicit Pledge() : mDone(false), mError(nullptr) {} + explicit Pledge() : mDone(false), mRejected(false) {} Pledge(const Pledge& aOther) = delete; Pledge& operator = (const Pledge&) = delete; @@ -97,10 +97,10 @@ public: mFunctors = new Functors(aOnSuccess, aOnFailure); if (mDone) { - if (!mError) { + if (!mRejected) { mFunctors->Succeed(mValue); } else { - mFunctors->Fail(*mError); + mFunctors->Fail(mError); } } } @@ -110,22 +110,11 @@ public: mValue = aValue; Resolve(); } -protected: - void Resolve() - { - if (!mDone) { - mDone = true; - MOZ_ASSERT(!mError); - if (mFunctors) { - mFunctors->Succeed(mValue); - } - } - } void Reject(ErrorType rv) { if (!mDone) { - mDone = true; + mDone = mRejected = true; mError = rv; if (mFunctors) { mFunctors->Fail(mError); @@ -133,104 +122,24 @@ protected: } } - ValueType mValue; -private: - ~Pledge() {}; - bool mDone; - nsRefPtr mError; - ScopedDeletePtr mFunctors; -}; - -template -class Pledge : public PledgeBase -{ - // TODO: Remove workaround once mozilla allows std::function from - // wo/std::function support, do template + virtual trick to accept lambdas - class FunctorsBase - { - public: - FunctorsBase() {} - virtual void Succeed(ValueType& result) = 0; - virtual void Fail(nsresult error) = 0; - virtual ~FunctorsBase() {}; - }; - -public: - explicit Pledge() : mDone(false), mError(NS_OK) {} - Pledge(const Pledge& aOther) = delete; - Pledge& operator = (const Pledge&) = delete; - - template - void Then(OnSuccessType aOnSuccess) - { - Then(aOnSuccess, [](nsresult){}); - } - - template - void Then(OnSuccessType aOnSuccess, OnFailureType aOnFailure) - { - class Functors : public FunctorsBase - { - public: - Functors(OnSuccessType& aOnSuccess, OnFailureType& aOnFailure) - : mOnSuccess(aOnSuccess), mOnFailure(aOnFailure) {} - - void Succeed(ValueType& result) - { - mOnSuccess(result); - } - void Fail(nsresult rv) - { - mOnFailure(rv); - }; - - OnSuccessType mOnSuccess; - OnFailureType mOnFailure; - }; - mFunctors = new Functors(aOnSuccess, aOnFailure); - - if (mDone) { - if (mError == NS_OK) { - mFunctors->Succeed(mValue); - } else { - mFunctors->Fail(mError); - } - } - } - - void Resolve(const ValueType& aValue) - { - mValue = aValue; - Resolve(); - } protected: void Resolve() { if (!mDone) { mDone = true; - MOZ_ASSERT(mError == NS_OK); + MOZ_ASSERT(!mRejected); if (mFunctors) { mFunctors->Succeed(mValue); } } } - void Reject(nsresult error) - { - if (!mDone) { - mDone = true; - mError = error; - if (mFunctors) { - mFunctors->Fail(mError); - } - } - } - ValueType mValue; private: ~Pledge() {}; bool mDone; - nsresult mError; + bool mRejected; + ErrorType mError; ScopedDeletePtr mFunctors; }; From e5af2b70b2283886c69a0eb85b0d50048b025421 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Wed, 16 Sep 2015 22:44:14 -0400 Subject: [PATCH 02/29] Bug 912342 - Move code MediaOperationTask from .h to .cpp. r=jesup --HG-- extra : commitid : L4YvvKBc9ft extra : rebase_source : 3f732a3e21b8a9038ce35f232c012169134248e9 --- dom/media/MediaManager.cpp | 145 +++++++++++++++++++++++++++++++++++++ dom/media/MediaManager.h | 145 ------------------------------------- 2 files changed, 145 insertions(+), 145 deletions(-) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 843b3373982e..89a1c09bfd5b 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -214,6 +214,151 @@ HostHasPermission(nsIURI &docURI) return false; } +// Generic class for running long media operations like Start off the main +// thread, and then (because nsDOMMediaStreams aren't threadsafe), +// ProxyReleases mStream since it's cycle collected. +class MediaOperationTask : public Task +{ +public: + // so we can send Stop without AddRef()ing from the MSG thread + MediaOperationTask(MediaOperation aType, + GetUserMediaCallbackMediaStreamListener* aListener, + DOMMediaStream* aStream, + DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback, + MediaEngineSource* aAudioSource, + MediaEngineSource* aVideoSource, + bool aBool, + uint64_t aWindowID, + already_AddRefed aError) + : mType(aType) + , mStream(aStream) + , mOnTracksAvailableCallback(aOnTracksAvailableCallback) + , mAudioSource(aAudioSource) + , mVideoSource(aVideoSource) + , mListener(aListener) + , mBool(aBool) + , mWindowID(aWindowID) + , mOnFailure(aError) + {} + + ~MediaOperationTask() + { + // MediaStreams can be released on any thread. + } + + void + ReturnCallbackError(nsresult rv, const char* errorLog); + + void + Run() + { + SourceMediaStream *source = mListener->GetSourceStream(); + // No locking between these is required as all the callbacks for the + // same MediaStream will occur on the same thread. + if (!source) // means the stream was never Activated() + return; + + switch (mType) { + case MEDIA_START: + { + NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); + nsresult rv; + + if (mAudioSource) { + rv = mAudioSource->Start(source, kAudioTrack); + if (NS_FAILED(rv)) { + ReturnCallbackError(rv, "Starting audio failed"); + return; + } + } + if (mVideoSource) { + rv = mVideoSource->Start(source, kVideoTrack); + if (NS_FAILED(rv)) { + ReturnCallbackError(rv, "Starting video failed"); + return; + } + } + // Start() queued the tracks to be added synchronously to avoid races + source->FinishAddTracks(); + + source->SetPullEnabled(true); + source->AdvanceKnownTracksTime(STREAM_TIME_MAX); + + MM_LOG(("started all sources")); + // Forward mOnTracksAvailableCallback to GetUserMediaNotificationEvent, + // because mOnTracksAvailableCallback needs to be added to mStream + // on the main thread. + nsIRunnable *event = + new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING, + mStream.forget(), + mOnTracksAvailableCallback.forget(), + mAudioSource != nullptr, + mVideoSource != nullptr, + mWindowID, mOnFailure.forget()); + // event must always be released on mainthread due to the JS callbacks + // in the TracksAvailableCallback + NS_DispatchToMainThread(event); + } + break; + + case MEDIA_STOP: + case MEDIA_STOP_TRACK: + { + NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); + if (mAudioSource) { + mAudioSource->Stop(source, kAudioTrack); + mAudioSource->Deallocate(); + } + if (mVideoSource) { + mVideoSource->Stop(source, kVideoTrack); + mVideoSource->Deallocate(); + } + // Do this after stopping all tracks with EndTrack() + if (mBool) { + source->Finish(); + } + + nsIRunnable *event = + new GetUserMediaNotificationEvent(mListener, + mType == MEDIA_STOP ? + GetUserMediaNotificationEvent::STOPPING : + GetUserMediaNotificationEvent::STOPPED_TRACK, + mAudioSource != nullptr, + mVideoSource != nullptr, + mWindowID); + // event must always be released on mainthread due to the JS callbacks + // in the TracksAvailableCallback + NS_DispatchToMainThread(event); + } + break; + + case MEDIA_DIRECT_LISTENERS: + { + NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); + if (mVideoSource) { + mVideoSource->SetDirectListeners(mBool); + } + } + break; + + default: + MOZ_ASSERT(false,"invalid MediaManager operation"); + break; + } + } + +private: + MediaOperation mType; + nsRefPtr mStream; + nsAutoPtr mOnTracksAvailableCallback; + nsRefPtr mAudioSource; // threadsafe + nsRefPtr mVideoSource; // threadsafe + nsRefPtr mListener; // threadsafe + bool mBool; + uint64_t mWindowID; + nsCOMPtr mOnFailure; +}; + /** * Send an error back to content. * Do this only on the main thread. The onSuccess callback is also passed here diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index d15d32726676..1149ead0be1c 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -310,151 +310,6 @@ private: nsAutoPtr mOnTracksAvailableCallback; }; -// Generic class for running long media operations like Start off the main -// thread, and then (because nsDOMMediaStreams aren't threadsafe), -// ProxyReleases mStream since it's cycle collected. -class MediaOperationTask : public Task -{ -public: - // so we can send Stop without AddRef()ing from the MSG thread - MediaOperationTask(MediaOperation aType, - GetUserMediaCallbackMediaStreamListener* aListener, - DOMMediaStream* aStream, - DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback, - MediaEngineSource* aAudioSource, - MediaEngineSource* aVideoSource, - bool aBool, - uint64_t aWindowID, - already_AddRefed aError) - : mType(aType) - , mStream(aStream) - , mOnTracksAvailableCallback(aOnTracksAvailableCallback) - , mAudioSource(aAudioSource) - , mVideoSource(aVideoSource) - , mListener(aListener) - , mBool(aBool) - , mWindowID(aWindowID) - , mOnFailure(aError) - {} - - ~MediaOperationTask() - { - // MediaStreams can be released on any thread. - } - - void - ReturnCallbackError(nsresult rv, const char* errorLog); - - void - Run() - { - SourceMediaStream *source = mListener->GetSourceStream(); - // No locking between these is required as all the callbacks for the - // same MediaStream will occur on the same thread. - if (!source) // means the stream was never Activated() - return; - - switch (mType) { - case MEDIA_START: - { - NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); - nsresult rv; - - if (mAudioSource) { - rv = mAudioSource->Start(source, kAudioTrack); - if (NS_FAILED(rv)) { - ReturnCallbackError(rv, "Starting audio failed"); - return; - } - } - if (mVideoSource) { - rv = mVideoSource->Start(source, kVideoTrack); - if (NS_FAILED(rv)) { - ReturnCallbackError(rv, "Starting video failed"); - return; - } - } - // Start() queued the tracks to be added synchronously to avoid races - source->FinishAddTracks(); - - source->SetPullEnabled(true); - source->AdvanceKnownTracksTime(STREAM_TIME_MAX); - - MM_LOG(("started all sources")); - // Forward mOnTracksAvailableCallback to GetUserMediaNotificationEvent, - // because mOnTracksAvailableCallback needs to be added to mStream - // on the main thread. - nsIRunnable *event = - new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING, - mStream.forget(), - mOnTracksAvailableCallback.forget(), - mAudioSource != nullptr, - mVideoSource != nullptr, - mWindowID, mOnFailure.forget()); - // event must always be released on mainthread due to the JS callbacks - // in the TracksAvailableCallback - NS_DispatchToMainThread(event); - } - break; - - case MEDIA_STOP: - case MEDIA_STOP_TRACK: - { - NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); - if (mAudioSource) { - mAudioSource->Stop(source, kAudioTrack); - mAudioSource->Deallocate(); - } - if (mVideoSource) { - mVideoSource->Stop(source, kVideoTrack); - mVideoSource->Deallocate(); - } - // Do this after stopping all tracks with EndTrack() - if (mBool) { - source->Finish(); - } - - nsIRunnable *event = - new GetUserMediaNotificationEvent(mListener, - mType == MEDIA_STOP ? - GetUserMediaNotificationEvent::STOPPING : - GetUserMediaNotificationEvent::STOPPED_TRACK, - mAudioSource != nullptr, - mVideoSource != nullptr, - mWindowID); - // event must always be released on mainthread due to the JS callbacks - // in the TracksAvailableCallback - NS_DispatchToMainThread(event); - } - break; - - case MEDIA_DIRECT_LISTENERS: - { - NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); - if (mVideoSource) { - mVideoSource->SetDirectListeners(mBool); - } - } - break; - - default: - MOZ_ASSERT(false,"invalid MediaManager operation"); - break; - } - } - -private: - MediaOperation mType; - nsRefPtr mStream; - nsAutoPtr mOnTracksAvailableCallback; - nsRefPtr mAudioSource; // threadsafe - nsRefPtr mVideoSource; // threadsafe - nsRefPtr mListener; // threadsafe - bool mBool; - uint64_t mWindowID; - nsCOMPtr mOnFailure; -}; - typedef nsTArray > StreamListeners; typedef nsClassHashtable WindowTable; From 99393ce5d5e553aad29ecee49a27ca18b972e3e3 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Wed, 16 Sep 2015 23:09:28 -0400 Subject: [PATCH 03/29] Bug 912342 - Add MediaStreamTrack.applyConstraints webidl. r=smaug --HG-- extra : commitid : 1biRecMTnjf extra : rebase_source : 30155647452ee303919c729fb4c474b8c50e89a7 --- dom/webidl/MediaStreamTrack.webidl | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/dom/webidl/MediaStreamTrack.webidl b/dom/webidl/MediaStreamTrack.webidl index 155f8afaa668..8edd8c2ee029 100644 --- a/dom/webidl/MediaStreamTrack.webidl +++ b/dom/webidl/MediaStreamTrack.webidl @@ -55,24 +55,26 @@ dictionary MediaTrackConstraints : MediaTrackConstraintSet { sequence advanced; }; -interface MediaStreamTrack { +[Exposed=Window] +interface MediaStreamTrack : EventTarget { readonly attribute DOMString kind; readonly attribute DOMString id; readonly attribute DOMString label; attribute boolean enabled; -// readonly attribute MediaStreamTrackState readyState; -// readonly attribute SourceTypeEnum sourceType; -// readonly attribute DOMString sourceId; -// attribute EventHandler onstarted; -// attribute EventHandler onmute; -// attribute EventHandler onunmute; +// readonly attribute boolean muted; +// attribute EventHandler onmute; +// attribute EventHandler onunmute; +// readonly attribute boolean _readonly; +// readonly attribute boolean remote; +// readonly attribute MediaStreamTrackState readyState; // attribute EventHandler onended; -// any getConstraint (DOMString constraintName, optional boolean mandatory = false); -// void setConstraint (DOMString constraintName, any constraintValue, optional boolean mandatory = false); -// MediaTrackConstraints? constraints (); -// void applyConstraints (MediaTrackConstraints constraints); -// void prependConstraint (DOMString constraintName, any constraintValue); -// void appendConstraint (DOMString constraintName, any constraintValue); -// attribute EventHandler onoverconstrained; +// MediaStreamTrack clone (); void stop (); +// MediaTrackCapabilities getCapabilities (); +// MediaTrackConstraints getConstraints (); +// MediaTrackSettings getSettings (); + + [Throws] + Promise applyConstraints (optional MediaTrackConstraints constraints); +// attribute EventHandler onoverconstrained; }; From 434ce0be70b102408efdbef3f0a53a22d8bcca90 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Sun, 20 Sep 2015 18:45:57 -0400 Subject: [PATCH 04/29] Bug 912342 - Change capture resolution. r=jesup --HG-- extra : commitid : I3MtL3fA2IA extra : rebase_source : 5ffa9bc955b35b2915afea6c5bff794ca97a4ea2 --- dom/media/DOMMediaStream.cpp | 8 ++ dom/media/DOMMediaStream.h | 7 ++ dom/media/MediaManager.cpp | 93 ++++++++++++++++++- dom/media/MediaManager.h | 14 ++- dom/media/MediaStreamTrack.cpp | 7 ++ dom/media/MediaStreamTrack.h | 3 + dom/media/webrtc/MediaEngine.h | 5 + dom/media/webrtc/MediaEngineDefault.cpp | 16 ++++ dom/media/webrtc/MediaEngineDefault.h | 6 ++ .../webrtc/MediaEngineGonkVideoSource.cpp | 8 ++ dom/media/webrtc/MediaEngineGonkVideoSource.h | 3 + .../webrtc/MediaEngineRemoteVideoSource.cpp | 18 ++++ .../webrtc/MediaEngineRemoteVideoSource.h | 3 + .../webrtc/MediaEngineTabVideoSource.cpp | 9 ++ dom/media/webrtc/MediaEngineTabVideoSource.h | 3 + dom/media/webrtc/MediaEngineWebRTC.h | 6 ++ dom/media/webrtc/MediaEngineWebRTCAudio.cpp | 17 ++++ 17 files changed, 223 insertions(+), 3 deletions(-) diff --git a/dom/media/DOMMediaStream.cpp b/dom/media/DOMMediaStream.cpp index 26209a21a1d1..cafe5f177c22 100644 --- a/dom/media/DOMMediaStream.cpp +++ b/dom/media/DOMMediaStream.cpp @@ -358,6 +358,14 @@ DOMMediaStream::StopTrack(TrackID aTrackID) } } +already_AddRefed +DOMMediaStream::ApplyConstraintsToTrack(TrackID aTrackID, + const MediaTrackConstraints& aConstraints, + ErrorResult &aRv) +{ + return nullptr; +} + bool DOMMediaStream::CombineWithPrincipal(nsIPrincipal* aPrincipal) { diff --git a/dom/media/DOMMediaStream.h b/dom/media/DOMMediaStream.h index 5cd214593724..2f5d82518b9e 100644 --- a/dom/media/DOMMediaStream.h +++ b/dom/media/DOMMediaStream.h @@ -48,6 +48,7 @@ class VideoTrack; class AudioTrackList; class VideoTrackList; class MediaTrackListListener; +struct MediaTrackConstraints; } // namespace dom namespace layers { @@ -77,6 +78,7 @@ class DOMMediaStream : public DOMEventTargetHelper typedef dom::MediaTrackListListener MediaTrackListListener; public: + typedef dom::MediaTrackConstraints MediaTrackConstraints; typedef uint8_t TrackTypeHints; DOMMediaStream(); @@ -121,6 +123,11 @@ public: virtual void StopTrack(TrackID aTrackID); + virtual already_AddRefed + ApplyConstraintsToTrack(TrackID aTrackID, + const MediaTrackConstraints& aConstraints, + ErrorResult &aRv); + virtual DOMLocalMediaStream* AsDOMLocalMediaStream() { return nullptr; } virtual DOMHwMediaStream* AsDOMHwMediaStream() { return nullptr; } diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 89a1c09bfd5b..3f161b274c1a 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -119,6 +119,7 @@ using dom::File; using dom::MediaStreamConstraints; using dom::MediaTrackConstraintSet; using dom::MediaTrackConstraints; +using dom::MediaStreamTrack; using dom::MediaStreamError; using dom::GetUserMediaRequest; using dom::Sequence; @@ -229,7 +230,8 @@ public: MediaEngineSource* aVideoSource, bool aBool, uint64_t aWindowID, - already_AddRefed aError) + already_AddRefed aError, + const dom::MediaTrackConstraints& aConstraints = dom::MediaTrackConstraints()) : mType(aType) , mStream(aStream) , mOnTracksAvailableCallback(aOnTracksAvailableCallback) @@ -239,6 +241,7 @@ public: , mBool(aBool) , mWindowID(aWindowID) , mOnFailure(aError) + , mConstraints(aConstraints) {} ~MediaOperationTask() @@ -332,6 +335,32 @@ public: } break; + case MEDIA_APPLYCONSTRAINTS_TRACK: + { + nsRefPtr mgr = MediaManager::GetInstance(); + + NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); + if (mAudioSource) { + mAudioSource->Restart(mConstraints, mgr->mPrefs); + } + if (mVideoSource) { + mVideoSource->Restart(mConstraints, mgr->mPrefs); + } + + // Need to dispatch something back to main to resolve promise + // redo this with pledge? + nsIRunnable *event = + new GetUserMediaNotificationEvent(mListener, + GetUserMediaNotificationEvent::APPLIED_CONSTRAINTS, + mAudioSource != nullptr, + mVideoSource != nullptr, + mWindowID); + // event must always be released on mainthread due to the JS callbacks + // in the TracksAvailableCallback + NS_DispatchToMainThread(event); + } + break; + case MEDIA_DIRECT_LISTENERS: { NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); @@ -357,6 +386,7 @@ private: bool mBool; uint64_t mWindowID; nsCOMPtr mOnFailure; + dom::MediaTrackConstraints mConstraints; }; /** @@ -615,6 +645,16 @@ nsresult AudioDevice::Allocate(const dom::MediaTrackConstraints &aConstraints, return GetSource()->Allocate(aConstraints, aPrefs, mID); } +nsresult VideoDevice::Restart(const dom::MediaTrackConstraints &aConstraints, + const MediaEnginePrefs &aPrefs) { + return GetSource()->Restart(aConstraints, aPrefs, mID); +} + +nsresult AudioDevice::Restart(const dom::MediaTrackConstraints &aConstraints, + const MediaEnginePrefs &aPrefs) { + return GetSource()->Restart(aConstraints, aPrefs, mID); +} + /** * A subclass that we only use to stash internal pointers to MediaStreamGraph objects * that need to be cleaned up. @@ -695,6 +735,29 @@ public: } } + virtual already_AddRefed + ApplyConstraintsToTrack(TrackID aTrackID, + const MediaTrackConstraints& aConstraints, + ErrorResult &aRv) override + { + if (mSourceStream) { + nsRefPtr track = GetDOMTrackFor(aTrackID); + if (track) { + mListener->ApplyConstraintsToTrack(aTrackID, + !!track->AsAudioStreamTrack(), + aConstraints); + } else { + LOG(("ApplyConstraintsToTrack(%d) on non-existant track", aTrackID)); + } + } + + nsPIDOMWindow* window = static_cast(mWindow.get()); + nsCOMPtr go = do_QueryInterface(window); + nsRefPtr p = Promise::Create(go, aRv); + p->MaybeResolve(false); + return p.forget(); + } + #if 0 virtual void NotifyMediaStreamTrackEnded(dom::MediaStreamTrack* aTrack) { @@ -3126,6 +3189,31 @@ GetUserMediaCallbackMediaStreamListener::StopSharing() } } +// ApplyConstraints for track + +void +GetUserMediaCallbackMediaStreamListener::ApplyConstraintsToTrack( + TrackID aID, + bool aIsAudio, + const MediaTrackConstraints& aConstraints) +{ + if (((aIsAudio && mAudioSource) || + (!aIsAudio && mVideoSource)) && !mStopped) + { + // XXX to support multiple tracks of a type in a stream, this should key off + // the TrackID and not just the type + MediaManager::PostTask(FROM_HERE, + new MediaOperationTask(MEDIA_APPLYCONSTRAINTS_TRACK, + this, nullptr, nullptr, + aIsAudio ? mAudioSource.get() : nullptr, + !aIsAudio ? mVideoSource.get() : nullptr, + mFinished, mWindowID, nullptr, aConstraints)); + } else { + LOG(("gUM track %d applyConstraints, but we don't have type %s", + aID, aIsAudio ? "audio" : "video")); + } +} + // Stop backend for track void @@ -3210,6 +3298,9 @@ GetUserMediaNotificationEvent::Run() case STOPPED_TRACK: msg = NS_LITERAL_STRING("shutdown"); break; + case APPLIED_CONSTRAINTS: + msg = NS_LITERAL_STRING("constraints-changed"); + break; } nsCOMPtr window = nsGlobalWindow::GetInnerWindowWithId(mWindowID); diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index 1149ead0be1c..76e711d131b0 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -47,6 +47,7 @@ namespace mozilla { namespace dom { struct MediaStreamConstraints; +struct MediaTrackConstraints; struct MediaTrackConstraintSet; } // namespace dom @@ -107,6 +108,9 @@ public: void StopTrack(TrackID aID, bool aIsAudio); + void ApplyConstraintsToTrack(TrackID aID, bool aIsAudio, + const dom::MediaTrackConstraints& aConstraints); + // mVideo/AudioSource are set by Activate(), so we assume they're capturing // if set and represent a real capture device. bool CapturingVideo() @@ -253,7 +257,8 @@ class GetUserMediaNotificationEvent: public nsRunnable enum GetUserMediaStatus { STARTING, STOPPING, - STOPPED_TRACK + STOPPED_TRACK, + APPLIED_CONSTRAINTS, }; GetUserMediaNotificationEvent(GetUserMediaCallbackMediaStreamListener* aListener, GetUserMediaStatus aStatus, @@ -291,7 +296,8 @@ typedef enum { MEDIA_START, MEDIA_STOP, MEDIA_STOP_TRACK, - MEDIA_DIRECT_LISTENERS + MEDIA_DIRECT_LISTENERS, + MEDIA_APPLYCONSTRAINTS_TRACK, } MediaOperation; class MediaManager; @@ -351,6 +357,8 @@ public: Source* GetSource(); nsresult Allocate(const dom::MediaTrackConstraints &aConstraints, const MediaEnginePrefs &aPrefs); + nsresult Restart(const dom::MediaTrackConstraints &aConstraints, + const MediaEnginePrefs &aPrefs); }; class AudioDevice : public MediaDevice @@ -363,6 +371,8 @@ public: Source* GetSource(); nsresult Allocate(const dom::MediaTrackConstraints &aConstraints, const MediaEnginePrefs &aPrefs); + nsresult Restart(const dom::MediaTrackConstraints &aConstraints, + const MediaEnginePrefs &aPrefs); }; // we could add MediaManager if needed diff --git a/dom/media/MediaStreamTrack.cpp b/dom/media/MediaStreamTrack.cpp index b6da955bde9c..2c5d9923296b 100644 --- a/dom/media/MediaStreamTrack.cpp +++ b/dom/media/MediaStreamTrack.cpp @@ -62,5 +62,12 @@ MediaStreamTrack::Stop() mStream->StopTrack(mTrackID); } +already_AddRefed +MediaStreamTrack::ApplyConstraints(const MediaTrackConstraints& aConstraints, + ErrorResult &aRv) +{ + return mStream->ApplyConstraintsToTrack(mTrackID, aConstraints, aRv); +} + } // namespace dom } // namespace mozilla diff --git a/dom/media/MediaStreamTrack.h b/dom/media/MediaStreamTrack.h index baaaf8bd44e0..210bc70942b7 100644 --- a/dom/media/MediaStreamTrack.h +++ b/dom/media/MediaStreamTrack.h @@ -9,6 +9,7 @@ #include "mozilla/DOMEventTargetHelper.h" #include "nsID.h" #include "StreamBuffer.h" +#include "MediaTrackConstraints.h" namespace mozilla { @@ -49,6 +50,8 @@ public: bool Enabled() { return mEnabled; } void SetEnabled(bool aEnabled); void Stop(); + already_AddRefed + ApplyConstraints(const dom::MediaTrackConstraints& aConstraints, ErrorResult &aRv); // Notifications from the MediaStreamGraph void NotifyEnded() { mEnded = true; } diff --git a/dom/media/webrtc/MediaEngine.h b/dom/media/webrtc/MediaEngine.h index e5400a12a6d4..fd71e8f0a486 100644 --- a/dom/media/webrtc/MediaEngine.h +++ b/dom/media/webrtc/MediaEngine.h @@ -111,6 +111,11 @@ public: /* Stop the device and release the corresponding MediaStream */ virtual nsresult Stop(SourceMediaStream *aSource, TrackID aID) = 0; + /* Restart with new capability */ + virtual nsresult Restart(const dom::MediaTrackConstraints& aConstraints, + const MediaEnginePrefs &aPrefs, + const nsString& aDeviceId) = 0; + /* Change device configuration. */ virtual nsresult Config(bool aEchoOn, uint32_t aEcho, bool aAgcOn, uint32_t aAGC, diff --git a/dom/media/webrtc/MediaEngineDefault.cpp b/dom/media/webrtc/MediaEngineDefault.cpp index 04ce46eee581..612255e3380e 100644 --- a/dom/media/webrtc/MediaEngineDefault.cpp +++ b/dom/media/webrtc/MediaEngineDefault.cpp @@ -201,6 +201,14 @@ MediaEngineDefaultVideoSource::Stop(SourceMediaStream *aSource, TrackID aID) return NS_OK; } +nsresult +MediaEngineDefaultVideoSource::Restart(const dom::MediaTrackConstraints& aConstraints, + const MediaEnginePrefs &aPrefs, + const nsString& aDeviceId) +{ + return NS_OK; +} + NS_IMETHODIMP MediaEngineDefaultVideoSource::Notify(nsITimer* aTimer) { @@ -470,6 +478,14 @@ MediaEngineDefaultAudioSource::Stop(SourceMediaStream *aSource, TrackID aID) return NS_OK; } +nsresult +MediaEngineDefaultAudioSource::Restart(const dom::MediaTrackConstraints& aConstraints, + const MediaEnginePrefs &aPrefs, + const nsString& aDeviceId) +{ + return NS_OK; +} + NS_IMETHODIMP MediaEngineDefaultAudioSource::Notify(nsITimer* aTimer) { diff --git a/dom/media/webrtc/MediaEngineDefault.h b/dom/media/webrtc/MediaEngineDefault.h index 1bc6d0c4a920..9485262f3ce9 100644 --- a/dom/media/webrtc/MediaEngineDefault.h +++ b/dom/media/webrtc/MediaEngineDefault.h @@ -49,6 +49,9 @@ public: virtual nsresult Deallocate() override; virtual nsresult Start(SourceMediaStream*, TrackID) override; virtual nsresult Stop(SourceMediaStream*, TrackID) override; + virtual nsresult Restart(const dom::MediaTrackConstraints& aConstraints, + const MediaEnginePrefs &aPrefs, + const nsString& aDeviceId) override; virtual void SetDirectListeners(bool aHasDirectListeners) override {}; virtual nsresult Config(bool aEchoOn, uint32_t aEcho, bool aAgcOn, uint32_t aAGC, @@ -119,6 +122,9 @@ public: virtual nsresult Deallocate() override; virtual nsresult Start(SourceMediaStream*, TrackID) override; virtual nsresult Stop(SourceMediaStream*, TrackID) override; + virtual nsresult Restart(const dom::MediaTrackConstraints& aConstraints, + const MediaEnginePrefs &aPrefs, + const nsString& aDeviceId) override; virtual void SetDirectListeners(bool aHasDirectListeners) override {}; virtual nsresult Config(bool aEchoOn, uint32_t aEcho, bool aAgcOn, uint32_t aAGC, diff --git a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp index c6966c8419ba..5639aa41dd82 100644 --- a/dom/media/webrtc/MediaEngineGonkVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineGonkVideoSource.cpp @@ -328,6 +328,14 @@ MediaEngineGonkVideoSource::Stop(SourceMediaStream* aSource, TrackID aID) return NS_OK; } +nsresult +MediaEngineGonkVideoSource::Restart(const dom::MediaTrackConstraints& aConstraints, + const MediaEnginePrefs& aPrefs, + const nsString& aDeviceId) +{ + return NS_OK; +} + /** * Initialization and Shutdown functions for the video source, called by the * constructor and destructor respectively. diff --git a/dom/media/webrtc/MediaEngineGonkVideoSource.h b/dom/media/webrtc/MediaEngineGonkVideoSource.h index 78a67487a775..faf362da729a 100644 --- a/dom/media/webrtc/MediaEngineGonkVideoSource.h +++ b/dom/media/webrtc/MediaEngineGonkVideoSource.h @@ -66,6 +66,9 @@ public: virtual nsresult Deallocate() override; virtual nsresult Start(SourceMediaStream* aStream, TrackID aID) override; virtual nsresult Stop(SourceMediaStream* aSource, TrackID aID) override; + virtual nsresult Restart(const dom::MediaTrackConstraints& aConstraints, + const MediaEnginePrefs &aPrefs, + const nsString& aDeviceId) override; virtual void NotifyPull(MediaStreamGraph* aGraph, SourceMediaStream* aSource, TrackID aId, diff --git a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp index 21939493737a..ecc786e9b4dd 100644 --- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp @@ -212,6 +212,24 @@ MediaEngineRemoteVideoSource::Stop(mozilla::SourceMediaStream* aSource, return NS_OK; } +nsresult +MediaEngineRemoteVideoSource::Restart(const dom::MediaTrackConstraints& aConstraints, + const MediaEnginePrefs& aPrefs, + const nsString& aDeviceId) +{ + if (mState == kStarted && mInitDone && + ChooseCapability(aConstraints, aPrefs, aDeviceId)) { + mozilla::camera::StopCapture(mCapEngine, mCaptureIndex); + if (mozilla::camera::StartCapture(mCapEngine, + mCaptureIndex, mCapability, this)) { + LOG(("StartCapture failed")); + return NS_ERROR_FAILURE; + } + } + + return NS_OK; +} + void MediaEngineRemoteVideoSource::NotifyPull(MediaStreamGraph* aGraph, SourceMediaStream* aSource, diff --git a/dom/media/webrtc/MediaEngineRemoteVideoSource.h b/dom/media/webrtc/MediaEngineRemoteVideoSource.h index 6e373225d867..70b1cb4b4d1e 100644 --- a/dom/media/webrtc/MediaEngineRemoteVideoSource.h +++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.h @@ -71,6 +71,9 @@ public: virtual nsresult Deallocate() override;; virtual nsresult Start(SourceMediaStream*, TrackID) override; virtual nsresult Stop(SourceMediaStream*, TrackID) override; + virtual nsresult Restart(const dom::MediaTrackConstraints& aConstraints, + const MediaEnginePrefs &aPrefs, + const nsString& aDeviceId) override; virtual void NotifyPull(MediaStreamGraph* aGraph, SourceMediaStream* aSource, TrackID aId, diff --git a/dom/media/webrtc/MediaEngineTabVideoSource.cpp b/dom/media/webrtc/MediaEngineTabVideoSource.cpp index b53c2991bc68..7d5ff9a5a8f5 100644 --- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp @@ -291,6 +291,15 @@ MediaEngineTabVideoSource::Stop(mozilla::SourceMediaStream*, mozilla::TrackID) return NS_OK; } +nsresult +MediaEngineTabVideoSource::Restart(const dom::MediaTrackConstraints& aConstraints, + const mozilla::MediaEnginePrefs& aPrefs, + const nsString& aDeviceId) +{ + // TODO + return NS_OK; +} + nsresult MediaEngineTabVideoSource::Config(bool, uint32_t, bool, uint32_t, bool, uint32_t, int32_t) { diff --git a/dom/media/webrtc/MediaEngineTabVideoSource.h b/dom/media/webrtc/MediaEngineTabVideoSource.h index 5e1b1e38abce..78e5e0e8b39a 100644 --- a/dom/media/webrtc/MediaEngineTabVideoSource.h +++ b/dom/media/webrtc/MediaEngineTabVideoSource.h @@ -29,6 +29,9 @@ class MediaEngineTabVideoSource : public MediaEngineVideoSource, nsIDOMEventList virtual void SetDirectListeners(bool aHasDirectListeners) override {}; virtual void NotifyPull(mozilla::MediaStreamGraph*, mozilla::SourceMediaStream*, mozilla::TrackID, mozilla::StreamTime) override; virtual nsresult Stop(mozilla::SourceMediaStream*, mozilla::TrackID) override; + virtual nsresult Restart(const dom::MediaTrackConstraints& aConstraints, + const mozilla::MediaEnginePrefs& aPrefs, + const nsString& aDeviceId) override; virtual nsresult Config(bool, uint32_t, bool, uint32_t, bool, uint32_t, int32_t) override; virtual bool IsFake() override; virtual const dom::MediaSourceEnum GetMediaSource() override { diff --git a/dom/media/webrtc/MediaEngineWebRTC.h b/dom/media/webrtc/MediaEngineWebRTC.h index 2ec0797059b7..6cf470727dc1 100644 --- a/dom/media/webrtc/MediaEngineWebRTC.h +++ b/dom/media/webrtc/MediaEngineWebRTC.h @@ -84,6 +84,9 @@ public: } nsresult Start(SourceMediaStream* aMediaStream, TrackID aId) override; nsresult Stop(SourceMediaStream* aMediaStream, TrackID aId) override; + nsresult Restart(const dom::MediaTrackConstraints& aConstraints, + const MediaEnginePrefs &aPrefs, + const nsString& aDeviceId) override; void SetDirectListeners(bool aDirect) override {} nsresult Config(bool aEchoOn, uint32_t aEcho, bool aAgcOn, @@ -155,6 +158,9 @@ public: virtual nsresult Deallocate() override; virtual nsresult Start(SourceMediaStream* aStream, TrackID aID) override; virtual nsresult Stop(SourceMediaStream* aSource, TrackID aID) override; + virtual nsresult Restart(const dom::MediaTrackConstraints& aConstraints, + const MediaEnginePrefs &aPrefs, + const nsString& aDeviceId) override; virtual void SetDirectListeners(bool aHasDirectListeners) override {}; virtual nsresult Config(bool aEchoOn, uint32_t aEcho, bool aAgcOn, uint32_t aAGC, diff --git a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp index c45beae4ce24..da3f2d86572a 100644 --- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp +++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp @@ -422,6 +422,14 @@ MediaEngineWebRTCMicrophoneSource::Stop(SourceMediaStream *aSource, TrackID aID) return NS_OK; } +nsresult +MediaEngineWebRTCMicrophoneSource::Restart(const dom::MediaTrackConstraints& aConstraints, + const MediaEnginePrefs &aPrefs, + const nsString& aDeviceId) +{ + return NS_OK; +} + void MediaEngineWebRTCMicrophoneSource::NotifyPull(MediaStreamGraph *aGraph, SourceMediaStream *aSource, @@ -664,6 +672,15 @@ MediaEngineWebRTCAudioCaptureSource::Stop(SourceMediaStream *aMediaStream, return NS_OK; } +nsresult +MediaEngineWebRTCAudioCaptureSource::Restart( + const dom::MediaTrackConstraints& aConstraints, + const MediaEnginePrefs &aPrefs, + const nsString& aDeviceId) +{ + return NS_OK; +} + uint32_t MediaEngineWebRTCAudioCaptureSource::GetBestFitnessDistance( const nsTArray& aConstraintSets, From 17d85435b2c365880bfacbebed132e3ac4e0ab8a Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Sat, 19 Sep 2015 00:49:07 -0400 Subject: [PATCH 05/29] Bug 912342 - Pass in Audio/VideoDevice in place of Audio/VideoSource. r=jesup --HG-- extra : commitid : KyF5JvNyJbV extra : rebase_source : e8fc7ff48eb38d5df55cd685e187a2069f66d6de --- dom/media/MediaManager.cpp | 163 ++++++++++++++++++----------------- dom/media/MediaManager.h | 169 +++++++++++++++++++------------------ 2 files changed, 169 insertions(+), 163 deletions(-) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 3f161b274c1a..b63b7a8f674f 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -226,8 +226,8 @@ public: GetUserMediaCallbackMediaStreamListener* aListener, DOMMediaStream* aStream, DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback, - MediaEngineSource* aAudioSource, - MediaEngineSource* aVideoSource, + AudioDevice* aAudioDevice, + VideoDevice* aVideoDevice, bool aBool, uint64_t aWindowID, already_AddRefed aError, @@ -235,8 +235,8 @@ public: : mType(aType) , mStream(aStream) , mOnTracksAvailableCallback(aOnTracksAvailableCallback) - , mAudioSource(aAudioSource) - , mVideoSource(aVideoSource) + , mAudioDevice(aAudioDevice) + , mVideoDevice(aVideoDevice) , mListener(aListener) , mBool(aBool) , mWindowID(aWindowID) @@ -267,15 +267,15 @@ public: NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); nsresult rv; - if (mAudioSource) { - rv = mAudioSource->Start(source, kAudioTrack); + if (mAudioDevice) { + rv = mAudioDevice->GetSource()->Start(source, kAudioTrack); if (NS_FAILED(rv)) { ReturnCallbackError(rv, "Starting audio failed"); return; } } - if (mVideoSource) { - rv = mVideoSource->Start(source, kVideoTrack); + if (mVideoDevice) { + rv = mVideoDevice->GetSource()->Start(source, kVideoTrack); if (NS_FAILED(rv)) { ReturnCallbackError(rv, "Starting video failed"); return; @@ -295,8 +295,8 @@ public: new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING, mStream.forget(), mOnTracksAvailableCallback.forget(), - mAudioSource != nullptr, - mVideoSource != nullptr, + mAudioDevice != nullptr, + mVideoDevice != nullptr, mWindowID, mOnFailure.forget()); // event must always be released on mainthread due to the JS callbacks // in the TracksAvailableCallback @@ -308,13 +308,13 @@ public: case MEDIA_STOP_TRACK: { NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); - if (mAudioSource) { - mAudioSource->Stop(source, kAudioTrack); - mAudioSource->Deallocate(); + if (mAudioDevice) { + mAudioDevice->GetSource()->Stop(source, kAudioTrack); + mAudioDevice->GetSource()->Deallocate(); } - if (mVideoSource) { - mVideoSource->Stop(source, kVideoTrack); - mVideoSource->Deallocate(); + if (mVideoDevice) { + mVideoDevice->GetSource()->Stop(source, kVideoTrack); + mVideoDevice->GetSource()->Deallocate(); } // Do this after stopping all tracks with EndTrack() if (mBool) { @@ -326,8 +326,8 @@ public: mType == MEDIA_STOP ? GetUserMediaNotificationEvent::STOPPING : GetUserMediaNotificationEvent::STOPPED_TRACK, - mAudioSource != nullptr, - mVideoSource != nullptr, + mAudioDevice != nullptr, + mVideoDevice != nullptr, mWindowID); // event must always be released on mainthread due to the JS callbacks // in the TracksAvailableCallback @@ -340,11 +340,11 @@ public: nsRefPtr mgr = MediaManager::GetInstance(); NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); - if (mAudioSource) { - mAudioSource->Restart(mConstraints, mgr->mPrefs); + if (mAudioDevice) { + mAudioDevice->Restart(mConstraints, mgr->mPrefs); } - if (mVideoSource) { - mVideoSource->Restart(mConstraints, mgr->mPrefs); + if (mVideoDevice) { + mVideoDevice->Restart(mConstraints, mgr->mPrefs); } // Need to dispatch something back to main to resolve promise @@ -352,8 +352,8 @@ public: nsIRunnable *event = new GetUserMediaNotificationEvent(mListener, GetUserMediaNotificationEvent::APPLIED_CONSTRAINTS, - mAudioSource != nullptr, - mVideoSource != nullptr, + mAudioDevice != nullptr, + mVideoDevice != nullptr, mWindowID); // event must always be released on mainthread due to the JS callbacks // in the TracksAvailableCallback @@ -364,8 +364,8 @@ public: case MEDIA_DIRECT_LISTENERS: { NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); - if (mVideoSource) { - mVideoSource->SetDirectListeners(mBool); + if (mVideoDevice) { + mVideoDevice->GetSource()->SetDirectListeners(mBool); } } break; @@ -380,8 +380,8 @@ private: MediaOperation mType; nsRefPtr mStream; nsAutoPtr mOnTracksAvailableCallback; - nsRefPtr mAudioSource; // threadsafe - nsRefPtr mVideoSource; // threadsafe + nsRefPtr mAudioDevice; // threadsafe + nsRefPtr mVideoDevice; // threadsafe nsRefPtr mListener; // threadsafe bool mBool; uint64_t mWindowID; @@ -665,23 +665,23 @@ public: static already_AddRefed CreateTrackUnionStream(nsIDOMWindow* aWindow, GetUserMediaCallbackMediaStreamListener* aListener, - MediaEngineSource* aAudioSource, - MediaEngineSource* aVideoSource, + AudioDevice* aAudioDevice, + VideoDevice* aVideoDevice, MediaStreamGraph* aMSG) { nsRefPtr stream = new nsDOMUserMediaStream(aListener, - aAudioSource, - aVideoSource); + aAudioDevice, + aVideoDevice); stream->InitTrackUnionStream(aWindow, aMSG); return stream.forget(); } nsDOMUserMediaStream(GetUserMediaCallbackMediaStreamListener* aListener, - MediaEngineSource *aAudioSource, - MediaEngineSource *aVideoSource) : + AudioDevice *aAudioDevice, + VideoDevice *aVideoDevice) : mListener(aListener), - mAudioSource(aAudioSource), - mVideoSource(aVideoSource), + mAudioDevice(aAudioDevice), + mVideoDevice(aVideoDevice), mEchoOn(true), mAgcOn(false), mNoiseOn(true), @@ -826,10 +826,10 @@ public: // MediaEngine supports only one video and on video track now and TrackID is // fixed in MediaEngine. if (aTrackID == kVideoTrack) { - return mVideoSource; + return mVideoDevice ? mVideoDevice->GetSource() : nullptr; } else if (aTrackID == kAudioTrack) { - return mAudioSource; + return mAudioDevice ? mAudioDevice->GetSource() : nullptr; } return nullptr; @@ -840,8 +840,8 @@ public: nsRefPtr mSourceStream; nsRefPtr mPort; nsRefPtr mListener; - nsRefPtr mAudioSource; // so we can turn on AEC - nsRefPtr mVideoSource; + nsRefPtr mAudioDevice; // so we can turn on AEC + nsRefPtr mVideoDevice; bool mEchoOn; bool mAgcOn; bool mNoiseOn; @@ -894,11 +894,11 @@ public: uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener* aListener, const nsCString& aOrigin, - MediaEngineSource* aAudioSource, - MediaEngineSource* aVideoSource, + AudioDevice* aAudioDevice, + VideoDevice* aVideoDevice, PeerIdentity* aPeerIdentity) - : mAudioSource(aAudioSource) - , mVideoSource(aVideoSource) + : mAudioDevice(aAudioDevice) + , mVideoDevice(aVideoDevice) , mWindowID(aWindowID) , mListener(aListener) , mOrigin(aOrigin) @@ -995,7 +995,7 @@ public: #endif MediaStreamGraph::GraphDriverType graphDriverType = - mAudioSource ? MediaStreamGraph::AUDIO_THREAD_DRIVER + mAudioDevice ? MediaStreamGraph::AUDIO_THREAD_DRIVER : MediaStreamGraph::SYSTEM_THREAD_DRIVER; MediaStreamGraph* msg = MediaStreamGraph::GetInstance(graphDriverType, @@ -1008,8 +1008,8 @@ public: // using the audio source and the SourceMediaStream, which acts as // placeholders. We re-route a number of stream internaly in the MSG and mix // them down instead. - if (mAudioSource && - mAudioSource->GetMediaSource() == dom::MediaSourceEnum::AudioCapture) { + if (mAudioDevice && + mAudioDevice->GetMediaSource() == dom::MediaSourceEnum::AudioCapture) { domStream = DOMLocalMediaStream::CreateAudioCaptureStream(window, msg); // It should be possible to pipe the capture stream to anything. CORS is // not a problem here, we got explicit user content. @@ -1022,7 +1022,7 @@ public: // avoid us blocking nsRefPtr trackunion = nsDOMUserMediaStream::CreateTrackUnionStream(window, mListener, - mAudioSource, mVideoSource, + mAudioDevice, mVideoDevice, msg); trackunion->GetStream()->AsProcessedStream()->SetAutofinish(true); nsRefPtr port = trackunion->GetStream()->AsProcessedStream()-> @@ -1067,7 +1067,7 @@ public: // Activate our listener. We'll call Start() on the source when get a callback // that the MediaStream has started consuming. The listener is freed // when the page is invalidated (on navigation or close). - mListener->Activate(stream.forget(), mAudioSource, mVideoSource); + mListener->Activate(stream.forget(), mAudioDevice, mVideoDevice); // Note: includes JS callbacks; must be released on MainThread TracksAvailableCallback* tracksAvailableCallback = @@ -1082,11 +1082,11 @@ public: // because that can take a while. // Pass ownership of trackunion to the MediaOperationTask // to ensure it's kept alive until the MediaOperationTask runs (at least). - MediaManager::PostTask( - FROM_HERE, new MediaOperationTask(MEDIA_START, mListener, domStream, - tracksAvailableCallback, mAudioSource, - mVideoSource, false, mWindowID, - mOnFailure.forget())); + MediaManager::PostTask(FROM_HERE, + new MediaOperationTask(MEDIA_START, mListener, domStream, + tracksAvailableCallback, + mAudioDevice, mVideoDevice, + false, mWindowID, mOnFailure.forget())); // We won't need mOnFailure now. mOnFailure = nullptr; @@ -1101,8 +1101,8 @@ public: private: nsCOMPtr mOnSuccess; nsCOMPtr mOnFailure; - nsRefPtr mAudioSource; - nsRefPtr mVideoSource; + nsRefPtr mAudioDevice; + nsRefPtr mVideoDevice; uint64_t mWindowID; nsRefPtr mListener; nsCString mOrigin; @@ -1408,13 +1408,10 @@ public: peerIdentity = new PeerIdentity(mConstraints.mPeerIdentity); } - NS_DispatchToMainThread(do_AddRef(new GetUserMediaStreamRunnable( - mOnSuccess, mOnFailure, mWindowID, mListener, mOrigin, - (mAudioDevice? mAudioDevice->GetSource() : nullptr), - (mVideoDevice? mVideoDevice->GetSource() : nullptr), - peerIdentity - ))); - + NS_DispatchToMainThread(do_AddRef( + new GetUserMediaStreamRunnable(mOnSuccess, mOnFailure, mWindowID, + mListener, mOrigin, mAudioDevice, + mVideoDevice, peerIdentity))); MOZ_ASSERT(!mOnSuccess); MOZ_ASSERT(!mOnFailure); } @@ -3135,10 +3132,10 @@ GetUserMediaCallbackMediaStreamListener::AudioConfig(bool aEchoOn, bool aNoiseOn, uint32_t aNoise, int32_t aPlayoutDelay) { - if (mAudioSource) { + if (mAudioDevice) { #ifdef MOZ_WEBRTC MediaManager::PostTask(FROM_HERE, - NewRunnableMethod(mAudioSource.get(), &MediaEngineSource::Config, + NewRunnableMethod(mAudioDevice->GetSource(), &MediaEngineSource::Config, aEchoOn, aEcho, aAgcOn, aAGC, aNoiseOn, aNoise, aPlayoutDelay)); #endif @@ -3156,7 +3153,7 @@ GetUserMediaCallbackMediaStreamListener::Invalidate() MediaManager::PostTask(FROM_HERE, new MediaOperationTask(MEDIA_STOP, this, nullptr, nullptr, - mAudioSource, mVideoSource, + mAudioDevice, mVideoDevice, mFinished, mWindowID, nullptr)); } @@ -3166,18 +3163,18 @@ void GetUserMediaCallbackMediaStreamListener::StopSharing() { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); - if (mVideoSource && !mStopped && - (mVideoSource->GetMediaSource() == dom::MediaSourceEnum::Screen || - mVideoSource->GetMediaSource() == dom::MediaSourceEnum::Application || - mVideoSource->GetMediaSource() == dom::MediaSourceEnum::Window)) { + if (mVideoDevice && !mStopped && + (mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Screen || + mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Application || + mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Window)) { // Stop the whole stream if there's no audio; just the video track if we have both MediaManager::PostTask(FROM_HERE, - new MediaOperationTask(mAudioSource ? MEDIA_STOP_TRACK : MEDIA_STOP, + new MediaOperationTask(mAudioDevice ? MEDIA_STOP_TRACK : MEDIA_STOP, this, nullptr, nullptr, - nullptr, mVideoSource, + nullptr, mVideoDevice, mFinished, mWindowID, nullptr)); - } else if (mAudioSource && - mAudioSource->GetMediaSource() == dom::MediaSourceEnum::AudioCapture) { + } else if (mAudioDevice && + mAudioDevice->GetMediaSource() == dom::MediaSourceEnum::AudioCapture) { nsCOMPtr window = nsGlobalWindow::GetInnerWindowWithId(mWindowID); MOZ_ASSERT(window); window->SetAudioCapture(false); @@ -3197,16 +3194,16 @@ GetUserMediaCallbackMediaStreamListener::ApplyConstraintsToTrack( bool aIsAudio, const MediaTrackConstraints& aConstraints) { - if (((aIsAudio && mAudioSource) || - (!aIsAudio && mVideoSource)) && !mStopped) + if (((aIsAudio && mAudioDevice) || + (!aIsAudio && mVideoDevice)) && !mStopped) { // XXX to support multiple tracks of a type in a stream, this should key off // the TrackID and not just the type MediaManager::PostTask(FROM_HERE, new MediaOperationTask(MEDIA_APPLYCONSTRAINTS_TRACK, this, nullptr, nullptr, - aIsAudio ? mAudioSource.get() : nullptr, - !aIsAudio ? mVideoSource.get() : nullptr, + aIsAudio ? mAudioDevice.get() : nullptr, + !aIsAudio ? mVideoDevice.get() : nullptr, mFinished, mWindowID, nullptr, aConstraints)); } else { LOG(("gUM track %d applyConstraints, but we don't have type %s", @@ -3219,16 +3216,16 @@ GetUserMediaCallbackMediaStreamListener::ApplyConstraintsToTrack( void GetUserMediaCallbackMediaStreamListener::StopTrack(TrackID aID, bool aIsAudio) { - if (((aIsAudio && mAudioSource) || - (!aIsAudio && mVideoSource)) && !mStopped) + if (((aIsAudio && mAudioDevice) || + (!aIsAudio && mVideoDevice)) && !mStopped) { // XXX to support multiple tracks of a type in a stream, this should key off // the TrackID and not just the type MediaManager::PostTask(FROM_HERE, new MediaOperationTask(MEDIA_STOP_TRACK, this, nullptr, nullptr, - aIsAudio ? mAudioSource.get() : nullptr, - !aIsAudio ? mVideoSource.get() : nullptr, + aIsAudio ? mAudioDevice.get() : nullptr, + !aIsAudio ? mVideoDevice.get() : nullptr, mFinished, mWindowID, nullptr)); } else { LOG(("gUM track %d ended, but we don't have type %s", @@ -3253,7 +3250,7 @@ GetUserMediaCallbackMediaStreamListener::NotifyDirectListeners(MediaStreamGraph* MediaManager::PostTask(FROM_HERE, new MediaOperationTask(MEDIA_DIRECT_LISTENERS, this, nullptr, nullptr, - mAudioSource, mVideoSource, + mAudioDevice, mVideoDevice, aHasListeners, mWindowID, nullptr)); } diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index 76e711d131b0..41dcb1a472d3 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -54,6 +54,65 @@ struct MediaTrackConstraintSet; extern PRLogModuleInfo* GetMediaManagerLog(); #define MM_LOG(msg) MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Debug, msg) +class MediaDevice : public nsIMediaDevice +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIMEDIADEVICE + + void SetId(const nsAString& aID); + virtual uint32_t GetBestFitnessDistance( + const nsTArray& aConstraintSets); +protected: + virtual ~MediaDevice() {} + explicit MediaDevice(MediaEngineSource* aSource, bool aIsVideo); + static uint32_t FitnessDistance(nsString aN, + const dom::OwningStringOrStringSequenceOrConstrainDOMStringParameters& aConstraint); +private: + static bool StringsContain(const dom::OwningStringOrStringSequence& aStrings, + nsString aN); + static uint32_t FitnessDistance(nsString aN, + const dom::ConstrainDOMStringParameters& aParams); +protected: + nsString mName; + nsString mID; + dom::MediaSourceEnum mMediaSource; + nsRefPtr mSource; +public: + dom::MediaSourceEnum GetMediaSource() { + return mMediaSource; + } + bool mIsVideo; +}; + +class VideoDevice : public MediaDevice +{ +public: + typedef MediaEngineVideoSource Source; + + explicit VideoDevice(Source* aSource); + NS_IMETHOD GetType(nsAString& aType); + Source* GetSource(); + nsresult Allocate(const dom::MediaTrackConstraints &aConstraints, + const MediaEnginePrefs &aPrefs); + nsresult Restart(const dom::MediaTrackConstraints &aConstraints, + const MediaEnginePrefs &aPrefs); +}; + +class AudioDevice : public MediaDevice +{ +public: + typedef MediaEngineAudioSource Source; + + explicit AudioDevice(Source* aSource); + NS_IMETHOD GetType(nsAString& aType); + Source* GetSource(); + nsresult Allocate(const dom::MediaTrackConstraints &aConstraints, + const MediaEnginePrefs &aPrefs); + nsresult Restart(const dom::MediaTrackConstraints &aConstraints, + const MediaEnginePrefs &aPrefs); +}; + /** * This class is an implementation of MediaStreamListener. This is used * to Start() and Stop() the underlying MediaEngineSource when MediaStreams @@ -80,13 +139,13 @@ public: } void Activate(already_AddRefed aStream, - MediaEngineSource* aAudioSource, - MediaEngineSource* aVideoSource) + AudioDevice* aAudioDevice, + VideoDevice* aVideoDevice) { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); mStream = aStream; - mAudioSource = aAudioSource; - mVideoSource = aVideoSource; + mAudioDevice = aAudioDevice; + mVideoDevice = aVideoDevice; mStream->AddListener(this); } @@ -111,46 +170,50 @@ public: void ApplyConstraintsToTrack(TrackID aID, bool aIsAudio, const dom::MediaTrackConstraints& aConstraints); - // mVideo/AudioSource are set by Activate(), so we assume they're capturing + // mVideo/AudioDevice are set by Activate(), so we assume they're capturing // if set and represent a real capture device. bool CapturingVideo() { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); - return mVideoSource && !mStopped && - mVideoSource->GetMediaSource() == dom::MediaSourceEnum::Camera && - (!mVideoSource->IsFake() || + return mVideoDevice && !mStopped && + mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Camera && + (!mVideoDevice->GetSource()->IsFake() || Preferences::GetBool("media.navigator.permission.fake")); } bool CapturingAudio() { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); - return mAudioSource && !mStopped && - (!mAudioSource->IsFake() || + return mAudioDevice && !mStopped && + (!mAudioDevice->GetSource()->IsFake() || Preferences::GetBool("media.navigator.permission.fake")); } bool CapturingScreen() { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); - return mVideoSource && !mStopped && !mVideoSource->IsAvailable() && - mVideoSource->GetMediaSource() == dom::MediaSourceEnum::Screen; + return mVideoDevice && !mStopped && + !mVideoDevice->GetSource()->IsAvailable() && + mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Screen; } bool CapturingWindow() { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); - return mVideoSource && !mStopped && !mVideoSource->IsAvailable() && - mVideoSource->GetMediaSource() == dom::MediaSourceEnum::Window; + return mVideoDevice && !mStopped && + !mVideoDevice->GetSource()->IsAvailable() && + mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Window; } bool CapturingApplication() { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); - return mVideoSource && !mStopped && !mVideoSource->IsAvailable() && - mVideoSource->GetMediaSource() == dom::MediaSourceEnum::Application; + return mVideoDevice && !mStopped && + !mVideoDevice->GetSource()->IsAvailable() && + mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Application; } bool CapturingBrowser() { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); - return mVideoSource && !mStopped && mVideoSource->IsAvailable() && - mVideoSource->GetMediaSource() == dom::MediaSourceEnum::Browser; + return mVideoDevice && !mStopped && + mVideoDevice->GetSource()->IsAvailable() && + mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Browser; } void SetStopped() @@ -191,11 +254,13 @@ public: { // Currently audio sources ignore NotifyPull, but they could // watch it especially for fake audio. - if (mAudioSource) { - mAudioSource->NotifyPull(aGraph, mStream, kAudioTrack, aDesiredTime); + if (mAudioDevice) { + mAudioDevice->GetSource()->NotifyPull(aGraph, mStream, kAudioTrack, + aDesiredTime); } - if (mVideoSource) { - mVideoSource->NotifyPull(aGraph, mStream, kVideoTrack, aDesiredTime); + if (mVideoDevice) { + mVideoDevice->GetSource()->NotifyPull(aGraph, mStream, kVideoTrack, + aDesiredTime); } } @@ -241,8 +306,8 @@ private: // Accessed from MediaStreamGraph thread, MediaManager thread, and MainThread // No locking needed as they're only addrefed except on the MediaManager thread - nsRefPtr mAudioSource; // threadsafe refcnt - nsRefPtr mVideoSource; // threadsafe refcnt + nsRefPtr mAudioDevice; // threadsafe refcnt + nsRefPtr mVideoDevice; // threadsafe refcnt nsRefPtr mStream; // threadsafe refcnt bool mFinished; @@ -319,62 +384,6 @@ private: typedef nsTArray > StreamListeners; typedef nsClassHashtable WindowTable; -class MediaDevice : public nsIMediaDevice -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIMEDIADEVICE - - void SetId(const nsAString& aID); - virtual uint32_t GetBestFitnessDistance( - const nsTArray& aConstraintSets); -protected: - virtual ~MediaDevice() {} - explicit MediaDevice(MediaEngineSource* aSource, bool aIsVideo); - static uint32_t FitnessDistance(nsString aN, - const dom::OwningStringOrStringSequenceOrConstrainDOMStringParameters& aConstraint); -private: - static bool StringsContain(const dom::OwningStringOrStringSequence& aStrings, - nsString aN); - static uint32_t FitnessDistance(nsString aN, - const dom::ConstrainDOMStringParameters& aParams); -protected: - nsString mName; - nsString mID; - dom::MediaSourceEnum mMediaSource; - nsRefPtr mSource; -public: - bool mIsVideo; -}; - -class VideoDevice : public MediaDevice -{ -public: - typedef MediaEngineVideoSource Source; - - explicit VideoDevice(Source* aSource); - NS_IMETHOD GetType(nsAString& aType); - Source* GetSource(); - nsresult Allocate(const dom::MediaTrackConstraints &aConstraints, - const MediaEnginePrefs &aPrefs); - nsresult Restart(const dom::MediaTrackConstraints &aConstraints, - const MediaEnginePrefs &aPrefs); -}; - -class AudioDevice : public MediaDevice -{ -public: - typedef MediaEngineAudioSource Source; - - explicit AudioDevice(Source* aSource); - NS_IMETHOD GetType(nsAString& aType); - Source* GetSource(); - nsresult Allocate(const dom::MediaTrackConstraints &aConstraints, - const MediaEnginePrefs &aPrefs); - nsresult Restart(const dom::MediaTrackConstraints &aConstraints, - const MediaEnginePrefs &aPrefs); -}; - // we could add MediaManager if needed typedef void (*WindowListenerCallback)(MediaManager *aThis, uint64_t aWindowID, From 5c97b1be39322b2d95eaeb70c71357d21ace22ae Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Sat, 19 Sep 2015 02:00:48 -0400 Subject: [PATCH 06/29] Bug 912342 - Move code SelectSettings to MediaConstraintsHelper. r=jesup --HG-- extra : commitid : IHOcGmMAzno extra : rebase_source : 371c265877854d57f094583066b145aae50ed638 --- dom/media/MediaManager.cpp | 129 +---------------------- dom/media/webrtc/MediaTrackConstraints.h | 124 ++++++++++++++++++++++ 2 files changed, 128 insertions(+), 125 deletions(-) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index b63b7a8f674f..d7af03430787 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -79,8 +79,6 @@ #include "mozilla/WindowsVersion.h" #endif -#include - // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to // GetTickCount() and conflicts with MediaStream::GetCurrentTime. #ifdef GetCurrentTime @@ -1157,127 +1155,6 @@ GetSources(MediaEngine *engine, dom::MediaSourceEnum aSrcType, } } -template -static bool -AreUnfitSettings(const MediaTrackConstraints &aConstraints, - nsTArray>& aSources) -{ - nsTArray aggregateConstraints; - aggregateConstraints.AppendElement(&aConstraints); - - for (auto& source : aSources) { - if (source->GetBestFitnessDistance(aggregateConstraints) != UINT32_MAX) { - return false; - } - } - return true; -} - -// Apply constrains to a supplied list of sources (removes items from the list) - -template -static const char* -SelectSettings(const MediaTrackConstraints &aConstraints, - nsTArray>& aSources) -{ - auto& c = aConstraints; - - // First apply top-level constraints. - - // Stack constraintSets that pass, starting with the required one, because the - // whole stack must be re-satisfied each time a capability-set is ruled out - // (this avoids storing state or pushing algorithm into the lower-level code). - nsTArray> unsatisfactory; - nsTArray aggregateConstraints; - aggregateConstraints.AppendElement(&c); - - std::multimap> ordered; - - for (uint32_t i = 0; i < aSources.Length();) { - uint32_t distance = aSources[i]->GetBestFitnessDistance(aggregateConstraints); - if (distance == UINT32_MAX) { - unsatisfactory.AppendElement(aSources[i]); - aSources.RemoveElementAt(i); - } else { - ordered.insert(std::pair>(distance, - aSources[i])); - ++i; - } - } - if (!aSources.Length()) { - // None selected. The spec says to report a constraint that satisfies NONE - // of the sources. Unfortunately, this is a bit laborious to find out, and - // requires updating as new constraints are added! - - if (c.mDeviceId.IsConstrainDOMStringParameters()) { - MediaTrackConstraints fresh; - fresh.mDeviceId = c.mDeviceId; - if (AreUnfitSettings(fresh, unsatisfactory)) { - return "deviceId"; - } - } - if (c.mWidth.IsConstrainLongRange()) { - MediaTrackConstraints fresh; - fresh.mWidth = c.mWidth; - if (AreUnfitSettings(fresh, unsatisfactory)) { - return "width"; - } - } - if (c.mHeight.IsConstrainLongRange()) { - MediaTrackConstraints fresh; - fresh.mHeight = c.mHeight; - if (AreUnfitSettings(fresh, unsatisfactory)) { - return "height"; - } - } - if (c.mFrameRate.IsConstrainDoubleRange()) { - MediaTrackConstraints fresh; - fresh.mFrameRate = c.mFrameRate; - if (AreUnfitSettings(fresh, unsatisfactory)) { - return "frameRate"; - } - } - if (c.mFacingMode.IsConstrainDOMStringParameters()) { - MediaTrackConstraints fresh; - fresh.mFacingMode = c.mFacingMode; - if (AreUnfitSettings(fresh, unsatisfactory)) { - return "facingMode"; - } - } - return ""; - } - - // Order devices by shortest distance - for (auto& ordinal : ordered) { - aSources.RemoveElement(ordinal.second); - aSources.AppendElement(ordinal.second); - } - - // Then apply advanced constraints. - - if (c.mAdvanced.WasPassed()) { - auto &array = c.mAdvanced.Value(); - - for (int i = 0; i < int(array.Length()); i++) { - aggregateConstraints.AppendElement(&array[i]); - nsTArray> rejects; - for (uint32_t j = 0; j < aSources.Length();) { - if (aSources[j]->GetBestFitnessDistance(aggregateConstraints) == UINT32_MAX) { - rejects.AppendElement(aSources[j]); - aSources.RemoveElementAt(j); - } else { - ++j; - } - } - if (!aSources.Length()) { - aSources.AppendElements(Move(rejects)); - aggregateConstraints.RemoveElementAt(aggregateConstraints.Length() - 1); - } - } - } - return nullptr; -} - static const char* SelectSettings(MediaStreamConstraints &aConstraints, nsTArray>& aSources) @@ -1304,13 +1181,15 @@ SelectSettings(MediaStreamConstraints &aConstraints, const char* badConstraint = nullptr; if (IsOn(aConstraints.mVideo)) { - badConstraint = SelectSettings(GetInvariant(aConstraints.mVideo), videos); + badConstraint = MediaConstraintsHelper::SelectSettings( + GetInvariant(aConstraints.mVideo), videos); for (auto& video : videos) { aSources.AppendElement(video); } } if (audios.Length() && IsOn(aConstraints.mAudio)) { - badConstraint = SelectSettings(GetInvariant(aConstraints.mAudio), audios); + badConstraint = MediaConstraintsHelper::SelectSettings( + GetInvariant(aConstraints.mAudio), audios); for (auto& audio : audios) { aSources.AppendElement(audio); } diff --git a/dom/media/webrtc/MediaTrackConstraints.h b/dom/media/webrtc/MediaTrackConstraints.h index ac1c3414622b..bcd6cc30e209 100644 --- a/dom/media/webrtc/MediaTrackConstraints.h +++ b/dom/media/webrtc/MediaTrackConstraints.h @@ -12,6 +12,8 @@ #include "mozilla/dom/MediaTrackConstraintSetBinding.h" #include "mozilla/dom/MediaTrackSupportedConstraintsBinding.h" +#include + namespace mozilla { template @@ -104,6 +106,128 @@ protected: GetMinimumFitnessDistance(const dom::MediaTrackConstraintSet &aConstraints, bool aAdvanced, const nsString& aDeviceId); + + template + static bool + AreUnfitSettings(const dom::MediaTrackConstraints &aConstraints, + nsTArray>& aSources) + { + nsTArray aggregateConstraints; + aggregateConstraints.AppendElement(&aConstraints); + + for (auto& source : aSources) { + if (source->GetBestFitnessDistance(aggregateConstraints) != UINT32_MAX) { + return false; + } + } + return true; + } + +public: + // Apply constrains to a supplied list of sources (removes items from the list) + + template + static const char* + SelectSettings(const dom::MediaTrackConstraints &aConstraints, + nsTArray>& aSources) + { + auto& c = aConstraints; + + // First apply top-level constraints. + + // Stack constraintSets that pass, starting with the required one, because the + // whole stack must be re-satisfied each time a capability-set is ruled out + // (this avoids storing state or pushing algorithm into the lower-level code). + nsTArray> unsatisfactory; + nsTArray aggregateConstraints; + aggregateConstraints.AppendElement(&c); + + std::multimap> ordered; + + for (uint32_t i = 0; i < aSources.Length();) { + uint32_t distance = aSources[i]->GetBestFitnessDistance(aggregateConstraints); + if (distance == UINT32_MAX) { + unsatisfactory.AppendElement(aSources[i]); + aSources.RemoveElementAt(i); + } else { + ordered.insert(std::pair>(distance, + aSources[i])); + ++i; + } + } + if (!aSources.Length()) { + // None selected. The spec says to report a constraint that satisfies NONE + // of the sources. Unfortunately, this is a bit laborious to find out, and + // requires updating as new constraints are added! + + if (c.mDeviceId.IsConstrainDOMStringParameters()) { + dom::MediaTrackConstraints fresh; + fresh.mDeviceId = c.mDeviceId; + if (AreUnfitSettings(fresh, unsatisfactory)) { + return "deviceId"; + } + } + if (c.mWidth.IsConstrainLongRange()) { + dom::MediaTrackConstraints fresh; + fresh.mWidth = c.mWidth; + if (AreUnfitSettings(fresh, unsatisfactory)) { + return "width"; + } + } + if (c.mHeight.IsConstrainLongRange()) { + dom::MediaTrackConstraints fresh; + fresh.mHeight = c.mHeight; + if (AreUnfitSettings(fresh, unsatisfactory)) { + return "height"; + } + } + if (c.mFrameRate.IsConstrainDoubleRange()) { + dom::MediaTrackConstraints fresh; + fresh.mFrameRate = c.mFrameRate; + if (AreUnfitSettings(fresh, unsatisfactory)) { + return "frameRate"; + } + } + if (c.mFacingMode.IsConstrainDOMStringParameters()) { + dom::MediaTrackConstraints fresh; + fresh.mFacingMode = c.mFacingMode; + if (AreUnfitSettings(fresh, unsatisfactory)) { + return "facingMode"; + } + } + return ""; + } + + // Order devices by shortest distance + for (auto& ordinal : ordered) { + aSources.RemoveElement(ordinal.second); + aSources.AppendElement(ordinal.second); + } + + // Then apply advanced constraints. + + if (c.mAdvanced.WasPassed()) { + auto &array = c.mAdvanced.Value(); + + for (int i = 0; i < int(array.Length()); i++) { + aggregateConstraints.AppendElement(&array[i]); + nsTArray> rejects; + for (uint32_t j = 0; j < aSources.Length();) { + if (aSources[j]->GetBestFitnessDistance(aggregateConstraints) == UINT32_MAX) { + rejects.AppendElement(aSources[j]); + aSources.RemoveElementAt(j); + } else { + ++j; + } + } + if (!aSources.Length()) { + aSources.AppendElements(Move(rejects)); + aggregateConstraints.RemoveElementAt(aggregateConstraints.Length() - 1); + } + } + } + return nullptr; + } }; } // namespace mozilla From 4fbccc5b502515cc901b2aacaec4eac993a9e342 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Sun, 20 Sep 2015 10:04:51 -0400 Subject: [PATCH 07/29] Bug 912342 - get Promise out. r=jesup --HG-- extra : commitid : L54TpPNzEgB extra : rebase_source : 29eceb81efe9ab96053b37a202714319be13fc80 --- dom/media/MediaManager.cpp | 192 ++++++++++++------ dom/media/MediaManager.h | 12 +- .../test_getUserMedia_constraints.html | 7 +- .../webrtc/MediaEngineRemoteVideoSource.cpp | 23 ++- 4 files changed, 157 insertions(+), 77 deletions(-) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index d7af03430787..a87a507d4d2e 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -333,32 +333,6 @@ public: } break; - case MEDIA_APPLYCONSTRAINTS_TRACK: - { - nsRefPtr mgr = MediaManager::GetInstance(); - - NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); - if (mAudioDevice) { - mAudioDevice->Restart(mConstraints, mgr->mPrefs); - } - if (mVideoDevice) { - mVideoDevice->Restart(mConstraints, mgr->mPrefs); - } - - // Need to dispatch something back to main to resolve promise - // redo this with pledge? - nsIRunnable *event = - new GetUserMediaNotificationEvent(mListener, - GetUserMediaNotificationEvent::APPLIED_CONSTRAINTS, - mAudioDevice != nullptr, - mVideoDevice != nullptr, - mWindowID); - // event must always be released on mainthread due to the JS callbacks - // in the TracksAvailableCallback - NS_DispatchToMainThread(event); - } - break; - case MEDIA_DIRECT_LISTENERS: { NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); @@ -726,9 +700,10 @@ public: // risky to do late in a release since that will affect all track ends, and not // just StopTrack()s. if (GetDOMTrackFor(aTrackID)) { - mListener->StopTrack(aTrackID, !!GetDOMTrackFor(aTrackID)->AsAudioStreamTrack()); + mListener->StopTrack(aTrackID, + !!GetDOMTrackFor(aTrackID)->AsAudioStreamTrack()); } else { - LOG(("StopTrack(%d) on non-existant track", aTrackID)); + LOG(("StopTrack(%d) on non-existent track", aTrackID)); } } } @@ -738,22 +713,45 @@ public: const MediaTrackConstraints& aConstraints, ErrorResult &aRv) override { - if (mSourceStream) { - nsRefPtr track = GetDOMTrackFor(aTrackID); - if (track) { - mListener->ApplyConstraintsToTrack(aTrackID, - !!track->AsAudioStreamTrack(), - aConstraints); - } else { - LOG(("ApplyConstraintsToTrack(%d) on non-existant track", aTrackID)); - } - } - nsPIDOMWindow* window = static_cast(mWindow.get()); nsCOMPtr go = do_QueryInterface(window); - nsRefPtr p = Promise::Create(go, aRv); - p->MaybeResolve(false); - return p.forget(); + nsRefPtr promise = Promise::Create(go, aRv); + + if (sInShutdown) { + nsRefPtr error = new MediaStreamError(window, + NS_LITERAL_STRING("AbortError"), + NS_LITERAL_STRING("In shutdown")); + promise->MaybeReject(error); + return promise.forget(); + } + if (!mSourceStream) { + nsRefPtr error = new MediaStreamError(window, + NS_LITERAL_STRING("InternalError"), + NS_LITERAL_STRING("No stream.")); + promise->MaybeReject(error); + return promise.forget(); + } + + nsRefPtr track = GetDOMTrackFor(aTrackID); + if (!track) { + LOG(("ApplyConstraintsToTrack(%d) on non-existent track", aTrackID)); + nsRefPtr error = new MediaStreamError(window, + NS_LITERAL_STRING("InternalError"), + NS_LITERAL_STRING("No track.")); + promise->MaybeReject(error); + return promise.forget(); + } + + typedef media::Pledge PledgeVoid; + + nsRefPtr p = mListener->ApplyConstraintsToTrack(window, + aTrackID, !!track->AsAudioStreamTrack(), aConstraints); + p->Then([promise](bool& aDummy) mutable { + promise->MaybeResolve(false); + }, [promise](MediaStreamError*& reason) mutable { + promise->MaybeReject(reason); + }); + return promise.forget(); } #if 0 @@ -804,14 +802,14 @@ public: } // let us intervene for direct listeners when someone does track.enabled = false - virtual void SetTrackEnabled(TrackID aID, bool aEnabled) override + virtual void SetTrackEnabled(TrackID aTrackID, bool aEnabled) override { // We encapsulate the SourceMediaStream and TrackUnion into one entity, so // we can handle the disabling at the SourceMediaStream - // We need to find the input track ID for output ID aID, so we let the TrackUnion + // We need to find the input track ID for output ID aTrackID, so we let the TrackUnion // forward the request to the source and translate the ID - GetStream()->AsProcessedStream()->ForwardTrackEnabled(aID, aEnabled); + GetStream()->AsProcessedStream()->ForwardTrackEnabled(aTrackID, aEnabled); } virtual DOMLocalMediaStream* AsDOMLocalMediaStream() override @@ -3067,33 +3065,102 @@ GetUserMediaCallbackMediaStreamListener::StopSharing() // ApplyConstraints for track -void +already_AddRefed GetUserMediaCallbackMediaStreamListener::ApplyConstraintsToTrack( - TrackID aID, + nsPIDOMWindow* aWindow, + TrackID aTrackID, bool aIsAudio, const MediaTrackConstraints& aConstraints) { - if (((aIsAudio && mAudioDevice) || - (!aIsAudio && mVideoDevice)) && !mStopped) + MOZ_ASSERT(NS_IsMainThread()); + nsRefPtr p = new PledgeVoid(); + + if (!(((aIsAudio && mAudioDevice) || + (!aIsAudio && mVideoDevice)) && !mStopped)) { - // XXX to support multiple tracks of a type in a stream, this should key off - // the TrackID and not just the type - MediaManager::PostTask(FROM_HERE, - new MediaOperationTask(MEDIA_APPLYCONSTRAINTS_TRACK, - this, nullptr, nullptr, - aIsAudio ? mAudioDevice.get() : nullptr, - !aIsAudio ? mVideoDevice.get() : nullptr, - mFinished, mWindowID, nullptr, aConstraints)); - } else { LOG(("gUM track %d applyConstraints, but we don't have type %s", - aID, aIsAudio ? "audio" : "video")); + aTrackID, aIsAudio ? "audio" : "video")); + p->Resolve(false); + return p.forget(); } + + // XXX to support multiple tracks of a type in a stream, this should key off + // the TrackID and not just the type + nsRefPtr audioDevice = aIsAudio ? mAudioDevice.get() : nullptr; + nsRefPtr videoDevice = !aIsAudio ? mVideoDevice.get() : nullptr; + + nsRefPtr mgr = MediaManager::GetInstance(); + uint32_t id = mgr->mOutstandingVoidPledges.Append(*p); + uint64_t windowId = aWindow->WindowID(); + + MediaManager::PostTask(FROM_HERE, NewTaskFrom([id, windowId, + audioDevice, videoDevice, + aConstraints]() mutable { + MOZ_ASSERT(MediaManager::IsInMediaThread()); + nsRefPtr mgr = MediaManager::GetInstance(); + const char* badConstraint = nullptr; + nsresult rv = NS_OK; + + if (audioDevice) { + rv = audioDevice->Restart(aConstraints, mgr->mPrefs); + if (rv == NS_ERROR_NOT_AVAILABLE) { + nsTArray> audios; + audios.AppendElement(audioDevice); + badConstraint = MediaConstraintsHelper::SelectSettings(aConstraints, + audios); + } + } else { + rv = videoDevice->Restart(aConstraints, mgr->mPrefs); + if (rv == NS_ERROR_NOT_AVAILABLE) { + nsTArray> videos; + videos.AppendElement(videoDevice); + badConstraint = MediaConstraintsHelper::SelectSettings(aConstraints, + videos); + } + } + NS_DispatchToMainThread(do_AddRef(NewRunnableFrom([id, windowId, rv, + badConstraint]() mutable { + MOZ_ASSERT(NS_IsMainThread()); + nsRefPtr mgr = MediaManager_GetInstance(); + if (!mgr) { + return NS_OK; + } + nsRefPtr p = mgr->mOutstandingVoidPledges.Remove(id); + if (p) { + if (NS_SUCCEEDED(rv)) { + p->Resolve(false); + } else { + nsPIDOMWindow *window = static_cast + (nsGlobalWindow::GetInnerWindowWithId(windowId)); + if (window) { + if (rv == NS_ERROR_NOT_AVAILABLE) { + nsString constraint; + constraint.AssignASCII(badConstraint); + nsRefPtr error = + new MediaStreamError(window, + NS_LITERAL_STRING("OverconstrainedError"), + NS_LITERAL_STRING(""), + constraint); + p->Reject(error); + } else { + nsRefPtr error = + new MediaStreamError(window, + NS_LITERAL_STRING("InternalError")); + p->Reject(error); + } + } + } + } + return NS_OK; + }))); + })); + return p.forget(); } // Stop backend for track void -GetUserMediaCallbackMediaStreamListener::StopTrack(TrackID aID, bool aIsAudio) +GetUserMediaCallbackMediaStreamListener::StopTrack(TrackID aTrackID, bool aIsAudio) { if (((aIsAudio && mAudioDevice) || (!aIsAudio && mVideoDevice)) && !mStopped) @@ -3108,7 +3175,7 @@ GetUserMediaCallbackMediaStreamListener::StopTrack(TrackID aID, bool aIsAudio) mFinished, mWindowID, nullptr)); } else { LOG(("gUM track %d ended, but we don't have type %s", - aID, aIsAudio ? "audio" : "video")); + aTrackID, aIsAudio ? "audio" : "video")); } } @@ -3174,9 +3241,6 @@ GetUserMediaNotificationEvent::Run() case STOPPED_TRACK: msg = NS_LITERAL_STRING("shutdown"); break; - case APPLIED_CONSTRAINTS: - msg = NS_LITERAL_STRING("constraints-changed"); - break; } nsCOMPtr window = nsGlobalWindow::GetInnerWindowWithId(mWindowID); diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index 41dcb1a472d3..b87a15191885 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -167,8 +167,12 @@ public: void StopTrack(TrackID aID, bool aIsAudio); - void ApplyConstraintsToTrack(TrackID aID, bool aIsAudio, - const dom::MediaTrackConstraints& aConstraints); + typedef media::Pledge PledgeVoid; + + already_AddRefed + ApplyConstraintsToTrack(nsPIDOMWindow* aWindow, + TrackID aID, bool aIsAudio, + const dom::MediaTrackConstraints& aConstraints); // mVideo/AudioDevice are set by Activate(), so we assume they're capturing // if set and represent a real capture device. @@ -323,7 +327,6 @@ class GetUserMediaNotificationEvent: public nsRunnable STARTING, STOPPING, STOPPED_TRACK, - APPLIED_CONSTRAINTS, }; GetUserMediaNotificationEvent(GetUserMediaCallbackMediaStreamListener* aListener, GetUserMediaStatus aStatus, @@ -362,7 +365,6 @@ typedef enum { MEDIA_STOP, MEDIA_STOP_TRACK, MEDIA_DIRECT_LISTENERS, - MEDIA_APPLYCONSTRAINTS_TRACK, } MediaOperation; class MediaManager; @@ -393,6 +395,7 @@ typedef void (*WindowListenerCallback)(MediaManager *aThis, class MediaManager final : public nsIMediaManagerService, public nsIObserver { + friend GetUserMediaCallbackMediaStreamListener; public: static already_AddRefed GetInstance(); @@ -520,6 +523,7 @@ private: static StaticRefPtr sSingleton; media::CoatCheck mOutstandingPledges; + media::CoatCheck mOutstandingVoidPledges; #if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK) nsRefPtr mCameraManager; #endif diff --git a/dom/media/tests/mochitest/test_getUserMedia_constraints.html b/dom/media/tests/mochitest/test_getUserMedia_constraints.html index e076060914df..eb1a39e7b20c 100644 --- a/dom/media/tests/mochitest/test_getUserMedia_constraints.html +++ b/dom/media/tests/mochitest/test_getUserMedia_constraints.html @@ -117,7 +117,12 @@ runTest(function() { is(e.constraint, test.constraint, test.message + " w/correct constraint."); } - }), p); + }), p) + .then(() => navigator.mediaDevices.getUserMedia({video: true, audio: true})) + .then(stream => stream.getVideoTracks()[0].applyConstraints({ width: 320 }) + .then(() => stream.getAudioTracks()[0].applyConstraints({ }))) + .then(() => ok(true, "applyConstraints code exercised")) + // TODO: Test outcome once fake devices support constraints (Bug 1088621) }); diff --git a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp index ecc786e9b4dd..1c2872926e05 100644 --- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp @@ -217,16 +217,23 @@ MediaEngineRemoteVideoSource::Restart(const dom::MediaTrackConstraints& aConstra const MediaEnginePrefs& aPrefs, const nsString& aDeviceId) { - if (mState == kStarted && mInitDone && - ChooseCapability(aConstraints, aPrefs, aDeviceId)) { - mozilla::camera::StopCapture(mCapEngine, mCaptureIndex); - if (mozilla::camera::StartCapture(mCapEngine, - mCaptureIndex, mCapability, this)) { - LOG(("StartCapture failed")); - return NS_ERROR_FAILURE; - } + if (!mInitDone) { + LOG(("Init not done")); + return NS_ERROR_FAILURE; + } + if (!ChooseCapability(aConstraints, aPrefs, aDeviceId)) { + return NS_ERROR_NOT_AVAILABLE; + } + if (mState != kStarted) { + return NS_OK; } + mozilla::camera::StopCapture(mCapEngine, mCaptureIndex); + if (mozilla::camera::StartCapture(mCapEngine, + mCaptureIndex, mCapability, this)) { + LOG(("StartCapture failed")); + return NS_ERROR_FAILURE; + } return NS_OK; } From c13216ec53996ca378996a03f0757abdd35a1489 Mon Sep 17 00:00:00 2001 From: Xidorn Quan Date: Mon, 21 Sep 2015 11:32:03 +1000 Subject: [PATCH 08/29] Bug 1205144 - Remove 'REMOVED' commands from output of mach-commands and mach-debug-commands. r=gps DONTBUILD --HG-- extra : source : 7d40827d58f699b57668ad80573e93b3b0a8d0b0 extra : amend_source : 98c5b7adbd1a330528d70a8f41096cd26fe49bdd --- python/mach/mach/commands/commandinfo.py | 10 ++++++++-- testing/mochitest/mach_commands.py | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/python/mach/mach/commands/commandinfo.py b/python/mach/mach/commands/commandinfo.py index e93bdd58e29c..cce85f859ddb 100644 --- a/python/mach/mach/commands/commandinfo.py +++ b/python/mach/mach/commands/commandinfo.py @@ -16,10 +16,16 @@ class BuiltinCommands(object): def __init__(self, context): self.context = context + @property + def command_keys(self): + # NOTE 'REMOVED' is a function in testing/mochitest/mach_commands.py + return (k for k, v in self.context.commands.command_handlers.items() + if not v.conditions or v.conditions[0].__name__ != 'REMOVED') + @Command('mach-commands', category='misc', description='List all mach commands.') def commands(self): - print("\n".join(self.context.commands.command_handlers.keys())) + print("\n".join(self.command_keys)) @Command('mach-debug-commands', category='misc', description='Show info about available mach commands.') @@ -29,7 +35,7 @@ class BuiltinCommands(object): import inspect handlers = self.context.commands.command_handlers - for command in sorted(handlers.keys()): + for command in sorted(self.command_keys): if match and match not in command: continue diff --git a/testing/mochitest/mach_commands.py b/testing/mochitest/mach_commands.py index be84adad194b..ec8399b39cc5 100644 --- a/testing/mochitest/mach_commands.py +++ b/testing/mochitest/mach_commands.py @@ -648,6 +648,9 @@ class RobocopCommands(MachCommandBase): return mochitest.run_robocop_test(self._mach_context, tests, 'robocop', **kwargs) +# NOTE python/mach/mach/commands/commandinfo.py references this function +# by name. If this function is renamed or removed, that file should +# be updated accordingly as well. def REMOVED(cls): """Command no longer exists! Use |mach mochitest| instead. From f0d1337fdc385fcf7f1b5e8d06f4be24ec06f842 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Thu, 17 Sep 2015 22:09:24 +0800 Subject: [PATCH 09/29] Bug 1177276 - Pref on canvas.captureStream by default. r=smaug,mt --HG-- extra : commitid : 8EBhXM9AkEM extra : rebase_source : 6f6171474350a20096db822e3524c6b2bbe20023 --- dom/canvas/test/crossorigin/test_canvas2d_crossorigin.html | 6 +----- dom/canvas/test/crossorigin/test_video_crossorigin.html | 7 +------ dom/canvas/test/reftest/reftest.list | 4 ++-- dom/canvas/test/test_capture.html | 5 +---- dom/canvas/test/webgl-mochitest/test_capture.html | 5 +---- dom/media/tests/mochitest/head.js | 1 - dom/tests/mochitest/general/test_interfaces.html | 2 +- modules/libpref/init/all.js | 3 +-- 8 files changed, 8 insertions(+), 25 deletions(-) diff --git a/dom/canvas/test/crossorigin/test_canvas2d_crossorigin.html b/dom/canvas/test/crossorigin/test_canvas2d_crossorigin.html index a12bd63960a4..ef8ba96dc9b3 100644 --- a/dom/canvas/test/crossorigin/test_canvas2d_crossorigin.html +++ b/dom/canvas/test/crossorigin/test_canvas2d_crossorigin.html @@ -205,11 +205,7 @@ function beginTest() { } } -var prefs = [ - [ "canvas.capturestream.enabled", true ], -]; -SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest); - +beginTest(); diff --git a/dom/canvas/test/crossorigin/test_video_crossorigin.html b/dom/canvas/test/crossorigin/test_video_crossorigin.html index 4183d13aa222..0ac69ac1a38e 100644 --- a/dom/canvas/test/crossorigin/test_video_crossorigin.html +++ b/dom/canvas/test/crossorigin/test_video_crossorigin.html @@ -211,13 +211,8 @@ function beginTest() { document.manager.runTests(corsTests, startTest); } -var prefs = [ - [ "canvas.capturestream.enabled", true ], -]; - SimpleTest.waitForExplicitFinish(); -SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest); - +beginTest(); diff --git a/dom/canvas/test/reftest/reftest.list b/dom/canvas/test/reftest/reftest.list index 354d22201b99..4f8768dbe291 100644 --- a/dom/canvas/test/reftest/reftest.list +++ b/dom/canvas/test/reftest/reftest.list @@ -20,7 +20,7 @@ pref(webgl.force-layers-readback,true) == webgl-clear-test.html?readback wrappe == webgl-resize-test.html wrapper.html?green.png # Check that captureStream() displays in a local video element -pref(canvas.capturestream.enabled,true) skip-if(winWidget&&layersGPUAccelerated&&d2d) == webgl-capturestream-test.html?preserve wrapper.html?green.png +skip-if(winWidget&&layersGPUAccelerated&&d2d) == webgl-capturestream-test.html?preserve wrapper.html?green.png # Some of the failure conditions are a little crazy. I'm (jgilbert) setting these based on # failures encountered when running on Try, and then targetting the Try config by @@ -157,6 +157,6 @@ pref(canvas.focusring.enabled,true) skip-if(B2G) skip-if(Android&&AndroidVersion pref(canvas.customfocusring.enabled,true) skip-if(B2G) skip-if(Android&&AndroidVersion<15,8,500) skip-if(winWidget) needs-focus == drawCustomFocusRing.html drawCustomFocusRing-ref.html # Check that captureStream() displays in a local video element -pref(canvas.capturestream.enabled,true) skip-if(winWidget&&layersGPUAccelerated&&d2d) == capturestream.html wrapper.html?green.png +skip-if(winWidget&&layersGPUAccelerated&&d2d) == capturestream.html wrapper.html?green.png fuzzy-if(Android,3,40) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),1,1) == 1177726-text-stroke-bounds.html 1177726-text-stroke-bounds-ref.html diff --git a/dom/canvas/test/test_capture.html b/dom/canvas/test/test_capture.html index 513ef4b1728f..ec2902b3ac9f 100644 --- a/dom/canvas/test/test_capture.html +++ b/dom/canvas/test/test_capture.html @@ -107,9 +107,6 @@ function beginTest() { SimpleTest.waitForExplicitFinish(); -var prefs = [ - [ "canvas.capturestream.enabled", true ], -]; -SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest); +beginTest(); diff --git a/dom/canvas/test/webgl-mochitest/test_capture.html b/dom/canvas/test/webgl-mochitest/test_capture.html index fad4ac37a6b3..489d67872361 100644 --- a/dom/canvas/test/webgl-mochitest/test_capture.html +++ b/dom/canvas/test/webgl-mochitest/test_capture.html @@ -171,9 +171,6 @@ function beginTest() { SimpleTest.waitForExplicitFinish(); -var prefs = [ - [ "canvas.capturestream.enabled", true ], -]; -SpecialPowers.pushPrefEnv({ "set" : prefs }, beginTest); +beginTest(); diff --git a/dom/media/tests/mochitest/head.js b/dom/media/tests/mochitest/head.js index 26e6ee3567e2..3295a6693a78 100644 --- a/dom/media/tests/mochitest/head.js +++ b/dom/media/tests/mochitest/head.js @@ -234,7 +234,6 @@ function setupEnvironment() { window.finish = () => SimpleTest.finish(); SpecialPowers.pushPrefEnv({ 'set': [ - ['canvas.capturestream.enabled', true], ['media.peerconnection.enabled', true], ['media.peerconnection.identity.enabled', true], ['media.peerconnection.identity.timeout', 120000], diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index 59bbc32596a6..3c4f753423fb 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -270,7 +270,7 @@ var interfaceNamesInGlobalScope = // IMPORTANT: Do not change this list without review from a DOM peer! {name: "CameraStateChangeEvent", b2g: true}, // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "CanvasCaptureMediaStream", disabled: true}, + {name: "CanvasCaptureMediaStream"}, // IMPORTANT: Do not change this list without review from a DOM peer! "CanvasGradient", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 12e0e8d2f0db..9c3aab7605a6 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -736,8 +736,7 @@ pref("canvas.hitregions.enabled", false); pref("canvas.filters.enabled", false); // Add support for canvas path objects pref("canvas.path.enabled", true); -// captureStream() on canvas disabled by default -pref("canvas.capturestream.enabled", false); +pref("canvas.capturestream.enabled", true); // We want the ability to forcibly disable platform a11y, because // some non-a11y-related components attempt to bring it up. See bug From 8721f1e9f897cb959afd5fc87ec8ef7629793985 Mon Sep 17 00:00:00 2001 From: "\"Chih-Kai (Patrick) Wang\"" Date: Mon, 5 Jan 2015 15:49:24 +0800 Subject: [PATCH 10/29] Bug 950660: Part 1: Support bind in TCPSocket from content process r=jdm --- dom/network/PTCPSocket.ipdl | 6 +++ dom/network/TCPSocketChild.cpp | 34 +++++++++++++++++ dom/network/TCPSocketParent.cpp | 68 +++++++++++++++++++++++++++++++++ dom/network/TCPSocketParent.h | 7 ++++ 4 files changed, 115 insertions(+) diff --git a/dom/network/PTCPSocket.ipdl b/dom/network/PTCPSocket.ipdl index b900e62ea1c5..cc44b0d18dfa 100644 --- a/dom/network/PTCPSocket.ipdl +++ b/dom/network/PTCPSocket.ipdl @@ -41,6 +41,12 @@ parent: // |binaryType| (from TCPOption.binaryType). Open(nsString host, uint16_t port, bool useSSL, bool useArrayBuffers); + // Ask parent to open a socket and bind the newly-opened socket to a local + // address specified in |localAddr| and |localPort|. + OpenBind(nsCString host, uint16_t port, + nsCString localAddr, uint16_t localPort, + bool useSSL, nsCString binaryType); + // When child's send() is called, this message requrests parent to send // data and update it's trackingNumber. Data(SendableData data, uint32_t trackingNumber); diff --git a/dom/network/TCPSocketChild.cpp b/dom/network/TCPSocketChild.cpp index 4d1d2472b0b7..38193d32714b 100644 --- a/dom/network/TCPSocketChild.cpp +++ b/dom/network/TCPSocketChild.cpp @@ -102,6 +102,23 @@ TCPSocketChild::SendOpen(TCPSocket* aSocket, bool aUseSSL, bool aUseArrayBuffers PTCPSocketChild::SendOpen(mHost, mPort, aUseSSL, aUseArrayBuffers); } +NS_IMETHODIMP +TCPSocketChild::SendWindowlessOpenBind(nsITCPSocketInternal* aSocket, + const nsACString& aRemoteHost, uint16_t aRemotePort, + const nsACString& aLocalHost, uint16_t aLocalPort, + bool aUseSSL) +{ + mSocket = aSocket; + AddIPDLReference(); + gNeckoChild->SendPTCPSocketConstructor(this, + NS_ConvertUTF8toUTF16(aRemoteHost), + aRemotePort); + PTCPSocketChild::SendOpenBind(nsCString(aRemoteHost), aRemotePort, + nsCString(aLocalHost), aLocalPort, + aUseSSL, NS_LITERAL_CSTRING("arraybuffer")); + return NS_OK; +} + void TCPSocketChildBase::ReleaseIPDLReference() { @@ -147,6 +164,16 @@ TCPSocketChild::RecvCallback(const nsString& aType, } else if (aData.type() == CallbackData::TSendableData) { const SendableData& data = aData.get_SendableData(); + if (data.type() == SendableData::TArrayOfuint8_t) { + // See if we can pass array directly. + nsCOMPtr nativeSocket = do_QueryInterface(mSocket); + if (nativeSocket) { + const InfallibleTArray& buffer = data.get_ArrayOfuint8_t(); + nativeSocket->CallListenerNativeArray(const_cast(buffer.Elements()), + buffer.Length()); + return true; + } + } AutoJSAPI api; if (NS_WARN_IF(!api.Init(mSocket->GetOwner()))) { return true; @@ -199,6 +226,13 @@ TCPSocketChild::SendSend(const ArrayBuffer& aData, return NS_OK; } +NS_IMETHODIMP +TCPSocketChild::SendSendArray(nsTArray *aArr, uint32_t aTrackingNumber) +{ + SendData(*aArr, aTrackingNumber); + return NS_OK; +} + void TCPSocketChild::SetSocket(TCPSocket* aSocket) { diff --git a/dom/network/TCPSocketParent.cpp b/dom/network/TCPSocketParent.cpp index f31054b2b3c0..e3a12fb9bbb0 100644 --- a/dom/network/TCPSocketParent.cpp +++ b/dom/network/TCPSocketParent.cpp @@ -16,6 +16,8 @@ #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/TabParent.h" #include "mozilla/HoldDropJSObjects.h" +#include "nsISocketTransportService.h" +#include "nsISocketTransport.h" #include "nsIScriptSecurityManager.h" #include "nsNetUtil.h" @@ -170,6 +172,72 @@ TCPSocketParent::RecvOpen(const nsString& aHost, const uint16_t& aPort, const bo return true; } +bool +TCPSocketParent::RecvOpenBind(const nsCString& aRemoteHost, + const uint16_t& aRemotePort, + const nsCString& aLocalAddr, + const uint16_t& aLocalPort, + const bool& aUseSSL, + const nsCString& aBinaryType) +{ + if (net::UsingNeckoIPCSecurity() && + !AssertAppProcessPermission(Manager()->Manager(), "tcp-socket")) { + FireInteralError(this, __LINE__); + return true; + } + + nsresult rv; + nsCOMPtr sts = + do_GetService("@mozilla.org/network/socket-transport-service;1", &rv); + if (NS_FAILED(rv)) { + FireInteralError(this, __LINE__); + return true; + } + + nsCOMPtr socketTransport; + rv = sts->CreateTransport(nullptr, 0, + aRemoteHost, aRemotePort, + nullptr, getter_AddRefs(socketTransport)); + if (NS_FAILED(rv)) { + FireInteralError(this, __LINE__); + return true; + } + + PRNetAddr prAddr; + if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, aLocalPort, &prAddr)) { + FireInteralError(this, __LINE__); + return true; + } + if (PR_SUCCESS != PR_StringToNetAddr(aLocalAddr.BeginReading(), &prAddr)) { + FireInteralError(this, __LINE__); + return true; + } + + mozilla::net::NetAddr addr; + PRNetAddrToNetAddr(&prAddr, &addr); + rv = socketTransport->Bind(&addr); + if (NS_FAILED(rv)) { + FireInteralError(this, __LINE__); + return true; + } + + // Obtain App ID + uint32_t appId = nsIScriptSecurityManager::NO_APP_ID; + const PContentParent *content = Manager()->Manager(); + const InfallibleTArray& browsers = content->ManagedPBrowserParent(); + if (browsers.Length() > 0) { + TabParent *tab = static_cast(browsers[0]); + appId = tab->OwnAppId(); + } + + mSocket = new TCPSocket(nullptr, aRemoteHost, aRemotePort, aUseSSL, + aBinaryType.EqualsLiteral("arraybuffer")); + mSocket->SetAppIdAndBrowser(appId, inBrowser); + mSocket->SetSocketBridgeParent(this); + NS_ENSURE_SUCCESS(mSocket->InitWithTransport(socketTransport), true); + return true; +} + bool TCPSocketParent::RecvStartTLS() { diff --git a/dom/network/TCPSocketParent.h b/dom/network/TCPSocketParent.h index add80d1fb347..efaf82b635c5 100644 --- a/dom/network/TCPSocketParent.h +++ b/dom/network/TCPSocketParent.h @@ -52,6 +52,13 @@ public: virtual bool RecvOpen(const nsString& aHost, const uint16_t& aPort, const bool& useSSL, const bool& aUseArrayBuffers) override; + virtual bool RecvOpenBind(const nsCString& aRemoteHost, + const uint16_t& aRemotePort, + const nsCString& aLocalAddr, + const uint16_t& aLocalPort, + const bool& aUseSSL, + const nsCString& aBinaryType) override; + virtual bool RecvStartTLS() override; virtual bool RecvSuspend() override; virtual bool RecvResume() override; From 4c2a61d99a6cdab9a6da68222d19e27481443c4f Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Sun, 20 Sep 2015 23:05:20 -0400 Subject: [PATCH 11/29] Bug 950660: Part 2 - Change TCPSocket interface to TCPSocketChild and unbitrot r=jdm --- dom/network/PTCPSocket.ipdl | 2 +- dom/network/TCPSocket.cpp | 82 +++++++++++++++++++++++++-------- dom/network/TCPSocket.h | 6 +++ dom/network/TCPSocketChild.cpp | 38 +++------------ dom/network/TCPSocketChild.h | 15 ++++++ dom/network/TCPSocketParent.cpp | 10 ++-- dom/network/TCPSocketParent.h | 2 +- 7 files changed, 100 insertions(+), 55 deletions(-) diff --git a/dom/network/PTCPSocket.ipdl b/dom/network/PTCPSocket.ipdl index cc44b0d18dfa..ced62c895cd1 100644 --- a/dom/network/PTCPSocket.ipdl +++ b/dom/network/PTCPSocket.ipdl @@ -45,7 +45,7 @@ parent: // address specified in |localAddr| and |localPort|. OpenBind(nsCString host, uint16_t port, nsCString localAddr, uint16_t localPort, - bool useSSL, nsCString binaryType); + bool useSSL, bool aUseArrayBuffers); // When child's send() is called, this message requrests parent to send // data and update it's trackingNumber. diff --git a/dom/network/TCPSocket.cpp b/dom/network/TCPSocket.cpp index d6e9365c6c88..c07afe1f2ba4 100644 --- a/dom/network/TCPSocket.cpp +++ b/dom/network/TCPSocket.cpp @@ -167,12 +167,14 @@ TCPSocket::TCPSocket(nsIGlobalObject* aGlobal, const nsAString& aHost, uint16_t , mInBrowser(false) #endif { - nsCOMPtr window = do_QueryInterface(aGlobal); - if (window && window->IsOuterWindow()) { - window = window->GetCurrentInnerWindow(); - } - if (window) { - mInnerWindowID = window->WindowID(); + if (aGlobal) { + nsCOMPtr window = do_QueryInterface(aGlobal); + if (window && window->IsOuterWindow()) { + window = window->GetCurrentInnerWindow(); + } + if (window) { + mInnerWindowID = window->WindowID(); + } } } @@ -234,6 +236,24 @@ TCPSocket::CreateStream() return NS_OK; } +nsresult +TCPSocket::InitWithUnconnectedTransport(nsISocketTransport* aTransport) +{ + mReadyState = TCPReadyState::Connecting; + mTransport = aTransport; + + MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Content); + + nsCOMPtr mainThread; + NS_GetMainThread(getter_AddRefs(mainThread)); + mTransport->SetEventSink(this, mainThread); + + nsresult rv = CreateStream(); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + nsresult TCPSocket::Init() { @@ -242,9 +262,8 @@ TCPSocket::Init() obs->AddObserver(this, "inner-window-destroyed", true); } - mReadyState = TCPReadyState::Connecting; - if (XRE_GetProcessType() == GeckoProcessType_Content) { + mReadyState = TCPReadyState::Connecting; mSocketBridgeChild = new TCPSocketChild(mHost, mPort); mSocketBridgeChild->SendOpen(this, mSsl, mUseArrayBuffers); return NS_OK; @@ -259,19 +278,12 @@ TCPSocket::Init() } else { socketTypes[0] = "starttls"; } + nsCOMPtr transport; nsresult rv = sts->CreateTransport(socketTypes, 1, NS_ConvertUTF16toUTF8(mHost), mPort, - nullptr, getter_AddRefs(mTransport)); + nullptr, getter_AddRefs(transport)); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr mainThread; - NS_GetMainThread(getter_AddRefs(mainThread)); - - mTransport->SetEventSink(this, mainThread); - - rv = CreateStream(); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; + return InitWithUnconnectedTransport(transport); } void @@ -485,6 +497,40 @@ TCPSocket::FireEvent(const nsAString& aType) FireDataEvent(api.cx(), aType, val); } +void +TCPSocket::FireDataEvent(const nsAString& aType, + const InfallibleTArray& buffer) +{ + AutoJSAPI api; + if (NS_WARN_IF(!api.Init(GetOwner()))) { + return NS_ERROR_FAILURE; + } + JSContext* cx = api.cx(); + JS::Rooted val(cx); + + bool ok = IPC::DeserializeArrayBuffer(cx, buffer, &val); + if (ok) { + FireDataEvent(aType, val); + } +} + +void +TCPSocket::FireDataEvent(const nsAString& aType, + const nsACString& aString) +{ + AutoJSAPI api; + if (NS_WARN_IF(!api.Init(GetOwner()))) { + return NS_ERROR_FAILURE; + } + JSContext* cx = api.cx(); + JS::Rooted val(cx); + + bool ok = ToJSValue(cx, NS_ConvertASCIItoUTF16(aString), &val); + if (ok) { + FireDataEvent(aType, val); + } +} + void TCPSocket::FireDataEvent(JSContext* aCx, const nsAString& aType, JS::Handle aData) { diff --git a/dom/network/TCPSocket.h b/dom/network/TCPSocket.h index 1f262d970811..0c5f1ddd8f24 100644 --- a/dom/network/TCPSocket.h +++ b/dom/network/TCPSocket.h @@ -164,8 +164,14 @@ public: // Dispatch an event of the given type at this object. void FireEvent(const nsAString& aType); // Dispatch a "data" event at this object. + void FireDataEvent(const nsAString& aType, const InfallibleTArray& buffer); + void FireDataEvent(const nsAString& aType, const nsAString& aString); void FireDataEvent(JSContext* aCx, const nsAString& aType, JS::Handle aData); + // Initialize this socket from a low-level connection that hasn't connected yet + // (called from RecvOpenBind() in TCPSocketParent). + nsresult InitWithUnconnectedTransport(nsISocketTransport* aTransport); + private: ~TCPSocket(); diff --git a/dom/network/TCPSocketChild.cpp b/dom/network/TCPSocketChild.cpp index 38193d32714b..db33a24c2a34 100644 --- a/dom/network/TCPSocketChild.cpp +++ b/dom/network/TCPSocketChild.cpp @@ -102,8 +102,8 @@ TCPSocketChild::SendOpen(TCPSocket* aSocket, bool aUseSSL, bool aUseArrayBuffers PTCPSocketChild::SendOpen(mHost, mPort, aUseSSL, aUseArrayBuffers); } -NS_IMETHODIMP -TCPSocketChild::SendWindowlessOpenBind(nsITCPSocketInternal* aSocket, +void +TCPSocketChild::SendWindowlessOpenBind(TCPSocket* aSocket, const nsACString& aRemoteHost, uint16_t aRemotePort, const nsACString& aLocalHost, uint16_t aLocalPort, bool aUseSSL) @@ -115,8 +115,7 @@ TCPSocketChild::SendWindowlessOpenBind(nsITCPSocketInternal* aSocket, aRemotePort); PTCPSocketChild::SendOpenBind(nsCString(aRemoteHost), aRemotePort, nsCString(aLocalHost), aLocalPort, - aUseSSL, NS_LITERAL_CSTRING("arraybuffer")); - return NS_OK; + aUseSSL, true); } void @@ -165,35 +164,12 @@ TCPSocketChild::RecvCallback(const nsString& aType, const SendableData& data = aData.get_SendableData(); if (data.type() == SendableData::TArrayOfuint8_t) { - // See if we can pass array directly. - nsCOMPtr nativeSocket = do_QueryInterface(mSocket); - if (nativeSocket) { - const InfallibleTArray& buffer = data.get_ArrayOfuint8_t(); - nativeSocket->CallListenerNativeArray(const_cast(buffer.Elements()), - buffer.Length()); - return true; - } - } - AutoJSAPI api; - if (NS_WARN_IF(!api.Init(mSocket->GetOwner()))) { - return true; - } - JSContext* cx = api.cx(); - JS::Rooted val(cx); - - if (data.type() == SendableData::TArrayOfuint8_t) { - bool ok = IPC::DeserializeArrayBuffer(cx, data.get_ArrayOfuint8_t(), &val); - NS_ENSURE_TRUE(ok, true); - + mSocket->FireDataEvent(cx, aType, data.get_ArrayOfuint8_t()); } else if (data.type() == SendableData::TnsCString) { - bool ok = ToJSValue(cx, NS_ConvertASCIItoUTF16(data.get_nsCString()), &val); - NS_ENSURE_TRUE(ok, true); - + mSocket->FireDataEvent(aType, data.get_nsCString()); } else { MOZ_CRASH("Invalid callback data type!"); } - mSocket->FireDataEvent(cx, aType, val); - } else { MOZ_CRASH("Invalid callback type!"); } @@ -227,9 +203,9 @@ TCPSocketChild::SendSend(const ArrayBuffer& aData, } NS_IMETHODIMP -TCPSocketChild::SendSendArray(nsTArray *aArr, uint32_t aTrackingNumber) +TCPSocketChild::SendSendArray(nsTArray& aArray, uint32_t aTrackingNumber) { - SendData(*aArr, aTrackingNumber); + SendData(aArray, aTrackingNumber); return NS_OK; } diff --git a/dom/network/TCPSocketChild.h b/dom/network/TCPSocketChild.h index 5674dd5d8424..18b6265e4abe 100644 --- a/dom/network/TCPSocketChild.h +++ b/dom/network/TCPSocketChild.h @@ -12,6 +12,13 @@ #include "nsCOMPtr.h" #include "js/TypeDecls.h" +namespace IPC { +bool +DeserializeArrayBuffer(JSContext* cx, + const InfallibleTArray& aBuffer, + JS::MutableHandle aVal); +} + namespace mozilla { namespace dom { @@ -43,11 +50,19 @@ public: ~TCPSocketChild(); void SendOpen(TCPSocket* aSocket, bool aUseSSL, bool aUseArrayBuffers); + void SendWindowlessOpenBind(TCPSocket* aSocket, + const nsACString& aRemoteHost, uint16_t aRemotePort, + const nsACString& aLocalHost, uint16_t aLocalPort, + bool aUseSSL); + NS_IMETHOD SendSendArray(nsTArray& aArray, + uint32_t aTrackingNumber); void SendSend(const nsACString& aData, uint32_t aTrackingNumber); nsresult SendSend(const ArrayBuffer& aData, uint32_t aByteOffset, uint32_t aByteLength, uint32_t aTrackingNumber); + void SendSendArray(nsTArray* arr, + uint32_t trackingNumber); void SetSocket(TCPSocket* aSocket); void GetHost(nsAString& aHost); diff --git a/dom/network/TCPSocketParent.cpp b/dom/network/TCPSocketParent.cpp index e3a12fb9bbb0..fc3d659139a6 100644 --- a/dom/network/TCPSocketParent.cpp +++ b/dom/network/TCPSocketParent.cpp @@ -178,7 +178,7 @@ TCPSocketParent::RecvOpenBind(const nsCString& aRemoteHost, const nsCString& aLocalAddr, const uint16_t& aLocalPort, const bool& aUseSSL, - const nsCString& aBinaryType) + const bool& aUseArrayBuffers) { if (net::UsingNeckoIPCSecurity() && !AssertAppProcessPermission(Manager()->Manager(), "tcp-socket")) { @@ -223,18 +223,20 @@ TCPSocketParent::RecvOpenBind(const nsCString& aRemoteHost, // Obtain App ID uint32_t appId = nsIScriptSecurityManager::NO_APP_ID; + bool inBrowser = false; const PContentParent *content = Manager()->Manager(); const InfallibleTArray& browsers = content->ManagedPBrowserParent(); if (browsers.Length() > 0) { TabParent *tab = static_cast(browsers[0]); appId = tab->OwnAppId(); + inBrowser = tab->IsBrowserElement(); } - mSocket = new TCPSocket(nullptr, aRemoteHost, aRemotePort, aUseSSL, - aBinaryType.EqualsLiteral("arraybuffer")); + mSocket = new TCPSocket(nullptr, NS_ConvertUTF8toUTF16(aRemoteHost), aRemotePort, aUseSSL, aUseArrayBuffers); mSocket->SetAppIdAndBrowser(appId, inBrowser); mSocket->SetSocketBridgeParent(this); - NS_ENSURE_SUCCESS(mSocket->InitWithTransport(socketTransport), true); + rv = mSocket->InitWithUnconnectedTransport(socketTransport); + NS_ENSURE_SUCCESS(rv, true); return true; } diff --git a/dom/network/TCPSocketParent.h b/dom/network/TCPSocketParent.h index efaf82b635c5..298498f91a50 100644 --- a/dom/network/TCPSocketParent.h +++ b/dom/network/TCPSocketParent.h @@ -57,7 +57,7 @@ public: const nsCString& aLocalAddr, const uint16_t& aLocalPort, const bool& aUseSSL, - const nsCString& aBinaryType) override; + const bool& aUseArrayBuffers) override; virtual bool RecvStartTLS() override; virtual bool RecvSuspend() override; From 73b9d568edd962980694176c941fb61b7ea6dae7 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Sun, 20 Sep 2015 23:05:20 -0400 Subject: [PATCH 12/29] Bug 950660: Part 3 - make TCPSocket/TCPSocketChild interface an IDL interface r=jdm --- dom/network/TCPSocket.cpp | 51 ++++++++------- dom/network/TCPSocket.h | 17 +---- dom/network/TCPSocketChild.cpp | 9 +-- dom/network/TCPSocketChild.h | 8 ++- dom/network/interfaces/moz.build | 1 + .../interfaces/nsITCPSocketCallback.idl | 62 +++++++++++++++++++ 6 files changed, 105 insertions(+), 43 deletions(-) create mode 100644 dom/network/interfaces/nsITCPSocketCallback.idl diff --git a/dom/network/TCPSocket.cpp b/dom/network/TCPSocket.cpp index c07afe1f2ba4..cc978c2d5f58 100644 --- a/dom/network/TCPSocket.cpp +++ b/dom/network/TCPSocket.cpp @@ -143,6 +143,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TCPSocket) NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback) NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) + NS_INTERFACE_MAP_ENTRY(nsITCPSocketCallback) NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) TCPSocket::TCPSocket(nsIGlobalObject* aGlobal, const nsAString& aHost, uint16_t aPort, @@ -460,12 +461,12 @@ TCPSocket::ActivateTLS() } } -void +NS_IMETHODIMP TCPSocket::FireErrorEvent(const nsAString& aName, const nsAString& aType) { if (mSocketBridgeParent) { mSocketBridgeParent->FireErrorEvent(aName, aType, mReadyState); - return; + return NS_OK; } TCPSocketErrorEventInit init; @@ -476,30 +477,32 @@ TCPSocket::FireErrorEvent(const nsAString& aName, const nsAString& aType) nsRefPtr event = TCPSocketErrorEvent::Constructor(this, NS_LITERAL_STRING("error"), init); + MOZ_ASSERT(event); event->SetTrusted(true); bool dummy; DispatchEvent(event, &dummy); + return NS_OK; } -void +NS_IMETHODIMP TCPSocket::FireEvent(const nsAString& aType) { if (mSocketBridgeParent) { mSocketBridgeParent->FireEvent(aType, mReadyState); - return; + return NS_OK; } AutoJSAPI api; if (NS_WARN_IF(!api.Init(GetOwner()))) { - return; + return NS_ERROR_FAILURE; } JS::Rooted val(api.cx()); - FireDataEvent(api.cx(), aType, val); + return FireDataEvent(api.cx(), aType, val); } -void -TCPSocket::FireDataEvent(const nsAString& aType, - const InfallibleTArray& buffer) +NS_IMETHODIMP +TCPSocket::FireDataArrayEvent(const nsAString& aType, + const InfallibleTArray& buffer) { AutoJSAPI api; if (NS_WARN_IF(!api.Init(GetOwner()))) { @@ -510,13 +513,14 @@ TCPSocket::FireDataEvent(const nsAString& aType, bool ok = IPC::DeserializeArrayBuffer(cx, buffer, &val); if (ok) { - FireDataEvent(aType, val); + return FireDataEvent(cx, aType, val); } + return NS_ERROR_FAILURE; } -void -TCPSocket::FireDataEvent(const nsAString& aType, - const nsACString& aString) +NS_IMETHODIMP +TCPSocket::FireDataStringEvent(const nsAString& aType, + const nsACString& aString) { AutoJSAPI api; if (NS_WARN_IF(!api.Init(GetOwner()))) { @@ -527,11 +531,12 @@ TCPSocket::FireDataEvent(const nsAString& aType, bool ok = ToJSValue(cx, NS_ConvertASCIItoUTF16(aString), &val); if (ok) { - FireDataEvent(aType, val); + return FireDataEvent(cx, aType, val); } + return NS_ERROR_FAILURE; } -void +NS_IMETHODIMP TCPSocket::FireDataEvent(JSContext* aCx, const nsAString& aType, JS::Handle aData) { MOZ_ASSERT(!mSocketBridgeParent); @@ -546,6 +551,7 @@ TCPSocket::FireDataEvent(JSContext* aCx, const nsAString& aType, JS::HandleSetTrusted(true); bool dummy; DispatchEvent(event, &dummy); + return NS_OK; } JSObject* @@ -733,11 +739,10 @@ TCPSocket::MaybeReportErrorAndCloseIfOpen(nsresult status) { } } - FireErrorEvent(errName, errorType); + NS_WARN_IF(NS_FAILED(FireErrorEvent(errName, errorType))); } - FireEvent(NS_LITERAL_STRING("close")); - return NS_OK; + return FireEvent(NS_LITERAL_STRING("close")); } void @@ -1105,26 +1110,28 @@ TCPSocket::SetAppIdAndBrowser(uint32_t aAppId, bool aInBrowser) #endif } -void +NS_IMETHODIMP TCPSocket::UpdateReadyState(uint32_t aReadyState) { MOZ_ASSERT(mSocketBridgeChild); mReadyState = static_cast(aReadyState); + return NS_OK; } -void +NS_IMETHODIMP TCPSocket::UpdateBufferedAmount(uint32_t aBufferedAmount, uint32_t aTrackingNumber) { if (aTrackingNumber != mTrackingNumber) { - return; + return NS_OK; } mBufferedAmount = aBufferedAmount; if (!mBufferedAmount) { if (mWaitingForDrain) { mWaitingForDrain = false; - FireEvent(NS_LITERAL_STRING("drain")); + return FireEvent(NS_LITERAL_STRING("drain")); } } + return NS_OK; } #ifdef MOZ_WIDGET_GONK diff --git a/dom/network/TCPSocket.h b/dom/network/TCPSocket.h index 0c5f1ddd8f24..b3c692325924 100644 --- a/dom/network/TCPSocket.h +++ b/dom/network/TCPSocket.h @@ -14,6 +14,7 @@ #include "nsISupportsImpl.h" #include "nsIObserver.h" #include "nsWeakReference.h" +#include "nsITCPSocketCallback.h" #include "js/RootingAPI.h" class nsISocketTransport; @@ -72,6 +73,7 @@ class TCPSocket final : public DOMEventTargetHelper , public nsIInputStreamCallback , public nsIObserver , public nsSupportsWeakReference + , public nsITCPSocketCallback { public: TCPSocket(nsIGlobalObject* aGlobal, const nsAString& aHost, uint16_t aPort, @@ -84,6 +86,7 @@ public: NS_DECL_NSITRANSPORTEVENTSINK NS_DECL_NSIINPUTSTREAMCALLBACK NS_DECL_NSIOBSERVER + NS_DECL_NSITCPSOCKETCALLBACK nsPIDOMWindow* GetParentObject() const { @@ -154,20 +157,6 @@ public: // Inform this socket that a buffered send() has completed sending. void NotifyCopyComplete(nsresult aStatus); - // Set this child socket's number of buffered bytes, based on the count from the parent - // process associated with the given sequence id. - void UpdateBufferedAmount(uint32_t aAmount, uint32_t aTrackingNumber); - // Set this child socket's ready state, based on the state in the parent process. - void UpdateReadyState(uint32_t aReadyState); - // Dispatch an "error" event at this object. - void FireErrorEvent(const nsAString& aName, const nsAString& aMessage); - // Dispatch an event of the given type at this object. - void FireEvent(const nsAString& aType); - // Dispatch a "data" event at this object. - void FireDataEvent(const nsAString& aType, const InfallibleTArray& buffer); - void FireDataEvent(const nsAString& aType, const nsAString& aString); - void FireDataEvent(JSContext* aCx, const nsAString& aType, JS::Handle aData); - // Initialize this socket from a low-level connection that hasn't connected yet // (called from RecvOpenBind() in TCPSocketParent). nsresult InitWithUnconnectedTransport(nsISocketTransport* aTransport); diff --git a/dom/network/TCPSocketChild.cpp b/dom/network/TCPSocketChild.cpp index db33a24c2a34..3c31467fb2e4 100644 --- a/dom/network/TCPSocketChild.cpp +++ b/dom/network/TCPSocketChild.cpp @@ -11,6 +11,7 @@ #include "mozilla/net/NeckoChild.h" #include "mozilla/dom/PBrowserChild.h" #include "mozilla/dom/TabChild.h" +#include "nsITCPSocketCallback.h" #include "TCPSocket.h" #include "nsContentUtils.h" #include "jsapi.h" @@ -93,7 +94,7 @@ TCPSocketChild::TCPSocketChild(const nsAString& aHost, const uint16_t& aPort) } void -TCPSocketChild::SendOpen(TCPSocket* aSocket, bool aUseSSL, bool aUseArrayBuffers) +TCPSocketChild::SendOpen(nsITCPSocketCallback* aSocket, bool aUseSSL, bool aUseArrayBuffers) { mSocket = aSocket; @@ -103,7 +104,7 @@ TCPSocketChild::SendOpen(TCPSocket* aSocket, bool aUseSSL, bool aUseArrayBuffers } void -TCPSocketChild::SendWindowlessOpenBind(TCPSocket* aSocket, +TCPSocketChild::SendWindowlessOpenBind(nsITCPSocketCallback* aSocket, const nsACString& aRemoteHost, uint16_t aRemotePort, const nsACString& aLocalHost, uint16_t aLocalPort, bool aUseSSL) @@ -164,9 +165,9 @@ TCPSocketChild::RecvCallback(const nsString& aType, const SendableData& data = aData.get_SendableData(); if (data.type() == SendableData::TArrayOfuint8_t) { - mSocket->FireDataEvent(cx, aType, data.get_ArrayOfuint8_t()); + mSocket->FireDataArrayEvent(aType, data.get_ArrayOfuint8_t()); } else if (data.type() == SendableData::TnsCString) { - mSocket->FireDataEvent(aType, data.get_nsCString()); + mSocket->FireDataStringEvent(aType, data.get_nsCString()); } else { MOZ_CRASH("Invalid callback data type!"); } diff --git a/dom/network/TCPSocketChild.h b/dom/network/TCPSocketChild.h index 18b6265e4abe..1adbe90d1d87 100644 --- a/dom/network/TCPSocketChild.h +++ b/dom/network/TCPSocketChild.h @@ -12,6 +12,8 @@ #include "nsCOMPtr.h" #include "js/TypeDecls.h" +class nsITCPSocketCallback; + namespace IPC { bool DeserializeArrayBuffer(JSContext* cx, @@ -36,7 +38,7 @@ protected: TCPSocketChildBase(); virtual ~TCPSocketChildBase(); - nsRefPtr mSocket; + nsCOMPtr mSocket; bool mIPCOpen; }; @@ -49,8 +51,8 @@ public: TCPSocketChild(const nsAString& aHost, const uint16_t& aPort); ~TCPSocketChild(); - void SendOpen(TCPSocket* aSocket, bool aUseSSL, bool aUseArrayBuffers); - void SendWindowlessOpenBind(TCPSocket* aSocket, + void SendOpen(nsITCPSocketCallback* aSocket, bool aUseSSL, bool aUseArrayBuffers); + void SendWindowlessOpenBind(nsITCPSocketCallback* aSocket, const nsACString& aRemoteHost, uint16_t aRemotePort, const nsACString& aLocalHost, uint16_t aLocalPort, bool aUseSSL); diff --git a/dom/network/interfaces/moz.build b/dom/network/interfaces/moz.build index 18f4ee6875d1..a503f951e819 100644 --- a/dom/network/interfaces/moz.build +++ b/dom/network/interfaces/moz.build @@ -6,6 +6,7 @@ XPIDL_SOURCES += [ 'nsIMozNavigatorNetwork.idl', + 'nsITCPSocketCallback.idl', 'nsIUDPSocketChild.idl', ] diff --git a/dom/network/interfaces/nsITCPSocketCallback.idl b/dom/network/interfaces/nsITCPSocketCallback.idl new file mode 100644 index 000000000000..a0250267dceb --- /dev/null +++ b/dom/network/interfaces/nsITCPSocketCallback.idl @@ -0,0 +1,62 @@ +/* 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/. */ + +/** + * MozTCPSocket exposes a TCP client and server sockets + * to highly privileged apps. It provides a buffered, non-blocking + * interface for sending. For receiving, it uses an asynchronous, + * event handler based interface. + */ + +#include "domstubs.idl" + +%{C++ +template class InfallibleTArray; +%} +[ref] native nsUint8TArrayRef(InfallibleTArray); +[ptr] native JSContextPtr(JSContext); + + +/* + * This interface is implemented in TCPSocket.cpp as an internal interface + * for use in cross-process socket implementation. + * Needed to account for multiple possible types that can be provided to + * the socket callbacks as arguments. + */ +[scriptable, uuid(ac2c4b69-cb79-4767-b1ce-bcf62945cd39)] +interface nsITCPSocketCallback : nsISupports { + // Limitation of TCPSocket's buffer size. + const unsigned long BUFFER_SIZE = 65536; + + // Dispatch an "error" event at this object with the given name and type. + void fireErrorEvent(in AString name, in AString type); + + // Dispatch a "data" event at this object with a string + void fireDataStringEvent(in DOMString type, in ACString data); + + // Dispatch a "data" event at this object with an Array + void fireDataArrayEvent(in DOMString type, [const] in nsUint8TArrayRef data); + + // Dispatch a "data" event at this object with an ArrayBuffer argument + void fireDataEvent(in JSContextPtr cx, in DOMString type, in jsval data); + + // Dispatch an event of the given type at this object. + void fireEvent(in DOMString type); + + // Update the DOM object's readyState. + // @param readyState + // new ready state + void updateReadyState(in unsigned long readystate); + + // Update the DOM object's bufferedAmount value with a tracking number to + // to allow tracking of which writes are "in-flight" + // @param bufferedAmount + // TCPSocket parent's bufferedAmount. + // @param trackingNumber + // A number to ensure the bufferedAmount is updated after data + // from child are sent to parent. + void updateBufferedAmount(in uint32_t bufferedAmount, + in uint32_t trackingNumber); +}; + From 028e16c84d2a0c71e27c4d65c04616d9476463c6 Mon Sep 17 00:00:00 2001 From: "\"Chih-Kai (Patrick) Wang\"" Date: Mon, 5 Jan 2015 15:49:50 +0800 Subject: [PATCH 13/29] Bug 950660: Part 4: Bridge TCPSocketChild to nr_socket r=bwc,jdm Improve use of TCPSocket to track in-flight writes and suppress extra runnables Adds lots of logging to nr_socket_buffered_stun.c Rework mtransport code to use new TCPSocketChild interface --- media/mtransport/build/moz.build | 2 + media/mtransport/moz.build | 2 + media/mtransport/nr_socket_prsock.cpp | 687 +++++++++++++++--- media/mtransport/nr_socket_prsock.h | 136 +++- media/mtransport/standalone/moz.build | 1 + media/mtransport/testlib/moz.build | 1 + .../nICEr/src/stun/nr_socket_buffered_stun.c | 34 +- .../src/peerconnection/PeerConnectionImpl.cpp | 6 - 8 files changed, 753 insertions(+), 116 deletions(-) diff --git a/media/mtransport/build/moz.build b/media/mtransport/build/moz.build index 969b7765bfaa..9732c0ee94e4 100644 --- a/media/mtransport/build/moz.build +++ b/media/mtransport/build/moz.build @@ -4,6 +4,8 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +include("/ipc/chromium/chromium-config.mozbuild") + EXPORTS.mtransport += [ '../dtlsidentity.h', '../m_cpp_utils.h', diff --git a/media/mtransport/moz.build b/media/mtransport/moz.build index 4b532c07db16..883507d3d299 100644 --- a/media/mtransport/moz.build +++ b/media/mtransport/moz.build @@ -4,6 +4,8 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +include("/ipc/chromium/chromium-config.mozbuild") + DIRS += [ '/media/mtransport/third_party', '/media/mtransport/build', diff --git a/media/mtransport/nr_socket_prsock.cpp b/media/mtransport/nr_socket_prsock.cpp index 7cf7af89af00..371a5a7efabe 100644 --- a/media/mtransport/nr_socket_prsock.cpp +++ b/media/mtransport/nr_socket_prsock.cpp @@ -106,6 +106,54 @@ nrappkit copyright: #include "nsXPCOM.h" #include "nsXULAppAPI.h" #include "runnable_utils.h" +#include "mozilla/SyncRunnable.h" +#include "nsTArray.h" +#include "mozilla/dom/TCPSocketBinding.h" +#include "nsITCPSocketCallback.h" + +#if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API) +// csi_platform.h deep in nrappkit defines LOG_INFO and LOG_WARNING +#ifdef LOG_INFO +#define LOG_TEMP_INFO LOG_INFO +#undef LOG_INFO +#endif +#ifdef LOG_WARNING +#define LOG_TEMP_WARNING LOG_WARNING +#undef LOG_WARNING +#endif +#if defined(LOG_DEBUG) +#define LOG_TEMP_DEBUG LOG_DEBUG +#undef LOG_DEBUG +#endif +#undef strlcpy + +// TCPSocketChild.h doesn't include TypedArray.h +namespace mozilla { +namespace dom { +class ArrayBuffer; +} +} +#include "mozilla/dom/network/TCPSocketChild.h" + +#ifdef LOG_TEMP_INFO +#define LOG_INFO LOG_TEMP_INFO +#endif +#ifdef LOG_TEMP_WARNING +#define LOG_WARNING LOG_TEMP_WARNING +#endif + +#ifdef LOG_TEMP_DEBUG +#define LOG_DEBUG LOG_TEMP_DEBUG +#endif +#ifdef XP_WIN +#ifdef LOG_DEBUG +#undef LOG_DEBUG +#endif +// cloned from csi_platform.h. Win32 doesn't like how we hide symbols +#define LOG_DEBUG 7 +#endif +#endif + extern "C" { #include "nr_api.h" @@ -203,6 +251,31 @@ static void ClearSingletonOnShutdown() } #endif +static nsIThread* GetIOThreadAndAddUse_s() +{ + // Always runs on STS thread! +#if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API) + // We need to safely release this on shutdown to avoid leaks + if (!sThread) { + sThread = new SingletonThreadHolder(NS_LITERAL_CSTRING("mtransport")); + NS_DispatchToMainThread(mozilla::WrapRunnableNM(&ClearSingletonOnShutdown)); + } + // Mark that we're using the shared thread and need it to stick around + sThread->AddUse(); + return sThread->GetThread(); +#else + static nsCOMPtr sThread; + if (!sThread) { + (void) NS_NewNamedThread("mtransport", getter_AddRefs(sThread)); + } + return sThread; +#endif +} + +NrSocketIpc::NrSocketIpc(nsIEventTarget *aThread) + : io_thread_(aThread) +{} + static TimeStamp nr_socket_short_term_violation_time; static TimeStamp nr_socket_long_term_violation_time; @@ -924,10 +997,10 @@ abort: return(_status); } -NS_IMPL_ISUPPORTS(NrSocketIpcProxy, nsIUDPSocketInternal) +NS_IMPL_ISUPPORTS(NrUdpSocketIpcProxy, nsIUDPSocketInternal) nsresult -NrSocketIpcProxy::Init(const nsRefPtr& socket) +NrUdpSocketIpcProxy::Init(const nsRefPtr& socket) { nsresult rv; sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); @@ -940,7 +1013,7 @@ NrSocketIpcProxy::Init(const nsRefPtr& socket) return NS_OK; } -NrSocketIpcProxy::~NrSocketIpcProxy() +NrUdpSocketIpcProxy::~NrUdpSocketIpcProxy() { // Send our ref to STS to be released RUN_ON_THREAD(sts_thread_, @@ -950,39 +1023,39 @@ NrSocketIpcProxy::~NrSocketIpcProxy() // IUDPSocketInternal interfaces // callback while error happened in UDP socket operation -NS_IMETHODIMP NrSocketIpcProxy::CallListenerError(const nsACString &message, - const nsACString &filename, - uint32_t line_number) { +NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerError(const nsACString &message, + const nsACString &filename, + uint32_t line_number) { return socket_->CallListenerError(message, filename, line_number); } // callback while receiving UDP packet -NS_IMETHODIMP NrSocketIpcProxy::CallListenerReceivedData(const nsACString &host, - uint16_t port, - const uint8_t *data, - uint32_t data_length) { +NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerReceivedData(const nsACString &host, + uint16_t port, + const uint8_t *data, + uint32_t data_length) { return socket_->CallListenerReceivedData(host, port, data, data_length); } // callback while UDP socket is opened -NS_IMETHODIMP NrSocketIpcProxy::CallListenerOpened() { +NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerOpened() { return socket_->CallListenerOpened(); } // callback while UDP socket is closed -NS_IMETHODIMP NrSocketIpcProxy::CallListenerClosed() { +NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerClosed() { return socket_->CallListenerClosed(); } -// NrSocketIpc Implementation -NrSocketIpc::NrSocketIpc() - : err_(false), - state_(NR_INIT), - io_thread_(GetIOThreadAndAddUse_s()), - monitor_("NrSocketIpc") { +// NrUdpSocketIpc Implementation +NrUdpSocketIpc::NrUdpSocketIpc() + : NrSocketIpc(GetIOThreadAndAddUse_s()), + monitor_("NrUdpSocketIpc"), + err_(false), + state_(NR_INIT) { } -NrSocketIpc::~NrSocketIpc() +NrUdpSocketIpc::~NrUdpSocketIpc() { // also guarantees socket_child_ is released from the io_thread, and // tells the SingletonThreadHolder we're done with it @@ -990,40 +1063,18 @@ NrSocketIpc::~NrSocketIpc() #if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API) // close(), but transfer the socket_child_ reference to die as well RUN_ON_THREAD(io_thread_, - mozilla::WrapRunnableNM(&NrSocketIpc::release_child_i, + mozilla::WrapRunnableNM(&NrUdpSocketIpc::release_child_i, socket_child_.forget().take(), sts_thread_), NS_DISPATCH_NORMAL); #endif } -/* static */ -nsIThread* NrSocketIpc::GetIOThreadAndAddUse_s() -{ - // Always runs on STS thread! -#if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API) - // We need to safely release this on shutdown to avoid leaks - if (!sThread) { - sThread = new SingletonThreadHolder(NS_LITERAL_CSTRING("mtransport")); - NS_DispatchToMainThread(mozilla::WrapRunnableNM(&ClearSingletonOnShutdown)); - } - // Mark that we're using the shared thread and need it to stick around - sThread->AddUse(); - return sThread->GetThread(); -#else - static nsCOMPtr sThread; - if (!sThread) { - (void) NS_NewNamedThread("mtransport", getter_AddRefs(sThread)); - } - return sThread; -#endif -} - // IUDPSocketInternal interfaces // callback while error happened in UDP socket operation -NS_IMETHODIMP NrSocketIpc::CallListenerError(const nsACString &message, - const nsACString &filename, - uint32_t line_number) { +NS_IMETHODIMP NrUdpSocketIpc::CallListenerError(const nsACString &message, + const nsACString &filename, + uint32_t line_number) { ASSERT_ON_THREAD(io_thread_); r_log(LOG_GENERIC, LOG_ERR, "UDP socket error:%s at %s:%d", @@ -1037,10 +1088,10 @@ NS_IMETHODIMP NrSocketIpc::CallListenerError(const nsACString &message, } // callback while receiving UDP packet -NS_IMETHODIMP NrSocketIpc::CallListenerReceivedData(const nsACString &host, - uint16_t port, - const uint8_t *data, - uint32_t data_length) { +NS_IMETHODIMP NrUdpSocketIpc::CallListenerReceivedData(const nsACString &host, + uint16_t port, + const uint8_t *data, + uint32_t data_length) { ASSERT_ON_THREAD(io_thread_); PRNetAddr addr; @@ -1067,15 +1118,15 @@ NS_IMETHODIMP NrSocketIpc::CallListenerReceivedData(const nsACString &host, RefPtr msg(new nr_udp_message(addr, buf)); RUN_ON_THREAD(sts_thread_, - mozilla::WrapRunnable(nsRefPtr(this), - &NrSocketIpc::recv_callback_s, + mozilla::WrapRunnable(nsRefPtr(this), + &NrUdpSocketIpc::recv_callback_s, msg), NS_DISPATCH_NORMAL); return NS_OK; } // callback while UDP socket is opened -NS_IMETHODIMP NrSocketIpc::CallListenerOpened() { +NS_IMETHODIMP NrUdpSocketIpc::CallListenerOpened() { ASSERT_ON_THREAD(io_thread_); ReentrantMonitorAutoEnter mon(monitor_); @@ -1129,7 +1180,7 @@ NS_IMETHODIMP NrSocketIpc::CallListenerOpened() { } // callback while UDP socket is closed -NS_IMETHODIMP NrSocketIpc::CallListenerClosed() { +NS_IMETHODIMP NrUdpSocketIpc::CallListenerClosed() { ASSERT_ON_THREAD(io_thread_); ReentrantMonitorAutoEnter mon(monitor_); @@ -1140,8 +1191,10 @@ NS_IMETHODIMP NrSocketIpc::CallListenerClosed() { return NS_OK; } -// nr_socket public APIs -int NrSocketIpc::create(nr_transport_addr *addr) { +// +// NrSocketBase methods. +// +int NrUdpSocketIpc::create(nr_transport_addr *addr) { ASSERT_ON_THREAD(sts_thread_); int r, _status; @@ -1155,12 +1208,6 @@ int NrSocketIpc::create(nr_transport_addr *addr) { ABORT(R_INTERNAL); } - // Bug 950660: Remote TCP socket is not supported yet. - if (NS_WARN_IF(addr->protocol != IPPROTO_UDP)) { - MOZ_ASSERT(false, "NrSocket over TCP is not e10s ready, see Bug 950660"); - ABORT(R_INTERNAL); - } - sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); if (NS_FAILED(rv)) { MOZ_ASSERT(false, "Failed to get STS thread"); @@ -1171,7 +1218,7 @@ int NrSocketIpc::create(nr_transport_addr *addr) { ABORT(r); } - // wildcard address will be resolved at NrSocketIpc::CallListenerVoid + // wildcard address will be resolved at NrUdpSocketIpc::CallListenerVoid if ((r=nr_transport_addr_copy(&my_addr_, addr))) { ABORT(r); } @@ -1179,8 +1226,8 @@ int NrSocketIpc::create(nr_transport_addr *addr) { state_ = NR_CONNECTING; RUN_ON_THREAD(io_thread_, - mozilla::WrapRunnable(nsRefPtr(this), - &NrSocketIpc::create_i, + mozilla::WrapRunnable(nsRefPtr(this), + &NrUdpSocketIpc::create_i, host, static_cast(port)), NS_DISPATCH_NORMAL); @@ -1198,7 +1245,7 @@ abort: return(_status); } -int NrSocketIpc::sendto(const void *msg, size_t len, int flags, +int NrUdpSocketIpc::sendto(const void *msg, size_t len, int flags, nr_transport_addr *to) { ASSERT_ON_THREAD(sts_thread_); @@ -1222,22 +1269,22 @@ int NrSocketIpc::sendto(const void *msg, size_t len, int flags, nsAutoPtr buf(new DataBuffer(static_cast(msg), len)); RUN_ON_THREAD(io_thread_, - mozilla::WrapRunnable(nsRefPtr(this), - &NrSocketIpc::sendto_i, + mozilla::WrapRunnable(nsRefPtr(this), + &NrUdpSocketIpc::sendto_i, addr, buf), NS_DISPATCH_NORMAL); return 0; } -void NrSocketIpc::close() { +void NrUdpSocketIpc::close() { ASSERT_ON_THREAD(sts_thread_); ReentrantMonitorAutoEnter mon(monitor_); state_ = NR_CLOSING; RUN_ON_THREAD(io_thread_, - mozilla::WrapRunnable(nsRefPtr(this), - &NrSocketIpc::close_i), + mozilla::WrapRunnable(nsRefPtr(this), + &NrUdpSocketIpc::close_i), NS_DISPATCH_NORMAL); //remove all enqueued messages @@ -1245,7 +1292,7 @@ void NrSocketIpc::close() { std::swap(received_msgs_, empty); } -int NrSocketIpc::recvfrom(void *buf, size_t maxlen, size_t *len, int flags, +int NrUdpSocketIpc::recvfrom(void *buf, size_t maxlen, size_t *len, int flags, nr_transport_addr *from) { ASSERT_ON_THREAD(sts_thread_); @@ -1289,7 +1336,7 @@ abort: return(_status); } -int NrSocketIpc::getaddr(nr_transport_addr *addrp) { +int NrUdpSocketIpc::getaddr(nr_transport_addr *addrp) { ASSERT_ON_THREAD(sts_thread_); ReentrantMonitorAutoEnter mon(monitor_); @@ -1301,38 +1348,39 @@ int NrSocketIpc::getaddr(nr_transport_addr *addrp) { return nr_transport_addr_copy(addrp, &my_addr_); } -int NrSocketIpc::connect(nr_transport_addr *addr) { +int NrUdpSocketIpc::connect(nr_transport_addr *addr) { MOZ_ASSERT(false); return R_INTERNAL; } -int NrSocketIpc::write(const void *msg, size_t len, size_t *written) { +int NrUdpSocketIpc::write(const void *msg, size_t len, size_t *written) { MOZ_ASSERT(false); return R_INTERNAL; } -int NrSocketIpc::read(void* buf, size_t maxlen, size_t *len) { +int NrUdpSocketIpc::read(void* buf, size_t maxlen, size_t *len) { MOZ_ASSERT(false); return R_INTERNAL; } -int NrSocketIpc::listen(int backlog) { +int NrUdpSocketIpc::listen(int backlog) { MOZ_ASSERT(false); return R_INTERNAL; } -int NrSocketIpc::accept(nr_transport_addr *addrp, nr_socket **sockp) { +int NrUdpSocketIpc::accept(nr_transport_addr *addrp, nr_socket **sockp) { MOZ_ASSERT(false); return R_INTERNAL; } // IO thread executors -void NrSocketIpc::create_i(const nsACString &host, const uint16_t port) { +void NrUdpSocketIpc::create_i(const nsACString &host, const uint16_t port) { ASSERT_ON_THREAD(io_thread_); nsresult rv; nsCOMPtr socketChild = do_CreateInstance("@mozilla.org/udp-socket-child;1", &rv); if (NS_FAILED(rv)) { + ReentrantMonitorAutoEnter mon(monitor_); err_ = true; MOZ_ASSERT(false, "Failed to create UDPSocketChild"); return; @@ -1349,7 +1397,7 @@ void NrSocketIpc::create_i(const nsACString &host, const uint16_t port) { socketChild = nullptr; } - nsRefPtr proxy(new NrSocketIpcProxy); + nsRefPtr proxy(new NrUdpSocketIpcProxy); rv = proxy->Init(this); if (NS_FAILED(rv)) { err_ = true; @@ -1368,17 +1416,16 @@ void NrSocketIpc::create_i(const nsACString &host, const uint16_t port) { } } -void NrSocketIpc::sendto_i(const net::NetAddr &addr, nsAutoPtr buf) { +void NrUdpSocketIpc::sendto_i(const net::NetAddr &addr, nsAutoPtr buf) { ASSERT_ON_THREAD(io_thread_); + ReentrantMonitorAutoEnter mon(monitor_); + if (!socket_child_) { MOZ_ASSERT(false); err_ = true; return; } - - ReentrantMonitorAutoEnter mon(monitor_); - if (NS_FAILED(socket_child_->SendWithAddress(&addr, buf->data(), buf->len()))) { @@ -1386,7 +1433,7 @@ void NrSocketIpc::sendto_i(const net::NetAddr &addr, nsAutoPtr buf) } } -void NrSocketIpc::close_i() { +void NrUdpSocketIpc::close_i() { ASSERT_ON_THREAD(io_thread_); if (socket_child_) { @@ -1398,8 +1445,8 @@ void NrSocketIpc::close_i() { #if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API) // close(), but transfer the socket_child_ reference to die as well // static -void NrSocketIpc::release_child_i(nsIUDPSocketChild* aChild, - nsCOMPtr sts_thread) { +void NrUdpSocketIpc::release_child_i(nsIUDPSocketChild* aChild, + nsCOMPtr sts_thread) { nsRefPtr socket_child_ref = already_AddRefed(aChild); if (socket_child_ref) { @@ -1407,16 +1454,16 @@ void NrSocketIpc::release_child_i(nsIUDPSocketChild* aChild, } // Tell SingletonThreadHolder we're done with it RUN_ON_THREAD(sts_thread, - mozilla::WrapRunnableNM(&NrSocketIpc::release_use_s), + mozilla::WrapRunnableNM(&NrUdpSocketIpc::release_use_s), NS_DISPATCH_NORMAL); } -void NrSocketIpc::release_use_s() { +void NrUdpSocketIpc::release_use_s() { sThread->ReleaseUse(); } #endif -void NrSocketIpc::recv_callback_s(RefPtr msg) { +void NrUdpSocketIpc::recv_callback_s(RefPtr msg) { ASSERT_ON_THREAD(sts_thread_); { @@ -1434,6 +1481,448 @@ void NrSocketIpc::recv_callback_s(RefPtr msg) { } } +#if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API) +// TCPSocket. +class NrTcpSocketIpc::TcpSocketReadyRunner: public nsRunnable +{ +public: + explicit TcpSocketReadyRunner(NrTcpSocketIpc *sck) + : socket_(sck) {} + + NS_IMETHODIMP Run() { + socket_->maybe_post_socket_ready(); + return NS_OK; + } + +private: + nsRefPtr socket_; +}; + + +NS_IMPL_ISUPPORTS(NrTcpSocketIpc, + nsITCPSocketCallback) + +NrTcpSocketIpc::NrTcpSocketIpc(nsIThread* aThread) + : NrSocketIpc(static_cast(aThread)), + mirror_state_(NR_INIT), + state_(NR_INIT), + buffered_bytes_(0), + tracking_number_(0) { +} + +NrTcpSocketIpc::~NrTcpSocketIpc() +{ + // also guarantees socket_child_ is released from the io_thread + + // close(), but transfer the socket_child_ reference to die as well + RUN_ON_THREAD(io_thread_, + mozilla::WrapRunnableNM(&NrTcpSocketIpc::release_child_i, + socket_child_.forget().take(), + sts_thread_), + NS_DISPATCH_NORMAL); +} + +// +// nsITCPSocketCallback methods +// +NS_IMETHODIMP NrTcpSocketIpc::UpdateReadyState(uint32_t aReadyState) { + NrSocketIpcState temp = NR_INIT; + switch (static_cast(aReadyState)) { + case dom::TCPReadyState::Connecting: + temp = NR_CONNECTING; + break; + case dom::TCPReadyState::Open: + temp = NR_CONNECTED; + break; + case dom::TCPReadyState::Closing: + temp = NR_CLOSING; + break; + case dom::TCPReadyState::Closed: + temp = NR_CLOSED; + break; + default: + MOZ_ASSERT(false, "Invalid ReadyState"); + return NS_OK; + } + if (mirror_state_ != temp) { + mirror_state_ = temp; + RUN_ON_THREAD(sts_thread_, + mozilla::WrapRunnable(nsRefPtr(this), + &NrTcpSocketIpc::update_state_s, + temp), + NS_DISPATCH_NORMAL); + } + return NS_OK; +} + +NS_IMETHODIMP NrTcpSocketIpc::UpdateBufferedAmount(uint32_t buffered_amount, + uint32_t tracking_number) { + RUN_ON_THREAD(sts_thread_, + mozilla::WrapRunnable(nsRefPtr(this), + &NrTcpSocketIpc::message_sent_s, + buffered_amount, + tracking_number), + NS_DISPATCH_NORMAL); + + return NS_OK; +} + +NS_IMETHODIMP NrTcpSocketIpc::FireDataArrayEvent(const nsAString& aType, + const InfallibleTArray& buffer) { + // Called when we received data. + uint8_t *buf = const_cast(buffer.Elements()); + + nsAutoPtr data_buf(new DataBuffer(buf, buffer.Length())); + nsRefPtr msg = new nr_tcp_message(data_buf); + + RUN_ON_THREAD(sts_thread_, + mozilla::WrapRunnable(nsRefPtr(this), + &NrTcpSocketIpc::recv_message_s, + msg), + NS_DISPATCH_NORMAL); + return NS_OK; +} + +NS_IMETHODIMP NrTcpSocketIpc::FireErrorEvent(const nsAString &type, + const nsAString &name) { + r_log(LOG_GENERIC, LOG_ERR, + "Error from TCPSocketChild: type: %s, name: %s", + NS_LossyConvertUTF16toASCII(type).get(), NS_LossyConvertUTF16toASCII(name).get()); + socket_child_ = nullptr; + + mirror_state_ = NR_CLOSED; + RUN_ON_THREAD(sts_thread_, + mozilla::WrapRunnable(nsRefPtr(this), + &NrTcpSocketIpc::update_state_s, + NR_CLOSED), + NS_DISPATCH_NORMAL); + + return NS_OK; +} + +// methods of nsITCPSocketCallback that we are not going to implement. + +NS_IMETHODIMP NrTcpSocketIpc::FireDataEvent(JSContext* aCx, + const nsAString &type, + const JS::HandleValue data) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP NrTcpSocketIpc::FireDataStringEvent(const nsAString &type, + const nsACString &data) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP NrTcpSocketIpc::FireEvent(const nsAString &type) { + // XXX support type.mData == 'close' at least + return NS_ERROR_NOT_IMPLEMENTED; +} + +// +// NrSocketBase methods. +// +int NrTcpSocketIpc::create(nr_transport_addr *addr) { + int r, _status; + nsresult rv; + int32_t port; + nsCString host; + + if (state_ != NR_INIT) { + ABORT(R_INTERNAL); + } + + sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) { + MOZ_ASSERT(false, "Failed to get STS thread"); + ABORT(R_INTERNAL); + } + + // Sanity check + if ((r=nr_transport_addr_get_addrstring_and_port(addr, &host, &port))) { + ABORT(r); + } + + if ((r=nr_transport_addr_copy(&my_addr_, addr))) { + ABORT(r); + } + + _status = 0; +abort: + return(_status); +} + +int NrTcpSocketIpc::sendto(const void *msg, size_t len, + int flags, nr_transport_addr *to) { + MOZ_ASSERT(false); + return R_INTERNAL; +} + +int NrTcpSocketIpc::recvfrom(void * buf, size_t maxlen, + size_t *len, int flags, + nr_transport_addr *from) { + MOZ_ASSERT(false); + return R_INTERNAL; +} + +int NrTcpSocketIpc::getaddr(nr_transport_addr *addrp) { + ASSERT_ON_THREAD(sts_thread_); + return nr_transport_addr_copy(addrp, &my_addr_); +} + +void NrTcpSocketIpc::close() { + ASSERT_ON_THREAD(sts_thread_); + + if (state_ == NR_CLOSED || state_ == NR_CLOSING) { + return; + } + + state_ = NR_CLOSING; + + RUN_ON_THREAD(io_thread_, + mozilla::WrapRunnable(nsRefPtr(this), + &NrTcpSocketIpc::close_i), + NS_DISPATCH_NORMAL); + + //remove all enqueued messages + std::queue> empty; + std::swap(msg_queue_, empty); +} + +int NrTcpSocketIpc::connect(nr_transport_addr *addr) { + nsCString remote_addr, local_addr; + int32_t remote_port, local_port; + int r, _status; + if ((r=nr_transport_addr_get_addrstring_and_port(addr, + &remote_addr, + &remote_port))) { + ABORT(r); + } + + if ((r=nr_transport_addr_get_addrstring_and_port(&my_addr_, + &local_addr, + &local_port))) { + MOZ_ASSERT(false); // shouldn't fail as it was sanity-checked in ::create() + ABORT(r); + } + + state_ = mirror_state_ = NR_CONNECTING; + RUN_ON_THREAD(io_thread_, + mozilla::WrapRunnable(nsRefPtr(this), + &NrTcpSocketIpc::connect_i, + remote_addr, + static_cast(remote_port), + local_addr, + static_cast(local_port)), + NS_DISPATCH_NORMAL); + + // Make caller wait for ready to write. + _status = R_WOULDBLOCK; + abort: + return _status; +} + +int NrTcpSocketIpc::write(const void *msg, size_t len, size_t *written) { + ASSERT_ON_THREAD(sts_thread_); + int _status = 0; + if (state_ != NR_CONNECTED) { + ABORT(R_FAILED); + } + + if (buffered_bytes_ + len >= nsITCPSocketCallback::BUFFER_SIZE) { + ABORT(R_WOULDBLOCK); + } + + buffered_bytes_ += len; + { + InfallibleTArray* arr = new InfallibleTArray(); + arr->AppendElements(static_cast(msg), len); + // keep track of un-acknowleged writes by tracking number. + writes_in_flight_.push_back(len); + RUN_ON_THREAD(io_thread_, + mozilla::WrapRunnable(nsRefPtr(this), + &NrTcpSocketIpc::write_i, + nsAutoPtr>(arr), + ++tracking_number_), + NS_DISPATCH_NORMAL); + } + *written = len; + abort: + return _status; +} + +int NrTcpSocketIpc::read(void* buf, size_t maxlen, size_t *len) { + int _status = 0; + if (state_ != NR_CONNECTED) { + ABORT(R_FAILED); + } + + if (msg_queue_.size() == 0) { + ABORT(R_WOULDBLOCK); + } + + { + nsRefPtr msg(msg_queue_.front()); + size_t consumed_len = std::min(maxlen, msg->unread_bytes()); + memcpy(buf, msg->reading_pointer(), consumed_len); + if (consumed_len < msg->unread_bytes()) { + // There is still something left in buffer. + msg->read_bytes += consumed_len; + } else { + msg_queue_.pop(); + } + *len = consumed_len; + } + + abort: + return _status; +} + +int NrTcpSocketIpc::listen(int backlog) { + MOZ_ASSERT(false); + return R_INTERNAL; +} + +int NrTcpSocketIpc::accept(nr_transport_addr *addrp, nr_socket **sockp) { + MOZ_ASSERT(false); + return R_INTERNAL; +} + +void NrTcpSocketIpc::connect_i(const nsACString &remote_addr, + uint16_t remote_port, + const nsACString &local_addr, + uint16_t local_port) { + ASSERT_ON_THREAD(io_thread_); + mirror_state_ = NR_CONNECTING; + + dom::TCPSocketChild* child = new dom::TCPSocketChild(NS_ConvertUTF8toUTF16(remote_addr), remote_port); + socket_child_ = child; + + // XXX remove remote! + socket_child_->SendWindowlessOpenBind(this, + remote_addr, remote_port, + local_addr, local_port, + /* use ssl */ false); +} + +void NrTcpSocketIpc::write_i(nsAutoPtr> arr, + uint32_t tracking_number) { + ASSERT_ON_THREAD(io_thread_); + if (!socket_child_) { + return; + } + socket_child_->SendSendArray(*arr, tracking_number); +} + +void NrTcpSocketIpc::close_i() { + ASSERT_ON_THREAD(io_thread_); + mirror_state_ = NR_CLOSING; + if (!socket_child_) { + return; + } + socket_child_->SendClose(); +} + +// close(), but transfer the socket_child_ reference to die as well +// static +void NrTcpSocketIpc::release_child_i(dom::TCPSocketChild* aChild, + nsCOMPtr sts_thread) { + nsRefPtr socket_child_ref = + already_AddRefed(aChild); + if (socket_child_ref) { + socket_child_ref->SendClose(); + } + // io_thread_ is MainThread, so no use to release +} + +void NrTcpSocketIpc::message_sent_s(uint32_t buffered_amount, + uint32_t tracking_number) { + ASSERT_ON_THREAD(sts_thread_); + + size_t num_unacked_writes = tracking_number_ - tracking_number; + while (writes_in_flight_.size() > num_unacked_writes) { + writes_in_flight_.pop_front(); + } + + for (size_t unacked_write_len : writes_in_flight_) { + buffered_amount += unacked_write_len; + } + + r_log(LOG_GENERIC, LOG_ERR, + "UpdateBufferedAmount: (tracking %u): %u, waiting: %s", + tracking_number, buffered_amount, + (poll_flags() & PR_POLL_WRITE) ? "yes" : "no"); + + buffered_bytes_ = buffered_amount; + maybe_post_socket_ready(); +} + +void NrTcpSocketIpc::recv_message_s(nr_tcp_message *msg) { + ASSERT_ON_THREAD(sts_thread_); + msg_queue_.push(msg); + maybe_post_socket_ready(); +} + +void NrTcpSocketIpc::update_state_s(NrSocketIpcState next_state) { + ASSERT_ON_THREAD(sts_thread_); + // only allow valid transitions + switch (state_) { + case NR_CONNECTING: + if (next_state == NR_CONNECTED) { + state_ = NR_CONNECTED; + maybe_post_socket_ready(); + } else { + state_ = next_state; // all states are valid from CONNECTING + } + break; + case NR_CONNECTED: + if (next_state != NR_CONNECTING) { + state_ = next_state; + } + break; + case NR_CLOSING: + if (next_state == NR_CLOSED) { + state_ = next_state; + } + break; + case NR_CLOSED: + break; + default: + MOZ_CRASH("update_state_s while in illegal state"); + } +} + +void NrTcpSocketIpc::maybe_post_socket_ready() { + bool has_event = false; + if (state_ == NR_CONNECTED) { + if (poll_flags() & PR_POLL_WRITE) { + // This effectively polls via the event loop until the + // NR_ASYNC_WAIT_WRITE is no longer armed. + if (buffered_bytes_ < nsITCPSocketCallback::BUFFER_SIZE) { + r_log(LOG_GENERIC, LOG_INFO, "Firing write callback (%u)", + (uint32_t)buffered_bytes_); + fire_callback(NR_ASYNC_WAIT_WRITE); + has_event = true; + } + } + if (poll_flags() & PR_POLL_READ) { + if (msg_queue_.size()) { + r_log(LOG_GENERIC, LOG_INFO, "Firing read callback (%u)", + (uint32_t)msg_queue_.size()); + fire_callback(NR_ASYNC_WAIT_READ); + has_event = true; + } + } + } + + // If any event has been posted, we post a runnable to see + // if the events have to be posted again. + if (has_event) { + nsRefPtr runnable = new TcpSocketReadyRunner(this); + NS_DispatchToCurrentThread(runnable); + } +} +#endif + } // close namespace @@ -1474,16 +1963,30 @@ static nr_socket_vtbl nr_socket_local_vtbl={ int nr_socket_local_create(void *obj, nr_transport_addr *addr, nr_socket **sockp) { RefPtr sock; + int r, _status; // create IPC bridge for content process if (XRE_IsParentProcess()) { sock = new NrSocket(); } else { - sock = new NrSocketIpc(); + switch (addr->protocol) { + case IPPROTO_UDP: + sock = new NrUdpSocketIpc(); + break; + case IPPROTO_TCP: +#if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API) + { + nsCOMPtr main_thread; + NS_GetMainThread(getter_AddRefs(main_thread)); + sock = new NrTcpSocketIpc(main_thread.get()); + } +#else + ABORT(R_REJECTED); +#endif + break; + } } - int r, _status; - r = sock->create(addr); if (r) ABORT(r); diff --git a/media/mtransport/nr_socket_prsock.h b/media/mtransport/nr_socket_prsock.h index 052529d9766d..c923da398a24 100644 --- a/media/mtransport/nr_socket_prsock.h +++ b/media/mtransport/nr_socket_prsock.h @@ -61,6 +61,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "nsProxyRelease.h" #include "nsThreadUtils.h" +#include "nsITCPSocketCallback.h" #include "databuffer.h" #include "m_cpp_utils.h" #include "mozilla/ReentrantMonitor.h" @@ -72,6 +73,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. typedef struct nr_socket_vtbl_ nr_socket_vtbl; typedef struct nr_socket_ nr_socket; +#if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API) +namespace mozilla { +namespace dom { +class TCPSocketChild; +} +} +#endif + namespace mozilla { namespace net { @@ -209,7 +218,22 @@ public: NR_CLOSED, }; - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrSocketIpc, override) + NrSocketIpc(nsIEventTarget* aThread); + +protected: + nsCOMPtr sts_thread_; + // Note: for UDP PBackground, this is a thread held by SingletonThreadHolder. + // For TCP PNecko, this is MainThread (and TCPSocket requires MainThread currently) + const nsCOMPtr io_thread_; + virtual ~NrSocketIpc() {}; + +private: + DISALLOW_COPY_ASSIGN(NrSocketIpc); +}; + +class NrUdpSocketIpc : public NrSocketIpc { +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrUdpSocketIpc, override) NS_IMETHODIMP CallListenerError(const nsACString &message, const nsACString &filename, @@ -221,7 +245,7 @@ public: NS_IMETHODIMP CallListenerOpened(); NS_IMETHODIMP CallListenerClosed(); - NrSocketIpc(); + NrUdpSocketIpc(); // Implementations of the NrSocketBase APIs virtual int create(nr_transport_addr *addr) override; @@ -239,11 +263,9 @@ public: virtual int accept(nr_transport_addr *addrp, nr_socket **sockp) override; private: - virtual ~NrSocketIpc(); + virtual ~NrUdpSocketIpc(); - DISALLOW_COPY_ASSIGN(NrSocketIpc); - - static nsIThread* GetIOThreadAndAddUse_s(); + DISALLOW_COPY_ASSIGN(NrUdpSocketIpc); // Main or private thread executors of the NrSocketBase APIs void create_i(const nsACString &host, const uint16_t port); @@ -256,32 +278,118 @@ private: // STS thread executor void recv_callback_s(RefPtr msg); + ReentrantMonitor monitor_; // protects err_and state_ bool err_; NrSocketIpcState state_; - std::queue > received_msgs_; + + std::queue> received_msgs_; nsRefPtr socket_child_; // only accessed from the io_thread - nsCOMPtr sts_thread_; - const nsCOMPtr io_thread_; - ReentrantMonitor monitor_; }; // The socket child holds onto one of these, which just passes callbacks // through and makes sure the ref to the NrSocketIpc is released on STS. -class NrSocketIpcProxy : public nsIUDPSocketInternal { +class NrUdpSocketIpcProxy : public nsIUDPSocketInternal { public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIUDPSOCKETINTERNAL - nsresult Init(const nsRefPtr& socket); + nsresult Init(const nsRefPtr& socket); private: - virtual ~NrSocketIpcProxy(); + virtual ~NrUdpSocketIpcProxy(); - nsRefPtr socket_; + nsRefPtr socket_; nsCOMPtr sts_thread_; }; +struct nr_tcp_message { + explicit nr_tcp_message(nsAutoPtr &data) + : read_bytes(0) + , data(data) { + } + + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nr_tcp_message); + + const uint8_t *reading_pointer() const { + return data->data() + read_bytes; + } + + size_t unread_bytes() const { + return data->len() - read_bytes; + } + + size_t read_bytes; + +private: + ~nr_tcp_message() {} + DISALLOW_COPY_ASSIGN(nr_tcp_message); + + nsAutoPtr data; +}; + +#if defined(MOZILLA_INTERNAL_API) && !defined(MOZILLA_XPCOMRT_API) +class NrTcpSocketIpc : public NrSocketIpc, + public nsITCPSocketCallback { +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSITCPSOCKETCALLBACK + + explicit NrTcpSocketIpc(nsIThread* aThread); + + // Implementations of the NrSocketBase APIs + virtual int create(nr_transport_addr *addr) override; + virtual int sendto(const void *msg, size_t len, + int flags, nr_transport_addr *to) override; + virtual int recvfrom(void * buf, size_t maxlen, + size_t *len, int flags, + nr_transport_addr *from) override; + virtual int getaddr(nr_transport_addr *addrp) override; + virtual void close() override; + virtual int connect(nr_transport_addr *addr) override; + virtual int write(const void *msg, size_t len, size_t *written) override; + virtual int read(void* buf, size_t maxlen, size_t *len) override; + virtual int listen(int backlog) override; + virtual int accept(nr_transport_addr *addrp, nr_socket **sockp) override; + +private: + class TcpSocketReadyRunner; + DISALLOW_COPY_ASSIGN(NrTcpSocketIpc); + virtual ~NrTcpSocketIpc(); + + // Main thread executors of the NrSocketBase APIs + void connect_i(const nsACString &remote_addr, + uint16_t remote_port, + const nsACString &local_addr, + uint16_t local_port); + void write_i(nsAutoPtr> buf, + uint32_t tracking_number); + void close_i(); + + static void release_child_i(dom::TCPSocketChild* aChild, nsCOMPtr ststhread); + + // STS thread executor + void message_sent_s(uint32_t bufferedAmount, uint32_t tracking_number); + void recv_message_s(nr_tcp_message *msg); + void update_state_s(NrSocketIpcState next_state); + void maybe_post_socket_ready(); + + // Accessed from UpdateReadyState (not sts_thread) to avoid sending + // runnables when not needed + NrSocketIpcState mirror_state_; + + // variables that can only be accessed on STS. + NrSocketIpcState state_; + std::queue> msg_queue_; + uint32_t buffered_bytes_; + uint32_t tracking_number_; + std::deque writes_in_flight_; + + // main thread. + nsRefPtr socket_child_; +}; +#endif + int nr_netaddr_to_transport_addr(const net::NetAddr *netaddr, nr_transport_addr *addr, int protocol); diff --git a/media/mtransport/standalone/moz.build b/media/mtransport/standalone/moz.build index ec59b576bc68..31f400a66b69 100644 --- a/media/mtransport/standalone/moz.build +++ b/media/mtransport/standalone/moz.build @@ -7,6 +7,7 @@ Library('mtransport_standalone') include('../common.build') +include("/ipc/chromium/chromium-config.mozbuild") # These files cannot be built in unified mode because of the redefinition of # getLogModule, UNIMPLEMENTED, nr_socket_long_term_violation_time, diff --git a/media/mtransport/testlib/moz.build b/media/mtransport/testlib/moz.build index 5a6e62a6cf25..b59d59800e57 100644 --- a/media/mtransport/testlib/moz.build +++ b/media/mtransport/testlib/moz.build @@ -5,6 +5,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. include('../common.build') +include("/ipc/chromium/chromium-config.mozbuild") # These files cannot be built in unified mode because of the redefinition of # getLogModule, UNIMPLEMENTED, nr_socket_long_term_violation_time, diff --git a/media/mtransport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c b/media/mtransport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c index f1d46d3e7a86..c4c042162515 100644 --- a/media/mtransport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c +++ b/media/mtransport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c @@ -38,6 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "p_buf.h" #include "nr_socket.h" @@ -374,8 +375,10 @@ static void nr_socket_buffered_stun_connected_cb(NR_SOCKET s, int how, void *arg assert(!sock->connected); sock->connected = 1; - if (sock->pending) + if (sock->pending) { + r_log(LOG_GENERIC, LOG_INFO, "Invoking writable_cb on connected (%u)", (uint32_t) sock->pending); nr_socket_buffered_stun_writable_cb(s, how, arg); + } } static int nr_socket_buffered_stun_connect(void *obj, nr_transport_addr *addr) @@ -398,6 +401,7 @@ static int nr_socket_buffered_stun_connect(void *obj, nr_transport_addr *addr) } ABORT(r); } else { + r_log(LOG_GENERIC, LOG_INFO, "Connected without blocking"); sock->connected = 1; } @@ -432,7 +436,9 @@ static int nr_socket_buffered_stun_write(void *obj,const void *msg, size_t len, /* Buffers are close to full, report error. Do this now so we never get partial writes */ if ((sock->pending + len) > sock->max_pending) { - r_log(LOG_GENERIC, LOG_INFO, "Write buffer for %s full", sock->remote_addr.as_string); + r_log(LOG_GENERIC, LOG_INFO, "Write buffer for %s full (%u + %u > %u) - re-arming @%p", + sock->remote_addr.as_string, (uint32_t)sock->pending, (uint32_t)len, (uint32_t)sock->max_pending, + &(sock->pending)); ABORT(R_WOULDBLOCK); } @@ -440,8 +446,13 @@ static int nr_socket_buffered_stun_write(void *obj,const void *msg, size_t len, if (sock->connected && !sock->pending) { r = nr_socket_write(sock->inner, msg, len, &written2, 0); if (r) { - if (r != R_WOULDBLOCK) + if (r != R_WOULDBLOCK) { + r_log(LOG_GENERIC, LOG_ERR, "Write error for %s - %d", + sock->remote_addr.as_string, r); ABORT(r); + } + r_log(LOG_GENERIC, LOG_INFO, "Write of %" PRIu64 " blocked for %s", + (uint64_t) len, sock->remote_addr.as_string); written2=0; } @@ -454,8 +465,12 @@ static int nr_socket_buffered_stun_write(void *obj,const void *msg, size_t len, if (len) { if ((r=nr_p_buf_write_to_chain(sock->p_bufs, &sock->pending_writes, - ((UCHAR *)msg) + written2, len))) + ((UCHAR *)msg) + written2, len))) { + r_log(LOG_GENERIC, LOG_ERR, "Write_to_chain error for %s - %d", + sock->remote_addr.as_string, r); + ABORT(r); + } sock->pending += len; } @@ -464,6 +479,9 @@ static int nr_socket_buffered_stun_write(void *obj,const void *msg, size_t len, if ((r=nr_socket_buffered_stun_arm_writable_cb(sock))) ABORT(r); } + r_log(LOG_GENERIC, LOG_INFO, "Write buffer not empty for %s %u - %s armed (@%p)", + sock->remote_addr.as_string, (uint32_t)sock->pending, + already_armed ? "already" : "", &sock->pending); *written = original_len; @@ -486,6 +504,8 @@ static void nr_socket_buffered_stun_writable_cb(NR_SOCKET s, int how, void *arg) n1->length - n1->r_offset, &written, 0))) { + r_log(LOG_GENERIC, LOG_ERR, "Write error for %s - %d", + sock->remote_addr.as_string, r); ABORT(r); } @@ -495,6 +515,9 @@ static void nr_socket_buffered_stun_writable_cb(NR_SOCKET s, int how, void *arg) if (n1->r_offset < n1->length) { /* We wrote something, but not everything */ + r_log(LOG_GENERIC, LOG_INFO, "Write in callback didn't write all (remaining %u of %u) for %s", + n1->length - n1->r_offset, n1->length, + sock->remote_addr.as_string); ABORT(R_WOULDBLOCK); } @@ -506,7 +529,10 @@ static void nr_socket_buffered_stun_writable_cb(NR_SOCKET s, int how, void *arg) assert(!sock->pending); _status=0; abort: + r_log(LOG_GENERIC, LOG_INFO, "Writable_cb %s (%u (%p) pending)", + sock->remote_addr.as_string, (uint32_t)sock->pending, &(sock->pending)); if (_status && _status != R_WOULDBLOCK) { + r_log(LOG_GENERIC, LOG_ERR, "Failure in writable_cb: %d", _status); nr_socket_buffered_stun_failed(sock); } else if (sock->pending) { nr_socket_buffered_stun_arm_writable_cb(sock); diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index 55da33301c90..a721ab18373e 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -622,12 +622,6 @@ PeerConnectionConfiguration::AddIceServer(const RTCIceServer &aServer) NS_ConvertUTF16toUTF8 credential(aServer.mCredential); NS_ConvertUTF16toUTF8 username(aServer.mUsername); - // Bug 1039655 - TURN TCP is not e10s ready - if ((transport == kNrIceTransportTcp) && - (!XRE_IsParentProcess())) { - continue; - } - if (!addTurnServer(host.get(), port, username.get(), credential.get(), From 382e758bf46c0e3e9d86375f46046f3c94c552f5 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Fri, 7 Aug 2015 07:39:12 +0900 Subject: [PATCH 14/29] Bug 774364 - Part 2: Move architecture specific function from BaseAssembler-x86-shared.h to BaseAssembler-x86.h and BaseAssembler-x64.h. r=sstangl --HG-- extra : rebase_source : fa23208393ce9df8ca4c3b16685dba412df6fa71 --- js/src/jit/x64/BaseAssembler-x64.h | 782 ++++++++++++++++ js/src/jit/x86-shared/Assembler-x86-shared.h | 11 +- .../jit/x86-shared/BaseAssembler-x86-shared.h | 865 +----------------- js/src/jit/x86/BaseAssembler-x86.h | 116 +++ 4 files changed, 908 insertions(+), 866 deletions(-) create mode 100644 js/src/jit/x64/BaseAssembler-x64.h create mode 100644 js/src/jit/x86/BaseAssembler-x86.h diff --git a/js/src/jit/x64/BaseAssembler-x64.h b/js/src/jit/x64/BaseAssembler-x64.h new file mode 100644 index 000000000000..c21c40882a39 --- /dev/null +++ b/js/src/jit/x64/BaseAssembler-x64.h @@ -0,0 +1,782 @@ +/* -*- 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_x64_BaseAssembler_x64_h +#define jit_x64_BaseAssembler_x64_h + +#include "jit/x86-shared/BaseAssembler-x86-shared.h" + +namespace js { +namespace jit { + +namespace X86Encoding { + +class BaseAssemblerX64 : public BaseAssembler +{ + public: + + // Arithmetic operations: + + void addq_rr(RegisterID src, RegisterID dst) + { + spew("addq %s, %s", GPReg64Name(src), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_ADD_GvEv, src, dst); + } + + void addq_mr(int32_t offset, RegisterID base, RegisterID dst) + { + spew("addq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_ADD_GvEv, offset, base, dst); + } + + void addq_mr(const void* addr, RegisterID dst) + { + spew("addq %p, %s", addr, GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_ADD_GvEv, addr, dst); + } + + void addq_ir(int32_t imm, RegisterID dst) + { + spew("addq $%d, %s", imm, GPReg64Name(dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, dst, GROUP1_OP_ADD); + m_formatter.immediate8s(imm); + } else { + if (dst == rax) + m_formatter.oneByteOp64(OP_ADD_EAXIv); + else + m_formatter.oneByteOp64(OP_GROUP1_EvIz, dst, GROUP1_OP_ADD); + m_formatter.immediate32(imm); + } + } + + void addq_im(int32_t imm, int32_t offset, RegisterID base) + { + spew("addq $%d, " MEM_ob, imm, ADDR_ob(offset, base)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, offset, base, GROUP1_OP_ADD); + m_formatter.immediate8s(imm); + } else { + m_formatter.oneByteOp64(OP_GROUP1_EvIz, offset, base, GROUP1_OP_ADD); + m_formatter.immediate32(imm); + } + } + + void addq_im(int32_t imm, const void* addr) + { + spew("addq $%d, %p", imm, addr); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, addr, GROUP1_OP_ADD); + m_formatter.immediate8s(imm); + } else { + m_formatter.oneByteOp64(OP_GROUP1_EvIz, addr, GROUP1_OP_ADD); + m_formatter.immediate32(imm); + } + } + + void andq_rr(RegisterID src, RegisterID dst) + { + spew("andq %s, %s", GPReg64Name(src), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_AND_GvEv, src, dst); + } + + void andq_mr(int32_t offset, RegisterID base, RegisterID dst) + { + spew("andq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_AND_GvEv, offset, base, dst); + } + + void andq_mr(int32_t offset, RegisterID base, RegisterID index, int scale, RegisterID dst) + { + spew("andq " MEM_obs ", %s", ADDR_obs(offset, base, index, scale), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_AND_GvEv, offset, base, index, scale, dst); + } + + void andq_mr(const void* addr, RegisterID dst) + { + spew("andq %p, %s", addr, GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_AND_GvEv, addr, dst); + } + + void orq_mr(int32_t offset, RegisterID base, RegisterID dst) + { + spew("orq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_OR_GvEv, offset, base, dst); + } + + void orq_mr(const void* addr, RegisterID dst) + { + spew("orq %p, %s", addr, GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_OR_GvEv, addr, dst); + } + + void andq_ir(int32_t imm, RegisterID dst) + { + spew("andq $0x%" PRIx64 ", %s", int64_t(imm), GPReg64Name(dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, dst, GROUP1_OP_AND); + m_formatter.immediate8s(imm); + } else { + if (dst == rax) + m_formatter.oneByteOp64(OP_AND_EAXIv); + else + m_formatter.oneByteOp64(OP_GROUP1_EvIz, dst, GROUP1_OP_AND); + m_formatter.immediate32(imm); + } + } + + void negq_r(RegisterID dst) + { + spew("negq %s", GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_GROUP3_Ev, dst, GROUP3_OP_NEG); + } + + void orq_rr(RegisterID src, RegisterID dst) + { + spew("orq %s, %s", GPReg64Name(src), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_OR_GvEv, src, dst); + } + + void orq_ir(int32_t imm, RegisterID dst) + { + spew("orq $0x%" PRIx64 ", %s", int64_t(imm), GPReg64Name(dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, dst, GROUP1_OP_OR); + m_formatter.immediate8s(imm); + } else { + if (dst == rax) + m_formatter.oneByteOp64(OP_OR_EAXIv); + else + m_formatter.oneByteOp64(OP_GROUP1_EvIz, dst, GROUP1_OP_OR); + m_formatter.immediate32(imm); + } + } + + void notq_r(RegisterID dst) + { + spew("notq %s", GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_GROUP3_Ev, dst, GROUP3_OP_NOT); + } + + void subq_rr(RegisterID src, RegisterID dst) + { + spew("subq %s, %s", GPReg64Name(src), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_SUB_GvEv, src, dst); + } + + void subq_rm(RegisterID src, int32_t offset, RegisterID base) + { + spew("subq %s, " MEM_ob, GPReg64Name(src), ADDR_ob(offset, base)); + m_formatter.oneByteOp64(OP_SUB_EvGv, offset, base, src); + } + + void subq_mr(int32_t offset, RegisterID base, RegisterID dst) + { + spew("subq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_SUB_GvEv, offset, base, dst); + } + + void subq_mr(const void* addr, RegisterID dst) + { + spew("subq %p, %s", addr, GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_SUB_GvEv, addr, dst); + } + + void subq_ir(int32_t imm, RegisterID dst) + { + spew("subq $%d, %s", imm, GPReg64Name(dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, dst, GROUP1_OP_SUB); + m_formatter.immediate8s(imm); + } else { + if (dst == rax) + m_formatter.oneByteOp64(OP_SUB_EAXIv); + else + m_formatter.oneByteOp64(OP_GROUP1_EvIz, dst, GROUP1_OP_SUB); + m_formatter.immediate32(imm); + } + } + + void xorq_rr(RegisterID src, RegisterID dst) + { + spew("xorq %s, %s", GPReg64Name(src), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_XOR_GvEv, src, dst); + } + + void xorq_ir(int32_t imm, RegisterID dst) + { + spew("xorq $0x%" PRIx64 ", %s", int64_t(imm), GPReg64Name(dst)); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, dst, GROUP1_OP_XOR); + m_formatter.immediate8s(imm); + } else { + if (dst == rax) + m_formatter.oneByteOp64(OP_XOR_EAXIv); + else + m_formatter.oneByteOp64(OP_GROUP1_EvIz, dst, GROUP1_OP_XOR); + m_formatter.immediate32(imm); + } + } + + void sarq_CLr(RegisterID dst) + { + spew("sarq %%cl, %s", GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_GROUP2_EvCL, dst, GROUP2_OP_SAR); + } + + void sarq_ir(int32_t imm, RegisterID dst) + { + MOZ_ASSERT(imm < 64); + spew("sarq $%d, %s", imm, GPReg64Name(dst)); + if (imm == 1) + m_formatter.oneByteOp64(OP_GROUP2_Ev1, dst, GROUP2_OP_SAR); + else { + m_formatter.oneByteOp64(OP_GROUP2_EvIb, dst, GROUP2_OP_SAR); + m_formatter.immediate8u(imm); + } + } + + void shlq_ir(int32_t imm, RegisterID dst) + { + MOZ_ASSERT(imm < 64); + spew("shlq $%d, %s", imm, GPReg64Name(dst)); + if (imm == 1) + m_formatter.oneByteOp64(OP_GROUP2_Ev1, dst, GROUP2_OP_SHL); + else { + m_formatter.oneByteOp64(OP_GROUP2_EvIb, dst, GROUP2_OP_SHL); + m_formatter.immediate8u(imm); + } + } + + void shrq_ir(int32_t imm, RegisterID dst) + { + MOZ_ASSERT(imm < 64); + spew("shrq $%d, %s", imm, GPReg64Name(dst)); + if (imm == 1) + m_formatter.oneByteOp64(OP_GROUP2_Ev1, dst, GROUP2_OP_SHR); + else { + m_formatter.oneByteOp64(OP_GROUP2_EvIb, dst, GROUP2_OP_SHR); + m_formatter.immediate8u(imm); + } + } + + void imulq_rr(RegisterID src, RegisterID dst) + { + spew("imulq %s, %s", GPReg64Name(src), GPReg64Name(dst)); + m_formatter.twoByteOp64(OP2_IMUL_GvEv, src, dst); + } + + // Comparisons: + + void cmpq_rr(RegisterID rhs, RegisterID lhs) + { + spew("cmpq %s, %s", GPReg64Name(rhs), GPReg64Name(lhs)); + m_formatter.oneByteOp64(OP_CMP_GvEv, rhs, lhs); + } + + void cmpq_rm(RegisterID rhs, int32_t offset, RegisterID base) + { + spew("cmpq %s, " MEM_ob, GPReg64Name(rhs), ADDR_ob(offset, base)); + m_formatter.oneByteOp64(OP_CMP_EvGv, offset, base, rhs); + } + + void cmpq_mr(int32_t offset, RegisterID base, RegisterID lhs) + { + spew("cmpq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(lhs)); + m_formatter.oneByteOp64(OP_CMP_GvEv, offset, base, lhs); + } + + void cmpq_ir(int32_t rhs, RegisterID lhs) + { + if (rhs == 0) { + testq_rr(lhs, lhs); + return; + } + + spew("cmpq $0x%" PRIx64 ", %s", int64_t(rhs), GPReg64Name(lhs)); + if (CAN_SIGN_EXTEND_8_32(rhs)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, lhs, GROUP1_OP_CMP); + m_formatter.immediate8s(rhs); + } else { + if (lhs == rax) + m_formatter.oneByteOp64(OP_CMP_EAXIv); + else + m_formatter.oneByteOp64(OP_GROUP1_EvIz, lhs, GROUP1_OP_CMP); + m_formatter.immediate32(rhs); + } + } + + void cmpq_im(int32_t rhs, int32_t offset, RegisterID base) + { + spew("cmpq $0x%" PRIx64 ", " MEM_ob, int64_t(rhs), ADDR_ob(offset, base)); + if (CAN_SIGN_EXTEND_8_32(rhs)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, offset, base, GROUP1_OP_CMP); + m_formatter.immediate8s(rhs); + } else { + m_formatter.oneByteOp64(OP_GROUP1_EvIz, offset, base, GROUP1_OP_CMP); + m_formatter.immediate32(rhs); + } + } + + void cmpq_im(int32_t rhs, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("cmpq $0x%x, " MEM_obs, rhs, ADDR_obs(offset, base, index, scale)); + if (CAN_SIGN_EXTEND_8_32(rhs)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, offset, base, index, scale, GROUP1_OP_CMP); + m_formatter.immediate8s(rhs); + } else { + m_formatter.oneByteOp64(OP_GROUP1_EvIz, offset, base, index, scale, GROUP1_OP_CMP); + m_formatter.immediate32(rhs); + } + } + void cmpq_im(int32_t rhs, const void* addr) + { + spew("cmpq $0x%" PRIx64 ", %p", int64_t(rhs), addr); + if (CAN_SIGN_EXTEND_8_32(rhs)) { + m_formatter.oneByteOp64(OP_GROUP1_EvIb, addr, GROUP1_OP_CMP); + m_formatter.immediate8s(rhs); + } else { + m_formatter.oneByteOp64(OP_GROUP1_EvIz, addr, GROUP1_OP_CMP); + m_formatter.immediate32(rhs); + } + } + void cmpq_rm(RegisterID rhs, const void* addr) + { + spew("cmpq %s, %p", GPReg64Name(rhs), addr); + m_formatter.oneByteOp64(OP_CMP_EvGv, addr, rhs); + } + + void testq_rr(RegisterID rhs, RegisterID lhs) + { + spew("testq %s, %s", GPReg64Name(rhs), GPReg64Name(lhs)); + m_formatter.oneByteOp64(OP_TEST_EvGv, lhs, rhs); + } + + void testq_ir(int32_t rhs, RegisterID lhs) + { + // If the mask fits in a 32-bit immediate, we can use testl with a + // 32-bit subreg. + if (CAN_ZERO_EXTEND_32_64(rhs)) { + testl_ir(rhs, lhs); + return; + } + spew("testq $0x%" PRIx64 ", %s", int64_t(rhs), GPReg64Name(lhs)); + if (lhs == rax) + m_formatter.oneByteOp64(OP_TEST_EAXIv); + else + m_formatter.oneByteOp64(OP_GROUP3_EvIz, lhs, GROUP3_OP_TEST); + m_formatter.immediate32(rhs); + } + + void testq_i32m(int32_t rhs, int32_t offset, RegisterID base) + { + spew("testq $0x%" PRIx64 ", " MEM_ob, int64_t(rhs), ADDR_ob(offset, base)); + m_formatter.oneByteOp64(OP_GROUP3_EvIz, offset, base, GROUP3_OP_TEST); + m_formatter.immediate32(rhs); + } + + void testq_i32m(int32_t rhs, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("testq $0x%4x, " MEM_obs, rhs, ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp64(OP_GROUP3_EvIz, offset, base, index, scale, GROUP3_OP_TEST); + m_formatter.immediate32(rhs); + } + + // Various move ops: + + void xchgq_rr(RegisterID src, RegisterID dst) + { + spew("xchgq %s, %s", GPReg64Name(src), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_XCHG_GvEv, src, dst); + } + void xchgq_rm(RegisterID src, int32_t offset, RegisterID base) + { + spew("xchgq %s, " MEM_ob, GPReg64Name(src), ADDR_ob(offset, base)); + m_formatter.oneByteOp64(OP_XCHG_GvEv, offset, base, src); + } + void xchgq_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("xchgq %s, " MEM_obs, GPReg64Name(src), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp64(OP_XCHG_GvEv, offset, base, index, scale, src); + } + + void movq_rr(RegisterID src, RegisterID dst) + { + spew("movq %s, %s", GPReg64Name(src), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_MOV_GvEv, src, dst); + } + + void movq_rm(RegisterID src, int32_t offset, RegisterID base) + { + spew("movq %s, " MEM_ob, GPReg64Name(src), ADDR_ob(offset, base)); + m_formatter.oneByteOp64(OP_MOV_EvGv, offset, base, src); + } + + void movq_rm_disp32(RegisterID src, int32_t offset, RegisterID base) + { + spew("movq %s, " MEM_o32b, GPReg64Name(src), ADDR_o32b(offset, base)); + m_formatter.oneByteOp64_disp32(OP_MOV_EvGv, offset, base, src); + } + + void movq_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("movq %s, " MEM_obs, GPReg64Name(src), ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp64(OP_MOV_EvGv, offset, base, index, scale, src); + } + + void movq_rm(RegisterID src, const void* addr) + { + if (src == rax && !IsAddressImmediate(addr)) { + movq_EAXm(addr); + return; + } + + spew("movq %s, %p", GPReg64Name(src), addr); + m_formatter.oneByteOp64(OP_MOV_EvGv, addr, src); + } + + void movq_mEAX(const void* addr) + { + if (IsAddressImmediate(addr)) { + movq_mr(addr, rax); + return; + } + + spew("movq %p, %%rax", addr); + m_formatter.oneByteOp64(OP_MOV_EAXOv); + m_formatter.immediate64(reinterpret_cast(addr)); + } + + void movq_EAXm(const void* addr) + { + if (IsAddressImmediate(addr)) { + movq_rm(rax, addr); + return; + } + + spew("movq %%rax, %p", addr); + m_formatter.oneByteOp64(OP_MOV_OvEAX); + m_formatter.immediate64(reinterpret_cast(addr)); + } + + void movq_mr(int32_t offset, RegisterID base, RegisterID dst) + { + spew("movq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_MOV_GvEv, offset, base, dst); + } + + void movq_mr_disp32(int32_t offset, RegisterID base, RegisterID dst) + { + spew("movq " MEM_o32b ", %s", ADDR_o32b(offset, base), GPReg64Name(dst)); + m_formatter.oneByteOp64_disp32(OP_MOV_GvEv, offset, base, dst); + } + + void movq_mr(int32_t offset, RegisterID base, RegisterID index, int scale, RegisterID dst) + { + spew("movq " MEM_obs ", %s", ADDR_obs(offset, base, index, scale), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_MOV_GvEv, offset, base, index, scale, dst); + } + + void movq_mr(const void* addr, RegisterID dst) + { + if (dst == rax && !IsAddressImmediate(addr)) { + movq_mEAX(addr); + return; + } + + spew("movq %p, %s", addr, GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_MOV_GvEv, addr, dst); + } + + void leaq_mr(int32_t offset, RegisterID base, RegisterID index, int scale, RegisterID dst) + { + spew("leaq " MEM_obs ", %s", ADDR_obs(offset, base, index, scale), GPReg64Name(dst)), + m_formatter.oneByteOp64(OP_LEA, offset, base, index, scale, dst); + } + + void movq_i32m(int32_t imm, int32_t offset, RegisterID base) + { + spew("movq $%d, " MEM_ob, imm, ADDR_ob(offset, base)); + m_formatter.oneByteOp64(OP_GROUP11_EvIz, offset, base, GROUP11_MOV); + m_formatter.immediate32(imm); + } + + void movq_i32m(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale) + { + spew("movq $%d, " MEM_obs, imm, ADDR_obs(offset, base, index, scale)); + m_formatter.oneByteOp64(OP_GROUP11_EvIz, offset, base, index, scale, GROUP11_MOV); + m_formatter.immediate32(imm); + } + void movq_i32m(int32_t imm, const void* addr) + { + spew("movq $%d, %p", imm, addr); + m_formatter.oneByteOp64(OP_GROUP11_EvIz, addr, GROUP11_MOV); + m_formatter.immediate32(imm); + } + + // Note that this instruction sign-extends its 32-bit immediate field to 64 + // bits and loads the 64-bit value into a 64-bit register. + // + // Note also that this is similar to the movl_i32r instruction, except that + // movl_i32r *zero*-extends its 32-bit immediate, and it has smaller code + // size, so it's preferred for values which could use either. + void movq_i32r(int32_t imm, RegisterID dst) + { + spew("movq $%d, %s", imm, GPRegName(dst)); + m_formatter.oneByteOp64(OP_GROUP11_EvIz, dst, GROUP11_MOV); + m_formatter.immediate32(imm); + } + + void movq_i64r(int64_t imm, RegisterID dst) + { + spew("movabsq $0x%" PRIx64 ", %s", imm, GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_MOV_EAXIv, dst); + m_formatter.immediate64(imm); + } + + void movslq_rr(RegisterID src, RegisterID dst) + { + spew("movslq %s, %s", GPReg32Name(src), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_MOVSXD_GvEv, src, dst); + } + void movslq_mr(int32_t offset, RegisterID base, RegisterID dst) + { + spew("movslq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_MOVSXD_GvEv, offset, base, dst); + } + void movslq_mr(int32_t offset, RegisterID base, RegisterID index, int scale, RegisterID dst) + { + spew("movslq " MEM_obs ", %s", ADDR_obs(offset, base, index, scale), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_MOVSXD_GvEv, offset, base, index, scale, dst); + } + + MOZ_WARN_UNUSED_RESULT JmpSrc + movl_ripr(RegisterID dst) + { + m_formatter.oneByteRipOp(OP_MOV_GvEv, 0, (RegisterID)dst); + JmpSrc label(m_formatter.size()); + spew("movl " MEM_o32r ", %s", ADDR_o32r(label.offset()), GPReg32Name(dst)); + return label; + } + + MOZ_WARN_UNUSED_RESULT JmpSrc + movl_rrip(RegisterID src) + { + m_formatter.oneByteRipOp(OP_MOV_EvGv, 0, (RegisterID)src); + JmpSrc label(m_formatter.size()); + spew("movl %s, " MEM_o32r "", GPReg32Name(src), ADDR_o32r(label.offset())); + return label; + } + + MOZ_WARN_UNUSED_RESULT JmpSrc + movq_ripr(RegisterID dst) + { + m_formatter.oneByteRipOp64(OP_MOV_GvEv, 0, dst); + JmpSrc label(m_formatter.size()); + spew("movq " MEM_o32r ", %s", ADDR_o32r(label.offset()), GPRegName(dst)); + return label; + } + + void leaq_mr(int32_t offset, RegisterID base, RegisterID dst) + { + spew("leaq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst)); + m_formatter.oneByteOp64(OP_LEA, offset, base, dst); + } + + MOZ_WARN_UNUSED_RESULT JmpSrc + leaq_rip(RegisterID dst) + { + m_formatter.oneByteRipOp64(OP_LEA, 0, dst); + JmpSrc label(m_formatter.size()); + spew("leaq " MEM_o32r ", %s", ADDR_o32r(label.offset()), GPRegName(dst)); + return label; + } + + // Flow control: + + void jmp_rip(int ripOffset) + { + // rip-relative addressing. + spew("jmp *%d(%%rip)", ripOffset); + m_formatter.oneByteRipOp(OP_GROUP5_Ev, ripOffset, GROUP5_OP_JMPN); + } + + void immediate64(int64_t imm) + { + spew(".quad %lld", (long long)imm); + m_formatter.immediate64(imm); + } + + // SSE operations: + + void vcvtsq2sd_rr(RegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpInt64Simd("vcvtsi2sd", VEX_SD, OP2_CVTSI2SD_VsdEd, src1, src0, dst); + } + void vcvtsq2ss_rr(RegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpInt64Simd("vcvtsi2ss", VEX_SS, OP2_CVTSI2SD_VsdEd, src1, src0, dst); + } + + void vcvtsi2sdq_rr(RegisterID src, XMMRegisterID dst) + { + twoByteOpInt64Simd("vcvtsi2sdq", VEX_SD, OP2_CVTSI2SD_VsdEd, src, invalid_xmm, dst); + } + + void vcvttsd2sq_rr(XMMRegisterID src, RegisterID dst) + { + twoByteOpSimdInt64("vcvttsd2si", VEX_SD, OP2_CVTTSD2SI_GdWsd, src, dst); + } + + void vcvttss2sq_rr(XMMRegisterID src, RegisterID dst) + { + twoByteOpSimdInt64("vcvttss2si", VEX_SS, OP2_CVTTSD2SI_GdWsd, src, dst); + } + + void vmovq_rr(XMMRegisterID src, RegisterID dst) + { + // While this is called "vmovq", it actually uses the vmovd encoding + // with a REX prefix modifying it to be 64-bit. + twoByteOpSimdInt64("vmovq", VEX_PD, OP2_MOVD_EdVd, (XMMRegisterID)dst, (RegisterID)src); + } + + void vmovq_rr(RegisterID src, XMMRegisterID dst) + { + // While this is called "vmovq", it actually uses the vmovd encoding + // with a REX prefix modifying it to be 64-bit. + twoByteOpInt64Simd("vmovq", VEX_PD, OP2_MOVD_VdEd, src, invalid_xmm, dst); + } + + MOZ_WARN_UNUSED_RESULT JmpSrc + vmovsd_ripr(XMMRegisterID dst) + { + return twoByteRipOpSimd("vmovsd", VEX_SD, OP2_MOVSD_VsdWsd, invalid_xmm, dst); + } + MOZ_WARN_UNUSED_RESULT JmpSrc + vmovss_ripr(XMMRegisterID dst) + { + return twoByteRipOpSimd("vmovss", VEX_SS, OP2_MOVSD_VsdWsd, invalid_xmm, dst); + } + MOZ_WARN_UNUSED_RESULT JmpSrc + vmovsd_rrip(XMMRegisterID src) + { + return twoByteRipOpSimd("vmovsd", VEX_SD, OP2_MOVSD_WsdVsd, invalid_xmm, src); + } + MOZ_WARN_UNUSED_RESULT JmpSrc + vmovss_rrip(XMMRegisterID src) + { + return twoByteRipOpSimd("vmovss", VEX_SS, OP2_MOVSD_WsdVsd, invalid_xmm, src); + } + MOZ_WARN_UNUSED_RESULT JmpSrc + vmovdqa_rrip(XMMRegisterID src) + { + return twoByteRipOpSimd("vmovdqa", VEX_PD, OP2_MOVDQ_WdqVdq, invalid_xmm, src); + } + MOZ_WARN_UNUSED_RESULT JmpSrc + vmovaps_rrip(XMMRegisterID src) + { + return twoByteRipOpSimd("vmovdqa", VEX_PS, OP2_MOVAPS_WsdVsd, invalid_xmm, src); + } + + MOZ_WARN_UNUSED_RESULT JmpSrc + vmovaps_ripr(XMMRegisterID dst) + { + return twoByteRipOpSimd("vmovaps", VEX_PS, OP2_MOVAPS_VsdWsd, invalid_xmm, dst); + } + + MOZ_WARN_UNUSED_RESULT JmpSrc + vmovdqa_ripr(XMMRegisterID dst) + { + return twoByteRipOpSimd("vmovdqa", VEX_PD, OP2_MOVDQ_VdqWdq, invalid_xmm, dst); + } + + private: + + MOZ_WARN_UNUSED_RESULT JmpSrc + twoByteRipOpSimd(const char* name, VexOperandType ty, TwoByteOpcodeID opcode, + XMMRegisterID src0, XMMRegisterID dst) + { + if (useLegacySSEEncoding(src0, dst)) { + m_formatter.legacySSEPrefix(ty); + m_formatter.twoByteRipOp(opcode, 0, dst); + JmpSrc label(m_formatter.size()); + if (IsXMMReversedOperands(opcode)) + spew("%-11s%s, " MEM_o32r "", legacySSEOpName(name), XMMRegName(dst), ADDR_o32r(label.offset())); + else + spew("%-11s" MEM_o32r ", %s", legacySSEOpName(name), ADDR_o32r(label.offset()), XMMRegName(dst)); + return label; + } + + m_formatter.twoByteRipOpVex(ty, opcode, 0, src0, dst); + JmpSrc label(m_formatter.size()); + if (src0 == invalid_xmm) { + if (IsXMMReversedOperands(opcode)) + spew("%-11s%s, " MEM_o32r "", name, XMMRegName(dst), ADDR_o32r(label.offset())); + else + spew("%-11s" MEM_o32r ", %s", name, ADDR_o32r(label.offset()), XMMRegName(dst)); + } else { + spew("%-11s" MEM_o32r ", %s, %s", name, ADDR_o32r(label.offset()), XMMRegName(src0), XMMRegName(dst)); + } + return label; + } + + void twoByteOpInt64Simd(const char* name, VexOperandType ty, TwoByteOpcodeID opcode, + RegisterID rm, XMMRegisterID src0, XMMRegisterID dst) + { + if (useLegacySSEEncoding(src0, dst)) { + if (IsXMMReversedOperands(opcode)) + spew("%-11s%s, %s", legacySSEOpName(name), XMMRegName(dst), GPRegName(rm)); + else + spew("%-11s%s, %s", legacySSEOpName(name), GPRegName(rm), XMMRegName(dst)); + m_formatter.legacySSEPrefix(ty); + m_formatter.twoByteOp64(opcode, rm, dst); + return; + } + + if (src0 == invalid_xmm) { + if (IsXMMReversedOperands(opcode)) + spew("%-11s%s, %s", name, XMMRegName(dst), GPRegName(rm)); + else + spew("%-11s%s, %s", name, GPRegName(rm), XMMRegName(dst)); + } else { + spew("%-11s%s, %s, %s", name, GPRegName(rm), XMMRegName(src0), XMMRegName(dst)); + } + m_formatter.twoByteOpVex64(ty, opcode, rm, src0, dst); + } + + void twoByteOpSimdInt64(const char* name, VexOperandType ty, TwoByteOpcodeID opcode, + XMMRegisterID rm, RegisterID dst) + { + if (useLegacySSEEncodingForOtherOutput()) { + if (IsXMMReversedOperands(opcode)) + spew("%-11s%s, %s", legacySSEOpName(name), GPRegName(dst), XMMRegName(rm)); + else if (opcode == OP2_MOVD_EdVd) + spew("%-11s%s, %s", legacySSEOpName(name), XMMRegName((XMMRegisterID)dst), GPRegName((RegisterID)rm)); + else + spew("%-11s%s, %s", legacySSEOpName(name), XMMRegName(rm), GPRegName(dst)); + m_formatter.legacySSEPrefix(ty); + m_formatter.twoByteOp64(opcode, (RegisterID)rm, dst); + return; + } + + if (IsXMMReversedOperands(opcode)) + spew("%-11s%s, %s", name, GPRegName(dst), XMMRegName(rm)); + else if (opcode == OP2_MOVD_EdVd) + spew("%-11s%s, %s", name, XMMRegName((XMMRegisterID)dst), GPRegName((RegisterID)rm)); + else + spew("%-11s%s, %s", name, XMMRegName(rm), GPRegName(dst)); + m_formatter.twoByteOpVex64(ty, opcode, (RegisterID)rm, invalid_xmm, (XMMRegisterID)dst); + } +}; + +typedef BaseAssemblerX64 BaseAssemblerSpecific; + +} // namespace X86Encoding + +} // namespace jit +} // namespace js + +#endif /* jit_x64_BaseAssembler_x64_h */ diff --git a/js/src/jit/x86-shared/Assembler-x86-shared.h b/js/src/jit/x86-shared/Assembler-x86-shared.h index 04e4790c2a5e..08abcc22ad8e 100644 --- a/js/src/jit/x86-shared/Assembler-x86-shared.h +++ b/js/src/jit/x86-shared/Assembler-x86-shared.h @@ -10,7 +10,14 @@ #include #include "jit/shared/Assembler-shared.h" -#include "jit/x86-shared/BaseAssembler-x86-shared.h" + +#if defined(JS_CODEGEN_X86) +# include "jit/x86/BaseAssembler-x86.h" +#elif defined(JS_CODEGEN_X64) +# include "jit/x64/BaseAssembler-x64.h" +#else +# error "Unknown architecture!" +#endif namespace js { namespace jit { @@ -261,7 +268,7 @@ class AssemblerX86Shared : public AssemblerShared } protected: - X86Encoding::BaseAssembler masm; + X86Encoding::BaseAssemblerSpecific masm; typedef X86Encoding::JmpSrc JmpSrc; typedef X86Encoding::JmpDst JmpDst; diff --git a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h index 270465c695d6..0b6754060101 100644 --- a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h +++ b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h @@ -256,20 +256,6 @@ public: // Arithmetic operations: -#ifdef JS_CODEGEN_X86 - void adcl_im(int32_t imm, const void* addr) - { - spew("adcl %d, %p", imm, addr); - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, addr, GROUP1_OP_ADC); - m_formatter.immediate8s(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, addr, GROUP1_OP_ADC); - m_formatter.immediate32(imm); - } - } -#endif - void addl_rr(RegisterID src, RegisterID dst) { spew("addl %s, %s", GPReg32Name(src), GPReg32Name(dst)); @@ -359,64 +345,6 @@ public: } } -#ifdef JS_CODEGEN_X64 - void addq_rr(RegisterID src, RegisterID dst) - { - spew("addq %s, %s", GPReg64Name(src), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_ADD_GvEv, src, dst); - } - - void addq_mr(int32_t offset, RegisterID base, RegisterID dst) - { - spew("addq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_ADD_GvEv, offset, base, dst); - } - - void addq_mr(const void* addr, RegisterID dst) - { - spew("addq %p, %s", addr, GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_ADD_GvEv, addr, dst); - } - - void addq_ir(int32_t imm, RegisterID dst) - { - spew("addq $%d, %s", imm, GPReg64Name(dst)); - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, dst, GROUP1_OP_ADD); - m_formatter.immediate8s(imm); - } else { - if (dst == rax) - m_formatter.oneByteOp64(OP_ADD_EAXIv); - else - m_formatter.oneByteOp64(OP_GROUP1_EvIz, dst, GROUP1_OP_ADD); - m_formatter.immediate32(imm); - } - } - - void addq_im(int32_t imm, int32_t offset, RegisterID base) - { - spew("addq $%d, " MEM_ob, imm, ADDR_ob(offset, base)); - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, offset, base, GROUP1_OP_ADD); - m_formatter.immediate8s(imm); - } else { - m_formatter.oneByteOp64(OP_GROUP1_EvIz, offset, base, GROUP1_OP_ADD); - m_formatter.immediate32(imm); - } - } - - void addq_im(int32_t imm, const void* addr) - { - spew("addq $%d, %p", imm, addr); - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, addr, GROUP1_OP_ADD); - m_formatter.immediate8s(imm); - } else { - m_formatter.oneByteOp64(OP_GROUP1_EvIz, addr, GROUP1_OP_ADD); - m_formatter.immediate32(imm); - } - } -#endif void addl_im(int32_t imm, const void* addr) { spew("addl $%d, %p", imm, addr); @@ -869,71 +797,6 @@ public: } } -#ifdef JS_CODEGEN_X64 - void andq_rr(RegisterID src, RegisterID dst) - { - spew("andq %s, %s", GPReg64Name(src), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_AND_GvEv, src, dst); - } - - void andq_mr(int32_t offset, RegisterID base, RegisterID dst) - { - spew("andq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_AND_GvEv, offset, base, dst); - } - - void andq_mr(int32_t offset, RegisterID base, RegisterID index, int scale, RegisterID dst) - { - spew("andq " MEM_obs ", %s", ADDR_obs(offset, base, index, scale), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_AND_GvEv, offset, base, index, scale, dst); - } - - void andq_mr(const void* addr, RegisterID dst) - { - spew("andq %p, %s", addr, GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_AND_GvEv, addr, dst); - } - - void orq_mr(int32_t offset, RegisterID base, RegisterID dst) - { - spew("orq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_OR_GvEv, offset, base, dst); - } - - void orq_mr(const void* addr, RegisterID dst) - { - spew("orq %p, %s", addr, GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_OR_GvEv, addr, dst); - } - - void andq_ir(int32_t imm, RegisterID dst) - { - spew("andq $0x%" PRIx64 ", %s", int64_t(imm), GPReg64Name(dst)); - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, dst, GROUP1_OP_AND); - m_formatter.immediate8s(imm); - } else { - if (dst == rax) - m_formatter.oneByteOp64(OP_AND_EAXIv); - else - m_formatter.oneByteOp64(OP_GROUP1_EvIz, dst, GROUP1_OP_AND); - m_formatter.immediate32(imm); - } - } -#else - void andl_im(int32_t imm, const void* addr) - { - spew("andl $0x%x, %p", imm, addr); - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, addr, GROUP1_OP_AND); - m_formatter.immediate8s(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, addr, GROUP1_OP_AND); - m_formatter.immediate32(imm); - } - } -#endif - void fld_m(int32_t offset, RegisterID base) { spew("fld " MEM_ob, ADDR_ob(offset, base)); @@ -1110,53 +973,6 @@ public: } } -#ifdef JS_CODEGEN_X64 - void negq_r(RegisterID dst) - { - spew("negq %s", GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_GROUP3_Ev, dst, GROUP3_OP_NEG); - } - - void orq_rr(RegisterID src, RegisterID dst) - { - spew("orq %s, %s", GPReg64Name(src), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_OR_GvEv, src, dst); - } - - void orq_ir(int32_t imm, RegisterID dst) - { - spew("orq $0x%" PRIx64 ", %s", int64_t(imm), GPReg64Name(dst)); - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, dst, GROUP1_OP_OR); - m_formatter.immediate8s(imm); - } else { - if (dst == rax) - m_formatter.oneByteOp64(OP_OR_EAXIv); - else - m_formatter.oneByteOp64(OP_GROUP1_EvIz, dst, GROUP1_OP_OR); - m_formatter.immediate32(imm); - } - } - - void notq_r(RegisterID dst) - { - spew("notq %s", GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_GROUP3_Ev, dst, GROUP3_OP_NOT); - } -#else - void orl_im(int32_t imm, const void* addr) - { - spew("orl $0x%x, %p", imm, addr); - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, addr, GROUP1_OP_OR); - m_formatter.immediate8s(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, addr, GROUP1_OP_OR); - m_formatter.immediate32(imm); - } - } -#endif - void subl_rr(RegisterID src, RegisterID dst) { spew("subl %s, %s", GPReg32Name(src), GPReg32Name(dst)); @@ -1283,59 +1099,6 @@ public: } } -#ifdef JS_CODEGEN_X64 - void subq_rr(RegisterID src, RegisterID dst) - { - spew("subq %s, %s", GPReg64Name(src), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_SUB_GvEv, src, dst); - } - - void subq_rm(RegisterID src, int32_t offset, RegisterID base) - { - spew("subq %s, " MEM_ob, GPReg64Name(src), ADDR_ob(offset, base)); - m_formatter.oneByteOp64(OP_SUB_EvGv, offset, base, src); - } - - void subq_mr(int32_t offset, RegisterID base, RegisterID dst) - { - spew("subq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_SUB_GvEv, offset, base, dst); - } - - void subq_mr(const void* addr, RegisterID dst) - { - spew("subq %p, %s", addr, GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_SUB_GvEv, addr, dst); - } - - void subq_ir(int32_t imm, RegisterID dst) - { - spew("subq $%d, %s", imm, GPReg64Name(dst)); - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, dst, GROUP1_OP_SUB); - m_formatter.immediate8s(imm); - } else { - if (dst == rax) - m_formatter.oneByteOp64(OP_SUB_EAXIv); - else - m_formatter.oneByteOp64(OP_GROUP1_EvIz, dst, GROUP1_OP_SUB); - m_formatter.immediate32(imm); - } - } -#else - void subl_im(int32_t imm, const void* addr) - { - spew("subl $%d, %p", imm, addr); - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, addr, GROUP1_OP_SUB); - m_formatter.immediate8s(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, addr, GROUP1_OP_SUB); - m_formatter.immediate32(imm); - } - } -#endif - void xorl_rr(RegisterID src, RegisterID dst) { spew("xorl %s, %s", GPReg32Name(src), GPReg32Name(dst)); @@ -1462,29 +1225,6 @@ public: } } -#ifdef JS_CODEGEN_X64 - void xorq_rr(RegisterID src, RegisterID dst) - { - spew("xorq %s, %s", GPReg64Name(src), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_XOR_GvEv, src, dst); - } - - void xorq_ir(int32_t imm, RegisterID dst) - { - spew("xorq $0x%" PRIx64 ", %s", int64_t(imm), GPReg64Name(dst)); - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, dst, GROUP1_OP_XOR); - m_formatter.immediate8s(imm); - } else { - if (dst == rax) - m_formatter.oneByteOp64(OP_XOR_EAXIv); - else - m_formatter.oneByteOp64(OP_GROUP1_EvIz, dst, GROUP1_OP_XOR); - m_formatter.immediate32(imm); - } - } -#endif - void sarl_ir(int32_t imm, RegisterID dst) { MOZ_ASSERT(imm < 32); @@ -1539,50 +1279,6 @@ public: m_formatter.oneByteOp(OP_GROUP2_EvCL, dst, GROUP2_OP_SHL); } -#ifdef JS_CODEGEN_X64 - void sarq_CLr(RegisterID dst) - { - spew("sarq %%cl, %s", GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_GROUP2_EvCL, dst, GROUP2_OP_SAR); - } - - void sarq_ir(int32_t imm, RegisterID dst) - { - MOZ_ASSERT(imm < 64); - spew("sarq $%d, %s", imm, GPReg64Name(dst)); - if (imm == 1) - m_formatter.oneByteOp64(OP_GROUP2_Ev1, dst, GROUP2_OP_SAR); - else { - m_formatter.oneByteOp64(OP_GROUP2_EvIb, dst, GROUP2_OP_SAR); - m_formatter.immediate8u(imm); - } - } - - void shlq_ir(int32_t imm, RegisterID dst) - { - MOZ_ASSERT(imm < 64); - spew("shlq $%d, %s", imm, GPReg64Name(dst)); - if (imm == 1) - m_formatter.oneByteOp64(OP_GROUP2_Ev1, dst, GROUP2_OP_SHL); - else { - m_formatter.oneByteOp64(OP_GROUP2_EvIb, dst, GROUP2_OP_SHL); - m_formatter.immediate8u(imm); - } - } - - void shrq_ir(int32_t imm, RegisterID dst) - { - MOZ_ASSERT(imm < 64); - spew("shrq $%d, %s", imm, GPReg64Name(dst)); - if (imm == 1) - m_formatter.oneByteOp64(OP_GROUP2_Ev1, dst, GROUP2_OP_SHR); - else { - m_formatter.oneByteOp64(OP_GROUP2_EvIb, dst, GROUP2_OP_SHR); - m_formatter.immediate8u(imm); - } - } -#endif - void bsr_rr(RegisterID src, RegisterID dst) { spew("bsr %s, %s", GPReg32Name(src), GPReg32Name(dst)); @@ -1619,14 +1315,6 @@ public: } } -#ifdef JS_CODEGEN_X64 - void imulq_rr(RegisterID src, RegisterID dst) - { - spew("imulq %s, %s", GPReg64Name(src), GPReg64Name(dst)); - m_formatter.twoByteOp64(OP2_IMUL_GvEv, src, dst); - } -#endif - void mull_r(RegisterID multiplier) { spew("mull %s", GPReg32Name(multiplier)); @@ -1849,85 +1537,6 @@ public: m_formatter.immediate32(rhs); } -#ifdef JS_CODEGEN_X64 - void cmpq_rr(RegisterID rhs, RegisterID lhs) - { - spew("cmpq %s, %s", GPReg64Name(rhs), GPReg64Name(lhs)); - m_formatter.oneByteOp64(OP_CMP_GvEv, rhs, lhs); - } - - void cmpq_rm(RegisterID rhs, int32_t offset, RegisterID base) - { - spew("cmpq %s, " MEM_ob, GPReg64Name(rhs), ADDR_ob(offset, base)); - m_formatter.oneByteOp64(OP_CMP_EvGv, offset, base, rhs); - } - - void cmpq_mr(int32_t offset, RegisterID base, RegisterID lhs) - { - spew("cmpq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(lhs)); - m_formatter.oneByteOp64(OP_CMP_GvEv, offset, base, lhs); - } - - void cmpq_ir(int32_t rhs, RegisterID lhs) - { - if (rhs == 0) { - testq_rr(lhs, lhs); - return; - } - - spew("cmpq $0x%" PRIx64 ", %s", int64_t(rhs), GPReg64Name(lhs)); - if (CAN_SIGN_EXTEND_8_32(rhs)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, lhs, GROUP1_OP_CMP); - m_formatter.immediate8s(rhs); - } else { - if (lhs == rax) - m_formatter.oneByteOp64(OP_CMP_EAXIv); - else - m_formatter.oneByteOp64(OP_GROUP1_EvIz, lhs, GROUP1_OP_CMP); - m_formatter.immediate32(rhs); - } - } - - void cmpq_im(int32_t rhs, int32_t offset, RegisterID base) - { - spew("cmpq $0x%" PRIx64 ", " MEM_ob, int64_t(rhs), ADDR_ob(offset, base)); - if (CAN_SIGN_EXTEND_8_32(rhs)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, offset, base, GROUP1_OP_CMP); - m_formatter.immediate8s(rhs); - } else { - m_formatter.oneByteOp64(OP_GROUP1_EvIz, offset, base, GROUP1_OP_CMP); - m_formatter.immediate32(rhs); - } - } - - void cmpq_im(int32_t rhs, int32_t offset, RegisterID base, RegisterID index, int scale) - { - spew("cmpq $0x%x, " MEM_obs, rhs, ADDR_obs(offset, base, index, scale)); - if (CAN_SIGN_EXTEND_8_32(rhs)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, offset, base, index, scale, GROUP1_OP_CMP); - m_formatter.immediate8s(rhs); - } else { - m_formatter.oneByteOp64(OP_GROUP1_EvIz, offset, base, index, scale, GROUP1_OP_CMP); - m_formatter.immediate32(rhs); - } - } - void cmpq_im(int32_t rhs, const void* addr) - { - spew("cmpq $0x%" PRIx64 ", %p", int64_t(rhs), addr); - if (CAN_SIGN_EXTEND_8_32(rhs)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, addr, GROUP1_OP_CMP); - m_formatter.immediate8s(rhs); - } else { - m_formatter.oneByteOp64(OP_GROUP1_EvIz, addr, GROUP1_OP_CMP); - m_formatter.immediate32(rhs); - } - } - void cmpq_rm(RegisterID rhs, const void* addr) - { - spew("cmpq %s, %p", GPReg64Name(rhs), addr); - m_formatter.oneByteOp64(OP_CMP_EvGv, addr, rhs); - } -#endif void cmpl_rm(RegisterID rhs, const void* addr) { spew("cmpl %s, %p", GPReg32Name(rhs), addr); @@ -2049,44 +1658,6 @@ public: m_formatter.immediate32(rhs); } -#ifdef JS_CODEGEN_X64 - void testq_rr(RegisterID rhs, RegisterID lhs) - { - spew("testq %s, %s", GPReg64Name(rhs), GPReg64Name(lhs)); - m_formatter.oneByteOp64(OP_TEST_EvGv, lhs, rhs); - } - - void testq_ir(int32_t rhs, RegisterID lhs) - { - // If the mask fits in a 32-bit immediate, we can use testl with a - // 32-bit subreg. - if (CAN_ZERO_EXTEND_32_64(rhs)) { - testl_ir(rhs, lhs); - return; - } - spew("testq $0x%" PRIx64 ", %s", int64_t(rhs), GPReg64Name(lhs)); - if (lhs == rax) - m_formatter.oneByteOp64(OP_TEST_EAXIv); - else - m_formatter.oneByteOp64(OP_GROUP3_EvIz, lhs, GROUP3_OP_TEST); - m_formatter.immediate32(rhs); - } - - void testq_i32m(int32_t rhs, int32_t offset, RegisterID base) - { - spew("testq $0x%" PRIx64 ", " MEM_ob, int64_t(rhs), ADDR_ob(offset, base)); - m_formatter.oneByteOp64(OP_GROUP3_EvIz, offset, base, GROUP3_OP_TEST); - m_formatter.immediate32(rhs); - } - - void testq_i32m(int32_t rhs, int32_t offset, RegisterID base, RegisterID index, int scale) - { - spew("testq $0x%4x, " MEM_obs, rhs, ADDR_obs(offset, base, index, scale)); - m_formatter.oneByteOp64(OP_GROUP3_EvIz, offset, base, index, scale, GROUP3_OP_TEST); - m_formatter.immediate32(rhs); - } -#endif - void testw_rr(RegisterID rhs, RegisterID lhs) { spew("testw %s, %s", GPReg16Name(rhs), GPReg16Name(lhs)); @@ -2187,24 +1758,6 @@ public: m_formatter.oneByteOp(OP_XCHG_GvEv, offset, base, index, scale, src); } -#ifdef JS_CODEGEN_X64 - void xchgq_rr(RegisterID src, RegisterID dst) - { - spew("xchgq %s, %s", GPReg64Name(src), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_XCHG_GvEv, src, dst); - } - void xchgq_rm(RegisterID src, int32_t offset, RegisterID base) - { - spew("xchgq %s, " MEM_ob, GPReg64Name(src), ADDR_ob(offset, base)); - m_formatter.oneByteOp64(OP_XCHG_GvEv, offset, base, src); - } - void xchgq_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) - { - spew("xchgq %s, " MEM_obs, GPReg64Name(src), ADDR_obs(offset, base, index, scale)); - m_formatter.oneByteOp64(OP_XCHG_GvEv, offset, base, index, scale, src); - } -#endif - void movl_rr(RegisterID src, RegisterID dst) { spew("movl %s, %s", GPReg32Name(src), GPReg32Name(dst)); @@ -2412,43 +1965,6 @@ public: #endif } -#ifdef JS_CODEGEN_X64 - void movq_rr(RegisterID src, RegisterID dst) - { - spew("movq %s, %s", GPReg64Name(src), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_MOV_GvEv, src, dst); - } - - void movq_rm(RegisterID src, int32_t offset, RegisterID base) - { - spew("movq %s, " MEM_ob, GPReg64Name(src), ADDR_ob(offset, base)); - m_formatter.oneByteOp64(OP_MOV_EvGv, offset, base, src); - } - - void movq_rm_disp32(RegisterID src, int32_t offset, RegisterID base) - { - spew("movq %s, " MEM_o32b, GPReg64Name(src), ADDR_o32b(offset, base)); - m_formatter.oneByteOp64_disp32(OP_MOV_EvGv, offset, base, src); - } - - void movq_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale) - { - spew("movq %s, " MEM_obs, GPReg64Name(src), ADDR_obs(offset, base, index, scale)); - m_formatter.oneByteOp64(OP_MOV_EvGv, offset, base, index, scale, src); - } - - void movq_rm(RegisterID src, const void* addr) - { - if (src == rax && !IsAddressImmediate(addr)) { - movq_EAXm(addr); - return; - } - - spew("movq %s, %p", GPReg64Name(src), addr); - m_formatter.oneByteOp64(OP_MOV_EvGv, addr, src); - } -#endif - void vmovq_rm(XMMRegisterID src, int32_t offset, RegisterID base) { // vmovq_rm can be encoded either as a true vmovq or as a vmovd with a @@ -2473,61 +1989,6 @@ public: twoByteOpSimd("vmovq", VEX_PD, OP2_MOVQ_WdVd, addr, invalid_xmm, src); } -#ifdef JS_CODEGEN_X64 - void movq_mEAX(const void* addr) - { - if (IsAddressImmediate(addr)) { - movq_mr(addr, rax); - return; - } - - spew("movq %p, %%rax", addr); - m_formatter.oneByteOp64(OP_MOV_EAXOv); - m_formatter.immediate64(reinterpret_cast(addr)); - } - - void movq_EAXm(const void* addr) - { - if (IsAddressImmediate(addr)) { - movq_rm(rax, addr); - return; - } - - spew("movq %%rax, %p", addr); - m_formatter.oneByteOp64(OP_MOV_OvEAX); - m_formatter.immediate64(reinterpret_cast(addr)); - } - - void movq_mr(int32_t offset, RegisterID base, RegisterID dst) - { - spew("movq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_MOV_GvEv, offset, base, dst); - } - - void movq_mr_disp32(int32_t offset, RegisterID base, RegisterID dst) - { - spew("movq " MEM_o32b ", %s", ADDR_o32b(offset, base), GPReg64Name(dst)); - m_formatter.oneByteOp64_disp32(OP_MOV_GvEv, offset, base, dst); - } - - void movq_mr(int32_t offset, RegisterID base, RegisterID index, int scale, RegisterID dst) - { - spew("movq " MEM_obs ", %s", ADDR_obs(offset, base, index, scale), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_MOV_GvEv, offset, base, index, scale, dst); - } - - void movq_mr(const void* addr, RegisterID dst) - { - if (dst == rax && !IsAddressImmediate(addr)) { - movq_mEAX(addr); - return; - } - - spew("movq %p, %s", addr, GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_MOV_GvEv, addr, dst); - } -#endif - void vmovq_mr(int32_t offset, RegisterID base, XMMRegisterID dst) { // vmovq_mr can be encoded either as a true vmovq or as a vmovd with a @@ -2552,95 +2013,6 @@ public: twoByteOpSimd("vmovq", VEX_SS, OP2_MOVQ_VdWd, addr, invalid_xmm, dst); } -#ifdef JS_CODEGEN_X64 - void leaq_mr(int32_t offset, RegisterID base, RegisterID index, int scale, RegisterID dst) - { - spew("leaq " MEM_obs ", %s", ADDR_obs(offset, base, index, scale), GPReg64Name(dst)), - m_formatter.oneByteOp64(OP_LEA, offset, base, index, scale, dst); - } - - void movq_i32m(int32_t imm, int32_t offset, RegisterID base) - { - spew("movq $%d, " MEM_ob, imm, ADDR_ob(offset, base)); - m_formatter.oneByteOp64(OP_GROUP11_EvIz, offset, base, GROUP11_MOV); - m_formatter.immediate32(imm); - } - - void movq_i32m(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale) - { - spew("movq $%d, " MEM_obs, imm, ADDR_obs(offset, base, index, scale)); - m_formatter.oneByteOp64(OP_GROUP11_EvIz, offset, base, index, scale, GROUP11_MOV); - m_formatter.immediate32(imm); - } - void movq_i32m(int32_t imm, const void* addr) - { - spew("movq $%d, %p", imm, addr); - m_formatter.oneByteOp64(OP_GROUP11_EvIz, addr, GROUP11_MOV); - m_formatter.immediate32(imm); - } - - // Note that this instruction sign-extends its 32-bit immediate field to 64 - // bits and loads the 64-bit value into a 64-bit register. - // - // Note also that this is similar to the movl_i32r instruction, except that - // movl_i32r *zero*-extends its 32-bit immediate, and it has smaller code - // size, so it's preferred for values which could use either. - void movq_i32r(int32_t imm, RegisterID dst) { - spew("movq $%d, %s", imm, GPRegName(dst)); - m_formatter.oneByteOp64(OP_GROUP11_EvIz, dst, GROUP11_MOV); - m_formatter.immediate32(imm); - } - - void movq_i64r(int64_t imm, RegisterID dst) - { - spew("movabsq $0x%" PRIx64 ", %s", imm, GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_MOV_EAXIv, dst); - m_formatter.immediate64(imm); - } - - void movslq_rr(RegisterID src, RegisterID dst) - { - spew("movslq %s, %s", GPReg32Name(src), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_MOVSXD_GvEv, src, dst); - } - void movslq_mr(int32_t offset, RegisterID base, RegisterID dst) - { - spew("movslq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_MOVSXD_GvEv, offset, base, dst); - } - void movslq_mr(int32_t offset, RegisterID base, RegisterID index, int scale, RegisterID dst) - { - spew("movslq " MEM_obs ", %s", ADDR_obs(offset, base, index, scale), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_MOVSXD_GvEv, offset, base, index, scale, dst); - } - - MOZ_WARN_UNUSED_RESULT JmpSrc - movl_ripr(RegisterID dst) - { - m_formatter.oneByteRipOp(OP_MOV_GvEv, 0, (RegisterID)dst); - JmpSrc label(m_formatter.size()); - spew("movl " MEM_o32r ", %s", ADDR_o32r(label.offset()), GPReg32Name(dst)); - return label; - } - - MOZ_WARN_UNUSED_RESULT JmpSrc - movl_rrip(RegisterID src) - { - m_formatter.oneByteRipOp(OP_MOV_EvGv, 0, (RegisterID)src); - JmpSrc label(m_formatter.size()); - spew("movl %s, " MEM_o32r "", GPReg32Name(src), ADDR_o32r(label.offset())); - return label; - } - - MOZ_WARN_UNUSED_RESULT JmpSrc - movq_ripr(RegisterID dst) - { - m_formatter.oneByteRipOp64(OP_MOV_GvEv, 0, dst); - JmpSrc label(m_formatter.size()); - spew("movq " MEM_o32r ", %s", ADDR_o32r(label.offset()), GPRegName(dst)); - return label; - } -#endif void movl_rm(RegisterID src, const void* addr) { if (src == rax @@ -2830,22 +2202,6 @@ public: spew("leal " MEM_ob ", %s", ADDR_ob(offset, base), GPReg32Name(dst)); m_formatter.oneByteOp(OP_LEA, offset, base, dst); } -#ifdef JS_CODEGEN_X64 - void leaq_mr(int32_t offset, RegisterID base, RegisterID dst) - { - spew("leaq " MEM_ob ", %s", ADDR_ob(offset, base), GPReg64Name(dst)); - m_formatter.oneByteOp64(OP_LEA, offset, base, dst); - } - - MOZ_WARN_UNUSED_RESULT JmpSrc - leaq_rip(RegisterID dst) - { - m_formatter.oneByteRipOp64(OP_LEA, 0, dst); - JmpSrc label(m_formatter.size()); - spew("leaq " MEM_o32r ", %s", ADDR_o32r(label.offset()), GPRegName(dst)); - return label; - } -#endif // Flow control: @@ -2924,20 +2280,6 @@ public: m_formatter.oneByteOp(OP_GROUP5_Ev, offset, base, index, scale, GROUP5_OP_JMPN); } -#ifdef JS_CODEGEN_X64 - void jmp_rip(int ripOffset) { - // rip-relative addressing. - spew("jmp *%d(%%rip)", ripOffset); - m_formatter.oneByteRipOp(OP_GROUP5_Ev, ripOffset, GROUP5_OP_JMPN); - } - - void immediate64(int64_t imm) - { - spew(".quad %lld", (long long)imm); - m_formatter.immediate64(imm); - } -#endif - void jCC_i(Condition cond, JmpDst dst) { int32_t diff = dst.offset() - m_formatter.size(); @@ -3099,17 +2441,6 @@ public: twoByteOpSimd("vcvtdq2ps", VEX_PS, OP2_CVTDQ2PS_VpsWdq, src, invalid_xmm, dst); } -#ifdef JS_CODEGEN_X64 - void vcvtsq2sd_rr(RegisterID src1, XMMRegisterID src0, XMMRegisterID dst) - { - twoByteOpInt64Simd("vcvtsi2sd", VEX_SD, OP2_CVTSI2SD_VsdEd, src1, src0, dst); - } - void vcvtsq2ss_rr(RegisterID src1, XMMRegisterID src0, XMMRegisterID dst) - { - twoByteOpInt64Simd("vcvtsi2ss", VEX_SS, OP2_CVTSI2SD_VsdEd, src1, src0, dst); - } -#endif - void vcvtsi2sd_mr(int32_t offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) { twoByteOpSimd("vcvtsi2sd", VEX_SD, OP2_CVTSI2SD_VsdEd, offset, base, src0, dst); @@ -3130,20 +2461,6 @@ public: twoByteOpSimd("vcvtsi2ss", VEX_SS, OP2_CVTSI2SD_VsdEd, offset, base, index, scale, src0, dst); } -#ifdef JS_CODEGEN_X86 - void vcvtsi2sd_mr(const void* address, XMMRegisterID src0, XMMRegisterID dst) - { - twoByteOpSimd("vcvtsi2sd", VEX_SD, OP2_CVTSI2SD_VsdEd, address, src0, dst); - } -#endif - -#ifdef JS_CODEGEN_X64 - void vcvtsi2sdq_rr(RegisterID src, XMMRegisterID dst) - { - twoByteOpInt64Simd("vcvtsi2sdq", VEX_SD, OP2_CVTSI2SD_VsdEd, src, invalid_xmm, dst); - } -#endif - void vcvttsd2si_rr(XMMRegisterID src, RegisterID dst) { twoByteOpSimdInt32("vcvttsd2si", VEX_SD, OP2_CVTTSD2SI_GdWsd, src, dst); @@ -3154,18 +2471,6 @@ public: twoByteOpSimdInt32("vcvttss2si", VEX_SS, OP2_CVTTSD2SI_GdWsd, src, dst); } -#ifdef JS_CODEGEN_X64 - void vcvttsd2sq_rr(XMMRegisterID src, RegisterID dst) - { - twoByteOpSimdInt64("vcvttsd2si", VEX_SD, OP2_CVTTSD2SI_GdWsd, src, dst); - } - - void vcvttss2sq_rr(XMMRegisterID src, RegisterID dst) - { - twoByteOpSimdInt64("vcvttss2si", VEX_SS, OP2_CVTTSD2SI_GdWsd, src, dst); - } -#endif - void vunpcklps_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) { twoByteOpSimd("vunpcklps", VEX_PS, OP2_UNPCKLPS_VsdWsd, src1, src0, dst); @@ -3397,22 +2702,6 @@ public: twoByteOpSimd("vmovd", VEX_PD, OP2_MOVD_EdVd, address, invalid_xmm, src); } -#ifdef JS_CODEGEN_X64 - void vmovq_rr(XMMRegisterID src, RegisterID dst) - { - // While this is called "vmovq", it actually uses the vmovd encoding - // with a REX prefix modifying it to be 64-bit. - twoByteOpSimdInt64("vmovq", VEX_PD, OP2_MOVD_EdVd, (XMMRegisterID)dst, (RegisterID)src); - } - - void vmovq_rr(RegisterID src, XMMRegisterID dst) - { - // While this is called "vmovq", it actually uses the vmovd encoding - // with a REX prefix modifying it to be 64-bit. - twoByteOpInt64Simd("vmovq", VEX_PD, OP2_MOVD_VdEd, src, invalid_xmm, dst); - } -#endif - void vmovsd_rm(XMMRegisterID src, int32_t offset, RegisterID base) { twoByteOpSimd("vmovsd", VEX_SD, OP2_MOVSD_WsdVsd, offset, base, invalid_xmm, src); @@ -3537,38 +2826,6 @@ public: { twoByteOpSimd("vmovups", VEX_PS, OP2_MOVPS_WpsVps, address, invalid_xmm, src); } -#ifdef JS_CODEGEN_X64 - MOZ_WARN_UNUSED_RESULT JmpSrc - vmovsd_ripr(XMMRegisterID dst) - { - return twoByteRipOpSimd("vmovsd", VEX_SD, OP2_MOVSD_VsdWsd, invalid_xmm, dst); - } - MOZ_WARN_UNUSED_RESULT JmpSrc - vmovss_ripr(XMMRegisterID dst) - { - return twoByteRipOpSimd("vmovss", VEX_SS, OP2_MOVSD_VsdWsd, invalid_xmm, dst); - } - MOZ_WARN_UNUSED_RESULT JmpSrc - vmovsd_rrip(XMMRegisterID src) - { - return twoByteRipOpSimd("vmovsd", VEX_SD, OP2_MOVSD_WsdVsd, invalid_xmm, src); - } - MOZ_WARN_UNUSED_RESULT JmpSrc - vmovss_rrip(XMMRegisterID src) - { - return twoByteRipOpSimd("vmovss", VEX_SS, OP2_MOVSD_WsdVsd, invalid_xmm, src); - } - MOZ_WARN_UNUSED_RESULT JmpSrc - vmovdqa_rrip(XMMRegisterID src) - { - return twoByteRipOpSimd("vmovdqa", VEX_PD, OP2_MOVDQ_WdqVdq, invalid_xmm, src); - } - MOZ_WARN_UNUSED_RESULT JmpSrc - vmovaps_rrip(XMMRegisterID src) - { - return twoByteRipOpSimd("vmovdqa", VEX_PS, OP2_MOVAPS_WsdVsd, invalid_xmm, src); - } -#endif void vmovaps_rr(XMMRegisterID src, XMMRegisterID dst) { @@ -3641,30 +2898,6 @@ public: twoByteOpSimd("vmovapd", VEX_PD, OP2_MOVAPD_VsdWsd, src, invalid_xmm, dst); } -#ifdef JS_CODEGEN_X64 - MOZ_WARN_UNUSED_RESULT JmpSrc - vmovaps_ripr(XMMRegisterID dst) - { - return twoByteRipOpSimd("vmovaps", VEX_PS, OP2_MOVAPS_VsdWsd, invalid_xmm, dst); - } - - MOZ_WARN_UNUSED_RESULT JmpSrc - vmovdqa_ripr(XMMRegisterID dst) - { - return twoByteRipOpSimd("vmovdqa", VEX_PD, OP2_MOVDQ_VdqWdq, invalid_xmm, dst); - } -#else - void vmovaps_mr(const void* address, XMMRegisterID dst) - { - twoByteOpSimd("vmovaps", VEX_PS, OP2_MOVAPS_VsdWsd, address, invalid_xmm, dst); - } - - void vmovdqa_mr(const void* address, XMMRegisterID dst) - { - twoByteOpSimd("vmovdqa", VEX_PD, OP2_MOVDQ_VdqWdq, address, invalid_xmm, dst); - } -#endif // JS_CODEGEN_X64 - void vmovdqu_rm(XMMRegisterID src, int32_t offset, RegisterID base) { twoByteOpSimd("vmovdqu", VEX_SS, OP2_MOVDQ_WdqVdq, offset, base, invalid_xmm, src); @@ -4037,20 +3270,6 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off m_formatter.immediate16u(imm); } -#ifdef JS_CODEGEN_X86 - void pusha() - { - spew("pusha"); - m_formatter.oneByteOp(OP_PUSHA); - } - - void popa() - { - spew("popa"); - m_formatter.oneByteOp(OP_POPA); - } -#endif - void mfence() { spew("mfence"); m_formatter.twoByteOp(OP_FENCE, (RegisterID)0, 6); @@ -4194,7 +3413,7 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off memcpy(buffer, m_formatter.buffer(), size()); } - private: + protected: static bool CAN_SIGN_EXTEND_8_32(int32_t value) { return value == (int32_t)(int8_t)value; } static bool CAN_SIGN_EXTEND_16_32(int32_t value) { return value == (int32_t)(int16_t)value; } static bool CAN_ZERO_EXTEND_8_32(int32_t value) { return value == (int32_t)(uint8_t)value; } @@ -4250,36 +3469,6 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off return name + 1; } - #ifdef JS_CODEGEN_X64 - MOZ_WARN_UNUSED_RESULT JmpSrc - twoByteRipOpSimd(const char* name, VexOperandType ty, TwoByteOpcodeID opcode, - XMMRegisterID src0, XMMRegisterID dst) - { - if (useLegacySSEEncoding(src0, dst)) { - m_formatter.legacySSEPrefix(ty); - m_formatter.twoByteRipOp(opcode, 0, dst); - JmpSrc label(m_formatter.size()); - if (IsXMMReversedOperands(opcode)) - spew("%-11s%s, " MEM_o32r "", legacySSEOpName(name), XMMRegName(dst), ADDR_o32r(label.offset())); - else - spew("%-11s" MEM_o32r ", %s", legacySSEOpName(name), ADDR_o32r(label.offset()), XMMRegName(dst)); - return label; - } - - m_formatter.twoByteRipOpVex(ty, opcode, 0, src0, dst); - JmpSrc label(m_formatter.size()); - if (src0 == invalid_xmm) { - if (IsXMMReversedOperands(opcode)) - spew("%-11s%s, " MEM_o32r "", name, XMMRegName(dst), ADDR_o32r(label.offset())); - else - spew("%-11s" MEM_o32r ", %s", name, ADDR_o32r(label.offset()), XMMRegName(dst)); - } else { - spew("%-11s" MEM_o32r ", %s, %s", name, ADDR_o32r(label.offset()), XMMRegName(src0), XMMRegName(dst)); - } - return label; - } -#endif - void twoByteOpSimd(const char* name, VexOperandType ty, TwoByteOpcodeID opcode, XMMRegisterID rm, XMMRegisterID src0, XMMRegisterID dst) { @@ -4490,32 +3679,6 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off m_formatter.twoByteOpVex(ty, opcode, rm, src0, dst); } -#ifdef JS_CODEGEN_X64 - void twoByteOpInt64Simd(const char* name, VexOperandType ty, TwoByteOpcodeID opcode, - RegisterID rm, XMMRegisterID src0, XMMRegisterID dst) - { - if (useLegacySSEEncoding(src0, dst)) { - if (IsXMMReversedOperands(opcode)) - spew("%-11s%s, %s", legacySSEOpName(name), XMMRegName(dst), GPRegName(rm)); - else - spew("%-11s%s, %s", legacySSEOpName(name), GPRegName(rm), XMMRegName(dst)); - m_formatter.legacySSEPrefix(ty); - m_formatter.twoByteOp64(opcode, rm, dst); - return; - } - - if (src0 == invalid_xmm) { - if (IsXMMReversedOperands(opcode)) - spew("%-11s%s, %s", name, XMMRegName(dst), GPRegName(rm)); - else - spew("%-11s%s, %s", name, GPRegName(rm), XMMRegName(dst)); - } else { - spew("%-11s%s, %s, %s", name, GPRegName(rm), XMMRegName(src0), XMMRegName(dst)); - } - m_formatter.twoByteOpVex64(ty, opcode, rm, src0, dst); - } -#endif - void twoByteOpSimdInt32(const char* name, VexOperandType ty, TwoByteOpcodeID opcode, XMMRegisterID rm, RegisterID dst) { @@ -4556,32 +3719,6 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off m_formatter.immediate8u(imm); } -#ifdef JS_CODEGEN_X64 - void twoByteOpSimdInt64(const char* name, VexOperandType ty, TwoByteOpcodeID opcode, - XMMRegisterID rm, RegisterID dst) - { - if (useLegacySSEEncodingForOtherOutput()) { - if (IsXMMReversedOperands(opcode)) - spew("%-11s%s, %s", legacySSEOpName(name), GPRegName(dst), XMMRegName(rm)); - else if (opcode == OP2_MOVD_EdVd) - spew("%-11s%s, %s", legacySSEOpName(name), XMMRegName((XMMRegisterID)dst), GPRegName((RegisterID)rm)); - else - spew("%-11s%s, %s", legacySSEOpName(name), XMMRegName(rm), GPRegName(dst)); - m_formatter.legacySSEPrefix(ty); - m_formatter.twoByteOp64(opcode, (RegisterID)rm, dst); - return; - } - - if (IsXMMReversedOperands(opcode)) - spew("%-11s%s, %s", name, GPRegName(dst), XMMRegName(rm)); - else if (opcode == OP2_MOVD_EdVd) - spew("%-11s%s, %s", name, XMMRegName((XMMRegisterID)dst), GPRegName((RegisterID)rm)); - else - spew("%-11s%s, %s", name, XMMRegName(rm), GPRegName(dst)); - m_formatter.twoByteOpVex64(ty, opcode, (RegisterID)rm, invalid_xmm, (XMMRegisterID)dst); - } -#endif - void twoByteOpSimdFlags(const char* name, VexOperandType ty, TwoByteOpcodeID opcode, XMMRegisterID rm, XMMRegisterID reg) { diff --git a/js/src/jit/x86/BaseAssembler-x86.h b/js/src/jit/x86/BaseAssembler-x86.h new file mode 100644 index 000000000000..c28330092906 --- /dev/null +++ b/js/src/jit/x86/BaseAssembler-x86.h @@ -0,0 +1,116 @@ +/* -*- 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_x86_BaseAssembler_x86_h +#define jit_x86_BaseAssembler_x86_h + +#include "jit/x86-shared/BaseAssembler-x86-shared.h" + +namespace js { +namespace jit { + +namespace X86Encoding { + +class BaseAssemblerX86 : public BaseAssembler +{ + public: + + // Arithmetic operations: + + void adcl_im(int32_t imm, const void* addr) + { + spew("adcl %d, %p", imm, addr); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, addr, GROUP1_OP_ADC); + m_formatter.immediate8s(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, addr, GROUP1_OP_ADC); + m_formatter.immediate32(imm); + } + } + + using BaseAssembler::andl_im; + void andl_im(int32_t imm, const void* addr) + { + spew("andl $0x%x, %p", imm, addr); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, addr, GROUP1_OP_AND); + m_formatter.immediate8s(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, addr, GROUP1_OP_AND); + m_formatter.immediate32(imm); + } + } + + using BaseAssembler::orl_im; + void orl_im(int32_t imm, const void* addr) + { + spew("orl $0x%x, %p", imm, addr); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, addr, GROUP1_OP_OR); + m_formatter.immediate8s(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, addr, GROUP1_OP_OR); + m_formatter.immediate32(imm); + } + } + + using BaseAssembler::subl_im; + void subl_im(int32_t imm, const void* addr) + { + spew("subl $%d, %p", imm, addr); + if (CAN_SIGN_EXTEND_8_32(imm)) { + m_formatter.oneByteOp(OP_GROUP1_EvIb, addr, GROUP1_OP_SUB); + m_formatter.immediate8s(imm); + } else { + m_formatter.oneByteOp(OP_GROUP1_EvIz, addr, GROUP1_OP_SUB); + m_formatter.immediate32(imm); + } + } + + // SSE operations: + + using BaseAssembler::vcvtsi2sd_mr; + void vcvtsi2sd_mr(const void* address, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vcvtsi2sd", VEX_SD, OP2_CVTSI2SD_VsdEd, address, src0, dst); + } + + using BaseAssembler::vmovaps_mr; + void vmovaps_mr(const void* address, XMMRegisterID dst) + { + twoByteOpSimd("vmovaps", VEX_PS, OP2_MOVAPS_VsdWsd, address, invalid_xmm, dst); + } + + using BaseAssembler::vmovdqa_mr; + void vmovdqa_mr(const void* address, XMMRegisterID dst) + { + twoByteOpSimd("vmovdqa", VEX_PD, OP2_MOVDQ_VdqWdq, address, invalid_xmm, dst); + } + + // Misc instructions: + + void pusha() + { + spew("pusha"); + m_formatter.oneByteOp(OP_PUSHA); + } + + void popa() + { + spew("popa"); + m_formatter.oneByteOp(OP_POPA); + } +}; + +typedef BaseAssemblerX86 BaseAssemblerSpecific; + +} // namespace X86Encoding + +} // namespace jit +} // namespace js + +#endif /* jit_x86_BaseAssembler_x86_h */ From f85e8206c96fc783dce0c3f652955e94b4d41f9d Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Fri, 7 Aug 2015 07:41:16 +0900 Subject: [PATCH 15/29] Bug 774364 - Part 3: Move Math.random() to macro assembler. r=sstangl,hev,nbp, f=rankov --HG-- extra : rebase_source : 1d77ed28dcb1999130294b9b6bf8cad1b2779382 --- js/src/jit/CodeGenerator.cpp | 123 +++++++++++++++++ js/src/jit/CodeGenerator.h | 4 + js/src/jit/MacroAssembler.h | 4 + js/src/jit/Registers.h | 20 +++ js/src/jit/arm/CodeGenerator-arm.cpp | 19 +-- js/src/jit/arm/CodeGenerator-arm.h | 2 +- js/src/jit/arm/LIR-arm.h | 17 --- js/src/jit/arm/Lowering-arm.cpp | 8 +- js/src/jit/arm/MacroAssembler-arm-inl.h | 14 ++ js/src/jit/arm/MacroAssembler-arm.cpp | 29 ++++ js/src/jit/arm/MacroAssembler-arm.h | 62 +++++++++ js/src/jit/arm64/CodeGenerator-arm64.cpp | 17 ++- js/src/jit/arm64/CodeGenerator-arm64.h | 2 +- js/src/jit/arm64/LIR-arm64.h | 17 --- js/src/jit/arm64/Lowering-arm64.cpp | 5 +- js/src/jit/arm64/MacroAssembler-arm64-inl.h | 15 +++ js/src/jit/arm64/MacroAssembler-arm64.h | 45 ++++++- js/src/jit/mips-shared/LIR-mips-shared.h | 17 --- .../jit/mips-shared/Lowering-mips-shared.cpp | 8 +- js/src/jit/mips32/CodeGenerator-mips32.cpp | 17 +-- js/src/jit/mips32/CodeGenerator-mips32.h | 2 +- js/src/jit/mips32/Lowering-mips32.cpp | 11 ++ js/src/jit/mips32/MacroAssembler-mips32-inl.h | 14 ++ js/src/jit/mips32/MacroAssembler-mips32.cpp | 71 ++++++++++ js/src/jit/mips32/MacroAssembler-mips32.h | 45 +++++++ js/src/jit/none/CodeGenerator-none.h | 1 + js/src/jit/none/LIR-none.h | 1 - js/src/jit/none/Lowering-none.h | 1 - js/src/jit/shared/Assembler-shared.h | 9 ++ js/src/jit/shared/LIR-shared.h | 51 +++++++ js/src/jit/x64/CodeGenerator-x64.cpp | 126 ------------------ js/src/jit/x64/CodeGenerator-x64.h | 4 - js/src/jit/x64/LIR-x64.h | 35 ----- js/src/jit/x64/Lowering-x64.cpp | 2 - js/src/jit/x64/MacroAssembler-x64-inl.h | 13 ++ js/src/jit/x64/MacroAssembler-x64.h | 35 +++++ .../x86-shared/CodeGenerator-x86-shared.cpp | 13 ++ .../jit/x86-shared/CodeGenerator-x86-shared.h | 2 + js/src/jit/x86-shared/Encoding-x86-shared.h | 4 + js/src/jit/x86/Assembler-x86.h | 61 +++++++++ js/src/jit/x86/BaseAssembler-x86.h | 54 ++++++++ js/src/jit/x86/CodeGenerator-x86.cpp | 16 --- js/src/jit/x86/CodeGenerator-x86.h | 2 - js/src/jit/x86/LIR-x86.h | 17 --- js/src/jit/x86/Lowering-x86.cpp | 9 +- js/src/jit/x86/MacroAssembler-x86-inl.h | 14 ++ js/src/jit/x86/MacroAssembler-x86.cpp | 57 ++++++++ js/src/jit/x86/MacroAssembler-x86.h | 83 ++++++++++++ 48 files changed, 902 insertions(+), 296 deletions(-) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 0eef2084fedf..5f8d9d6007bc 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -10304,5 +10304,128 @@ CodeGenerator::visitNewTarget(LNewTarget *ins) masm.bind(&done); } +// Out-of-line math_random_no_outparam call for LRandom. +class OutOfLineRandom : public OutOfLineCodeBase +{ + LRandom* lir_; + + public: + explicit OutOfLineRandom(LRandom* lir) + : lir_(lir) + { } + + void accept(CodeGenerator* codegen) { + codegen->visitOutOfLineRandom(this); + } + + LRandom* lir() const { + return lir_; + } +}; + +static const uint64_t RNG_HIGH_MASK = (0xFFFFFFFFFFFFFFFFULL >> + (RNG_STATE_WIDTH - RNG_HIGH_BITS)) << RNG_LOW_BITS; +static const double RNG_DSCALE_INV = 1 / RNG_DSCALE; + +void +CodeGenerator::visitRandom(LRandom* ins) +{ + FloatRegister output = ToFloatRegister(ins->output()); + Register JSCompartmentReg = ToRegister(ins->temp1()); +#ifdef JS_PUNBOX64 + Register64 rngStateReg = Register64(ToRegister(ins->tempMaybeEAX())); + Register64 highReg = Register64(ToRegister(ins->tempMaybeEDX())); +#else + Register64 rngStateReg = Register64(ToRegister(ins->temp2()), ToRegister(ins->temp3())); + Register64 highReg = Register64(ToRegister(ins->tempMaybeEAX()), ToRegister(ins->tempMaybeEDX())); +#endif + // tempReg is used only on x86. + Register tempReg = ToRegister(ins->tempMaybeEAX()); + + // rngState = cx->compartment()->rngState; + masm.loadJSContext(JSCompartmentReg); + masm.loadPtr(Address(JSCompartmentReg, JSContext::offsetOfCompartment()), JSCompartmentReg); + masm.load64(Address(JSCompartmentReg, JSCompartment::offsetOfRngState()), rngStateReg); + + // if rngState == 0, escape from inlined code and call + // math_random_no_outparam. + OutOfLineRandom* ool = new(alloc()) OutOfLineRandom(ins); + addOutOfLineCode(ool, ins->mir()); + masm.branchTest64(Assembler::Zero, rngStateReg, rngStateReg, tempReg, ool->entry()); + + // rngState = rngState * RNG_MULTIPLIER; + masm.mul64(Imm64(RNG_MULTIPLIER), rngStateReg); + + // rngState += RNG_ADDEND; + masm.add64(Imm32(RNG_ADDEND), rngStateReg); + + // rngState &= RNG_MASK; + masm.and64(Imm64(RNG_MASK), rngStateReg); + + // if rngState == 0, escape from inlined code and call + // math_random_no_outparam. + masm.branchTest64(Assembler::Zero, rngStateReg, rngStateReg, tempReg, ool->entry()); + + // high = (rngState >> (RNG_STATE_WIDTH - RNG_HIGH_BITS)) << RNG_LOW_BITS; + masm.move64(rngStateReg, highReg); + masm.lshift64(Imm32(RNG_LOW_BITS - (RNG_STATE_WIDTH - RNG_HIGH_BITS)), highReg); + masm.and64(Imm64(RNG_HIGH_MASK), highReg); +#ifdef JS_CODEGEN_X86 + // eax and edx are overwritten by mul64 on x86. + masm.push64(highReg); +#endif + + // rngState = rngState * RNG_MULTIPLIER; + masm.mul64(Imm64(RNG_MULTIPLIER), rngStateReg); + + // rngState += RNG_ADDEND; + masm.add64(Imm32(RNG_ADDEND), rngStateReg); + + // rngState &= RNG_MASK; + masm.and64(Imm64(RNG_MASK), rngStateReg); + + // cx->compartment()->rngState = rngState; + masm.store64(rngStateReg, Address(JSCompartmentReg, JSCompartment::offsetOfRngState())); + + // low = rngState >> (RNG_STATE_WIDTH - RNG_LOW_BITS); + const Register64& lowReg = rngStateReg; + masm.rshift64(Imm32(RNG_STATE_WIDTH - RNG_LOW_BITS), lowReg); + + // output = double(high | low); +#ifdef JS_CODEGEN_X86 + masm.pop64(highReg); +#endif + masm.or64(highReg, lowReg); + masm.convertUInt64ToDouble(lowReg, tempReg, output); + + // output = output * RNG_DSCALE_INV; + masm.mulDoublePtr(ImmPtr(&RNG_DSCALE_INV), tempReg, output); + + masm.bind(ool->rejoin()); +} + +void +CodeGenerator::visitOutOfLineRandom(OutOfLineRandom* ool) +{ + LRandom* ins = ool->lir(); + Register temp1 = ToRegister(ins->tempMaybeEAX()); + Register temp2 = ToRegister(ins->tempMaybeEDX()); + MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg); + + LiveRegisterSet regs; + setReturnDoubleRegs(®s); + saveVolatile(regs); + + masm.loadJSContext(temp1); + + masm.setupUnalignedABICall(temp2); + masm.passABIArg(temp1); + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, math_random_no_outparam), MoveOp::DOUBLE); + + restoreVolatile(regs); + + masm.jump(ool->rejoin()); +} + } // namespace jit } // namespace js diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index 49096d64dc03..547b4c526709 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -45,6 +45,7 @@ class OutOfLineIsCallable; class OutOfLineRegExpExec; class OutOfLineRegExpTest; class OutOfLineLambdaArrow; +class OutOfLineRandom; class CodeGenerator : public CodeGeneratorSpecific { @@ -382,6 +383,9 @@ class CodeGenerator : public CodeGeneratorSpecific void visitAsmJSInterruptCheck(LAsmJSInterruptCheck* lir); void visitRecompileCheck(LRecompileCheck* ins); + void visitRandom(LRandom* ins); + void visitOutOfLineRandom(OutOfLineRandom* ool); + IonScriptCounts* extractScriptCounts() { IonScriptCounts* counts = scriptCounts_; scriptCounts_ = nullptr; // prevent delete in dtor diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 1436fcefc28e..2dca49ba0e1e 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -680,6 +680,8 @@ class MacroAssembler : public MacroAssemblerSpecific inline void andPtr(Register src, Register dest) PER_ARCH; inline void andPtr(Imm32 imm, Register dest) PER_ARCH; + inline void and64(Imm64 imm, Register64 dest) PER_ARCH; + inline void or32(Register src, Register dest) PER_SHARED_ARCH; inline void or32(Imm32 imm, Register dest) PER_SHARED_ARCH; inline void or32(Imm32 imm, const Address& dest) PER_SHARED_ARCH; @@ -687,6 +689,8 @@ class MacroAssembler : public MacroAssemblerSpecific inline void orPtr(Register src, Register dest) PER_ARCH; inline void orPtr(Imm32 imm, Register dest) PER_ARCH; + inline void or64(Register64 src, Register64 dest) PER_ARCH; + inline void xor32(Register src, Register dest) DEFINED_ON(x86_shared); inline void xor32(Imm32 imm, Register dest) PER_SHARED_ARCH; diff --git a/js/src/jit/Registers.h b/js/src/jit/Registers.h index 1bcad45302f7..0bde25884d8f 100644 --- a/js/src/jit/Registers.h +++ b/js/src/jit/Registers.h @@ -93,6 +93,26 @@ struct Register { } }; +struct Register64 +{ +#ifdef JS_PUNBOX64 + Register reg; +#else + Register high; + Register low; +#endif + +#ifdef JS_PUNBOX64 + explicit MOZ_CONSTEXPR Register64(Register r) + : reg(r) + {} +#else + MOZ_CONSTEXPR Register64(Register h, Register l) + : high(h), low(l) + {} +#endif +}; + class RegisterDump { public: diff --git a/js/src/jit/arm/CodeGenerator-arm.cpp b/js/src/jit/arm/CodeGenerator-arm.cpp index 17759c372ba0..3567018bfa8d 100644 --- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -10,7 +10,6 @@ #include "jscntxt.h" #include "jscompartment.h" -#include "jsmath.h" #include "jsnum.h" #include "jit/CodeGenerator.h" @@ -2675,16 +2674,12 @@ CodeGeneratorARM::visitMemoryBarrier(LMemoryBarrier* ins) } void -CodeGeneratorARM::visitRandom(LRandom* ins) +CodeGeneratorARM::setReturnDoubleRegs(LiveRegisterSet* regs) { - Register temp = ToRegister(ins->temp()); - Register temp2 = ToRegister(ins->temp2()); - - masm.loadJSContext(temp); - - masm.setupUnalignedABICall(temp2); - masm.passABIArg(temp); - masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, math_random_no_outparam), MoveOp::DOUBLE); - - MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg); + MOZ_ASSERT(ReturnFloat32Reg.code_ == FloatRegisters::s0); + MOZ_ASSERT(ReturnDoubleReg.code_ == FloatRegisters::s0); + FloatRegister s1 = {FloatRegisters::s1, VFPRegister::Single}; + regs->add(ReturnFloat32Reg); + regs->add(s1); + regs->add(ReturnDoubleReg); } diff --git a/js/src/jit/arm/CodeGenerator-arm.h b/js/src/jit/arm/CodeGenerator-arm.h index 7b5dd345de74..8f1520bdbe03 100644 --- a/js/src/jit/arm/CodeGenerator-arm.h +++ b/js/src/jit/arm/CodeGenerator-arm.h @@ -216,7 +216,7 @@ class CodeGeneratorARM : public CodeGeneratorShared void generateInvalidateEpilogue(); - void visitRandom(LRandom* ins); + void setReturnDoubleRegs(LiveRegisterSet* regs); // Generating a result. template diff --git a/js/src/jit/arm/LIR-arm.h b/js/src/jit/arm/LIR-arm.h index 2a6c8a46ceb9..a88bc0b422d7 100644 --- a/js/src/jit/arm/LIR-arm.h +++ b/js/src/jit/arm/LIR-arm.h @@ -497,23 +497,6 @@ class LAsmJSAtomicBinopCallout : public LCallInstructionHelper<1, 2, 0> } }; -// Math.random(). -class LRandom : public LCallInstructionHelper<1, 0, 2> -{ - public: - LIR_HEADER(Random) - LRandom(const LDefinition& temp, const LDefinition& temp2) { - setTemp(0, temp); - setTemp(1, temp2); - } - const LDefinition* temp() { - return getTemp(0); - } - const LDefinition* temp2() { - return getTemp(1); - } -}; - } // namespace jit } // namespace js diff --git a/js/src/jit/arm/Lowering-arm.cpp b/js/src/jit/arm/Lowering-arm.cpp index ab5244577f15..3395023fd575 100644 --- a/js/src/jit/arm/Lowering-arm.cpp +++ b/js/src/jit/arm/Lowering-arm.cpp @@ -741,6 +741,10 @@ LIRGeneratorARM::visitSubstr(MSubstr* ins) void LIRGeneratorARM::visitRandom(MRandom* ins) { - LRandom* lir = new(alloc()) LRandom(tempFixed(CallTempReg0), tempFixed(CallTempReg1)); - defineReturn(lir, ins); + LRandom *lir = new(alloc()) LRandom(temp(), + temp(), + temp(), + temp(), + temp()); + defineFixed(lir, ins, LFloatReg(ReturnDoubleReg)); } diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 25f7882c50f5..b8584ccc5da0 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -63,6 +63,13 @@ MacroAssembler::andPtr(Imm32 imm, Register dest) ma_and(imm, dest); } +void +MacroAssembler::and64(Imm64 imm, Register64 dest) +{ + and32(Imm32(imm.value & 0xFFFFFFFFL), dest.low); + and32(Imm32((imm.value >> 32) & 0xFFFFFFFFL), dest.high); +} + void MacroAssembler::or32(Register src, Register dest) { @@ -96,6 +103,13 @@ MacroAssembler::orPtr(Imm32 imm, Register dest) ma_orr(imm, dest); } +void +MacroAssembler::or64(Register64 src, Register64 dest) +{ + or32(src.low, dest.low); + or32(src.high, dest.high); +} + void MacroAssembler::xor32(Imm32 imm, Register dest) { diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index cf2270e70c3f..e81927c89c90 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -90,6 +90,19 @@ MacroAssemblerARM::convertUInt32ToDouble(Register src, FloatRegister dest_) as_vcvt(dest, dest.uintOverlay()); } +static const double TO_DOUBLE_HIGH_SCALE = 0x100000000; + +void +MacroAssemblerARMCompat::convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest) +{ + convertUInt32ToDouble(src.high, dest); + movePtr(ImmPtr(&TO_DOUBLE_HIGH_SCALE), ScratchRegister); + loadDouble(Address(ScratchRegister, 0), ScratchDoubleReg); + mulDouble(ScratchDoubleReg, dest); + convertUInt32ToDouble(src.low, ScratchDoubleReg); + addDouble(ScratchDoubleReg, dest); +} + void MacroAssemblerARM::convertUInt32ToFloat32(Register src, FloatRegister dest_) { @@ -3373,6 +3386,22 @@ template void MacroAssemblerARMCompat::storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const BaseIndex& dest, MIRType slotType); + +void +MacroAssemblerARMCompat::branchTest64(Condition cond, Register64 lhs, Register64 rhs, + Register temp, Label* label) +{ + if (cond == Assembler::Zero) { + MOZ_ASSERT(lhs.low == rhs.low); + MOZ_ASSERT(lhs.high == rhs.high); + mov(lhs.low, ScratchRegister); + asMasm().or32(lhs.high, ScratchRegister); + branchTestPtr(cond, ScratchRegister, ScratchRegister, label); + } else { + MOZ_CRASH("Unsupported condition"); + } +} + void MacroAssemblerARMCompat::moveValue(const Value& val, Register type, Register data) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 244fdb4934a1..c14b817401ff 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -987,6 +987,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM subPtr(imm, lhs); branch32(cond, lhs, Imm32(0), label); } + void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp, Label* label); void moveValue(const Value& val, Register type, Register data); CodeOffsetJump jumpWithPatch(RepatchLabel* label, Condition cond = Always, @@ -1203,6 +1204,11 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void addPtr(Register src, Register dest); void addPtr(const Address& src, Register dest); + void add64(Imm32 imm, Register64 dest) { + ma_add(imm, dest.low, SetCC); + ma_adc(Imm32(0), dest.high, LeaveCC); + } + void not32(Register reg); void move32(Imm32 imm, Register dest); void move32(Register src, Register dest); @@ -1212,6 +1218,10 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void movePtr(ImmPtr imm, Register dest); void movePtr(AsmJSImmPtr imm, Register dest); void movePtr(ImmGCPtr imm, Register dest); + void move64(Register64 src, Register64 dest) { + move32(src.low, dest.low); + move32(src.high, dest.high); + } void load8SignExtend(const Address& address, Register dest); void load8SignExtend(const BaseIndex& src, Register dest); @@ -1228,6 +1238,10 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void load32(const Address& address, Register dest); void load32(const BaseIndex& address, Register dest); void load32(AbsoluteAddress address, Register dest); + void load64(const Address& address, Register64 dest) { + load32(address, dest.low); + load32(Address(address.base, address.offset + 4), dest.high); + } void loadPtr(const Address& address, Register dest); void loadPtr(const BaseIndex& src, Register dest); @@ -1294,6 +1308,11 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void store32_NoSecondScratch(Imm32 src, const Address& address); + void store64(Register64 src, Address address) { + store32(src.low, address); + store32(src.high, Address(address.base, address.offset + 4)); + } + template void storePtr(ImmWord imm, T address); template void storePtr(ImmPtr imm, T address); template void storePtr(ImmGCPtr imm, T address); @@ -1642,6 +1661,39 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void mulBy3(const Register& src, const Register& dest) { as_add(dest, src, lsl(src, 1)); } + void mul64(Imm64 imm, const Register64& dest) { + // LOW32 = LOW(LOW(dest) * LOW(imm)); + // HIGH32 = LOW(HIGH(dest) * LOW(imm)) [multiply imm into upper bits] + // + LOW(LOW(dest) * HIGH(imm)) [multiply dest into upper bits] + // + HIGH(LOW(dest) * LOW(imm)) [carry] + + // HIGH(dest) = LOW(HIGH(dest) * LOW(imm)); + ma_mov(Imm32(imm.value & 0xFFFFFFFFL), ScratchRegister); + as_mul(dest.high, dest.high, ScratchRegister); + + // high:low = LOW(dest) * LOW(imm); + as_umull(secondScratchReg_, ScratchRegister, dest.low, ScratchRegister); + + // HIGH(dest) += high; + as_add(dest.high, dest.high, O2Reg(secondScratchReg_)); + + // HIGH(dest) += LOW(LOW(dest) * HIGH(imm)); + if (((imm.value >> 32) & 0xFFFFFFFFL) == 5) + as_add(secondScratchReg_, dest.low, lsl(dest.low, 2)); + else + MOZ_CRASH("Not supported imm"); + as_add(dest.high, dest.high, O2Reg(secondScratchReg_)); + + // LOW(dest) = low; + ma_mov(ScratchRegister, dest.low); + } + + void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest); + void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) { + movePtr(imm, ScratchRegister); + loadDouble(Address(ScratchRegister, 0), ScratchDoubleReg); + mulDouble(ScratchDoubleReg, dest); + } void setStackArg(Register reg, uint32_t arg); @@ -1670,9 +1722,19 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void rshiftPtrArithmetic(Imm32 imm, Register dest) { ma_asr(imm, dest, dest); } + void rshift64(Imm32 imm, Register64 dest) { + as_mov(dest.low, lsr(dest.low, imm.value)); + as_orr(dest.low, dest.low, lsl(dest.high, 32 - imm.value)); + as_mov(dest.high, lsr(dest.high, imm.value)); + } void lshiftPtr(Imm32 imm, Register dest) { ma_lsl(imm, dest, dest); } + void lshift64(Imm32 imm, Register64 dest) { + as_mov(dest.high, lsl(dest.high, imm.value)); + as_orr(dest.high, dest.high, lsr(dest.low, 32 - imm.value)); + as_mov(dest.low, lsl(dest.low, imm.value)); + } // If source is a double, load it into dest. If source is int32, convert it // to double. Else, branch to failure. diff --git a/js/src/jit/arm64/CodeGenerator-arm64.cpp b/js/src/jit/arm64/CodeGenerator-arm64.cpp index c649bb63417a..0b2ad6916a53 100644 --- a/js/src/jit/arm64/CodeGenerator-arm64.cpp +++ b/js/src/jit/arm64/CodeGenerator-arm64.cpp @@ -608,12 +608,6 @@ CodeGeneratorARM64::generateInvalidateEpilogue() MOZ_CRASH("generateInvalidateEpilogue"); } -void -CodeGeneratorARM64::visitRandom(LRandom* ins) -{ - MOZ_CRASH("visitRandom"); -} - template Register getBase(U* mir) @@ -732,3 +726,14 @@ CodeGeneratorARM64::visitNegF(LNegF* ins) { MOZ_CRASH("visitNegF"); } + +void +CodeGeneratorARM64::setReturnDoubleRegs(LiveRegisterSet* regs) +{ + MOZ_ASSERT(ReturnFloat32Reg.code_ == FloatRegisters::s0); + MOZ_ASSERT(ReturnDoubleReg.code_ == FloatRegisters::d0); + FloatRegister s1 = {FloatRegisters::s1, FloatRegisters::Single}; + regs->add(ReturnFloat32Reg); + regs->add(s1); + regs->add(ReturnDoubleReg); +} diff --git a/js/src/jit/arm64/CodeGenerator-arm64.h b/js/src/jit/arm64/CodeGenerator-arm64.h index 43471347d7c9..313e1fbf858a 100644 --- a/js/src/jit/arm64/CodeGenerator-arm64.h +++ b/js/src/jit/arm64/CodeGenerator-arm64.h @@ -220,7 +220,7 @@ class CodeGeneratorARM64 : public CodeGeneratorShared void generateInvalidateEpilogue(); - void visitRandom(LRandom* ins); + void setReturnDoubleRegs(LiveRegisterSet* regs); protected: void postAsmJSCall(LAsmJSCall* lir) { diff --git a/js/src/jit/arm64/LIR-arm64.h b/js/src/jit/arm64/LIR-arm64.h index 9cb0739c8945..dc729bfd755a 100644 --- a/js/src/jit/arm64/LIR-arm64.h +++ b/js/src/jit/arm64/LIR-arm64.h @@ -407,23 +407,6 @@ class LAsmJSLoadFuncPtr : public LInstructionHelper<1, 1, 1> } }; -// Math.random(). -class LRandom : public LCallInstructionHelper<1, 0, 2> -{ - public: - LIR_HEADER(Random) - LRandom(const LDefinition& temp, const LDefinition& temp2) { - setTemp(0, temp); - setTemp(1, temp2); - } - const LDefinition* temp() { - return getTemp(0); - } - const LDefinition* temp2() { - return getTemp(1); - } -}; - } // namespace jit } // namespace js diff --git a/js/src/jit/arm64/Lowering-arm64.cpp b/js/src/jit/arm64/Lowering-arm64.cpp index 5bd9fb86e88e..7d329834e424 100644 --- a/js/src/jit/arm64/Lowering-arm64.cpp +++ b/js/src/jit/arm64/Lowering-arm64.cpp @@ -304,5 +304,8 @@ LIRGeneratorARM64::visitSubstr(MSubstr* ins) void LIRGeneratorARM64::visitRandom(MRandom* ins) { - MOZ_CRASH("visitRandom"); + LRandom *lir = new(alloc()) LRandom(temp(), + temp(), + temp()); + defineFixed(lir, ins, LFloatReg(ReturnDoubleReg)); } diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index 0778b054e3e8..eb2225231689 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -73,6 +73,15 @@ MacroAssembler::andPtr(Imm32 imm, Register dest) And(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); } +void +MacroAssembler::and64(Imm64 imm, Register64 dest) +{ + vixl::UseScratchRegisterScope temps(this); + const Register scratch = temps.AcquireX().asUnsized(); + mov(ImmWord(imm.value), scratch); + andPtr(scratch, dest.reg); +} + void MacroAssembler::or32(Imm32 imm, Register dest) { @@ -108,6 +117,12 @@ MacroAssembler::orPtr(Imm32 imm, Register dest) Orr(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); } +void +MacroAssembler::or64(Register64 src, Register64 dest) +{ + orPtr(src.reg, dest.reg); +} + void MacroAssembler::xor32(Imm32 imm, Register dest) { diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index fe4d9ffc34be..8c7e13b204f8 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -784,6 +784,9 @@ class MacroAssemblerCompat : public vixl::MacroAssembler BufferOffset load = movePatchablePtr(ImmPtr(imm.value), dest); writeDataRelocation(imm, load); } + void move64(Register64 src, Register64 dest) { + movePtr(src.reg, dest.reg); + } void mov(ImmWord imm, Register dest) { movePtr(imm, dest); @@ -989,6 +992,10 @@ class MacroAssemblerCompat : public vixl::MacroAssembler Str(scratch32, MemOperand(ARMRegister(address.base, 64), address.offset)); } + void store64(Register64 src, Address address) { + storePtr(src.reg, address); + } + // SIMD. void loadInt32x1(const Address& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } void loadInt32x1(const BaseIndex& addr, FloatRegister dest) { MOZ_CRASH("NYI"); } @@ -1068,6 +1075,9 @@ class MacroAssemblerCompat : public vixl::MacroAssembler void rshiftPtr(Imm32 imm, Register src, Register dest) { Lsr(ARMRegister(dest, 64), ARMRegister(src, 64), imm.value); } + void rshift64(Imm32 imm, Register64 dest) { + rshiftPtr(imm, dest.reg); + } void rshiftPtrArithmetic(Imm32 imm, Register dest) { Asr(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value); @@ -1075,6 +1085,9 @@ class MacroAssemblerCompat : public vixl::MacroAssembler void lshiftPtr(Imm32 imm, Register dest) { Lsl(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value); } + void lshift64(Imm32 imm, Register64 dest) { + lshiftPtr(imm, dest.reg); + } void testPtr(Register lhs, Register rhs) { Tst(ARMRegister(lhs, 64), Operand(ARMRegister(rhs, 64))); @@ -1162,7 +1175,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler } void loadDouble(const Address& src, FloatRegister dest) { - Ldr(ARMFPRegister(dest, 64), MemOperand(ARMRegister(src.base,64), src.offset)); + Ldr(ARMFPRegister(dest, 64), MemOperand(src)); } void loadDouble(const BaseIndex& src, FloatRegister dest) { ARMRegister base(src.base, 64); @@ -1306,6 +1319,9 @@ class MacroAssemblerCompat : public vixl::MacroAssembler movePtr(ImmWord((uintptr_t)address.addr), scratch64.asUnsized()); ldr(ARMRegister(dest, 32), MemOperand(scratch64)); } + void load64(const Address& address, Register64 dest) { + loadPtr(address, dest.reg); + } void load8SignExtend(const Address& address, Register dest) { Ldrsb(ARMRegister(dest, 32), MemOperand(ARMRegister(address.base, 64), address.offset)); @@ -1366,6 +1382,9 @@ class MacroAssemblerCompat : public vixl::MacroAssembler Adds(scratch32, scratch32, Operand(imm.value)); Str(scratch32, MemOperand(ARMRegister(dest.base, 64), dest.offset)); } + void add64(Imm32 imm, Register64 dest) { + Add(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), Operand(imm.value)); + } void sub32(Imm32 imm, Register dest) { Sub(ARMRegister(dest, 32), ARMRegister(dest, 32), Operand(imm.value)); @@ -1911,6 +1930,9 @@ class MacroAssemblerCompat : public vixl::MacroAssembler Cmp(ARMRegister(value.valueReg(), 64), Operand(scratch64)); B(label, cond); } + void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp, Label* label) { + branchTestPtr(cond, lhs.reg, rhs.reg, label); + } void compareDouble(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs) { Fcmp(ARMFPRegister(lhs, 64), ARMFPRegister(rhs, 64)); @@ -2958,6 +2980,27 @@ class MacroAssemblerCompat : public vixl::MacroAssembler Add(xdest, xsrc, Operand(xsrc, vixl::LSL, 1)); } + void mul64(Imm64 imm, const Register64& dest) { + vixl::UseScratchRegisterScope temps(this); + const ARMRegister scratch64 = temps.AcquireX(); + MOZ_ASSERT(dest.reg != scratch64.asUnsized()); + mov(ImmWord(imm.value), scratch64.asUnsized()); + Mul(ARMRegister(dest.reg, 64), ARMRegister(dest.reg, 64), scratch64); + } + + void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest) { + Ucvtf(ARMFPRegister(dest, 64), ARMRegister(src.reg, 64)); + } + void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) { + vixl::UseScratchRegisterScope temps(this); + const Register scratch = temps.AcquireX().asUnsized(); + MOZ_ASSERT(temp != scratch); + movePtr(imm, scratch); + const ARMFPRegister scratchDouble = temps.AcquireD(); + Ldr(scratchDouble, MemOperand(Address(scratch, 0))); + fmul(ARMFPRegister(dest, 64), ARMFPRegister(dest, 64), scratchDouble); + } + template void branchAdd32(Condition cond, T src, Register dest, Label* label) { adds32(src, dest); diff --git a/js/src/jit/mips-shared/LIR-mips-shared.h b/js/src/jit/mips-shared/LIR-mips-shared.h index 596acf6b51ef..8ddbaa9cd6bb 100644 --- a/js/src/jit/mips-shared/LIR-mips-shared.h +++ b/js/src/jit/mips-shared/LIR-mips-shared.h @@ -284,23 +284,6 @@ class LAsmJSLoadFuncPtr : public LInstructionHelper<1, 1, 0> } }; -// Math.random(). -class LRandom : public LCallInstructionHelper<1, 0, 2> -{ - public: - LIR_HEADER(Random) - LRandom(const LDefinition& temp, const LDefinition& temp2) { - setTemp(0, temp); - setTemp(1, temp2); - } - const LDefinition* temp() { - return getTemp(0); - } - const LDefinition* temp2() { - return getTemp(1); - } -}; - } // namespace jit } // namespace js diff --git a/js/src/jit/mips-shared/Lowering-mips-shared.cpp b/js/src/jit/mips-shared/Lowering-mips-shared.cpp index 653a19d605de..45b26a824539 100644 --- a/js/src/jit/mips-shared/Lowering-mips-shared.cpp +++ b/js/src/jit/mips-shared/Lowering-mips-shared.cpp @@ -415,6 +415,10 @@ LIRGeneratorMIPSShared::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayEleme void LIRGeneratorMIPSShared::visitRandom(MRandom* ins) { - LRandom* lir = new(alloc()) LRandom(tempFixed(CallTempReg0), tempFixed(CallTempReg1)); - defineReturn(lir, ins); + LRandom *lir = new(alloc()) LRandom(temp(), + temp(), + temp(), + temp(), + temp()); + defineFixed(lir, ins, LFloatReg(ReturnDoubleReg)); } diff --git a/js/src/jit/mips32/CodeGenerator-mips32.cpp b/js/src/jit/mips32/CodeGenerator-mips32.cpp index bf6f1e62d97d..db71c3bccd39 100644 --- a/js/src/jit/mips32/CodeGenerator-mips32.cpp +++ b/js/src/jit/mips32/CodeGenerator-mips32.cpp @@ -10,7 +10,6 @@ #include "jscntxt.h" #include "jscompartment.h" -#include "jsmath.h" #include "jsnum.h" #include "jit/CodeGenerator.h" @@ -2120,16 +2119,10 @@ CodeGeneratorMIPS::visitNegF(LNegF* ins) } void -CodeGeneratorMIPS::visitRandom(LRandom* ins) +CodeGeneratorMIPS::setReturnDoubleRegs(LiveRegisterSet* regs) { - Register temp = ToRegister(ins->temp()); - Register temp2 = ToRegister(ins->temp2()); - - masm.loadJSContext(temp); - - masm.setupUnalignedABICall(temp2); - masm.passABIArg(temp); - masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, math_random_no_outparam), MoveOp::DOUBLE); - - MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg); + MOZ_ASSERT(ReturnFloat32Reg.code_ == ReturnDoubleReg.code_); + regs->add(ReturnFloat32Reg); + regs->add(ReturnDoubleReg.singleOverlay(1)); + regs->add(ReturnDoubleReg); } diff --git a/js/src/jit/mips32/CodeGenerator-mips32.h b/js/src/jit/mips32/CodeGenerator-mips32.h index 197cbf6dd81c..1e56d0ade080 100644 --- a/js/src/jit/mips32/CodeGenerator-mips32.h +++ b/js/src/jit/mips32/CodeGenerator-mips32.h @@ -241,7 +241,7 @@ class CodeGeneratorMIPS : public CodeGeneratorShared void generateInvalidateEpilogue(); - void visitRandom(LRandom* ins); + void setReturnDoubleRegs(LiveRegisterSet* regs); protected: void visitEffectiveAddress(LEffectiveAddress* ins); diff --git a/js/src/jit/mips32/Lowering-mips32.cpp b/js/src/jit/mips32/Lowering-mips32.cpp index 20ce11faa5dd..aa9a55795bd9 100644 --- a/js/src/jit/mips32/Lowering-mips32.cpp +++ b/js/src/jit/mips32/Lowering-mips32.cpp @@ -173,3 +173,14 @@ LIRGeneratorMIPS::lowerTruncateFToInt32(MTruncateToInt32* ins) define(new(alloc()) LTruncateFToInt32(useRegister(opd), LDefinition::BogusTemp()), ins); } + +void +LIRGeneratorMIPS::visitRandom(MRandom* ins) +{ + LRandom *lir = new(alloc()) LRandom(temp(), + temp(), + temp(), + temp(), + temp()); + defineFixed(lir, ins, LFloatReg(ReturnDoubleReg)); +} diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index 77936954d10d..bb8bbb3eba12 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -61,6 +61,13 @@ MacroAssembler::andPtr(Imm32 imm, Register dest) ma_and(dest, imm); } +void +MacroAssembler::and64(Imm64 imm, Register64 dest) +{ + and32(Imm32(imm.value & LOW_32_MASK), dest.low); + and32(Imm32((imm.value >> 32) & LOW_32_MASK), dest.high); +} + void MacroAssembler::or32(Register src, Register dest) { @@ -93,6 +100,13 @@ MacroAssembler::orPtr(Imm32 imm, Register dest) ma_or(dest, imm); } +void +MacroAssembler::or64(Register64 src, Register64 dest) +{ + or32(src.low, dest.low); + or32(src.high, dest.high); +} + void MacroAssembler::xor32(Imm32 imm, Register dest) { diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index ec00d289ed2f..976aa7db86e4 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -77,6 +77,63 @@ MacroAssemblerMIPSCompat::convertUInt32ToDouble(Register src, FloatRegister dest as_addd(dest, dest, SecondScratchDoubleReg); } +void +MacroAssemblerMIPSCompat::mul64(Imm64 imm, const Register64& dest) +{ + // LOW32 = LOW(LOW(dest) * LOW(imm)); + // HIGH32 = LOW(HIGH(dest) * LOW(imm)) [multiply imm into upper bits] + // + LOW(LOW(dest) * HIGH(imm)) [multiply dest into upper bits] + // + HIGH(LOW(dest) * LOW(imm)) [carry] + + // HIGH(dest) = LOW(HIGH(dest) * LOW(imm)); + ma_li(ScratchRegister, Imm32(imm.value & LOW_32_MASK)); + as_multu(dest.high, ScratchRegister); + as_mflo(dest.high); + + // mfhi:mflo = LOW(dest) * LOW(imm); + as_multu(dest.low, ScratchRegister); + + // HIGH(dest) += mfhi; + as_mfhi(ScratchRegister); + as_addu(dest.high, dest.high, ScratchRegister); + + if (((imm.value >> 32) & LOW_32_MASK) == 5) { + // Optimized case for Math.random(). + + // HIGH(dest) += LOW(LOW(dest) * HIGH(imm)); + as_sll(ScratchRegister, dest.low, 2); + as_addu(ScratchRegister, ScratchRegister, dest.low); + as_addu(dest.high, dest.high, ScratchRegister); + + // LOW(dest) = mflo; + as_mflo(dest.low); + } else { + // tmp = mflo + as_mflo(SecondScratchReg); + + // HIGH(dest) += LOW(LOW(dest) * HIGH(imm)); + ma_li(ScratchRegister, Imm32((imm.value >> 32) & LOW_32_MASK)); + as_multu(dest.low, ScratchRegister); + as_mflo(ScratchRegister); + as_addu(dest.high, dest.high, ScratchRegister); + + // LOW(dest) = tmp; + ma_move(dest.low, SecondScratchReg); + } +} + +static const double TO_DOUBLE_HIGH_SCALE = 0x100000000; + +void +MacroAssemblerMIPSCompat::convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest) +{ + convertUInt32ToDouble(src.high, dest); + loadConstantDouble(TO_DOUBLE_HIGH_SCALE, ScratchDoubleReg); + mulDouble(ScratchDoubleReg, dest); + convertUInt32ToDouble(src.low, ScratchDoubleReg); + addDouble(ScratchDoubleReg, dest); +} + void MacroAssemblerMIPSCompat::convertUInt32ToFloat32(Register src, FloatRegister dest) { @@ -2558,6 +2615,20 @@ MacroAssemblerMIPSCompat::branchTestBooleanTruthy(bool b, const ValueOperand& op ma_b(operand.payloadReg(), operand.payloadReg(), label, b ? NonZero : Zero); } +void +MacroAssemblerMIPSCompat::branchTest64(Condition cond, Register64 lhs, Register64 rhs, + Register temp, Label* label) +{ + if (cond == Assembler::Zero) { + MOZ_ASSERT(lhs.low == rhs.low); + MOZ_ASSERT(lhs.high == rhs.high); + as_or(ScratchRegister, lhs.low, lhs.high); + branchTestPtr(cond, ScratchRegister, ScratchRegister, label); + } else { + MOZ_CRASH("Unsupported condition"); + } +} + Register MacroAssemblerMIPSCompat::extractObject(const Address& address, Register scratch) { diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index f5cae05ee304..1216a1d7a338 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -65,6 +65,10 @@ static Register CallReg = t9; static const int defaultShift = 3; static_assert(1 << defaultShift == sizeof(JS::Value), "The defaultShift is wrong"); +static const uint32_t LOW_32_MASK = (1LL << 32) - 1; +static const int32_t LOW_32_OFFSET = 0; +static const int32_t HIGH_32_OFFSET = 4; + class MacroAssemblerMIPS : public Assembler { protected: @@ -676,6 +680,8 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS loadPtr(lhs, SecondScratchReg); branchTestPtr(cond, SecondScratchReg, imm, label); } + void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp, + Label* label); void branchPtr(Condition cond, Register lhs, Register rhs, Label* label) { ma_b(lhs, rhs, label, cond); } @@ -1101,6 +1107,11 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void add32(Register src, Register dest); void add32(Imm32 imm, Register dest); void add32(Imm32 imm, const Address& dest); + void add64(Imm32 imm, Register64 dest) { + as_addiu(dest.low, dest.low, imm.value); + as_sltiu(ScratchRegister, dest.low, imm.value); + as_addu(dest.high, dest.high, ScratchRegister); + } void sub32(Imm32 imm, Register dest); void sub32(Register src, Register dest); @@ -1140,6 +1151,10 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void move32(Imm32 imm, Register dest); void move32(Register src, Register dest); + void move64(Register64 src, Register64 dest) { + move32(src.low, dest.low); + move32(src.high, dest.high); + } void movePtr(Register src, Register dest); void movePtr(ImmWord imm, Register dest); @@ -1163,6 +1178,10 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void load32(const BaseIndex& address, Register dest); void load32(AbsoluteAddress address, Register dest); void load32(AsmJSAbsoluteAddress address, Register dest); + void load64(const Address& address, Register64 dest) { + load32(Address(address.base, address.offset + LOW_32_OFFSET), dest.low); + load32(Address(address.base, address.offset + HIGH_32_OFFSET), dest.high); + } void loadPtr(const Address& address, Register dest); void loadPtr(const BaseIndex& src, Register dest); @@ -1233,6 +1252,11 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS store32(src, address); } + void store64(Register64 src, Address address) { + store32(src.low, Address(address.base, address.offset + LOW_32_OFFSET)); + store32(src.high, Address(address.base, address.offset + HIGH_32_OFFSET)); + } + template void storePtr(ImmWord imm, T address); template void storePtr(ImmPtr imm, T address); template void storePtr(ImmGCPtr imm, T address); @@ -1302,6 +1326,15 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS as_addu(dest, dest, src); } + void mul64(Imm64 imm, const Register64& dest); + + void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest); + void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) { + movePtr(imm, ScratchRegister); + loadDouble(Address(ScratchRegister, 0), ScratchDoubleReg); + mulDouble(ScratchDoubleReg, dest); + } + void breakpoint(); void branchDouble(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs, @@ -1322,9 +1355,21 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void rshiftPtrArithmetic(Imm32 imm, Register dest) { ma_sra(dest, dest, imm); } + void rshift64(Imm32 imm, Register64 dest) { + as_srl(dest.low, dest.low, imm.value); + as_sll(ScratchRegister, dest.high, 32 - imm.value); + as_or(dest.low, dest.low, ScratchRegister); + as_srl(dest.high, dest.high, imm.value); + } void lshiftPtr(Imm32 imm, Register dest) { ma_sll(dest, dest, imm); } + void lshift64(Imm32 imm, Register64 dest) { + as_sll(dest.high, dest.high, imm.value); + as_srl(ScratchRegister, dest.low, 32 - imm.value); + as_or(dest.high, dest.high, ScratchRegister); + as_sll(dest.low, dest.low, imm.value); + } // If source is a double, load it into dest. If source is int32, // convert it to double. Else, branch to failure. diff --git a/js/src/jit/none/CodeGenerator-none.h b/js/src/jit/none/CodeGenerator-none.h index 6d6164d0d298..ad62ea452b2a 100644 --- a/js/src/jit/none/CodeGenerator-none.h +++ b/js/src/jit/none/CodeGenerator-none.h @@ -51,6 +51,7 @@ class CodeGeneratorNone : public CodeGeneratorShared ValueOperand ToOutValue(LInstruction*) { MOZ_CRASH(); } ValueOperand ToTempValue(LInstruction*, size_t) { MOZ_CRASH(); } void generateInvalidateEpilogue() { MOZ_CRASH(); } + void setReturnDoubleRegs(LiveRegisterSet* regs) { MOZ_CRASH(); } }; typedef CodeGeneratorNone CodeGeneratorSpecific; diff --git a/js/src/jit/none/LIR-none.h b/js/src/jit/none/LIR-none.h index c4959a392ce0..c61ff5cfe6c7 100644 --- a/js/src/jit/none/LIR-none.h +++ b/js/src/jit/none/LIR-none.h @@ -112,7 +112,6 @@ class LModPowTwoI : public LInstructionHelper<1, 1, 0> class LGuardShape : public LInstruction {}; class LGuardObjectGroup : public LInstruction {}; class LMulI : public LInstruction {}; -class LRandom : public LInstructionHelper<1, 0, 5> {}; } // namespace jit } // namespace js diff --git a/js/src/jit/none/Lowering-none.h b/js/src/jit/none/Lowering-none.h index ef946427fe04..4f6a8950118c 100644 --- a/js/src/jit/none/Lowering-none.h +++ b/js/src/jit/none/Lowering-none.h @@ -87,7 +87,6 @@ class LIRGeneratorNone : public LIRGeneratorShared void visitSimdValueX4(MSimdValueX4* lir) { MOZ_CRASH(); } void visitSubstr(MSubstr*) { MOZ_CRASH(); } void visitSimdBinaryArith(js::jit::MSimdBinaryArith*) { MOZ_CRASH(); } - void visitRandom(MRandom* ) { MOZ_CRASH(); } }; diff --git a/js/src/jit/shared/Assembler-shared.h b/js/src/jit/shared/Assembler-shared.h index 5f26b43c3019..896a4c95eaff 100644 --- a/js/src/jit/shared/Assembler-shared.h +++ b/js/src/jit/shared/Assembler-shared.h @@ -125,6 +125,15 @@ struct ImmWord { } }; +// Used for 64-bit immediates which do not require relocation. +struct Imm64 +{ + uint64_t value; + + explicit Imm64(uint64_t value) : value(value) + { } +}; + #ifdef DEBUG static inline bool IsCompilingAsmJS() diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index 53ca728139ac..56f5416d97eb 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -7176,6 +7176,57 @@ class LArrowNewTarget : public LInstructionHelper } }; +// Math.random(). +#ifdef JS_PUNBOX64 +# define LRANDOM_NUM_TEMPS 3 +#else +# define LRANDOM_NUM_TEMPS 5 +#endif + +class LRandom : public LInstructionHelper<1, 0, LRANDOM_NUM_TEMPS> +{ + public: + LIR_HEADER(Random) + LRandom(const LDefinition &tempMaybeEAX, const LDefinition &tempMaybeEDX, + const LDefinition &temp1 +#ifndef JS_PUNBOX64 + , const LDefinition &temp2, const LDefinition &temp3 +#endif + ) + { + setTemp(0, tempMaybeEAX); + setTemp(1, tempMaybeEDX); + setTemp(2, temp1); +#ifndef JS_PUNBOX64 + setTemp(3, temp2); + setTemp(4, temp3); +#endif + } + // On x86, following 2 methods return eax and edx necessary for mull. + // On others, following 2 methods return ordinary temporary registers. + const LDefinition* tempMaybeEAX() { + return getTemp(0); + } + const LDefinition* tempMaybeEDX() { + return getTemp(1); + } + const LDefinition *temp1() { + return getTemp(2); + } +#ifndef JS_PUNBOX64 + const LDefinition *temp2() { + return getTemp(3); + } + const LDefinition *temp3() { + return getTemp(4); + } +#endif + + MRandom* mir() const { + return mir_->toRandom(); + } +}; + } // namespace jit } // namespace js diff --git a/js/src/jit/x64/CodeGenerator-x64.cpp b/js/src/jit/x64/CodeGenerator-x64.cpp index b2743a38897c..1ec5560a80f3 100644 --- a/js/src/jit/x64/CodeGenerator-x64.cpp +++ b/js/src/jit/x64/CodeGenerator-x64.cpp @@ -841,129 +841,3 @@ CodeGeneratorX64::visitTruncateFToInt32(LTruncateFToInt32* ins) // call a stub if it fails. emitTruncateFloat32(input, output, ins->mir()); } - -namespace js { -namespace jit { - -// Out-of-line math_random_no_outparam call for LRandom. -class OutOfLineRandom : public OutOfLineCodeBase -{ - LRandom* lir_; - - public: - explicit OutOfLineRandom(LRandom* lir) - : lir_(lir) - { } - - void accept(CodeGeneratorX64* codegen) { - codegen->visitOutOfLineRandom(this); - } - - LRandom* lir() const { - return lir_; - } -}; - -} // namespace jit -} // namespace js - -static const double RNG_DSCALE_INV = 1 / RNG_DSCALE; - -void -CodeGeneratorX64::visitRandom(LRandom* ins) -{ - FloatRegister output = ToFloatRegister(ins->output()); - - Register JSCompartmentReg = ToRegister(ins->temp()); - Register rngStateReg = ToRegister(ins->temp2()); - Register highReg = ToRegister(ins->temp3()); - Register lowReg = ToRegister(ins->temp4()); - Register rngMaskReg = ToRegister(ins->temp5()); - - // rngState = cx->compartment()->rngState - masm.loadJSContext(JSCompartmentReg); - masm.loadPtr(Address(JSCompartmentReg, JSContext::offsetOfCompartment()), JSCompartmentReg); - masm.loadPtr(Address(JSCompartmentReg, JSCompartment::offsetOfRngState()), rngStateReg); - - // if rngState == 0, escape from inlined code and call - // math_random_no_outparam. - OutOfLineRandom* ool = new(alloc()) OutOfLineRandom(ins); - addOutOfLineCode(ool, ins->mir()); - masm.branchTestPtr(Assembler::Zero, rngStateReg, rngStateReg, ool->entry()); - - // nextstate = rngState * RNG_MULTIPLIER; - Register& rngMultiplierReg = lowReg; - masm.movq(ImmWord(RNG_MULTIPLIER), rngMultiplierReg); - masm.imulq(rngMultiplierReg, rngStateReg); - - // nextstate += RNG_ADDEND; - masm.addq(Imm32(RNG_ADDEND), rngStateReg); - - // nextstate &= RNG_MASK; - masm.movq(ImmWord(RNG_MASK), rngMaskReg); - masm.andq(rngMaskReg, rngStateReg); - - // rngState = nextstate - - // if rngState == 0, escape from inlined code and call - // math_random_no_outparam. - masm.j(Assembler::Zero, ool->entry()); - - // high = (nextstate >> (RNG_STATE_WIDTH - RNG_HIGH_BITS)) << RNG_LOW_BITS; - masm.movq(rngStateReg, highReg); - masm.shrq(Imm32(RNG_STATE_WIDTH - RNG_HIGH_BITS), highReg); - masm.shlq(Imm32(RNG_LOW_BITS), highReg); - - // nextstate = rngState * RNG_MULTIPLIER; - masm.imulq(rngMultiplierReg, rngStateReg); - - // nextstate += RNG_ADDEND; - masm.addq(Imm32(RNG_ADDEND), rngStateReg); - - // nextstate &= RNG_MASK; - masm.andq(rngMaskReg, rngStateReg); - - // low = nextstate >> (RNG_STATE_WIDTH - RNG_LOW_BITS); - masm.movq(rngStateReg, lowReg); - masm.shrq(Imm32(RNG_STATE_WIDTH - RNG_LOW_BITS), lowReg); - - // output = double(high | low); - masm.orq(highReg, lowReg); - masm.vcvtsi2sdq(lowReg, output); - - // output = output * RNG_DSCALE_INV; - Register& rngDscaleInvReg = lowReg; - masm.movq(ImmPtr(&RNG_DSCALE_INV), rngDscaleInvReg); - masm.vmulsd(Operand(rngDscaleInvReg, 0), output, output); - - // cx->compartment()->rngState = nextstate - masm.storePtr(rngStateReg, Address(JSCompartmentReg, JSCompartment::offsetOfRngState())); - - masm.bind(ool->rejoin()); -} - -void -CodeGeneratorX64::visitOutOfLineRandom(OutOfLineRandom* ool) -{ - LRandom* ins = ool->lir(); - Register temp = ToRegister(ins->temp()); - Register temp2 = ToRegister(ins->temp2()); - MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg); - - LiveRegisterSet regs; - regs.add(ReturnFloat32Reg); - regs.add(ReturnDoubleReg); - regs.add(ReturnInt32x4Reg); - regs.add(ReturnFloat32x4Reg); - saveVolatile(regs); - - masm.loadJSContext(temp); - - masm.setupUnalignedABICall(temp2); - masm.passABIArg(temp); - masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, math_random_no_outparam), MoveOp::DOUBLE); - - restoreVolatile(regs); - - masm.jump(ool->rejoin()); -} diff --git a/js/src/jit/x64/CodeGenerator-x64.h b/js/src/jit/x64/CodeGenerator-x64.h index 6895bdd1dc7c..0d21d7a87f42 100644 --- a/js/src/jit/x64/CodeGenerator-x64.h +++ b/js/src/jit/x64/CodeGenerator-x64.h @@ -12,8 +12,6 @@ namespace js { namespace jit { -class OutOfLineRandom; - class CodeGeneratorX64 : public CodeGeneratorX86Shared { CodeGeneratorX64* thisFromCtor() { @@ -61,8 +59,6 @@ class CodeGeneratorX64 : public CodeGeneratorX86Shared void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins); void visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble* lir); void visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32* lir); - void visitRandom(LRandom* ins); - void visitOutOfLineRandom(OutOfLineRandom* ool); }; typedef CodeGeneratorX64 CodeGeneratorSpecific; diff --git a/js/src/jit/x64/LIR-x64.h b/js/src/jit/x64/LIR-x64.h index f6dafc9dd6ee..a808a5510fa6 100644 --- a/js/src/jit/x64/LIR-x64.h +++ b/js/src/jit/x64/LIR-x64.h @@ -99,41 +99,6 @@ class LAsmJSLoadFuncPtr : public LInstructionHelper<1, 1, 1> } }; -// Math.random(). -class LRandom : public LInstructionHelper<1, 0, 5> -{ - public: - LIR_HEADER(Random) - LRandom(const LDefinition &temp, const LDefinition &temp2, const LDefinition &temp3, - const LDefinition &temp4, const LDefinition &temp5) - { - setTemp(0, temp); - setTemp(1, temp2); - setTemp(2, temp3); - setTemp(3, temp4); - setTemp(4, temp5); - } - const LDefinition* temp() { - return getTemp(0); - } - const LDefinition* temp2() { - return getTemp(1); - } - const LDefinition *temp3() { - return getTemp(2); - } - const LDefinition *temp4() { - return getTemp(3); - } - const LDefinition *temp5() { - return getTemp(4); - } - - MRandom* mir() const { - return mir_->toRandom(); - } -}; - } // namespace jit } // namespace js diff --git a/js/src/jit/x64/Lowering-x64.cpp b/js/src/jit/x64/Lowering-x64.cpp index 8042020bdc20..af91a9f88e3d 100644 --- a/js/src/jit/x64/Lowering-x64.cpp +++ b/js/src/jit/x64/Lowering-x64.cpp @@ -337,8 +337,6 @@ void LIRGeneratorX64::visitRandom(MRandom* ins) { LRandom *lir = new(alloc()) LRandom(temp(), - temp(), - temp(), temp(), temp()); defineFixed(lir, ins, LFloatReg(ReturnDoubleReg)); diff --git a/js/src/jit/x64/MacroAssembler-x64-inl.h b/js/src/jit/x64/MacroAssembler-x64-inl.h index 6a5ff97927aa..47ae0754fec0 100644 --- a/js/src/jit/x64/MacroAssembler-x64-inl.h +++ b/js/src/jit/x64/MacroAssembler-x64-inl.h @@ -29,6 +29,13 @@ MacroAssembler::andPtr(Imm32 imm, Register dest) andq(imm, dest); } +void +MacroAssembler::and64(Imm64 imm, Register64 dest) +{ + movq(ImmWord(uintptr_t(imm.value)), ScratchReg); + andq(ScratchReg, dest.reg); +} + void MacroAssembler::orPtr(Register src, Register dest) { @@ -41,6 +48,12 @@ MacroAssembler::orPtr(Imm32 imm, Register dest) orq(imm, dest); } +void +MacroAssembler::or64(Register64 src, Register64 dest) +{ + orq(src.reg, dest.reg); +} + void MacroAssembler::xorPtr(Register src, Register dest) { diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index 16207ae70ca1..d5739fd2ae2b 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -604,6 +604,9 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared void addPtr(const Address& src, Register dest) { addq(Operand(src), dest); } + void add64(Imm32 imm, Register64 dest) { + addq(imm, dest.reg); + } void subPtr(Imm32 imm, Register dest) { subq(imm, dest); } @@ -619,6 +622,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared void mulBy3(const Register& src, const Register& dest) { lea(Operand(src, src, TimesTwo), dest); } + void mul64(Imm64 imm, const Register64& dest) { + movq(ImmWord(uintptr_t(imm.value)), ScratchReg); + imulq(ScratchReg, dest.reg); + } void branch32(Condition cond, AbsoluteAddress lhs, Imm32 rhs, Label* label) { if (X86Encoding::IsAddressImmediate(lhs.addr)) { @@ -741,6 +748,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared j(cond, label); } + void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp, Label* label) { + branchTestPtr(cond, lhs.reg, rhs.reg, label); + } + void movePtr(Register src, Register dest) { movq(src, dest); } @@ -759,6 +770,9 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared void movePtr(ImmGCPtr imm, Register dest) { movq(imm, dest); } + void move64(Register64 src, Register64 dest) { + movq(src.reg, dest.reg); + } void loadPtr(AbsoluteAddress address, Register dest) { if (X86Encoding::IsAddressImmediate(address.addr)) { movq(Operand(address), dest); @@ -790,6 +804,9 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared load32(Address(scratch, 0x0), dest); } } + void load64(const Address& address, Register64 dest) { + movq(Operand(address), dest.reg); + } template void storePtr(ImmWord imm, T address) { if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) { @@ -837,15 +854,24 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared store32(src, Address(scratch, 0x0)); } } + void store64(Register64 src, Address address) { + movq(src.reg, Operand(address)); + } void rshiftPtr(Imm32 imm, Register dest) { shrq(imm, dest); } void rshiftPtrArithmetic(Imm32 imm, Register dest) { sarq(imm, dest); } + void rshift64(Imm32 imm, Register64 dest) { + shrq(imm, dest.reg); + } void lshiftPtr(Imm32 imm, Register dest) { shlq(imm, dest); } + void lshift64(Imm32 imm, Register64 dest) { + shlq(imm, dest.reg); + } void splitTag(Register src, Register dest) { if (src != dest) @@ -1370,6 +1396,15 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared vcvtsq2ss(src, dest, dest); } + void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest) { + vcvtsi2sdq(src.reg, dest); + } + + void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) { + movq(imm, ScratchReg); + vmulsd(Operand(ScratchReg, 0), dest, dest); + } + void inc64(AbsoluteAddress dest) { if (X86Encoding::IsAddressImmediate(dest.addr)) { addPtr(Imm32(1), Operand(dest)); diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp index 31e494fa6b6c..40cff8339825 100644 --- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp @@ -3644,5 +3644,18 @@ CodeGeneratorX86Shared::visitMemoryBarrier(LMemoryBarrier* ins) masm.storeLoadFence(); } +void +CodeGeneratorX86Shared::setReturnDoubleRegs(LiveRegisterSet* regs) +{ + MOZ_ASSERT(ReturnFloat32Reg.encoding() == X86Encoding::xmm0); + MOZ_ASSERT(ReturnDoubleReg.encoding() == X86Encoding::xmm0); + MOZ_ASSERT(ReturnInt32x4Reg.encoding() == X86Encoding::xmm0); + MOZ_ASSERT(ReturnFloat32x4Reg.encoding() == X86Encoding::xmm0); + regs->add(ReturnFloat32Reg); + regs->add(ReturnDoubleReg); + regs->add(ReturnInt32x4Reg); + regs->add(ReturnFloat32x4Reg); +} + } // namespace jit } // namespace js diff --git a/js/src/jit/x86-shared/CodeGenerator-x86-shared.h b/js/src/jit/x86-shared/CodeGenerator-x86-shared.h index 366746478d5e..2200d9152aa5 100644 --- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.h +++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.h @@ -300,6 +300,8 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared // Generating no result. template void atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type arrayType, const S& value, const T& mem); + + void setReturnDoubleRegs(LiveRegisterSet* regs); }; // An out-of-line bailout thunk. diff --git a/js/src/jit/x86-shared/Encoding-x86-shared.h b/js/src/jit/x86-shared/Encoding-x86-shared.h index 3f5cb332b038..3a618d828c19 100644 --- a/js/src/jit/x86-shared/Encoding-x86-shared.h +++ b/js/src/jit/x86-shared/Encoding-x86-shared.h @@ -176,6 +176,7 @@ enum TwoByteOpcodeID { OP2_ANDPD_VpdWpd = 0x54, OP2_ORPD_VpdWpd = 0x56, OP2_XORPD_VpdWpd = 0x57, + OP2_PUNPCKLDQ = 0x62, OP2_PCMPGTD_VdqWdq = 0x66, OP2_MOVD_VdEd = 0x6E, OP2_MOVDQ_VsdWsd = 0x6F, @@ -187,11 +188,14 @@ enum TwoByteOpcodeID { OP2_PSRLDQ_Vd = 0x73, OP2_PCMPEQW = 0x75, OP2_PCMPEQD_VdqWdq = 0x76, + OP2_HADDPD = 0x7C, OP2_MOVD_EdVd = 0x7E, OP2_MOVQ_VdWd = 0x7E, OP2_MOVDQ_WdqVdq = 0x7F, OP2_JCC_rel32 = 0x80, OP_SETCC = 0x90, + OP2_SHLD = 0xA4, + OP2_SHRD = 0xAC, OP_FENCE = 0xAE, OP2_IMUL_GvEv = 0xAF, OP2_CMPXCHG_GvEb = 0xB0, diff --git a/js/src/jit/x86/Assembler-x86.h b/js/src/jit/x86/Assembler-x86.h index 5809961982da..780d71b020a7 100644 --- a/js/src/jit/x86/Assembler-x86.h +++ b/js/src/jit/x86/Assembler-x86.h @@ -51,6 +51,7 @@ static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32x4Reg = FloatRegister(X86Enc static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Single); static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Double); static MOZ_CONSTEXPR_VAR FloatRegister ScratchSimdReg = xmm7; +static MOZ_CONSTEXPR_VAR FloatRegister ScratchInt32x4Reg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Int32x4); // Avoid ebp, which is the FramePointer, which is unavailable in some modes. static MOZ_CONSTEXPR_VAR Register ArgumentsRectifierReg = esi; @@ -375,6 +376,66 @@ class Assembler : public AssemblerX86Shared append(AsmJSAbsoluteLink(CodeOffsetLabel(src.offset()), lhs.kind())); } + void adcl(Imm32 imm, Register dest) { + masm.adcl_ir(imm.value, dest.encoding()); + } + + void mull(Register multiplier) { + masm.mull_r(multiplier.encoding()); + } + + void shldl(const Imm32 imm, Register src, Register dest) { + masm.shldl_irr(imm.value, src.encoding(), dest.encoding()); + } + void shrdl(const Imm32 imm, Register src, Register dest) { + masm.shrdl_irr(imm.value, src.encoding(), dest.encoding()); + } + + void vhaddpd(FloatRegister src, FloatRegister dest) { + MOZ_ASSERT(HasSSE2()); + MOZ_ASSERT(src.size() == 16); + MOZ_ASSERT(dest.size() == 16); + masm.vhaddpd_rr(src.encoding(), dest.encoding()); + } + void vsubpd(const Operand& src1, FloatRegister src0, FloatRegister dest) { + MOZ_ASSERT(HasSSE2()); + MOZ_ASSERT(src0.size() == 16); + MOZ_ASSERT(dest.size() == 16); + switch (src1.kind()) { + case Operand::MEM_REG_DISP: + masm.vsubpd_mr(src1.disp(), src1.base(), src0.encoding(), dest.encoding()); + break; + case Operand::MEM_ADDRESS32: + masm.vsubpd_mr(src1.address(), src0.encoding(), dest.encoding()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + } + } + + void vpunpckldq(FloatRegister src1, FloatRegister src0, FloatRegister dest) { + MOZ_ASSERT(HasSSE2()); + MOZ_ASSERT(src0.size() == 16); + MOZ_ASSERT(src1.size() == 16); + MOZ_ASSERT(dest.size() == 16); + masm.vpunpckldq_rr(src1.encoding(), src0.encoding(), dest.encoding()); + } + void vpunpckldq(const Operand& src1, FloatRegister src0, FloatRegister dest) { + MOZ_ASSERT(HasSSE2()); + MOZ_ASSERT(src0.size() == 16); + MOZ_ASSERT(dest.size() == 16); + switch (src1.kind()) { + case Operand::MEM_REG_DISP: + masm.vpunpckldq_mr(src1.disp(), src1.base(), src0.encoding(), dest.encoding()); + break; + case Operand::MEM_ADDRESS32: + masm.vpunpckldq_mr(src1.address(), src0.encoding(), dest.encoding()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + } + } + void jmp(ImmPtr target, Relocation::Kind reloc = Relocation::HARDCODED) { JmpSrc src = masm.jmp(); addPendingJump(src, target, reloc); diff --git a/js/src/jit/x86/BaseAssembler-x86.h b/js/src/jit/x86/BaseAssembler-x86.h index c28330092906..25624c61bb0b 100644 --- a/js/src/jit/x86/BaseAssembler-x86.h +++ b/js/src/jit/x86/BaseAssembler-x86.h @@ -20,6 +20,14 @@ class BaseAssemblerX86 : public BaseAssembler // Arithmetic operations: + void adcl_ir(int32_t imm, RegisterID dst) + { + spew("adcl $%d, %s", imm, GPReg32Name(dst)); + MOZ_ASSERT(CAN_SIGN_EXTEND_8_32(imm)); + m_formatter.oneByteOp(OP_GROUP1_EvIb, dst, GROUP1_OP_ADC); + m_formatter.immediate8s(imm); + } + void adcl_im(int32_t imm, const void* addr) { spew("adcl %d, %p", imm, addr); @@ -71,6 +79,22 @@ class BaseAssemblerX86 : public BaseAssembler } } + void shldl_irr(int32_t imm, RegisterID src, RegisterID dst) + { + MOZ_ASSERT(imm < 32); + spew("shldl $%d, %s, %s", imm, GPReg32Name(src), GPReg32Name(dst)); + m_formatter.twoByteOp8(OP2_SHLD, dst, src); + m_formatter.immediate8u(imm); + } + + void shrdl_irr(int32_t imm, RegisterID src, RegisterID dst) + { + MOZ_ASSERT(imm < 32); + spew("shrdl $%d, %s, %s", imm, GPReg32Name(src), GPReg32Name(dst)); + m_formatter.twoByteOp8(OP2_SHRD, dst, src); + m_formatter.immediate8u(imm); + } + // SSE operations: using BaseAssembler::vcvtsi2sd_mr; @@ -91,6 +115,36 @@ class BaseAssemblerX86 : public BaseAssembler twoByteOpSimd("vmovdqa", VEX_PD, OP2_MOVDQ_VdqWdq, address, invalid_xmm, dst); } + void vhaddpd_rr(XMMRegisterID src, XMMRegisterID dst) + { + twoByteOpSimdFlags("vhaddpd", VEX_PD, OP2_HADDPD, src, dst); + } + + void vsubpd_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vsubpd", VEX_PD, OP2_SUBPS_VpsWps, src1, src0, dst); + } + void vsubpd_mr(int32_t offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vsubpd", VEX_PD, OP2_SUBPS_VpsWps, offset, base, src0, dst); + } + void vsubpd_mr(const void* address, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vsubpd", VEX_PD, OP2_SUBPS_VpsWps, address, src0, dst); + } + + void vpunpckldq_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) { + twoByteOpSimd("vpunpckldq", VEX_PD, OP2_PUNPCKLDQ, src1, src0, dst); + } + void vpunpckldq_mr(int32_t offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vpunpckldq", VEX_PD, OP2_PUNPCKLDQ, offset, base, src0, dst); + } + void vpunpckldq_mr(const void* addr, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vpunpckldq", VEX_PD, OP2_PUNPCKLDQ, addr, src0, dst); + } + // Misc instructions: void pusha() diff --git a/js/src/jit/x86/CodeGenerator-x86.cpp b/js/src/jit/x86/CodeGenerator-x86.cpp index 4bcbb6034753..8e47c90b4c87 100644 --- a/js/src/jit/x86/CodeGenerator-x86.cpp +++ b/js/src/jit/x86/CodeGenerator-x86.cpp @@ -9,7 +9,6 @@ #include "mozilla/Casting.h" #include "mozilla/DebugOnly.h" -#include "jsmath.h" #include "jsnum.h" #include "jit/IonCaches.h" @@ -1105,18 +1104,3 @@ CodeGeneratorX86::visitOutOfLineTruncateFloat32(OutOfLineTruncateFloat32* ool) masm.jump(ool->rejoin()); } - -void -CodeGeneratorX86::visitRandom(LRandom* ins) -{ - Register temp = ToRegister(ins->temp()); - Register temp2 = ToRegister(ins->temp2()); - - masm.loadJSContext(temp); - - masm.setupUnalignedABICall(temp2); - masm.passABIArg(temp); - masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, math_random_no_outparam), MoveOp::DOUBLE); - - MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg); -} diff --git a/js/src/jit/x86/CodeGenerator-x86.h b/js/src/jit/x86/CodeGenerator-x86.h index 3c3e2ee1eab9..a2b83cb083ce 100644 --- a/js/src/jit/x86/CodeGenerator-x86.h +++ b/js/src/jit/x86/CodeGenerator-x86.h @@ -72,8 +72,6 @@ class CodeGeneratorX86 : public CodeGeneratorX86Shared void visitOutOfLineTruncate(OutOfLineTruncate* ool); void visitOutOfLineTruncateFloat32(OutOfLineTruncateFloat32* ool); - void visitRandom(LRandom* ins); - private: void asmJSAtomicComputeAddress(Register addrTemp, Register ptrReg, bool boundsCheck, int32_t offset, int32_t endOffset); diff --git a/js/src/jit/x86/LIR-x86.h b/js/src/jit/x86/LIR-x86.h index 764ee4498ff1..5a3ec0e8b764 100644 --- a/js/src/jit/x86/LIR-x86.h +++ b/js/src/jit/x86/LIR-x86.h @@ -122,23 +122,6 @@ class LAsmJSLoadFuncPtr : public LInstructionHelper<1, 1, 0> } }; -// Math.random(). -class LRandom : public LCallInstructionHelper<1, 0, 2> -{ - public: - LIR_HEADER(Random) - LRandom(const LDefinition& temp, const LDefinition& temp2) { - setTemp(0, temp); - setTemp(1, temp2); - } - const LDefinition* temp() { - return getTemp(0); - } - const LDefinition* temp2() { - return getTemp(1); - } -}; - } // namespace jit } // namespace js diff --git a/js/src/jit/x86/Lowering-x86.cpp b/js/src/jit/x86/Lowering-x86.cpp index f1b40cfd5dde..ee5d8c002ef1 100644 --- a/js/src/jit/x86/Lowering-x86.cpp +++ b/js/src/jit/x86/Lowering-x86.cpp @@ -441,6 +441,11 @@ LIRGeneratorX86::visitSubstr(MSubstr* ins) void LIRGeneratorX86::visitRandom(MRandom* ins) { - LRandom* lir = new(alloc()) LRandom(tempFixed(CallTempReg0), tempFixed(CallTempReg1)); - defineReturn(lir, ins); + // eax and edx are necessary for mull. + LRandom *lir = new(alloc()) LRandom(tempFixed(eax), + tempFixed(edx), + temp(), + temp(), + temp()); + defineFixed(lir, ins, LFloatReg(ReturnDoubleReg)); } diff --git a/js/src/jit/x86/MacroAssembler-x86-inl.h b/js/src/jit/x86/MacroAssembler-x86-inl.h index b5ca8186754f..c4da16960d4c 100644 --- a/js/src/jit/x86/MacroAssembler-x86-inl.h +++ b/js/src/jit/x86/MacroAssembler-x86-inl.h @@ -29,6 +29,13 @@ MacroAssembler::andPtr(Imm32 imm, Register dest) andl(imm, dest); } +void +MacroAssembler::and64(Imm64 imm, Register64 dest) +{ + andl(Imm32(imm.value & 0xFFFFFFFFL), dest.low); + andl(Imm32((imm.value >> 32) & 0xFFFFFFFFL), dest.high); +} + void MacroAssembler::orPtr(Register src, Register dest) { @@ -41,6 +48,13 @@ MacroAssembler::orPtr(Imm32 imm, Register dest) orl(imm, dest); } +void +MacroAssembler::or64(Register64 src, Register64 dest) +{ + orl(src.low, dest.low); + orl(src.high, dest.high); +} + void MacroAssembler::xorPtr(Register src, Register dest) { diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index 17f8ca9c15c3..3c4e55e74cba 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -6,6 +6,7 @@ #include "jit/x86/MacroAssembler-x86.h" +#include "mozilla/Alignment.h" #include "mozilla/Casting.h" #include "jit/Bailouts.h" @@ -20,6 +21,62 @@ using namespace js; using namespace js::jit; +// vpunpckldq requires 16-byte boundary for memory operand. +// See convertUInt64ToDouble for the details. +MOZ_ALIGNED_DECL(static const uint64_t, 16) TO_DOUBLE[4] = { + 0x4530000043300000LL, + 0x0LL, + 0x4330000000000000LL, + 0x4530000000000000LL +}; + +void +MacroAssemblerX86::convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest) +{ + // Following operation uses entire 128-bit of dest XMM register. + // Currently higher 64-bit is free when we have access to lower 64-bit. + MOZ_ASSERT(dest.size() == 8); + FloatRegister dest128 = FloatRegister(dest.encoding(), FloatRegisters::Int32x4); + + // Assume that src is represented as following: + // src = 0x HHHHHHHH LLLLLLLL + + // Move src to dest (=dest128) and ScratchInt32x4Reg (=scratch): + // dest = 0x 00000000 00000000 00000000 LLLLLLLL + // scratch = 0x 00000000 00000000 00000000 HHHHHHHH + vmovd(src.low, dest128); + vmovd(src.high, ScratchInt32x4Reg); + + // Unpack and interleave dest and scratch to dest: + // dest = 0x 00000000 00000000 HHHHHHHH LLLLLLLL + vpunpckldq(ScratchInt32x4Reg, dest128, dest128); + + // Unpack and interleave dest and a constant C1 to dest: + // C1 = 0x 00000000 00000000 45300000 43300000 + // dest = 0x 45300000 HHHHHHHH 43300000 LLLLLLLL + // here, each 64-bit part of dest represents following double: + // HI(dest) = 0x 1.00000HHHHHHHH * 2**84 == 2**84 + 0x HHHHHHHH 00000000 + // LO(dest) = 0x 1.00000LLLLLLLL * 2**52 == 2**52 + 0x 00000000 LLLLLLLL + movePtr(ImmPtr(TO_DOUBLE), temp); + vpunpckldq(Operand(temp, 0), dest128, dest128); + + // Subtract a constant C2 from dest, for each 64-bit part: + // C2 = 0x 45300000 00000000 43300000 00000000 + // here, each 64-bit part of C2 represents following double: + // HI(C2) = 0x 1.0000000000000 * 2**84 == 2**84 + // LO(C2) = 0x 1.0000000000000 * 2**52 == 2**52 + // after the operation each 64-bit part of dest represents following: + // HI(dest) = double(0x HHHHHHHH 00000000) + // LO(dest) = double(0x 00000000 LLLLLLLL) + vsubpd(Operand(temp, sizeof(uint64_t) * 2), dest128, dest128); + + // Add HI(dest) and LO(dest) in double and store it into LO(dest), + // LO(dest) = double(0x HHHHHHHH 00000000) + double(0x 00000000 LLLLLLLL) + // = double(0x HHHHHHHH LLLLLLLL) + // = double(src) + vhaddpd(dest128, dest128); +} + MacroAssemblerX86::Double* MacroAssemblerX86::getDouble(double d) { diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 64e079aad67a..cd73064b6168 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -240,6 +240,14 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared push(tagOf(addr)); push(payloadOfAfterStackPush(addr)); } + void push64(Register64 src) { + push(src.high); + push(src.low); + } + void pop64(Register64 dest) { + pop(dest.low); + pop(dest.high); + } void storePayload(const Value& val, Operand dest) { jsval_layout jv = JSVAL_TO_IMPL(val); if (val.isMarkable()) @@ -607,6 +615,10 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared void addPtr(const Address& src, Register dest) { addl(Operand(src), dest); } + void add64(Imm32 imm, Register64 dest) { + addl(imm, dest.low); + adcl(Imm32(0), dest.high); + } void subPtr(Imm32 imm, Register dest) { sub32(imm, dest); } @@ -622,6 +634,38 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared void mulBy3(const Register& src, const Register& dest) { lea(Operand(src, src, TimesTwo), dest); } + // Note: this function clobbers eax and edx. + void mul64(Imm64 imm, const Register64& dest) { + // LOW32 = LOW(LOW(dest) * LOW(imm)); + // HIGH32 = LOW(HIGH(dest) * LOW(imm)) [multiply imm into upper bits] + // + LOW(LOW(dest) * HIGH(imm)) [multiply dest into upper bits] + // + HIGH(LOW(dest) * LOW(imm)) [carry] + + MOZ_ASSERT(dest.low != eax && dest.low != edx); + MOZ_ASSERT(dest.high != eax && dest.high != edx); + + // HIGH(dest) = LOW(HIGH(dest) * LOW(imm)); + movl(Imm32(imm.value & 0xFFFFFFFFL), edx); + imull(edx, dest.high); + + // edx:eax = LOW(dest) * LOW(imm); + movl(Imm32(imm.value & 0xFFFFFFFFL), edx); + movl(dest.low, eax); + mull(edx); + + // HIGH(dest) += edx; + addl(edx, dest.high); + + // HIGH(dest) += LOW(LOW(dest) * HIGH(imm)); + if (((imm.value >> 32) & 0xFFFFFFFFL) == 5) + leal(Operand(dest.low, dest.low, TimesFour), edx); + else + MOZ_CRASH("Unsupported imm"); + addl(edx, dest.high); + + // LOW(dest) = eax; + movl(eax, dest.low); + } void branch32(Condition cond, AbsoluteAddress lhs, Imm32 rhs, Label* label) { cmp32(Operand(lhs), rhs); @@ -712,6 +756,18 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared j(cond, label); } + void branchTest64(Condition cond, Register64 lhs, Register64 rhs, Register temp, Label* label) { + if (cond == Assembler::Zero) { + MOZ_ASSERT(lhs.low == rhs.low); + MOZ_ASSERT(lhs.high == rhs.high); + movl(lhs.low, temp); + orl(lhs.high, temp); + branchTestPtr(cond, temp, temp, label); + } else { + MOZ_CRASH("Unsupported condition"); + } + } + void movePtr(ImmWord imm, Register dest) { movl(Imm32(imm.value), dest); } @@ -724,6 +780,10 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared void movePtr(ImmGCPtr imm, Register dest) { movl(imm, dest); } + void move64(Register64 src, Register64 dest) { + movl(src.low, dest.low); + movl(src.high, dest.high); + } void loadPtr(const Address& address, Register dest) { movl(Operand(address), dest); } @@ -742,6 +802,10 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared void load32(AbsoluteAddress address, Register dest) { movl(Operand(address), dest); } + void load64(const Address& address, Register64 dest) { + movl(Operand(address), dest.low); + movl(Operand(Address(address.base, address.offset + 4)), dest.high); + } template void storePtr(ImmWord imm, T address) { movl(Imm32(imm.value), Operand(address)); @@ -769,6 +833,10 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared void store32(Register src, AbsoluteAddress address) { movl(src, Operand(address)); } + void store64(Register64 src, Address address) { + movl(src.low, Operand(address)); + movl(src.high, Operand(Address(address.base, address.offset + 4))); + } void setStackArg(Register reg, uint32_t arg) { movl(reg, Operand(esp, arg * sizeof(intptr_t))); @@ -1060,9 +1128,17 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared void rshiftPtrArithmetic(Imm32 imm, Register dest) { sarl(imm, dest); } + void rshift64(Imm32 imm, Register64 dest) { + shrdl(imm, dest.high, dest.low); + shrl(imm, dest.high); + } void lshiftPtr(Imm32 imm, Register dest) { shll(imm, dest); } + void lshift64(Imm32 imm, Register64 dest) { + shldl(imm, dest.low, dest.high); + shll(imm, dest.low); + } void loadInstructionPointerAfterCall(Register dest) { movl(Operand(StackPointer, 0x0), dest); @@ -1087,6 +1163,13 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared convertDoubleToFloat32(dest, dest); } + void convertUInt64ToDouble(Register64 src, Register temp, FloatRegister dest); + + void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) { + movl(imm, temp); + vmulsd(Operand(temp, 0), dest, dest); + } + void inc64(AbsoluteAddress dest) { addl(Imm32(1), Operand(dest)); Label noOverflow; From fa41a95f625c8ba8859b1df770a9a3b60e0eeb80 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Fri, 7 Aug 2015 07:42:17 +0900 Subject: [PATCH 16/29] Bug 774364 - Part 4: Add setRNGState testing function. r=sstangl --HG-- extra : rebase_source : 94f14759ccc270b0cf3de5550e81a0c9faa24a0d --- js/src/builtin/TestingFunctions.cpp | 23 +++++++++++ js/src/jit-test/tests/basic/math-random.js | 44 ++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 js/src/jit-test/tests/basic/math-random.js diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 4875eddd7c07..8d4fc0f590e7 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -2792,6 +2792,23 @@ GetLcovInfo(JSContext* cx, unsigned argc, Value* vp) return true; } +#ifdef DEBUG +static bool +SetRNGState(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + if (!args.requireAtLeast(cx, "SetRNGState", 1)) + return false; + + double seed; + if (!ToNumber(cx, args[0], &seed)) + return false; + + cx->compartment()->rngState = static_cast(seed) & RNG_MASK; + return true; +} +#endif + static const JSFunctionSpecWithHelp TestingFunctions[] = { JS_FN_HELP("gc", ::GC, 0, 0, "gc([obj] | 'compartment' [, 'shrinking'])", @@ -3241,6 +3258,12 @@ gc::ZealModeHelpText), " Generate LCOV tracefile for the given compartment. If no global are provided then\n" " the current global is used as the default one.\n"), +#ifdef DEBUG + JS_FN_HELP("setRNGState", SetRNGState, 1, 0, +"setRNGState(seed)", +" Set this compartment's RNG state.\n"), +#endif + JS_FS_HELP_END }; diff --git a/js/src/jit-test/tests/basic/math-random.js b/js/src/jit-test/tests/basic/math-random.js new file mode 100644 index 000000000000..14e2b65efe05 --- /dev/null +++ b/js/src/jit-test/tests/basic/math-random.js @@ -0,0 +1,44 @@ +function test() { + // With this seed, state won't be reset in 10000 iteration. The result is + // deterministic and it can be used to check the correctness of + // implementation. + setRNGState(0x12341234); + + function f() { + let x = []; + for (let i = 0; i < 10000; i++) { + x.push(Math.random()); + } + return x; + } + let x = f(); + assertEq(x[0], 0.3562073961260165); + assertEq(x[10], 0.9777930699941514); + assertEq(x[100], 0.9146259915430884); + assertEq(x[1000], 0.315983055288946); + assertEq(x[2000], 0.7132284805929497); + assertEq(x[3000], 0.9621073641614717); + assertEq(x[4000], 0.3928228025111996); + assertEq(x[5000], 0.555710685962832); + assertEq(x[6000], 0.5207553912782503); + assertEq(x[7000], 0.08268413491723015); + assertEq(x[8000], 0.031796243723989925); + assertEq(x[9000], 0.900683320457098); + assertEq(x[9999], 0.7750389203054577); + + // With this seed, state will be reset before calculating high bits. + // The result is nondeterministic, but it should be in [0, 1) range. + setRNGState(0); + x = f(); + assertEq(x[0] >= 0 && x[0] < 1, true); + + // With this seed, high bits will be 0 and state will be reset before + // calculating low bits. The result is also nondeterministic, but it should + // be in [0, 1 / (1 << 26)) range. + setRNGState(0x615c0e462aa9); + x = f(); + assertEq(x[0] >= 0 && x[0] < 1 / (1 << 26), true); +} + +if (typeof setRNGState == "function") + test(); From bac0aaf828b87cd490efdfa0b447262dec8a3c8d Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Sat, 12 Sep 2015 11:01:17 +0900 Subject: [PATCH 17/29] Bug 1203964 - Part 1: Move MacroAssembler::rshiftPtr into generic macro assembler. r=h4writer --HG-- extra : rebase_source : 8c4f7494b43202c867f7215acac7a2e53bb24bc9 --- js/src/jit/MacroAssembler.h | 6 ++++++ js/src/jit/arm/MacroAssembler-arm-inl.h | 9 ++++++++ js/src/jit/arm/MacroAssembler-arm.h | 3 --- js/src/jit/arm64/MacroAssembler-arm64-inl.h | 21 +++++++++++++++++++ js/src/jit/arm64/MacroAssembler-arm64.h | 10 +-------- js/src/jit/mips32/MacroAssembler-mips32-inl.h | 9 ++++++++ js/src/jit/mips32/MacroAssembler-mips32.h | 3 --- js/src/jit/none/MacroAssembler-none.h | 1 - js/src/jit/x64/MacroAssembler-x64-inl.h | 9 ++++++++ js/src/jit/x64/MacroAssembler-x64.cpp | 10 +++++++++ js/src/jit/x64/MacroAssembler-x64.h | 12 +---------- js/src/jit/x86/MacroAssembler-x86-inl.h | 9 ++++++++ js/src/jit/x86/MacroAssembler-x86.h | 3 --- 13 files changed, 75 insertions(+), 30 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 2dca49ba0e1e..ef2d167119eb 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -697,6 +697,12 @@ class MacroAssembler : public MacroAssemblerSpecific inline void xorPtr(Register src, Register dest) PER_ARCH; inline void xorPtr(Imm32 imm, Register dest) PER_ARCH; + // =============================================================== + // Shift functions + + inline void rshiftPtr(Imm32 imm, Register dest) PER_ARCH; + inline void rshiftPtr(Imm32 imm, Register src, Register dest) DEFINED_ON(arm64); + //}}} check_macroassembler_style public: diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index b8584ccc5da0..773231b18198 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -128,6 +128,15 @@ MacroAssembler::xorPtr(Imm32 imm, Register dest) ma_eor(imm, dest); } +// =============================================================== +// Shift functions + +void +MacroAssembler::rshiftPtr(Imm32 imm, Register dest) +{ + ma_lsr(imm, dest, dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index c14b817401ff..aeb7cd5a715c 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1716,9 +1716,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void checkStackAlignment(); - void rshiftPtr(Imm32 imm, Register dest) { - ma_lsr(imm, dest, dest); - } void rshiftPtrArithmetic(Imm32 imm, Register dest) { ma_asr(imm, dest, dest); } diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index eb2225231689..ad48333713e9 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -141,9 +141,30 @@ MacroAssembler::xorPtr(Imm32 imm, Register dest) Eor(ARMRegister(dest, 64), ARMRegister(dest, 64), Operand(imm.value)); } +// =============================================================== +// Shift functions + +void +MacroAssembler::rshiftPtr(Imm32 imm, Register dest) +{ + Lsr(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value); +} + +void +MacroAssembler::rshiftPtr(Imm32 imm, Register src, Register dest) +{ + Lsr(ARMRegister(dest, 64), ARMRegister(src, 64), imm.value); +} + //}}} check_macroassembler_style // =============================================================== +void +MacroAssemblerCompat::rshift64(Imm32 imm, Register64 dest) +{ + asMasm().rshiftPtr(imm, dest.reg); +} + template void MacroAssemblerCompat::andToStackPtr(T t) diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 8c7e13b204f8..1c76261c0f89 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -1069,15 +1069,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler branchPtr(cond, lhs, getStackPointer(), label); } - void rshiftPtr(Imm32 imm, Register dest) { - Lsr(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value); - } - void rshiftPtr(Imm32 imm, Register src, Register dest) { - Lsr(ARMRegister(dest, 64), ARMRegister(src, 64), imm.value); - } - void rshift64(Imm32 imm, Register64 dest) { - rshiftPtr(imm, dest.reg); - } + inline void rshift64(Imm32 imm, Register64 dest); void rshiftPtrArithmetic(Imm32 imm, Register dest) { Asr(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value); diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index bb8bbb3eba12..c117d6bdfcac 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -125,6 +125,15 @@ MacroAssembler::xorPtr(Imm32 imm, Register dest) ma_xor(dest, imm); } +// =============================================================== +// Shift functions + +void +MacroAssembler::rshiftPtr(Imm32 imm, Register dest) +{ + ma_srl(dest, dest, imm); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 1216a1d7a338..f50b540cd893 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -1349,9 +1349,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void restoreStackPointer(); static void calculateAlignedStackPointer(void** stackPointer); - void rshiftPtr(Imm32 imm, Register dest) { - ma_srl(dest, dest, imm); - } void rshiftPtrArithmetic(Imm32 imm, Register dest) { ma_sra(dest, dest, imm); } diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index acb038c31d86..5b967f555c95 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -422,7 +422,6 @@ class MacroAssemblerNone : public Assembler template void storeUnboxedValue(ConstantOrRegister, MIRType, T, MIRType) { MOZ_CRASH(); } template void storeUnboxedPayload(ValueOperand value, T, size_t) { MOZ_CRASH(); } - void rshiftPtr(Imm32, Register) { MOZ_CRASH(); } void rshiftPtrArithmetic(Imm32, Register) { MOZ_CRASH(); } void lshiftPtr(Imm32, Register) { MOZ_CRASH(); } void convertUInt32ToDouble(Register, FloatRegister) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/MacroAssembler-x64-inl.h b/js/src/jit/x64/MacroAssembler-x64-inl.h index 47ae0754fec0..3ac0ca9512bb 100644 --- a/js/src/jit/x64/MacroAssembler-x64-inl.h +++ b/js/src/jit/x64/MacroAssembler-x64-inl.h @@ -66,6 +66,15 @@ MacroAssembler::xorPtr(Imm32 imm, Register dest) xorq(imm, dest); } +// =============================================================== +// Shift functions + +void +MacroAssembler::rshiftPtr(Imm32 imm, Register dest) +{ + shrq(imm, dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp index eca7ac6dc356..753fa6a857e4 100644 --- a/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -183,6 +183,16 @@ MacroAssemblerX64::finish() MacroAssemblerX86Shared::finish(); } +void +MacroAssemblerX64::branchPrivatePtr(Condition cond, Address lhs, Register ptr, Label* label) +{ + ScratchRegisterScope scratch(asMasm()); + if (ptr != scratch) + movePtr(ptr, scratch); + asMasm().rshiftPtr(Imm32(1), scratch); + branchPtr(cond, lhs, scratch, label); +} + void MacroAssemblerX64::handleFailureWithHandlerTail(void* handler) { diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index d5739fd2ae2b..ceb0a2165877 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -692,14 +692,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared branchPtr(cond, lhs, ImmWord(uintptr_t(ptr.value) >> 1), label); } - void branchPrivatePtr(Condition cond, Address lhs, Register ptr, Label* label) { - ScratchRegisterScope scratch(asMasm()); - if (ptr != scratch) - movePtr(ptr, scratch); - rshiftPtr(Imm32(1), scratch); - branchPtr(cond, lhs, scratch, label); - } - + void branchPrivatePtr(Condition cond, Address lhs, Register ptr, Label* label); template void branchPtr(Condition cond, const T& lhs, const S& ptr, Label* label) { cmpPtr(Operand(lhs), ptr); @@ -857,9 +850,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared void store64(Register64 src, Address address) { movq(src.reg, Operand(address)); } - void rshiftPtr(Imm32 imm, Register dest) { - shrq(imm, dest); - } void rshiftPtrArithmetic(Imm32 imm, Register dest) { sarq(imm, dest); } diff --git a/js/src/jit/x86/MacroAssembler-x86-inl.h b/js/src/jit/x86/MacroAssembler-x86-inl.h index c4da16960d4c..0f7053848d76 100644 --- a/js/src/jit/x86/MacroAssembler-x86-inl.h +++ b/js/src/jit/x86/MacroAssembler-x86-inl.h @@ -67,6 +67,15 @@ MacroAssembler::xorPtr(Imm32 imm, Register dest) xorl(imm, dest); } +// =============================================================== +// Shift functions + +void +MacroAssembler::rshiftPtr(Imm32 imm, Register dest) +{ + shrl(imm, dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index cd73064b6168..aed8732e6f60 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -1122,9 +1122,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared } } - void rshiftPtr(Imm32 imm, Register dest) { - shrl(imm, dest); - } void rshiftPtrArithmetic(Imm32 imm, Register dest) { sarl(imm, dest); } From 72dc86fadd5afd6ae0e428668fd4c7ef1c55438c Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Sat, 12 Sep 2015 11:11:39 +0900 Subject: [PATCH 18/29] Bug 1203964 - Part 2: Move MacroAssembler::rshiftPtrArithmetic into generic macro assembler. r=jandem --HG-- extra : rebase_source : 3cdaaee1984f5e0aece4dfe937bce1ed856204da --- js/src/jit/MacroAssembler.h | 2 ++ js/src/jit/arm/MacroAssembler-arm-inl.h | 6 ++++++ js/src/jit/arm/MacroAssembler-arm.h | 3 --- js/src/jit/arm64/MacroAssembler-arm64-inl.h | 6 ++++++ js/src/jit/arm64/MacroAssembler-arm64.h | 3 --- js/src/jit/mips32/MacroAssembler-mips32-inl.h | 6 ++++++ js/src/jit/mips32/MacroAssembler-mips32.h | 3 --- js/src/jit/none/MacroAssembler-none.h | 1 - js/src/jit/x64/MacroAssembler-x64-inl.h | 6 ++++++ js/src/jit/x64/MacroAssembler-x64.h | 3 --- js/src/jit/x86/MacroAssembler-x86-inl.h | 6 ++++++ js/src/jit/x86/MacroAssembler-x86.h | 3 --- 12 files changed, 32 insertions(+), 16 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index ef2d167119eb..ca19c617b18c 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -703,6 +703,8 @@ class MacroAssembler : public MacroAssemblerSpecific inline void rshiftPtr(Imm32 imm, Register dest) PER_ARCH; inline void rshiftPtr(Imm32 imm, Register src, Register dest) DEFINED_ON(arm64); + inline void rshiftPtrArithmetic(Imm32 imm, Register dest) PER_ARCH; + //}}} check_macroassembler_style public: diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 773231b18198..46a43bbc1bbe 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -137,6 +137,12 @@ MacroAssembler::rshiftPtr(Imm32 imm, Register dest) ma_lsr(imm, dest, dest); } +void +MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest) +{ + ma_asr(imm, dest, dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index aeb7cd5a715c..08c6e4a462cd 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1716,9 +1716,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void checkStackAlignment(); - void rshiftPtrArithmetic(Imm32 imm, Register dest) { - ma_asr(imm, dest, dest); - } void rshift64(Imm32 imm, Register64 dest) { as_mov(dest.low, lsr(dest.low, imm.value)); as_orr(dest.low, dest.low, lsl(dest.high, 32 - imm.value)); diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index ad48333713e9..d9f2b706f2b9 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -156,6 +156,12 @@ MacroAssembler::rshiftPtr(Imm32 imm, Register src, Register dest) Lsr(ARMRegister(dest, 64), ARMRegister(src, 64), imm.value); } +void +MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest) +{ + Asr(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 1c76261c0f89..1c0ec59a82b8 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -1071,9 +1071,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler inline void rshift64(Imm32 imm, Register64 dest); - void rshiftPtrArithmetic(Imm32 imm, Register dest) { - Asr(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value); - } void lshiftPtr(Imm32 imm, Register dest) { Lsl(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value); } diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index c117d6bdfcac..4c559407aff5 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -134,6 +134,12 @@ MacroAssembler::rshiftPtr(Imm32 imm, Register dest) ma_srl(dest, dest, imm); } +void +MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest) +{ + ma_sra(dest, dest, imm); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index f50b540cd893..17463f4bde07 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -1349,9 +1349,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void restoreStackPointer(); static void calculateAlignedStackPointer(void** stackPointer); - void rshiftPtrArithmetic(Imm32 imm, Register dest) { - ma_sra(dest, dest, imm); - } void rshift64(Imm32 imm, Register64 dest) { as_srl(dest.low, dest.low, imm.value); as_sll(ScratchRegister, dest.high, 32 - imm.value); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index 5b967f555c95..22203e6abf1f 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -422,7 +422,6 @@ class MacroAssemblerNone : public Assembler template void storeUnboxedValue(ConstantOrRegister, MIRType, T, MIRType) { MOZ_CRASH(); } template void storeUnboxedPayload(ValueOperand value, T, size_t) { MOZ_CRASH(); } - void rshiftPtrArithmetic(Imm32, Register) { MOZ_CRASH(); } void lshiftPtr(Imm32, Register) { MOZ_CRASH(); } void convertUInt32ToDouble(Register, FloatRegister) { MOZ_CRASH(); } void convertUInt32ToFloat32(Register, FloatRegister) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/MacroAssembler-x64-inl.h b/js/src/jit/x64/MacroAssembler-x64-inl.h index 3ac0ca9512bb..eec2455545ce 100644 --- a/js/src/jit/x64/MacroAssembler-x64-inl.h +++ b/js/src/jit/x64/MacroAssembler-x64-inl.h @@ -75,6 +75,12 @@ MacroAssembler::rshiftPtr(Imm32 imm, Register dest) shrq(imm, dest); } +void +MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest) +{ + sarq(imm, dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index ceb0a2165877..bfd43b53fb7c 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -850,9 +850,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared void store64(Register64 src, Address address) { movq(src.reg, Operand(address)); } - void rshiftPtrArithmetic(Imm32 imm, Register dest) { - sarq(imm, dest); - } void rshift64(Imm32 imm, Register64 dest) { shrq(imm, dest.reg); } diff --git a/js/src/jit/x86/MacroAssembler-x86-inl.h b/js/src/jit/x86/MacroAssembler-x86-inl.h index 0f7053848d76..012600288547 100644 --- a/js/src/jit/x86/MacroAssembler-x86-inl.h +++ b/js/src/jit/x86/MacroAssembler-x86-inl.h @@ -76,6 +76,12 @@ MacroAssembler::rshiftPtr(Imm32 imm, Register dest) shrl(imm, dest); } +void +MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest) +{ + sarl(imm, dest); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index aed8732e6f60..aaa5e77d5a1a 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -1122,9 +1122,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared } } - void rshiftPtrArithmetic(Imm32 imm, Register dest) { - sarl(imm, dest); - } void rshift64(Imm32 imm, Register64 dest) { shrdl(imm, dest.high, dest.low); shrl(imm, dest.high); From 8250d9dc2ce7eb69b086a27855d1791ce1027d56 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Sat, 12 Sep 2015 11:16:25 +0900 Subject: [PATCH 19/29] Bug 1203964 - Part 3: Move MacroAssembler::rshift64 into generic macro assembler. r=hev --HG-- extra : rebase_source : 4eba3c9ed0c8141c267cd4e2985074ef2c80a2a1 --- js/src/jit/MacroAssembler.h | 2 ++ js/src/jit/arm/MacroAssembler-arm-inl.h | 8 ++++++++ js/src/jit/arm/MacroAssembler-arm.h | 5 ----- js/src/jit/arm64/MacroAssembler-arm64-inl.h | 12 ++++++------ js/src/jit/arm64/MacroAssembler-arm64.h | 2 -- js/src/jit/mips32/MacroAssembler-mips32-inl.h | 10 ++++++++++ js/src/jit/mips32/MacroAssembler-mips32.h | 6 ------ js/src/jit/x64/MacroAssembler-x64-inl.h | 6 ++++++ js/src/jit/x64/MacroAssembler-x64.h | 3 --- js/src/jit/x86/MacroAssembler-x86-inl.h | 7 +++++++ js/src/jit/x86/MacroAssembler-x86.h | 4 ---- 11 files changed, 39 insertions(+), 26 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index ca19c617b18c..2d116c09ee85 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -705,6 +705,8 @@ class MacroAssembler : public MacroAssemblerSpecific inline void rshiftPtrArithmetic(Imm32 imm, Register dest) PER_ARCH; + inline void rshift64(Imm32 imm, Register64 dest) PER_ARCH; + //}}} check_macroassembler_style public: diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 46a43bbc1bbe..ae48272d53df 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -143,6 +143,14 @@ MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest) ma_asr(imm, dest, dest); } +void +MacroAssembler::rshift64(Imm32 imm, Register64 dest) +{ + as_mov(dest.low, lsr(dest.low, imm.value)); + as_orr(dest.low, dest.low, lsl(dest.high, 32 - imm.value)); + as_mov(dest.high, lsr(dest.high, imm.value)); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 08c6e4a462cd..532b168f81b6 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1716,11 +1716,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void checkStackAlignment(); - void rshift64(Imm32 imm, Register64 dest) { - as_mov(dest.low, lsr(dest.low, imm.value)); - as_orr(dest.low, dest.low, lsl(dest.high, 32 - imm.value)); - as_mov(dest.high, lsr(dest.high, imm.value)); - } void lshiftPtr(Imm32 imm, Register dest) { ma_lsl(imm, dest, dest); } diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index d9f2b706f2b9..44f5b7132f58 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -162,15 +162,15 @@ MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest) Asr(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value); } +void +MacroAssembler::rshift64(Imm32 imm, Register64 dest) +{ + rshiftPtr(imm, dest.reg); +} + //}}} check_macroassembler_style // =============================================================== -void -MacroAssemblerCompat::rshift64(Imm32 imm, Register64 dest) -{ - asMasm().rshiftPtr(imm, dest.reg); -} - template void MacroAssemblerCompat::andToStackPtr(T t) diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 1c0ec59a82b8..e24c92cf2561 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -1069,8 +1069,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler branchPtr(cond, lhs, getStackPointer(), label); } - inline void rshift64(Imm32 imm, Register64 dest); - void lshiftPtr(Imm32 imm, Register dest) { Lsl(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value); } diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index 4c559407aff5..093e4ac700fd 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -140,6 +140,16 @@ MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest) ma_sra(dest, dest, imm); } +void +MacroAssembler::rshift64(Imm32 imm, Register64 dest) +{ + ScratchRegisterScope scratch(*this); + as_srl(dest.low, dest.low, imm.value); + as_sll(scratch, dest.high, 32 - imm.value); + as_or(dest.low, dest.low, scratch); + as_srl(dest.high, dest.high, imm.value); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 17463f4bde07..f758f052f43b 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -1349,12 +1349,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void restoreStackPointer(); static void calculateAlignedStackPointer(void** stackPointer); - void rshift64(Imm32 imm, Register64 dest) { - as_srl(dest.low, dest.low, imm.value); - as_sll(ScratchRegister, dest.high, 32 - imm.value); - as_or(dest.low, dest.low, ScratchRegister); - as_srl(dest.high, dest.high, imm.value); - } void lshiftPtr(Imm32 imm, Register dest) { ma_sll(dest, dest, imm); } diff --git a/js/src/jit/x64/MacroAssembler-x64-inl.h b/js/src/jit/x64/MacroAssembler-x64-inl.h index eec2455545ce..c4f8e248a94d 100644 --- a/js/src/jit/x64/MacroAssembler-x64-inl.h +++ b/js/src/jit/x64/MacroAssembler-x64-inl.h @@ -81,6 +81,12 @@ MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest) sarq(imm, dest); } +void +MacroAssembler::rshift64(Imm32 imm, Register64 dest) +{ + shrq(imm, dest.reg); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index bfd43b53fb7c..48d1e3770892 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -850,9 +850,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared void store64(Register64 src, Address address) { movq(src.reg, Operand(address)); } - void rshift64(Imm32 imm, Register64 dest) { - shrq(imm, dest.reg); - } void lshiftPtr(Imm32 imm, Register dest) { shlq(imm, dest); } diff --git a/js/src/jit/x86/MacroAssembler-x86-inl.h b/js/src/jit/x86/MacroAssembler-x86-inl.h index 012600288547..22a05ce9c6be 100644 --- a/js/src/jit/x86/MacroAssembler-x86-inl.h +++ b/js/src/jit/x86/MacroAssembler-x86-inl.h @@ -82,6 +82,13 @@ MacroAssembler::rshiftPtrArithmetic(Imm32 imm, Register dest) sarl(imm, dest); } +void +MacroAssembler::rshift64(Imm32 imm, Register64 dest) +{ + shrdl(imm, dest.high, dest.low); + shrl(imm, dest.high); +} + //}}} check_macroassembler_style // =============================================================== diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index aaa5e77d5a1a..3892faac9cab 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -1122,10 +1122,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared } } - void rshift64(Imm32 imm, Register64 dest) { - shrdl(imm, dest.high, dest.low); - shrl(imm, dest.high); - } void lshiftPtr(Imm32 imm, Register dest) { shll(imm, dest); } From bb6e2b2e1a299fe1f7ddb8ed2713bc879b45962a Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Sun, 13 Sep 2015 07:33:35 +0900 Subject: [PATCH 20/29] Bug 1203964 - Part 4: Move MacroAssembler::lshiftPtr into generic macro assembler. r=nbp --HG-- extra : rebase_source : 5f74ff1b2ea0cc5f6869119b8beb19f07c5cfd59 --- js/src/jit/MacroAssembler.h | 2 ++ js/src/jit/arm/MacroAssembler-arm-inl.h | 6 ++++++ js/src/jit/arm/MacroAssembler-arm.h | 3 --- js/src/jit/arm64/MacroAssembler-arm64-inl.h | 12 ++++++++++++ js/src/jit/arm64/MacroAssembler-arm64.cpp | 7 +++++++ js/src/jit/arm64/MacroAssembler-arm64.h | 12 ++---------- js/src/jit/mips32/MacroAssembler-mips32-inl.h | 6 ++++++ js/src/jit/mips32/MacroAssembler-mips32.h | 3 --- js/src/jit/none/MacroAssembler-none.h | 1 - js/src/jit/x64/MacroAssembler-x64-inl.h | 6 ++++++ js/src/jit/x64/MacroAssembler-x64.h | 3 --- js/src/jit/x86/MacroAssembler-x86-inl.h | 6 ++++++ js/src/jit/x86/MacroAssembler-x86.h | 3 --- 13 files changed, 47 insertions(+), 23 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 2d116c09ee85..66d733ec3820 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -700,6 +700,8 @@ class MacroAssembler : public MacroAssemblerSpecific // =============================================================== // Shift functions + inline void lshiftPtr(Imm32 imm, Register dest) PER_ARCH; + inline void rshiftPtr(Imm32 imm, Register dest) PER_ARCH; inline void rshiftPtr(Imm32 imm, Register src, Register dest) DEFINED_ON(arm64); diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index ae48272d53df..063f2210f21a 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -131,6 +131,12 @@ MacroAssembler::xorPtr(Imm32 imm, Register dest) // =============================================================== // Shift functions +void +MacroAssembler::lshiftPtr(Imm32 imm, Register dest) +{ + ma_lsl(imm, dest, dest); +} + void MacroAssembler::rshiftPtr(Imm32 imm, Register dest) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 532b168f81b6..b49699a5ee03 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1716,9 +1716,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void checkStackAlignment(); - void lshiftPtr(Imm32 imm, Register dest) { - ma_lsl(imm, dest, dest); - } void lshift64(Imm32 imm, Register64 dest) { as_mov(dest.high, lsl(dest.high, imm.value)); as_orr(dest.high, dest.high, lsr(dest.low, 32 - imm.value)); diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index 44f5b7132f58..c4718155d282 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -144,6 +144,12 @@ MacroAssembler::xorPtr(Imm32 imm, Register dest) // =============================================================== // Shift functions +void +MacroAssembler::lshiftPtr(Imm32 imm, Register dest) +{ + Lsl(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value); +} + void MacroAssembler::rshiftPtr(Imm32 imm, Register dest) { @@ -171,6 +177,12 @@ MacroAssembler::rshift64(Imm32 imm, Register64 dest) //}}} check_macroassembler_style // =============================================================== +void +MacroAssemblerCompat::lshift64(Imm32 imm, Register64 dest) +{ + asMasm().lshiftPtr(imm, dest.reg); +} + template void MacroAssemblerCompat::andToStackPtr(T t) diff --git a/js/src/jit/arm64/MacroAssembler-arm64.cpp b/js/src/jit/arm64/MacroAssembler-arm64.cpp index c53d348aac81..b564dea8322a 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.cpp +++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp @@ -124,6 +124,13 @@ MacroAssemblerCompat::movePatchablePtr(ImmWord ptr, Register dest) (uint8_t*)&instructionScratch, literalAddr); } +void +MacroAssemblerCompat::loadPrivate(const Address& src, Register dest) +{ + loadPtr(src, dest); + asMasm().lshiftPtr(Imm32(1), dest); +} + void MacroAssemblerCompat::handleFailureWithHandlerTail(void* handler) { diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index e24c92cf2561..c6dc7cd457d4 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -853,10 +853,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler Ldr(dest64, MemOperand(ARMRegister(base, 64), index64, vixl::LSL, scale)); } - void loadPrivate(const Address& src, Register dest) { - loadPtr(src, dest); - lshiftPtr(Imm32(1), dest); - } + void loadPrivate(const Address& src, Register dest); void store8(Register src, const Address& address) { Strb(ARMRegister(src, 32), MemOperand(ARMRegister(address.base, 64), address.offset)); @@ -1069,12 +1066,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler branchPtr(cond, lhs, getStackPointer(), label); } - void lshiftPtr(Imm32 imm, Register dest) { - Lsl(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value); - } - void lshift64(Imm32 imm, Register64 dest) { - lshiftPtr(imm, dest.reg); - } + inline void lshift64(Imm32 imm, Register64 dest); void testPtr(Register lhs, Register rhs) { Tst(ARMRegister(lhs, 64), Operand(ARMRegister(rhs, 64))); diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index 093e4ac700fd..0419a195fb9f 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -128,6 +128,12 @@ MacroAssembler::xorPtr(Imm32 imm, Register dest) // =============================================================== // Shift functions +void +MacroAssembler::lshiftPtr(Imm32 imm, Register dest) +{ + ma_sll(dest, dest, imm); +} + void MacroAssembler::rshiftPtr(Imm32 imm, Register dest) { diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index f758f052f43b..e9815da9fa90 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -1349,9 +1349,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void restoreStackPointer(); static void calculateAlignedStackPointer(void** stackPointer); - void lshiftPtr(Imm32 imm, Register dest) { - ma_sll(dest, dest, imm); - } void lshift64(Imm32 imm, Register64 dest) { as_sll(dest.high, dest.high, imm.value); as_srl(ScratchRegister, dest.low, 32 - imm.value); diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index 22203e6abf1f..eedecbca0219 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -422,7 +422,6 @@ class MacroAssemblerNone : public Assembler template void storeUnboxedValue(ConstantOrRegister, MIRType, T, MIRType) { MOZ_CRASH(); } template void storeUnboxedPayload(ValueOperand value, T, size_t) { MOZ_CRASH(); } - void lshiftPtr(Imm32, Register) { MOZ_CRASH(); } void convertUInt32ToDouble(Register, FloatRegister) { MOZ_CRASH(); } void convertUInt32ToFloat32(Register, FloatRegister) { MOZ_CRASH(); } void inc64(AbsoluteAddress) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/MacroAssembler-x64-inl.h b/js/src/jit/x64/MacroAssembler-x64-inl.h index c4f8e248a94d..8b9cf2685096 100644 --- a/js/src/jit/x64/MacroAssembler-x64-inl.h +++ b/js/src/jit/x64/MacroAssembler-x64-inl.h @@ -69,6 +69,12 @@ MacroAssembler::xorPtr(Imm32 imm, Register dest) // =============================================================== // Shift functions +void +MacroAssembler::lshiftPtr(Imm32 imm, Register dest) +{ + shlq(imm, dest); +} + void MacroAssembler::rshiftPtr(Imm32 imm, Register dest) { diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index 48d1e3770892..3d2148e649f3 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -850,9 +850,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared void store64(Register64 src, Address address) { movq(src.reg, Operand(address)); } - void lshiftPtr(Imm32 imm, Register dest) { - shlq(imm, dest); - } void lshift64(Imm32 imm, Register64 dest) { shlq(imm, dest.reg); } diff --git a/js/src/jit/x86/MacroAssembler-x86-inl.h b/js/src/jit/x86/MacroAssembler-x86-inl.h index 22a05ce9c6be..27c59a517ab5 100644 --- a/js/src/jit/x86/MacroAssembler-x86-inl.h +++ b/js/src/jit/x86/MacroAssembler-x86-inl.h @@ -70,6 +70,12 @@ MacroAssembler::xorPtr(Imm32 imm, Register dest) // =============================================================== // Shift functions +void +MacroAssembler::lshiftPtr(Imm32 imm, Register dest) +{ + shll(imm, dest); +} + void MacroAssembler::rshiftPtr(Imm32 imm, Register dest) { diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 3892faac9cab..5f0aeb590e18 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -1122,9 +1122,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared } } - void lshiftPtr(Imm32 imm, Register dest) { - shll(imm, dest); - } void lshift64(Imm32 imm, Register64 dest) { shldl(imm, dest.low, dest.high); shll(imm, dest.low); From bf61d82b0c26ae3e20b0e24d1b3887769b1e9f55 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Sun, 13 Sep 2015 07:33:35 +0900 Subject: [PATCH 21/29] Bug 1203964 - Part 5: Move MacroAssembler::lshift64 into generic macro assembler. r=sstangl --HG-- extra : rebase_source : 50578325a8227ea4101b5535cb8a609632f79a51 --- js/src/jit/MacroAssembler.h | 2 ++ js/src/jit/arm/MacroAssembler-arm-inl.h | 8 ++++++++ js/src/jit/arm/MacroAssembler-arm.h | 6 ------ js/src/jit/arm64/MacroAssembler-arm64-inl.h | 12 ++++++------ js/src/jit/arm64/MacroAssembler-arm64.h | 2 -- js/src/jit/mips32/MacroAssembler-mips32-inl.h | 10 ++++++++++ js/src/jit/mips32/MacroAssembler-mips32.h | 7 ------- js/src/jit/x64/MacroAssembler-x64-inl.h | 6 ++++++ js/src/jit/x64/MacroAssembler-x64.h | 3 --- js/src/jit/x86/MacroAssembler-x86-inl.h | 7 +++++++ js/src/jit/x86/MacroAssembler-x86.h | 5 ----- 11 files changed, 39 insertions(+), 29 deletions(-) diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 66d733ec3820..d937813080cb 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -702,6 +702,8 @@ class MacroAssembler : public MacroAssemblerSpecific inline void lshiftPtr(Imm32 imm, Register dest) PER_ARCH; + inline void lshift64(Imm32 imm, Register64 dest) PER_ARCH; + inline void rshiftPtr(Imm32 imm, Register dest) PER_ARCH; inline void rshiftPtr(Imm32 imm, Register src, Register dest) DEFINED_ON(arm64); diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 063f2210f21a..5d233be5ff10 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -137,6 +137,14 @@ MacroAssembler::lshiftPtr(Imm32 imm, Register dest) ma_lsl(imm, dest, dest); } +void +MacroAssembler::lshift64(Imm32 imm, Register64 dest) +{ + as_mov(dest.high, lsl(dest.high, imm.value)); + as_orr(dest.high, dest.high, lsr(dest.low, 32 - imm.value)); + as_mov(dest.low, lsl(dest.low, imm.value)); +} + void MacroAssembler::rshiftPtr(Imm32 imm, Register dest) { diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index b49699a5ee03..09a9a1a399a5 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1716,12 +1716,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void checkStackAlignment(); - void lshift64(Imm32 imm, Register64 dest) { - as_mov(dest.high, lsl(dest.high, imm.value)); - as_orr(dest.high, dest.high, lsr(dest.low, 32 - imm.value)); - as_mov(dest.low, lsl(dest.low, imm.value)); - } - // If source is a double, load it into dest. If source is int32, convert it // to double. Else, branch to failure. void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure); diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index c4718155d282..a3236dad598f 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -150,6 +150,12 @@ MacroAssembler::lshiftPtr(Imm32 imm, Register dest) Lsl(ARMRegister(dest, 64), ARMRegister(dest, 64), imm.value); } +void +MacroAssembler::lshift64(Imm32 imm, Register64 dest) +{ + lshiftPtr(imm, dest.reg); +} + void MacroAssembler::rshiftPtr(Imm32 imm, Register dest) { @@ -177,12 +183,6 @@ MacroAssembler::rshift64(Imm32 imm, Register64 dest) //}}} check_macroassembler_style // =============================================================== -void -MacroAssemblerCompat::lshift64(Imm32 imm, Register64 dest) -{ - asMasm().lshiftPtr(imm, dest.reg); -} - template void MacroAssemblerCompat::andToStackPtr(T t) diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index c6dc7cd457d4..df615d57af70 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -1066,8 +1066,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler branchPtr(cond, lhs, getStackPointer(), label); } - inline void lshift64(Imm32 imm, Register64 dest); - void testPtr(Register lhs, Register rhs) { Tst(ARMRegister(lhs, 64), Operand(ARMRegister(rhs, 64))); } diff --git a/js/src/jit/mips32/MacroAssembler-mips32-inl.h b/js/src/jit/mips32/MacroAssembler-mips32-inl.h index 0419a195fb9f..e2faa4a518b8 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h +++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h @@ -134,6 +134,16 @@ MacroAssembler::lshiftPtr(Imm32 imm, Register dest) ma_sll(dest, dest, imm); } +void +MacroAssembler::lshift64(Imm32 imm, Register64 dest) +{ + ScratchRegisterScope scratch(*this); + as_sll(dest.high, dest.high, imm.value); + as_srl(scratch, dest.low, 32 - imm.value); + as_or(dest.high, dest.high, scratch); + as_sll(dest.low, dest.low, imm.value); +} + void MacroAssembler::rshiftPtr(Imm32 imm, Register dest) { diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index e9815da9fa90..05143518634d 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -1349,13 +1349,6 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void restoreStackPointer(); static void calculateAlignedStackPointer(void** stackPointer); - void lshift64(Imm32 imm, Register64 dest) { - as_sll(dest.high, dest.high, imm.value); - as_srl(ScratchRegister, dest.low, 32 - imm.value); - as_or(dest.high, dest.high, ScratchRegister); - as_sll(dest.low, dest.low, imm.value); - } - // If source is a double, load it into dest. If source is int32, // convert it to double. Else, branch to failure. void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure); diff --git a/js/src/jit/x64/MacroAssembler-x64-inl.h b/js/src/jit/x64/MacroAssembler-x64-inl.h index 8b9cf2685096..8cd44ea46433 100644 --- a/js/src/jit/x64/MacroAssembler-x64-inl.h +++ b/js/src/jit/x64/MacroAssembler-x64-inl.h @@ -75,6 +75,12 @@ MacroAssembler::lshiftPtr(Imm32 imm, Register dest) shlq(imm, dest); } +void +MacroAssembler::lshift64(Imm32 imm, Register64 dest) +{ + shlq(imm, dest.reg); +} + void MacroAssembler::rshiftPtr(Imm32 imm, Register dest) { diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index 3d2148e649f3..0077d8337719 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -850,9 +850,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared void store64(Register64 src, Address address) { movq(src.reg, Operand(address)); } - void lshift64(Imm32 imm, Register64 dest) { - shlq(imm, dest.reg); - } void splitTag(Register src, Register dest) { if (src != dest) diff --git a/js/src/jit/x86/MacroAssembler-x86-inl.h b/js/src/jit/x86/MacroAssembler-x86-inl.h index 27c59a517ab5..25b8acbe2063 100644 --- a/js/src/jit/x86/MacroAssembler-x86-inl.h +++ b/js/src/jit/x86/MacroAssembler-x86-inl.h @@ -76,6 +76,13 @@ MacroAssembler::lshiftPtr(Imm32 imm, Register dest) shll(imm, dest); } +void +MacroAssembler::lshift64(Imm32 imm, Register64 dest) +{ + shldl(imm, dest.low, dest.high); + shll(imm, dest.low); +} + void MacroAssembler::rshiftPtr(Imm32 imm, Register dest) { diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 5f0aeb590e18..99eef85c1cab 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -1122,11 +1122,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared } } - void lshift64(Imm32 imm, Register64 dest) { - shldl(imm, dest.low, dest.high); - shll(imm, dest.low); - } - void loadInstructionPointerAfterCall(Register dest) { movl(Operand(StackPointer, 0x0), dest); } From 1616f4b3d2953eaae9ffc2406c2cd340b4f679bb Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Sat, 19 Sep 2015 10:15:30 -0700 Subject: [PATCH 22/29] Bumping manifests a=b2g-bump --- b2g/config/aries/sources.xml | 2 +- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator-l/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/nexus-5-l/sources.xml | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/b2g/config/aries/sources.xml b/b2g/config/aries/sources.xml index 640d152b708f..39b34f5a3719 100644 --- a/b2g/config/aries/sources.xml +++ b/b2g/config/aries/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index b88ab2dea64f..142aa5f85f85 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index f3749aeb814a..b9a4741e5ae1 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -20,7 +20,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index fd79080a4044..427c9a37dcca 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -18,7 +18,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 3030c23473cc..8e4f091035d9 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-l/sources.xml b/b2g/config/emulator-l/sources.xml index bc7e924d040a..c51a2c5d19ac 100644 --- a/b2g/config/emulator-l/sources.xml +++ b/b2g/config/emulator-l/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index f3749aeb814a..b9a4741e5ae1 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -20,7 +20,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index c0875a80dd73..8c34e25af09d 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 08423cdfea53..945cec1e33c6 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -18,7 +18,7 @@ - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index 38fae1f3740a..cb14b8337007 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -17,7 +17,7 @@ - + From 12b806d4a5d3f5654e48440a56b5b6c8474f7ff8 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Sun, 20 Sep 2015 00:30:09 -0700 Subject: [PATCH 23/29] Bumping gaia.json for 3 gaia revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/8530acf7157f Author: Timothy Guan-tin Chien Desc: Merge pull request #31860 from timdream/modal-dialog-prompt Bug 1168600 - Enter on keyboard should confirm window.prompt() dialog, r=albertopq ======== https://hg.mozilla.org/integration/gaia-central/rev/d08ed3a262fd Author: Timothy Guan-tin Chien Desc: Bug 1168600 - Follow up, Gij test for enter on prompt dialog ======== https://hg.mozilla.org/integration/gaia-central/rev/88f4f9b24fbb Author: Timothy Guan-tin Chien Desc: Bug 1168600 - Enter on keyboard should confirm window.prompt() dialog --- b2g/config/gaia.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 5f76ac29edbc..219b65761d8d 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "e67d319d0854e32e23210784eb9c4e1b8a025adb", + "git_revision": "637e2851ef119c4e29e176802d27e28b17c764c0", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "62487ac0eb5432a716c1a8405bd9c5ebc9db2b1d", + "revision": "8530acf7157fb6380997b4b58769677e5856983f", "repo_path": "integration/gaia-central" } From f5add15413bb5fa72ece38bde925e9ac70ad8bed Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Sun, 20 Sep 2015 00:32:54 -0700 Subject: [PATCH 24/29] Bumping manifests a=b2g-bump --- b2g/config/aries/sources.xml | 2 +- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator-l/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/nexus-5-l/sources.xml | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/b2g/config/aries/sources.xml b/b2g/config/aries/sources.xml index 39b34f5a3719..ce89369ce7ce 100644 --- a/b2g/config/aries/sources.xml +++ b/b2g/config/aries/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 142aa5f85f85..1098e436438b 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index b9a4741e5ae1..5cd335343733 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 427c9a37dcca..a8ec2b5e0c7b 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 8e4f091035d9..a3a372986e69 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-l/sources.xml b/b2g/config/emulator-l/sources.xml index c51a2c5d19ac..abed5d29564d 100644 --- a/b2g/config/emulator-l/sources.xml +++ b/b2g/config/emulator-l/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index b9a4741e5ae1..5cd335343733 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 8c34e25af09d..87e1d805014a 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 945cec1e33c6..9e271a8d668a 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index cb14b8337007..4ab521836d65 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + From 89f0faabcf32ea376e3a684a88d63fcca71e4fb6 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Sun, 20 Sep 2015 20:21:47 -0700 Subject: [PATCH 25/29] Bumping gaia.json for 3 gaia revision(s) a=gaia-bump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ======== https://hg.mozilla.org/integration/gaia-central/rev/71b3fccca59c Author: Hubert Figuière Desc: Merge pull request #31686 from hfiguiere/bug1201705-playlist-tab-test Bug 1201705 - Test playlist tab. r=justindarc ======== https://hg.mozilla.org/integration/gaia-central/rev/da360dca856f Author: Hubert Figuière Desc: Bug 1201705 - Part 2: Test 'recently added', 'highest rated' and 'shuffle all' playlists. ======== https://hg.mozilla.org/integration/gaia-central/rev/d2a94a2eb278 Author: Hubert Figuière Desc: Bug 1201705 - Part 1: Make the playlist samples 10sec long to allow for action. --- b2g/config/gaia.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 219b65761d8d..e77026602bfb 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "637e2851ef119c4e29e176802d27e28b17c764c0", + "git_revision": "2d370fa35c1a0ee2a637e3772c0843586a5f96c9", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "8530acf7157fb6380997b4b58769677e5856983f", + "revision": "71b3fccca59c5a80c05e5ed99e1f5108c1b1ffad", "repo_path": "integration/gaia-central" } From 701b7147f48b7d8593a619e16e1b9967ce20a275 Mon Sep 17 00:00:00 2001 From: B2G Bumper Bot Date: Sun, 20 Sep 2015 20:24:31 -0700 Subject: [PATCH 26/29] Bumping manifests a=b2g-bump --- b2g/config/aries/sources.xml | 2 +- b2g/config/dolphin/sources.xml | 2 +- b2g/config/emulator-ics/sources.xml | 2 +- b2g/config/emulator-jb/sources.xml | 2 +- b2g/config/emulator-kk/sources.xml | 2 +- b2g/config/emulator-l/sources.xml | 2 +- b2g/config/emulator/sources.xml | 2 +- b2g/config/flame-kk/sources.xml | 2 +- b2g/config/nexus-4/sources.xml | 2 +- b2g/config/nexus-5-l/sources.xml | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/b2g/config/aries/sources.xml b/b2g/config/aries/sources.xml index ce89369ce7ce..bdf765b5234b 100644 --- a/b2g/config/aries/sources.xml +++ b/b2g/config/aries/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 1098e436438b..0c3e518d25c7 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index 5cd335343733..9ce981beb043 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index a8ec2b5e0c7b..7b2cc79bb9f9 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index a3a372986e69..ba1963342d52 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-l/sources.xml b/b2g/config/emulator-l/sources.xml index abed5d29564d..41744b17be9a 100644 --- a/b2g/config/emulator-l/sources.xml +++ b/b2g/config/emulator-l/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index 5cd335343733..9ce981beb043 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 87e1d805014a..96c7be2199ef 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 9e271a8d668a..8573b5db25bb 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index 4ab521836d65..25f34195aa56 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + From ab464dd743a1a72e5a7d22f993be0af3706ba743 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sun, 20 Sep 2015 22:10:01 -0700 Subject: [PATCH 27/29] Bug 1205930 - Tighten up warnings handling in media/omx-plugin/. r=gerald. MetaData.h uses multi-char literals. This is kind of gross but probably safe and hard to change, so this patch allows it while disallowing all other compiler warnings. (This approach is already used in dom/media/moz.build.) (An aside: I originally tried using |#pragma GCC ignoring -Wmultichar| to temporarily disable the warnings in MetaData.h. But that works in gcc but not in g++ because of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431!) --HG-- extra : rebase_source : 15ab8d3d6fe4d102b54e270ac7a6ff06af4cbe42 --- media/omx-plugin/lib/gb/libstagefright/moz.build | 7 ++++--- media/omx-plugin/lib/gb235/libstagefright/moz.build | 7 ++++--- media/omx-plugin/lib/hc/libstagefright/moz.build | 7 ++++--- media/omx-plugin/lib/ics/libstagefright/moz.build | 7 ++++--- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/media/omx-plugin/lib/gb/libstagefright/moz.build b/media/omx-plugin/lib/gb/libstagefright/moz.build index 6eafd6c2edd0..41ce90186881 100644 --- a/media/omx-plugin/lib/gb/libstagefright/moz.build +++ b/media/omx-plugin/lib/gb/libstagefright/moz.build @@ -9,6 +9,10 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk': SOURCES += [ 'libstagefright.cpp', ] + # Some codec-related code uses multi-character constants; allow this. + # XXX: could instead use the FOURCC macro to define these constants. + if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']: + SOURCES['libstagefright.cpp'].flags += ['-Wno-error=multichar'] SharedLibrary('stagefright') @@ -24,6 +28,3 @@ USE_LIBS += [ # Don't use STL wrappers; this isn't Gecko code DISABLE_STL_WRAPPING = True NO_VISIBILITY_FLAGS = True - -# XXX: We should fix these warnings. -ALLOW_COMPILER_WARNINGS = True diff --git a/media/omx-plugin/lib/gb235/libstagefright/moz.build b/media/omx-plugin/lib/gb235/libstagefright/moz.build index 6eafd6c2edd0..41ce90186881 100644 --- a/media/omx-plugin/lib/gb235/libstagefright/moz.build +++ b/media/omx-plugin/lib/gb235/libstagefright/moz.build @@ -9,6 +9,10 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk': SOURCES += [ 'libstagefright.cpp', ] + # Some codec-related code uses multi-character constants; allow this. + # XXX: could instead use the FOURCC macro to define these constants. + if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']: + SOURCES['libstagefright.cpp'].flags += ['-Wno-error=multichar'] SharedLibrary('stagefright') @@ -24,6 +28,3 @@ USE_LIBS += [ # Don't use STL wrappers; this isn't Gecko code DISABLE_STL_WRAPPING = True NO_VISIBILITY_FLAGS = True - -# XXX: We should fix these warnings. -ALLOW_COMPILER_WARNINGS = True diff --git a/media/omx-plugin/lib/hc/libstagefright/moz.build b/media/omx-plugin/lib/hc/libstagefright/moz.build index 6eafd6c2edd0..41ce90186881 100644 --- a/media/omx-plugin/lib/hc/libstagefright/moz.build +++ b/media/omx-plugin/lib/hc/libstagefright/moz.build @@ -9,6 +9,10 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk': SOURCES += [ 'libstagefright.cpp', ] + # Some codec-related code uses multi-character constants; allow this. + # XXX: could instead use the FOURCC macro to define these constants. + if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']: + SOURCES['libstagefright.cpp'].flags += ['-Wno-error=multichar'] SharedLibrary('stagefright') @@ -24,6 +28,3 @@ USE_LIBS += [ # Don't use STL wrappers; this isn't Gecko code DISABLE_STL_WRAPPING = True NO_VISIBILITY_FLAGS = True - -# XXX: We should fix these warnings. -ALLOW_COMPILER_WARNINGS = True diff --git a/media/omx-plugin/lib/ics/libstagefright/moz.build b/media/omx-plugin/lib/ics/libstagefright/moz.build index a32172bdb3f2..efc7ebc6f914 100644 --- a/media/omx-plugin/lib/ics/libstagefright/moz.build +++ b/media/omx-plugin/lib/ics/libstagefright/moz.build @@ -9,6 +9,10 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk': SOURCES += [ 'libstagefright.cpp', ] + # Some codec-related code uses multi-character constants; allow this. + # XXX: could instead use the FOURCC macro to define these constants. + if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']: + SOURCES['libstagefright.cpp'].flags += ['-Wno-error=multichar'] SharedLibrary('stagefright') @@ -24,6 +28,3 @@ USE_LIBS += [ # Don't use STL wrappers; this isn't Gecko code DISABLE_STL_WRAPPING = True NO_VISIBILITY_FLAGS = True - -# XXX: We should fix these warnings. -ALLOW_COMPILER_WARNINGS = True From 531c5e92eed5d9f67cdb259b1f06ed07de4cf586 Mon Sep 17 00:00:00 2001 From: Nigel Babu Date: Mon, 21 Sep 2015 13:57:10 +0530 Subject: [PATCH 28/29] Backed out changeset af909b481b95 (bug 772796) for causing crashes (See bug 1206483), a=Tomcat --- editor/libeditor/nsHTMLEditRules.cpp | 44 ----- editor/libeditor/tests/mochitest.ini | 1 - editor/libeditor/tests/test_bug772796.html | 218 --------------------- 3 files changed, 263 deletions(-) delete mode 100644 editor/libeditor/tests/test_bug772796.html diff --git a/editor/libeditor/nsHTMLEditRules.cpp b/editor/libeditor/nsHTMLEditRules.cpp index ef6c3129e356..55395f02be70 100644 --- a/editor/libeditor/nsHTMLEditRules.cpp +++ b/editor/libeditor/nsHTMLEditRules.cpp @@ -5614,27 +5614,6 @@ nsHTMLEditRules::GetPromotedPoint(RulesEndpoint aWhere, nsIDOMNode* aNode, if (mHTMLEditor->IsVisBreak(nextNode->AsDOMNode())) { break; } - - // Check for newlines in pre-formatted text nodes. - bool isPRE; - mHTMLEditor->IsPreformatted(nextNode->AsDOMNode(), &isPRE); - if (isPRE) { - nsCOMPtr textNode = do_QueryInterface(nextNode); - if (textNode) { - nsAutoString tempString; - textNode->GetData(tempString); - int32_t newlinePos = tempString.FindChar(nsCRT::LF); - if (newlinePos >= 0) { - if ((uint32_t)newlinePos + 1 == tempString.Length()) { - // No need for special processing if the newline is at the end. - break; - } - *outNode = nextNode->AsDOMNode(); - *outOffset = newlinePos + 1; - return; - } - } - } NS_ENSURE_TRUE(mHTMLEditor, /* void */); nextNode = mHTMLEditor->GetNextHTMLNode(node, offset, true); } @@ -5802,29 +5781,6 @@ nsHTMLEditRules::GetNodesForOperation(nsTArray>& aArrayOfRange int32_t rangeCount = aArrayOfRanges.Length(); nsresult res = NS_OK; - // Split text nodes. This is necessary, since GetPromotedPoint() may return a - // range ending in a text node in case where part of a pre-formatted - // elements needs to be moved. - for (int32_t i = 0; i < rangeCount; i++) { - nsRefPtr r = aArrayOfRanges[i]; - nsCOMPtr endParent = do_QueryInterface(r->GetEndParent()); - - if (mHTMLEditor->IsTextNode(endParent)) { - int32_t offset = r->EndOffset(); - - // Split the text node. - nsCOMPtr tempNode; - res = mHTMLEditor->SplitNode(endParent->AsDOMNode(), offset, - getter_AddRefs(tempNode)); - NS_ENSURE_SUCCESS(res, res); - - // Correct the range. - // The new end parent becomes the parent node of the text. - nsCOMPtr newParent = endParent->GetParent(); - r->SetEnd(newParent, newParent->IndexOf(endParent)); - } - } - // Bust up any inlines that cross our range endpoints, but only if we are // allowed to touch content. diff --git a/editor/libeditor/tests/mochitest.ini b/editor/libeditor/tests/mochitest.ini index 9557c8d383c7..88553dae8a47 100644 --- a/editor/libeditor/tests/mochitest.ini +++ b/editor/libeditor/tests/mochitest.ini @@ -130,7 +130,6 @@ skip-if = toolkit == 'android' || e10s [test_bug757371.html] [test_bug757771.html] [test_bug767684.html] -[test_bug772796.html] [test_bug773262.html] [test_bug780035.html] [test_bug787432.html] diff --git a/editor/libeditor/tests/test_bug772796.html b/editor/libeditor/tests/test_bug772796.html deleted file mode 100644 index 297f60d0ccf7..000000000000 --- a/editor/libeditor/tests/test_bug772796.html +++ /dev/null @@ -1,218 +0,0 @@ - - - - - - Test for Bug 772796 - - - - - - -Mozilla Bug 772796 -

- - -
- -
-
-  
-
-
- - From 4d29aa7e01a47be4bc1dbdaef3bcbe07f5d90840 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Mon, 21 Sep 2015 14:00:43 +0200 Subject: [PATCH 29/29] Backed out 1 changesets (bug 1193293) on developers requests Backed out changeset c79d3947c307 (bug 1193293) --- editor/composer/nsEditorSpellCheck.cpp | 46 +++++++++++++++++++++----- editor/libeditor/nsEditor.cpp | 9 +++++ editor/nsIEditorSpellCheck.idl | 9 ++++- 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/editor/composer/nsEditorSpellCheck.cpp b/editor/composer/nsEditorSpellCheck.cpp index d96dc83a1cfa..7efc6a140c50 100644 --- a/editor/composer/nsEditorSpellCheck.cpp +++ b/editor/composer/nsEditorSpellCheck.cpp @@ -635,6 +635,34 @@ nsEditorSpellCheck::SetCurrentDictionary(const nsAString& aDictionary) return mSpellChecker->SetCurrentDictionary(aDictionary); } +NS_IMETHODIMP +nsEditorSpellCheck::CheckCurrentDictionary() +{ + mSpellChecker->CheckCurrentDictionary(); + + // Check if our current dictionary is still available. + nsAutoString currentDictionary; + nsresult rv = GetCurrentDictionary(currentDictionary); + if (NS_SUCCEEDED(rv) && !currentDictionary.IsEmpty()) { + return NS_OK; + } + + // If our preferred current dictionary has gone, pick another one. + nsTArray dictList; + rv = mSpellChecker->GetDictionaryList(&dictList); + NS_ENSURE_SUCCESS(rv, rv); + + if (dictList.Length() > 0) { + // Use RAII object to prevent content preferences being written during + // this call. + UpdateDictionaryHolder holder(this); + rv = SetCurrentDictionary(dictList[0]); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; +} + NS_IMETHODIMP nsEditorSpellCheck::UninitSpellChecker() { @@ -807,14 +835,6 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher) #endif } - // Auxiliary status. - nsresult rv2; - - // We obtain a list of available dictionaries. - nsTArray dictList; - rv2 = mSpellChecker->GetDictionaryList(&dictList); - NS_ENSURE_SUCCESS(rv2, rv2); - // Priority 1: // If we successfully fetched a dictionary from content prefs, do not go // further. Use this exact dictionary. @@ -825,7 +845,7 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher) if (!(flags & nsIPlaintextEditor::eEditorMailMask)) { dictName.Assign(aFetcher->mDictionary); if (!dictName.IsEmpty()) { - if (NS_SUCCEEDED(TryDictionary(dictName, dictList, DICT_NORMAL_COMPARE))) { + if (NS_SUCCEEDED(SetCurrentDictionary(dictName))) { #ifdef DEBUG_DICT printf("***** Assigned from content preferences |%s|\n", NS_ConvertUTF16toUTF8(dictName).get()); @@ -851,6 +871,14 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher) NS_ConvertUTF16toUTF8(dictName).get()); #endif + // Auxiliary status. + nsresult rv2; + + // We obtain a list of available dictionaries. + nsTArray dictList; + rv2 = mSpellChecker->GetDictionaryList(&dictList); + NS_ENSURE_SUCCESS(rv2, rv2); + // Get the preference value. nsAutoString preferredDict; preferredDict = Preferences::GetLocalizedString("spellchecker.dictionary"); diff --git a/editor/libeditor/nsEditor.cpp b/editor/libeditor/nsEditor.cpp index bfd12eae413e..083b73861553 100644 --- a/editor/libeditor/nsEditor.cpp +++ b/editor/libeditor/nsEditor.cpp @@ -1328,6 +1328,15 @@ NS_IMETHODIMP nsEditor::Observe(nsISupports* aSubj, const char *aTopic, // When nsIEditorSpellCheck::GetCurrentDictionary changes if (mInlineSpellChecker) { + // if the current dictionary is no longer available, find another one + nsCOMPtr editorSpellCheck; + mInlineSpellChecker->GetSpellChecker(getter_AddRefs(editorSpellCheck)); + if (editorSpellCheck) { + // Note: This might change the current dictionary, which may call + // this observer recursively. + editorSpellCheck->CheckCurrentDictionary(); + } + // update the inline spell checker to reflect the new current dictionary mInlineSpellChecker->SpellCheckRange(nullptr); // causes recheck } diff --git a/editor/nsIEditorSpellCheck.idl b/editor/nsIEditorSpellCheck.idl index 7e113a6102d0..c211742020d3 100644 --- a/editor/nsIEditorSpellCheck.idl +++ b/editor/nsIEditorSpellCheck.idl @@ -9,10 +9,17 @@ interface nsIEditor; interface nsITextServicesFilter; interface nsIEditorSpellCheckCallback; -[scriptable, uuid(c9e630b8-79fd-4546-b068-be1b2a84c347)] +[scriptable, uuid(dd32ef3b-a7d8-43d1-9617-5f2dddbe29eb)] interface nsIEditorSpellCheck : nsISupports { + /** + * Call this on any change in installed dictionaries to ensure that the spell + * checker is not using a current dictionary which is no longer available. + * If the current dictionary is no longer available, then pick another one. + */ + void checkCurrentDictionary(); + /** * Returns true if we can enable spellchecking. If there are no available * dictionaries, this will return false.