зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound. a=merge on a CLOSED TREE
This commit is contained in:
Коммит
d696b8eb57
|
@ -2,13 +2,14 @@ var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content
|
|||
var gNewWindow = null;
|
||||
|
||||
add_task(async function() {
|
||||
registerCleanupFunction(function() {
|
||||
registerCleanupFunction(async function() {
|
||||
clearAllPluginPermissions();
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
|
||||
Services.prefs.clearUserPref("plugins.click_to_play");
|
||||
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
|
||||
gNewWindow.close();
|
||||
await BrowserTestUtils.waitForEvent(gNewWindow, "unload", true);
|
||||
gNewWindow = null;
|
||||
window.focus();
|
||||
});
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
"use strict";
|
||||
|
||||
const LIGHT_THEME_COLORS = {
|
||||
"accentcolor": "#FFF",
|
||||
"textcolor": "#000",
|
||||
"frame": "#FFF",
|
||||
"tab_background_text": "#000",
|
||||
};
|
||||
|
||||
const DARK_THEME_COLORS = {
|
||||
"accentcolor": "#000",
|
||||
"textcolor": "#FFF",
|
||||
"frame": "#000",
|
||||
"tab_background_text": "#FFF",
|
||||
};
|
||||
|
||||
const TOOLBAR_MAPPING = {
|
||||
|
@ -142,10 +142,10 @@ add_task(async function browseraction_theme_icons_dark_theme() {
|
|||
|
||||
add_task(async function browseraction_theme_icons_different_toolbars() {
|
||||
let themeData = {
|
||||
"accentcolor": "#000",
|
||||
"textcolor": "#fff",
|
||||
"frame": "#000",
|
||||
"tab_background_text": "#fff",
|
||||
"toolbar": "#fff",
|
||||
"toolbar_text": "#000",
|
||||
"bookmark_text": "#000",
|
||||
};
|
||||
await testStaticTheme({
|
||||
themeData,
|
||||
|
|
|
@ -108,9 +108,6 @@ void AudioCaptureStream::ProcessInput(GraphTime aFrom, GraphTime aTo,
|
|||
// This calls MixerCallback below
|
||||
mMixer.FinishMixing();
|
||||
}
|
||||
|
||||
// Regardless of the status of the input tracks, we go foward.
|
||||
mTracks.AdvanceKnownTracksTime(GraphTimeToStreamTimeWithBlocking((aTo)));
|
||||
}
|
||||
|
||||
void AudioCaptureStream::MixerCallback(AudioDataValue* aMixedBuffer,
|
||||
|
|
|
@ -115,8 +115,7 @@ OutputStreamDriver::OutputStreamDriver(SourceMediaStream* aSourceStream,
|
|||
MOZ_ASSERT(mSourceStream);
|
||||
mSourceStream->AddTrack(aTrackId, new VideoSegment());
|
||||
mSourceStream->AddTrackListener(mTrackListener, aTrackId);
|
||||
mSourceStream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
|
||||
mSourceStream->SetPullEnabled(true);
|
||||
mSourceStream->SetPullingEnabled(aTrackId, true);
|
||||
|
||||
// All CanvasCaptureMediaStreams shall at least get one frame.
|
||||
mFrameCaptureRequested = true;
|
||||
|
|
|
@ -4194,7 +4194,6 @@ RefPtr<SourceListener::InitPromise> SourceListener::InitializeAsync() {
|
|||
|
||||
// Start() queued the tracks to be added synchronously to avoid races
|
||||
stream->FinishAddTracks();
|
||||
stream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
|
||||
LOG(("started all sources"));
|
||||
|
||||
aHolder.Resolve(true, __func__);
|
||||
|
@ -4208,8 +4207,6 @@ RefPtr<SourceListener::InitPromise> SourceListener::InitializeAsync() {
|
|||
return InitPromise::CreateAndResolve(true, __func__);
|
||||
}
|
||||
|
||||
mStream->SetPullEnabled(true);
|
||||
|
||||
for (DeviceState* state :
|
||||
{mAudioDeviceState.get(), mVideoDeviceState.get()}) {
|
||||
if (!state) {
|
||||
|
@ -4222,6 +4219,15 @@ RefPtr<SourceListener::InitPromise> SourceListener::InitializeAsync() {
|
|||
state->mDeviceEnabled = true;
|
||||
state->mTrackEnabled = true;
|
||||
state->mTrackEnabledTime = TimeStamp::Now();
|
||||
|
||||
if (state->mDevice->GetMediaSource() !=
|
||||
MediaSourceEnum::AudioCapture) {
|
||||
// For AudioCapture mStream is a dummy stream, so we don't try to
|
||||
// enable pulling - there won't be a track to enable it for.
|
||||
mStream->SetPullingEnabled(
|
||||
state == mAudioDeviceState.get() ? kAudioTrack : kVideoTrack,
|
||||
true);
|
||||
}
|
||||
}
|
||||
return InitPromise::CreateAndResolve(true, __func__);
|
||||
},
|
||||
|
@ -4296,11 +4302,12 @@ void SourceListener::Remove() {
|
|||
// We disable pulling before removing so we don't risk having live tracks
|
||||
// without a listener attached - that wouldn't produce data and would be
|
||||
// illegal to the graph.
|
||||
mStream->SetPullEnabled(false);
|
||||
if (mAudioDeviceState) {
|
||||
mStream->SetPullingEnabled(kAudioTrack, false);
|
||||
mStream->RemoveTrackListener(mAudioDeviceState->mListener, kAudioTrack);
|
||||
}
|
||||
if (mVideoDeviceState) {
|
||||
mStream->SetPullingEnabled(kVideoTrack, false);
|
||||
mStream->RemoveTrackListener(mVideoDeviceState->mListener, kVideoTrack);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -196,7 +196,7 @@ void MediaStreamGraphImpl::UpdateCurrentTimeForStreams(
|
|||
// out.
|
||||
if (stream->mFinished && !stream->mNotifiedFinished &&
|
||||
mProcessedTime >= stream->StreamTimeToGraphTime(
|
||||
stream->GetStreamTracks().GetAllTracksEnd())) {
|
||||
stream->GetStreamTracks().GetLatestTrackEnd())) {
|
||||
stream->mNotifiedFinished = true;
|
||||
SetStreamOrderDirty();
|
||||
}
|
||||
|
@ -1200,7 +1200,7 @@ void MediaStreamGraphImpl::UpdateGraph(GraphTime aEndBlockingDecisions) {
|
|||
// The stream's not suspended, and since it's finished, underruns won't
|
||||
// stop it playing out. So there's no blocking other than what we impose
|
||||
// here.
|
||||
GraphTime endTime = stream->GetStreamTracks().GetAllTracksEnd() +
|
||||
GraphTime endTime = stream->GetStreamTracks().GetLatestTrackEnd() +
|
||||
stream->mTracksStartTime;
|
||||
if (endTime <= mStateComputedTime) {
|
||||
LOG(LogLevel::Verbose,
|
||||
|
@ -1221,12 +1221,21 @@ void MediaStreamGraphImpl::UpdateGraph(GraphTime aEndBlockingDecisions) {
|
|||
} else {
|
||||
stream->mStartBlocking = WillUnderrun(stream, aEndBlockingDecisions);
|
||||
|
||||
SourceMediaStream* s = stream->AsSourceStream();
|
||||
if (s && s->mPullEnabled) {
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
if (SourceMediaStream* s = stream->AsSourceStream()) {
|
||||
for (StreamTracks::TrackIter i(s->mTracks); !i.IsEnded(); i.Next()) {
|
||||
if (i->IsEnded()) {
|
||||
continue;
|
||||
}
|
||||
SourceMediaStream::TrackData* data;
|
||||
{
|
||||
MutexAutoLock lock(s->mMutex);
|
||||
data = s->FindDataForTrack(i->GetID());
|
||||
}
|
||||
MOZ_ASSERT(data);
|
||||
if (!data->mPullingEnabled) {
|
||||
continue;
|
||||
}
|
||||
if (i->GetEnd() <
|
||||
stream->GraphTimeToStreamTime(aEndBlockingDecisions)) {
|
||||
LOG(LogLevel::Error,
|
||||
|
@ -1246,6 +1255,7 @@ void MediaStreamGraphImpl::UpdateGraph(GraphTime aEndBlockingDecisions) {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif /* MOZ_DIAGNOSTIC_ASSERT_ENABLED */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1307,7 +1317,7 @@ void MediaStreamGraphImpl::Process() {
|
|||
ps->ProcessInput(mProcessedTime, mStateComputedTime,
|
||||
ProcessedMediaStream::ALLOW_FINISH);
|
||||
NS_ASSERTION(
|
||||
stream->mTracks.GetEnd() >=
|
||||
stream->mTracks.GetEarliestTrackEnd() >=
|
||||
GraphTimeToStreamTimeWithBlocking(stream, mStateComputedTime),
|
||||
"Stream did not produce enough data");
|
||||
}
|
||||
|
@ -1964,7 +1974,6 @@ void MediaStream::FinishOnGraphThread() {
|
|||
}
|
||||
#endif
|
||||
mFinished = true;
|
||||
mTracks.AdvanceKnownTracksTime(STREAM_TIME_MAX);
|
||||
|
||||
// Let the MSG knows that this stream can be destroyed if necessary to avoid
|
||||
// unnecessarily processing it in the future.
|
||||
|
@ -2460,8 +2469,6 @@ void MediaStream::AddMainThreadListener(
|
|||
SourceMediaStream::SourceMediaStream()
|
||||
: MediaStream(),
|
||||
mMutex("mozilla::media::SourceMediaStream"),
|
||||
mUpdateKnownTracksTime(0),
|
||||
mPullEnabled(false),
|
||||
mFinishPending(false) {}
|
||||
|
||||
nsresult SourceMediaStream::OpenAudioInput(CubebUtils::AudioDeviceID aID,
|
||||
|
@ -2498,39 +2505,53 @@ void SourceMediaStream::DestroyImpl() {
|
|||
MediaStream::DestroyImpl();
|
||||
}
|
||||
|
||||
void SourceMediaStream::SetPullEnabled(bool aEnabled) {
|
||||
void SourceMediaStream::SetPullingEnabled(TrackID aTrackID, bool aEnabled) {
|
||||
class Message : public ControlMessage {
|
||||
public:
|
||||
Message(SourceMediaStream* aStream, bool aEnabled)
|
||||
: ControlMessage(nullptr), mStream(aStream), mEnabled(aEnabled) {}
|
||||
Message(SourceMediaStream* aStream, TrackID aTrackID, bool aEnabled)
|
||||
: ControlMessage(nullptr),
|
||||
mStream(aStream),
|
||||
mTrackID(aTrackID),
|
||||
mEnabled(aEnabled) {}
|
||||
void Run() override {
|
||||
MutexAutoLock lock(mStream->mMutex);
|
||||
mStream->mPullEnabled = mEnabled;
|
||||
TrackData* data = mStream->FindDataForTrack(mTrackID);
|
||||
if (!data) {
|
||||
// We can't enable pulling for a track that was never added. We ignore
|
||||
// this if we're disabling pulling, since shutdown sequences are
|
||||
// complex. If there's truly an issue we'll have issues enabling anyway.
|
||||
MOZ_ASSERT_IF(mEnabled,
|
||||
mStream->mTracks.FindTrack(mTrackID) &&
|
||||
mStream->mTracks.FindTrack(mTrackID)->IsEnded());
|
||||
return;
|
||||
}
|
||||
data->mPullingEnabled = mEnabled;
|
||||
}
|
||||
SourceMediaStream* mStream;
|
||||
TrackID mTrackID;
|
||||
bool mEnabled;
|
||||
};
|
||||
GraphImpl()->AppendMessage(MakeUnique<Message>(this, aEnabled));
|
||||
GraphImpl()->AppendMessage(MakeUnique<Message>(this, aTrackID, aEnabled));
|
||||
}
|
||||
|
||||
bool SourceMediaStream::PullNewData(GraphTime aDesiredUpToTime) {
|
||||
TRACE_AUDIO_CALLBACK_COMMENT("SourceMediaStream %p", this);
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (!mPullEnabled || mFinished) {
|
||||
if (mFinished) {
|
||||
return false;
|
||||
}
|
||||
// Compute how much stream time we'll need assuming we don't block
|
||||
// the stream at all.
|
||||
StreamTime t = GraphTimeToStreamTime(aDesiredUpToTime);
|
||||
StreamTime current = mTracks.GetEnd();
|
||||
StreamTime current = mTracks.GetEarliestTrackEnd();
|
||||
LOG(LogLevel::Verbose,
|
||||
("%p: Calling NotifyPull aStream=%p t=%f current end=%f", GraphImpl(),
|
||||
this, GraphImpl()->MediaTimeToSeconds(t),
|
||||
GraphImpl()->MediaTimeToSeconds(current)));
|
||||
if (t <= current) {
|
||||
return false;
|
||||
}
|
||||
for (const TrackData& track : mUpdateTracks) {
|
||||
if (!track.mPullingEnabled) {
|
||||
continue;
|
||||
}
|
||||
if (track.mCommands & TrackEventCommand::TRACK_EVENT_ENDED) {
|
||||
continue;
|
||||
}
|
||||
|
@ -2602,11 +2623,8 @@ void SourceMediaStream::ExtractPendingInput(GraphTime aCurrentTime) {
|
|||
mUpdateTracks.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
if (!mFinished) {
|
||||
mTracks.AdvanceKnownTracksTime(mUpdateKnownTracksTime);
|
||||
}
|
||||
|
||||
if (mTracks.GetEnd() > 0) {
|
||||
if (mTracks.GetEarliestTrackEnd() > 0) {
|
||||
mHasCurrentData = true;
|
||||
}
|
||||
|
||||
|
@ -2631,6 +2649,7 @@ void SourceMediaStream::AddTrackInternal(TrackID aID, TrackRate aRate,
|
|||
data->mEndOfFlushedData = 0;
|
||||
data->mCommands = TRACK_CREATE;
|
||||
data->mData = aSegment;
|
||||
data->mPullingEnabled = false;
|
||||
ResampleAudioToGraphSampleRate(data, aSegment);
|
||||
if (!(aFlags & ADDTRACK_QUEUED) && GraphImpl()) {
|
||||
GraphImpl()->EnsureNextIteration();
|
||||
|
@ -2846,15 +2865,6 @@ void SourceMediaStream::EndTrack(TrackID aID) {
|
|||
}
|
||||
}
|
||||
|
||||
void SourceMediaStream::AdvanceKnownTracksTime(StreamTime aKnownTime) {
|
||||
MutexAutoLock lock(mMutex);
|
||||
MOZ_ASSERT(aKnownTime >= mUpdateKnownTracksTime);
|
||||
mUpdateKnownTracksTime = aKnownTime;
|
||||
if (auto graph = GraphImpl()) {
|
||||
graph->EnsureNextIteration();
|
||||
}
|
||||
}
|
||||
|
||||
void SourceMediaStream::FinishPendingWithLockHeld() {
|
||||
mMutex.AssertCurrentThreadOwns();
|
||||
mFinishPending = true;
|
||||
|
|
|
@ -420,7 +420,7 @@ class MediaStream : public mozilla::LinkedListElement<MediaStream> {
|
|||
* This must be idempotent.
|
||||
*/
|
||||
virtual void DestroyImpl();
|
||||
StreamTime GetTracksEnd() const { return mTracks.GetEnd(); }
|
||||
StreamTime GetTracksEnd() const { return mTracks.GetEarliestTrackEnd(); }
|
||||
#ifdef DEBUG
|
||||
void DumpTrackInfo() const { return mTracks.DumpTrackInfo(); }
|
||||
#endif
|
||||
|
@ -658,13 +658,14 @@ class SourceMediaStream : public MediaStream {
|
|||
// Main thread only
|
||||
|
||||
/**
|
||||
* Enable or disable pulling. When pulling is enabled, NotifyPull
|
||||
* gets called on MediaStream/TrackListeners for this stream during the
|
||||
* MediaStreamGraph control loop. Pulling is initially disabled.
|
||||
* Due to unavoidable race conditions, after a call to SetPullEnabled(false)
|
||||
* Enable or disable pulling for a specific track.
|
||||
* When pulling is enabled, NotifyPull gets called on the corresponding
|
||||
* MediaStreamTrackListeners for this stream during the MediaStreamGraph
|
||||
* control loop. Pulling is initially disabled for all tracks. Due to
|
||||
* unavoidable race conditions, after a call to SetPullingEnabled(false)
|
||||
* it is still possible for a NotifyPull to occur.
|
||||
*/
|
||||
void SetPullEnabled(bool aEnabled);
|
||||
void SetPullingEnabled(TrackID aTrackID, bool aEnabled);
|
||||
|
||||
// Users of audio inputs go through the stream so it can track when the
|
||||
// last stream referencing an input goes away, so it can close the cubeb
|
||||
|
@ -698,9 +699,8 @@ class SourceMediaStream : public MediaStream {
|
|||
ADDTRACK_QUEUED = 0x01 // Queue track add until FinishAddTracks()
|
||||
};
|
||||
/**
|
||||
* Add a new track to the stream starting at the stream's current time
|
||||
* (which must be greater than or equal to the last time passed to
|
||||
* AdvanceKnownTracksTime). Takes ownership of aSegment.
|
||||
* Add a new track to the stream starting at the stream's current time.
|
||||
* Takes ownership of aSegment.
|
||||
*/
|
||||
void AddTrack(TrackID aID, MediaSegment* aSegment, uint32_t aFlags = 0) {
|
||||
AddTrackInternal(aID, GraphRate(), aSegment, aFlags);
|
||||
|
@ -739,12 +739,6 @@ class SourceMediaStream : public MediaStream {
|
|||
* Ignored if the track does not exist.
|
||||
*/
|
||||
void EndTrack(TrackID aID);
|
||||
/**
|
||||
* Indicate that no tracks will be added starting before time aKnownTime.
|
||||
* aKnownTime must be >= its value at the last call to AdvanceKnownTracksTime.
|
||||
*/
|
||||
void AdvanceKnownTracksTime(StreamTime aKnownTime);
|
||||
void AdvanceKnownTracksTimeWithLockHeld(StreamTime aKnownTime);
|
||||
/**
|
||||
* Indicate that this stream should enter the "finished" state. All tracks
|
||||
* must have been ended via EndTrack. The finish time of the stream is
|
||||
|
@ -816,6 +810,8 @@ class SourceMediaStream : public MediaStream {
|
|||
// Each time the track updates are flushed to the media graph thread,
|
||||
// this is cleared.
|
||||
uint32_t mCommands;
|
||||
// True if the producer of this track is having data pulled by the graph.
|
||||
bool mPullingEnabled;
|
||||
};
|
||||
|
||||
bool NeedsMixing();
|
||||
|
@ -867,7 +863,6 @@ class SourceMediaStream : public MediaStream {
|
|||
// held together.
|
||||
Mutex mMutex;
|
||||
// protected by mMutex
|
||||
StreamTime mUpdateKnownTracksTime;
|
||||
// This time stamp will be updated in adding and blocked SourceMediaStream,
|
||||
// |AddStreamGraphThread| and |AdvanceTimeVaryingValuesToCurrentTime| in
|
||||
// particularly.
|
||||
|
@ -875,7 +870,6 @@ class SourceMediaStream : public MediaStream {
|
|||
nsTArray<TrackData> mUpdateTracks;
|
||||
nsTArray<TrackData> mPendingTracks;
|
||||
nsTArray<TrackBound<DirectMediaStreamTrackListener>> mDirectTrackListeners;
|
||||
bool mPullEnabled;
|
||||
bool mFinishPending;
|
||||
};
|
||||
|
||||
|
|
|
@ -15,8 +15,7 @@ extern LazyLogModule gMediaStreamGraphLog;
|
|||
#define STREAM_LOG(type, msg) MOZ_LOG(gMediaStreamGraphLog, type, msg)
|
||||
|
||||
void StreamTracks::DumpTrackInfo() const {
|
||||
STREAM_LOG(LogLevel::Info,
|
||||
("DumpTracks: mTracksKnownTime %" PRId64, mTracksKnownTime));
|
||||
STREAM_LOG(LogLevel::Info, ("Dumping StreamTracks"));
|
||||
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
|
||||
Track* track = mTracks[i];
|
||||
if (track->IsEnded()) {
|
||||
|
@ -29,8 +28,8 @@ void StreamTracks::DumpTrackInfo() const {
|
|||
}
|
||||
#endif
|
||||
|
||||
StreamTime StreamTracks::GetEnd() const {
|
||||
StreamTime t = mTracksKnownTime;
|
||||
StreamTime StreamTracks::GetEarliestTrackEnd() const {
|
||||
StreamTime t = STREAM_TIME_MAX;
|
||||
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
|
||||
Track* track = mTracks[i];
|
||||
if (!track->IsEnded()) {
|
||||
|
@ -40,11 +39,7 @@ StreamTime StreamTracks::GetEnd() const {
|
|||
return t;
|
||||
}
|
||||
|
||||
StreamTime StreamTracks::GetAllTracksEnd() const {
|
||||
if (mTracksKnownTime < STREAM_TIME_MAX) {
|
||||
// A track might be added.
|
||||
return STREAM_TIME_MAX;
|
||||
}
|
||||
StreamTime StreamTracks::GetLatestTrackEnd() const {
|
||||
StreamTime t = 0;
|
||||
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
|
||||
Track* track = mTracks[i];
|
||||
|
|
|
@ -144,7 +144,6 @@ class StreamTracks {
|
|||
|
||||
StreamTracks()
|
||||
: mGraphRate(0),
|
||||
mTracksKnownTime(0),
|
||||
mForgottenTime(0),
|
||||
mTracksDirty(false)
|
||||
#ifdef DEBUG
|
||||
|
@ -194,35 +193,21 @@ class StreamTracks {
|
|||
mTracks.InsertElementSorted(track, CompareTracksByID());
|
||||
mTracksDirty = true;
|
||||
|
||||
if (mTracksKnownTime == STREAM_TIME_MAX) {
|
||||
// There exists code like
|
||||
// http://mxr.mozilla.org/mozilla-central/source/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp?rev=96b197deb91e&mark=1292-1297#1292
|
||||
NS_WARNING(
|
||||
"Adding track to StreamTracks that should have no more tracks");
|
||||
} else {
|
||||
// NS_ASSERTION(mTracksKnownTime <= aStart, "Start time too early");
|
||||
}
|
||||
return *track;
|
||||
}
|
||||
|
||||
void AdvanceKnownTracksTime(StreamTime aKnownTime) {
|
||||
NS_ASSERTION(aKnownTime >= mTracksKnownTime,
|
||||
"Can't move tracks-known time earlier");
|
||||
mTracksKnownTime = aKnownTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* The end time for the StreamTracks is the latest time for which we have
|
||||
* data for all tracks that haven't ended by that time.
|
||||
*/
|
||||
StreamTime GetEnd() const;
|
||||
StreamTime GetEarliestTrackEnd() const;
|
||||
|
||||
/**
|
||||
* Returns the earliest time >= 0 at which all tracks have ended
|
||||
* and all their data has been played out and no new tracks can be added,
|
||||
* or STREAM_TIME_MAX if there is no such time.
|
||||
* Returns the earliest time >= 0 at which all tracks have ended and all
|
||||
* their data has been played out, or STREAM_TIME_MAX if there is no such
|
||||
* time.
|
||||
*/
|
||||
StreamTime GetAllTracksEnd() const;
|
||||
StreamTime GetLatestTrackEnd() const;
|
||||
|
||||
#ifdef DEBUG
|
||||
void DumpTrackInfo() const;
|
||||
|
@ -299,9 +284,6 @@ class StreamTracks {
|
|||
|
||||
protected:
|
||||
TrackRate mGraphRate; // StreamTime per second
|
||||
// Any new tracks added will start at or after this time. In other words, the
|
||||
// track list is complete and correct for all times less than this time.
|
||||
StreamTime mTracksKnownTime;
|
||||
StreamTime mForgottenTime;
|
||||
|
||||
private:
|
||||
|
|
|
@ -143,8 +143,6 @@ void TrackUnionStream::ProcessInput(GraphTime aFrom, GraphTime aTo,
|
|||
// all our tracks have actually finished and been removed from our map,
|
||||
// so we're finished now.
|
||||
FinishOnGraphThread();
|
||||
} else {
|
||||
mTracks.AdvanceKnownTracksTime(GraphTimeToStreamTimeWithBlocking(aTo));
|
||||
}
|
||||
if (allHaveCurrentData) {
|
||||
// We can make progress if we're not blocked
|
||||
|
|
|
@ -95,8 +95,7 @@ class DecodedStreamGraphListener {
|
|||
return;
|
||||
}
|
||||
if (aStream) {
|
||||
int64_t t = aStream->StreamTimeToMicroseconds(aCurrentTrackTime);
|
||||
mOnOutput.Notify(t);
|
||||
mOnOutput.Notify(aStream->StreamTimeToMicroseconds(aCurrentTrackTime));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,9 +231,8 @@ DecodedStreamData::DecodedStreamData(
|
|||
mNextAudioTime(aInit.mStartTime),
|
||||
mHaveSentFinishAudio(false),
|
||||
mHaveSentFinishVideo(false),
|
||||
mStream(aOutputStreamManager->mSourceStream)
|
||||
mStream(aOutputStreamManager->mSourceStream),
|
||||
// DecodedStreamGraphListener will resolve these promises.
|
||||
,
|
||||
mListener(MakeRefPtr<DecodedStreamGraphListener>(
|
||||
mStream, aInit.mAudioTrackID, std::move(aAudioPromise),
|
||||
aInit.mVideoTrackID, std::move(aVideoPromise), aMainThread)),
|
||||
|
@ -724,12 +722,6 @@ StreamTime DecodedStream::SentDuration() {
|
|||
return std::max(mData->mStreamAudioWritten, mData->mStreamVideoWritten);
|
||||
}
|
||||
|
||||
void DecodedStream::AdvanceTracks() {
|
||||
AssertOwnerThread();
|
||||
|
||||
mData->mStream->AdvanceKnownTracksTime(mStreamTimeOffset + SentDuration());
|
||||
}
|
||||
|
||||
void DecodedStream::SendData() {
|
||||
AssertOwnerThread();
|
||||
MOZ_ASSERT(mStartTime.isSome(), "Must be called after StartPlayback()");
|
||||
|
@ -741,7 +733,6 @@ void DecodedStream::SendData() {
|
|||
|
||||
SendAudio(mParams.mVolume, mSameOrigin, mPrincipalHandle);
|
||||
SendVideo(mSameOrigin, mPrincipalHandle);
|
||||
AdvanceTracks();
|
||||
}
|
||||
|
||||
TimeUnit DecodedStream::GetEndTime(TrackType aType) const {
|
||||
|
|
|
@ -81,10 +81,8 @@ class DecodedStream : public media::MediaSink {
|
|||
const PrincipalHandle& aPrincipalHandle);
|
||||
void SendVideo(bool aIsSameOrigin, const PrincipalHandle& aPrincipalHandle);
|
||||
StreamTime SentDuration();
|
||||
void AdvanceTracks();
|
||||
void SendData();
|
||||
void NotifyOutput(int64_t aTime);
|
||||
void NotifyTrackEnd(StreamTime aEndTime);
|
||||
|
||||
void AssertOwnerThread() const {
|
||||
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
||||
|
|
|
@ -562,9 +562,6 @@ void AudioNodeStream::ProduceOutputBeforeInput(GraphTime aFrom) {
|
|||
|
||||
void AudioNodeStream::AdvanceOutputSegment() {
|
||||
StreamTracks::Track* track = EnsureTrack(AUDIO_TRACK);
|
||||
// No more tracks will be coming
|
||||
mTracks.AdvanceKnownTracksTime(STREAM_TIME_MAX);
|
||||
|
||||
AudioSegment* segment = track->Get<AudioSegment>();
|
||||
|
||||
AudioChunk copyChunk = *mLastChunks[0].AsMutableChunk();
|
||||
|
|
|
@ -58,6 +58,7 @@ ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
|
|||
, mCompositorMightResample(false)
|
||||
, mNeedsComposite(false)
|
||||
, mQueuedAsyncPaints(false)
|
||||
, mNotifyingWidgetListener(false)
|
||||
, mPaintSequenceNumber(0)
|
||||
, mForwarder(new ShadowLayerForwarder(this))
|
||||
{
|
||||
|
@ -85,6 +86,9 @@ ClientLayerManager::~ClientLayerManager()
|
|||
void
|
||||
ClientLayerManager::Destroy()
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mNotifyingWidgetListener,
|
||||
"Try to avoid destroying widgets and layer managers during DidCompositeWindow, if you can");
|
||||
|
||||
// It's important to call ClearCachedResource before Destroy because the
|
||||
// former will early-return if the later has already run.
|
||||
ClearCachedResources();
|
||||
|
@ -495,11 +499,18 @@ ClientLayerManager::DidComposite(TransactionId aTransactionId,
|
|||
if (aTransactionId.IsValid()) {
|
||||
nsIWidgetListener *listener = mWidget->GetWidgetListener();
|
||||
if (listener) {
|
||||
mNotifyingWidgetListener = true;
|
||||
listener->DidCompositeWindow(aTransactionId, aCompositeStart, aCompositeEnd);
|
||||
mNotifyingWidgetListener = false;
|
||||
}
|
||||
listener = mWidget->GetAttachedWidgetListener();
|
||||
if (listener) {
|
||||
listener->DidCompositeWindow(aTransactionId, aCompositeStart, aCompositeEnd);
|
||||
// DidCompositeWindow might have called Destroy on us and nulled out mWidget,
|
||||
// see bug 1510058.
|
||||
// Re-check it here.
|
||||
if (mWidget) {
|
||||
listener = mWidget->GetAttachedWidgetListener();
|
||||
if (listener) {
|
||||
listener->DidCompositeWindow(aTransactionId, aCompositeStart, aCompositeEnd);
|
||||
}
|
||||
}
|
||||
if (mTransactionIdAllocator) {
|
||||
mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId);
|
||||
|
|
|
@ -327,6 +327,7 @@ private:
|
|||
bool mCompositorMightResample;
|
||||
bool mNeedsComposite;
|
||||
bool mQueuedAsyncPaints;
|
||||
bool mNotifyingWidgetListener;
|
||||
|
||||
// An incrementing sequence number for paints.
|
||||
// Incremented in BeginTransaction(), but not for repeat transactions.
|
||||
|
|
|
@ -699,7 +699,7 @@ SurfaceTextureHost::PushResourceUpdates(wr::TransactionBuilder& aResources,
|
|||
{
|
||||
auto method = aOp == TextureHost::ADD_IMAGE ? &wr::TransactionBuilder::AddExternalImage
|
||||
: &wr::TransactionBuilder::UpdateExternalImage;
|
||||
auto bufferType = wr::WrExternalImageBufferType::TextureRectHandle;
|
||||
auto bufferType = wr::WrExternalImageBufferType::TextureExternalHandle;
|
||||
|
||||
switch (GetFormat()) {
|
||||
case gfx::SurfaceFormat::R8G8B8X8:
|
||||
|
|
|
@ -984,8 +984,11 @@ GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts)
|
|||
}
|
||||
break;
|
||||
case GeckoProcessType_RDD:
|
||||
if (mSandboxLevel > 0 && !PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX")) {
|
||||
// TODO: Implement sandbox for RDD process, Bug 1498624.
|
||||
if (!PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX")) {
|
||||
if (!mSandboxBroker.SetSecurityLevelForRDDProcess()) {
|
||||
return false;
|
||||
}
|
||||
shouldSandboxCurrentProcess = true;
|
||||
}
|
||||
break;
|
||||
case GeckoProcessType_Default:
|
||||
|
|
|
@ -370,6 +370,11 @@ set_define('JS_JITSPEW',
|
|||
set_config('JS_JITSPEW',
|
||||
depends_if('--enable-jitspew')(lambda _: True))
|
||||
|
||||
# Also enable the structured spewer
|
||||
set_define('JS_STRUCTURED_SPEW',
|
||||
depends_if('--enable-jitspew')(lambda _: True))
|
||||
set_config('JS_STRUCTURED_SPEW',
|
||||
depends_if('--enable-jitspew')(lambda _: True))
|
||||
# When enabled, masm will generate assumeUnreachable calls that act as
|
||||
# assertions in the generated code. This option is worth disabling when you
|
||||
# have to track mutated values through the generated code, to avoid constantly
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "gc/FreeOp.h"
|
||||
#include "gc/Policy.h"
|
||||
#include "gc/PublicIterators.h"
|
||||
#include "jit/BaselineIC.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/Ion.h"
|
||||
#include "jit/JitRealm.h"
|
||||
|
@ -18,6 +19,7 @@
|
|||
|
||||
#include "gc/GC-inl.h"
|
||||
#include "gc/Marking-inl.h"
|
||||
#include "vm/JSScript-inl.h"
|
||||
#include "vm/Realm-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
@ -260,11 +262,20 @@ Zone::discardJitCode(FreeOp* fop, bool discardBaselineCode, bool releaseTypes)
|
|||
script->baselineScript()->setControlFlowGraph(nullptr);
|
||||
}
|
||||
|
||||
// Try to release the script's TypeScript. This should happen last
|
||||
// because we can't do this when the script still has JIT code.
|
||||
// Try to release the script's TypeScript. This should happen after
|
||||
// releasing JIT code because we can't do this when the script still has
|
||||
// JIT code.
|
||||
if (releaseTypes) {
|
||||
script->maybeReleaseTypes();
|
||||
}
|
||||
|
||||
// The optimizedStubSpace will be purged below so make sure ICScript
|
||||
// doesn't point into it. We do this after (potentially) releasing types
|
||||
// because TypeScript contains the ICScript* and there's no need to
|
||||
// purge stubs if we just destroyed the Typescript.
|
||||
if (discardBaselineCode && script->hasICScript()) {
|
||||
script->icScript()->purgeOptimizedStubs(script->zone());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1063,6 +1063,7 @@ InitFromBailout(JSContext* cx, size_t frameNo,
|
|||
|
||||
const uint32_t pcOff = script->pcToOffset(pc);
|
||||
BaselineScript* baselineScript = script->baselineScript();
|
||||
ICScript* icScript = script->icScript();
|
||||
|
||||
#ifdef DEBUG
|
||||
uint32_t expectedDepth;
|
||||
|
@ -1120,7 +1121,7 @@ InitFromBailout(JSContext* cx, size_t frameNo,
|
|||
// Not every monitored op has a monitored fallback stub, e.g.
|
||||
// JSOP_NEWOBJECT, which always returns the same type for a
|
||||
// particular script/pc location.
|
||||
ICEntry& icEntry = baselineScript->icEntryFromPCOffset(pcOff);
|
||||
ICEntry& icEntry = icScript->icEntryFromPCOffset(pcOff);
|
||||
ICFallbackStub* fallbackStub = icEntry.firstStub()->getChainFallback();
|
||||
if (fallbackStub->isMonitoredFallback()) {
|
||||
enterMonitorChain = true;
|
||||
|
@ -1137,7 +1138,7 @@ InitFromBailout(JSContext* cx, size_t frameNo,
|
|||
builder.setResumeFramePtr(prevFramePtr);
|
||||
|
||||
if (enterMonitorChain) {
|
||||
ICEntry& icEntry = baselineScript->icEntryFromPCOffset(pcOff);
|
||||
ICEntry& icEntry = icScript->icEntryFromPCOffset(pcOff);
|
||||
ICFallbackStub* fallbackStub = icEntry.firstStub()->getChainFallback();
|
||||
MOZ_ASSERT(fallbackStub->isMonitoredFallback());
|
||||
JitSpew(JitSpew_BaselineBailouts, " [TYPE-MONITOR CHAIN]");
|
||||
|
@ -1317,7 +1318,7 @@ InitFromBailout(JSContext* cx, size_t frameNo,
|
|||
|
||||
// Calculate and write out return address.
|
||||
// The icEntry in question MUST have an inlinable fallback stub.
|
||||
ICEntry& icEntry = baselineScript->icEntryFromPCOffset(pcOff);
|
||||
ICEntry& icEntry = icScript->icEntryFromPCOffset(pcOff);
|
||||
MOZ_ASSERT(IsInlinableFallback(icEntry.firstStub()->getChainFallback()));
|
||||
|
||||
RetAddrEntry& retAddrEntry =
|
||||
|
|
|
@ -2414,65 +2414,6 @@ ICCacheIR_Updated::stubDataStart()
|
|||
return reinterpret_cast<uint8_t*>(this) + stubInfo_->stubDataOffset();
|
||||
}
|
||||
|
||||
/* static */ ICCacheIR_Regular*
|
||||
ICCacheIR_Regular::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
|
||||
ICCacheIR_Regular& other)
|
||||
{
|
||||
const CacheIRStubInfo* stubInfo = other.stubInfo();
|
||||
MOZ_ASSERT(stubInfo->makesGCCalls());
|
||||
|
||||
size_t bytesNeeded = stubInfo->stubDataOffset() + stubInfo->stubDataSize();
|
||||
void* newStub = space->alloc(bytesNeeded);
|
||||
if (!newStub) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ICCacheIR_Regular* res = new(newStub) ICCacheIR_Regular(other.jitCode(), stubInfo);
|
||||
stubInfo->copyStubData(&other, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* static */ ICCacheIR_Monitored*
|
||||
ICCacheIR_Monitored::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
|
||||
ICCacheIR_Monitored& other)
|
||||
{
|
||||
const CacheIRStubInfo* stubInfo = other.stubInfo();
|
||||
MOZ_ASSERT(stubInfo->makesGCCalls());
|
||||
|
||||
size_t bytesNeeded = stubInfo->stubDataOffset() + stubInfo->stubDataSize();
|
||||
void* newStub = space->alloc(bytesNeeded);
|
||||
if (!newStub) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ICCacheIR_Monitored* res = new(newStub) ICCacheIR_Monitored(other.jitCode(), firstMonitorStub,
|
||||
stubInfo);
|
||||
stubInfo->copyStubData(&other, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* static */ ICCacheIR_Updated*
|
||||
ICCacheIR_Updated::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
|
||||
ICCacheIR_Updated& other)
|
||||
{
|
||||
const CacheIRStubInfo* stubInfo = other.stubInfo();
|
||||
MOZ_ASSERT(stubInfo->makesGCCalls());
|
||||
|
||||
size_t bytesNeeded = stubInfo->stubDataOffset() + stubInfo->stubDataSize();
|
||||
void* newStub = space->alloc(bytesNeeded);
|
||||
if (!newStub) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ICCacheIR_Updated* res = new(newStub) ICCacheIR_Updated(other.jitCode(), stubInfo);
|
||||
res->updateStubGroup() = other.updateStubGroup();
|
||||
res->updateStubId() = other.updateStubId();
|
||||
|
||||
stubInfo->copyStubData(&other, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitCallStringConcatResult()
|
||||
{
|
||||
|
|
|
@ -50,10 +50,8 @@ BaselineCompiler::BaselineCompiler(JSContext* cx, TempAllocator& alloc, JSScript
|
|||
alloc_(alloc),
|
||||
analysis_(alloc, script),
|
||||
frame(script, masm),
|
||||
stubSpace_(),
|
||||
icEntries_(),
|
||||
pcMappingEntries_(),
|
||||
icLoadLabels_(),
|
||||
icEntryIndex_(0),
|
||||
pushedBeforeCall_(0),
|
||||
#ifdef DEBUG
|
||||
inCall_(false),
|
||||
|
@ -246,7 +244,6 @@ BaselineCompiler::compile()
|
|||
debugOsrEpilogueOffset_.offset(),
|
||||
profilerEnterFrameToggleOffset_.offset(),
|
||||
profilerExitFrameToggleOffset_.offset(),
|
||||
icEntries_.length(),
|
||||
retAddrEntries_.length(),
|
||||
pcMappingIndexEntries.length(),
|
||||
pcEntries.length(),
|
||||
|
@ -272,32 +269,16 @@ BaselineCompiler::compile()
|
|||
MOZ_ASSERT(pcEntries.length() > 0);
|
||||
baselineScript->copyPCMappingEntries(pcEntries);
|
||||
|
||||
// Copy ICEntries and RetAddrEntries.
|
||||
if (icEntries_.length() > 0) {
|
||||
baselineScript->copyICEntries(script, &icEntries_[0]);
|
||||
}
|
||||
// Copy RetAddrEntries.
|
||||
if (retAddrEntries_.length() > 0) {
|
||||
baselineScript->copyRetAddrEntries(script, &retAddrEntries_[0]);
|
||||
}
|
||||
|
||||
// Adopt fallback stubs from the compiler into the baseline script.
|
||||
baselineScript->adoptFallbackStubs(&stubSpace_);
|
||||
|
||||
// If profiler instrumentation is enabled, toggle instrumentation on.
|
||||
if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime())) {
|
||||
baselineScript->toggleProfilerInstrumentation(true);
|
||||
}
|
||||
|
||||
// Patch IC loads using IC entries.
|
||||
for (size_t i = 0; i < icLoadLabels_.length(); i++) {
|
||||
CodeOffset label = icLoadLabels_[i].label;
|
||||
size_t icEntry = icLoadLabels_[i].icEntry;
|
||||
ICEntry* entryAddr = &(baselineScript->icEntry(icEntry));
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, label),
|
||||
ImmPtr(entryAddr),
|
||||
ImmPtr((void*)-1));
|
||||
}
|
||||
|
||||
if (modifiesArguments_) {
|
||||
baselineScript->setModifiesArguments();
|
||||
}
|
||||
|
@ -585,34 +566,36 @@ BaselineCompiler::emitOutOfLinePostBarrierSlot()
|
|||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emitIC(ICStub* stub, bool isForOp)
|
||||
BaselineCompiler::emitNextIC()
|
||||
{
|
||||
MOZ_ASSERT_IF(isForOp, BytecodeOpHasIC(JSOp(*pc)));
|
||||
// Emit a call to an IC stored in ICScript. Calls to this must match the
|
||||
// ICEntry order in ICScript: first the non-op IC entries for |this| and
|
||||
// formal arguments, then the for-op IC entries for JOF_IC ops.
|
||||
|
||||
if (!stub) {
|
||||
return false;
|
||||
}
|
||||
uint32_t pcOffset = script->pcToOffset(pc);
|
||||
|
||||
CodeOffset patchOffset, callOffset;
|
||||
EmitCallIC(masm, &patchOffset, &callOffset);
|
||||
// We don't use every ICEntry and we can skip unreachable ops, so we have
|
||||
// to loop until we find an ICEntry for the current pc.
|
||||
const ICEntry* entry;
|
||||
do {
|
||||
entry = &script->icScript()->icEntry(icEntryIndex_);
|
||||
icEntryIndex_++;
|
||||
} while (entry->pcOffset() < pcOffset);
|
||||
|
||||
// ICs need both an ICEntry and a RetAddrEntry.
|
||||
MOZ_RELEASE_ASSERT(entry->pcOffset() == pcOffset);
|
||||
MOZ_ASSERT_IF(entry->isForOp(), BytecodeOpHasIC(JSOp(*pc)));
|
||||
|
||||
CodeOffset callOffset;
|
||||
EmitCallIC(masm, entry, &callOffset);
|
||||
|
||||
RetAddrEntry::Kind kind =
|
||||
entry->isForOp() ? RetAddrEntry::Kind::IC : RetAddrEntry::Kind::NonOpIC;
|
||||
|
||||
RetAddrEntry::Kind kind = isForOp ? RetAddrEntry::Kind::IC : RetAddrEntry::Kind::NonOpIC;
|
||||
if (!retAddrEntries_.emplaceBack(script->pcToOffset(pc), kind, callOffset)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!icEntries_.emplaceBack(stub, script->pcToOffset(pc), isForOp)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!addICLoadLabel(patchOffset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -947,8 +930,7 @@ BaselineCompiler::emitWarmUpCounterIncrement(bool allowOsr)
|
|||
if (JSOp(*pc) == JSOP_LOOPENTRY) {
|
||||
// During the loop entry we can try to OSR into ion.
|
||||
// The ic has logic for this.
|
||||
ICWarmUpCounter_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitNonOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
@ -982,8 +964,7 @@ BaselineCompiler::emitArgumentTypeChecks()
|
|||
frame.pushThis();
|
||||
frame.popRegsAndSync(1);
|
||||
|
||||
ICTypeMonitor_Fallback::Compiler compiler(cx, uint32_t(0));
|
||||
if (!emitNonOpIC(compiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -991,8 +972,7 @@ BaselineCompiler::emitArgumentTypeChecks()
|
|||
frame.pushArg(i);
|
||||
frame.popRegsAndSync(1);
|
||||
|
||||
ICTypeMonitor_Fallback::Compiler compiler(cx, i + 1);
|
||||
if (!emitNonOpIC(compiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1435,8 +1415,7 @@ BaselineCompiler::emitToBoolean()
|
|||
masm.branchTestBoolean(Assembler::Equal, R0, &skipIC);
|
||||
|
||||
// Call IC
|
||||
ICToBool_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1531,8 +1510,7 @@ BaselineCompiler::emit_JSOP_POS()
|
|||
masm.branchTestNumber(Assembler::Equal, R0, &done);
|
||||
|
||||
// Call IC.
|
||||
ICToNumber_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2159,8 +2137,7 @@ BaselineCompiler::emitBinaryArith()
|
|||
frame.popRegsAndSync(2);
|
||||
|
||||
// Call IC
|
||||
ICBinaryArith_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2176,8 +2153,7 @@ BaselineCompiler::emitUnaryArith()
|
|||
frame.popRegsAndSync(1);
|
||||
|
||||
// Call IC
|
||||
ICUnaryArith_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2243,8 +2219,7 @@ BaselineCompiler::emitCompare()
|
|||
frame.popRegsAndSync(2);
|
||||
|
||||
// Call IC.
|
||||
ICCompare_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2314,13 +2289,7 @@ BaselineCompiler::emit_JSOP_NEWARRAY()
|
|||
// Pass length in R0.
|
||||
masm.move32(Imm32(AssertedCast<int32_t>(length)), R0.scratchReg());
|
||||
|
||||
ObjectGroup* group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
|
||||
if (!group) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ICNewArray_Fallback::Compiler stubCompiler(cx, group);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2372,8 +2341,7 @@ BaselineCompiler::emit_JSOP_INITELEM_ARRAY()
|
|||
masm.moveValue(Int32Value(AssertedCast<int32_t>(index)), R1);
|
||||
|
||||
// Call IC.
|
||||
ICSetElem_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2387,8 +2355,7 @@ BaselineCompiler::emit_JSOP_NEWOBJECT()
|
|||
{
|
||||
frame.syncStack(0);
|
||||
|
||||
ICNewObject_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2401,8 +2368,7 @@ BaselineCompiler::emit_JSOP_NEWINIT()
|
|||
{
|
||||
frame.syncStack(0);
|
||||
|
||||
ICNewObject_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2428,8 +2394,7 @@ BaselineCompiler::emit_JSOP_INITELEM()
|
|||
frame.pushScratchValue();
|
||||
|
||||
// Call IC.
|
||||
ICSetElem_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2479,8 +2444,7 @@ BaselineCompiler::emit_JSOP_INITPROP()
|
|||
masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
|
||||
|
||||
// Call IC.
|
||||
ICSetProp_Fallback::Compiler compiler(cx);
|
||||
if (!emitOpIC(compiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2508,8 +2472,7 @@ BaselineCompiler::emit_JSOP_GETELEM()
|
|||
frame.popRegsAndSync(2);
|
||||
|
||||
// Call IC.
|
||||
ICGetElem_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2531,8 +2494,7 @@ BaselineCompiler::emit_JSOP_GETELEM_SUPER()
|
|||
// Keep obj on the stack.
|
||||
frame.pushScratchValue();
|
||||
|
||||
ICGetElem_Fallback::Compiler stubCompiler(cx, /* hasReceiver = */ true);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2561,8 +2523,7 @@ BaselineCompiler::emit_JSOP_SETELEM()
|
|||
frame.pushScratchValue();
|
||||
|
||||
// Call IC.
|
||||
ICSetElem_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2653,8 +2614,7 @@ BaselineCompiler::emit_JSOP_IN()
|
|||
{
|
||||
frame.popRegsAndSync(2);
|
||||
|
||||
ICIn_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2667,8 +2627,7 @@ BaselineCompiler::emit_JSOP_HASOWN()
|
|||
{
|
||||
frame.popRegsAndSync(2);
|
||||
|
||||
ICHasOwn_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2704,8 +2663,7 @@ BaselineCompiler::emit_JSOP_GETGNAME()
|
|||
masm.movePtr(ImmGCPtr(&script->global().lexicalEnvironment()), R0.scratchReg());
|
||||
|
||||
// Call IC.
|
||||
ICGetName_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2779,8 +2737,7 @@ BaselineCompiler::emit_JSOP_SETPROP()
|
|||
frame.syncStack(0);
|
||||
|
||||
// Call IC.
|
||||
ICSetProp_Fallback::Compiler compiler(cx);
|
||||
if (!emitOpIC(compiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2865,8 +2822,7 @@ BaselineCompiler::emit_JSOP_GETPROP()
|
|||
frame.popRegsAndSync(1);
|
||||
|
||||
// Call IC.
|
||||
ICGetProp_Fallback::Compiler compiler(cx);
|
||||
if (!emitOpIC(compiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2901,8 +2857,7 @@ BaselineCompiler::emit_JSOP_GETPROP_SUPER()
|
|||
masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
|
||||
frame.pop();
|
||||
|
||||
ICGetProp_Fallback::Compiler compiler(cx, /* hasReceiver = */ true);
|
||||
if (!emitOpIC(compiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2988,8 +2943,7 @@ BaselineCompiler::emit_JSOP_GETALIASEDVAR()
|
|||
|
||||
if (ionCompileable_) {
|
||||
// No need to monitor types if we know Ion can't compile this script.
|
||||
ICTypeMonitor_Fallback::Compiler compiler(cx, nullptr);
|
||||
if (!emitOpIC(compiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -3015,8 +2969,7 @@ BaselineCompiler::emit_JSOP_SETALIASEDVAR()
|
|||
masm.tagValue(JSVAL_TYPE_OBJECT, R2.scratchReg(), R0);
|
||||
|
||||
// Call SETPROP IC.
|
||||
ICSetProp_Fallback::Compiler compiler(cx);
|
||||
if (!emitOpIC(compiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3055,8 +3008,7 @@ BaselineCompiler::emit_JSOP_GETNAME()
|
|||
masm.loadPtr(frame.addressOfEnvironmentChain(), R0.scratchReg());
|
||||
|
||||
// Call IC.
|
||||
ICGetName_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3077,8 +3029,7 @@ BaselineCompiler::emit_JSOP_BINDNAME()
|
|||
}
|
||||
|
||||
// Call IC.
|
||||
ICBindName_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3145,8 +3096,7 @@ BaselineCompiler::emit_JSOP_GETIMPORT()
|
|||
|
||||
if (ionCompileable_) {
|
||||
// No need to monitor types if we know Ion can't compile this script.
|
||||
ICTypeMonitor_Fallback::Compiler compiler(cx, nullptr);
|
||||
if (!emitOpIC(compiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -3160,8 +3110,7 @@ BaselineCompiler::emit_JSOP_GETINTRINSIC()
|
|||
{
|
||||
frame.syncStack(0);
|
||||
|
||||
ICGetIntrinsic_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3375,8 +3324,7 @@ BaselineCompiler::emit_JSOP_INITELEM_INC()
|
|||
masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R1);
|
||||
|
||||
// Call IC.
|
||||
ICSetElem_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3673,9 +3621,7 @@ BaselineCompiler::emitCall()
|
|||
masm.move32(Imm32(argc), R0.scratchReg());
|
||||
|
||||
// Call IC
|
||||
ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ construct,
|
||||
/* isSpread = */ false);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3695,9 +3641,7 @@ BaselineCompiler::emitSpreadCall()
|
|||
|
||||
// Call IC
|
||||
bool construct = JSOp(*pc) == JSOP_SPREADNEW || JSOp(*pc) == JSOP_SPREADSUPERCALL;
|
||||
ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ construct,
|
||||
/* isSpread = */ true);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3853,8 +3797,7 @@ BaselineCompiler::emit_JSOP_INSTANCEOF()
|
|||
{
|
||||
frame.popRegsAndSync(2);
|
||||
|
||||
ICInstanceOf_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3867,8 +3810,7 @@ BaselineCompiler::emit_JSOP_TYPEOF()
|
|||
{
|
||||
frame.popRegsAndSync(1);
|
||||
|
||||
ICTypeOf_Fallback::Compiler stubCompiler(cx);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -4536,8 +4478,7 @@ BaselineCompiler::emit_JSOP_ITER()
|
|||
{
|
||||
frame.popRegsAndSync(1);
|
||||
|
||||
ICGetIterator_Fallback::Compiler compiler(cx);
|
||||
if (!emitOpIC(compiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -4551,8 +4492,7 @@ BaselineCompiler::emit_JSOP_MOREITER()
|
|||
frame.syncStack(0);
|
||||
masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
|
||||
|
||||
ICIteratorMore_Fallback::Compiler compiler(cx);
|
||||
if (!emitOpIC(compiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -4593,8 +4533,11 @@ BaselineCompiler::emit_JSOP_ENDITER()
|
|||
}
|
||||
frame.popRegsAndSync(1);
|
||||
|
||||
ICIteratorClose_Fallback::Compiler compiler(cx);
|
||||
return emitOpIC(compiler.getStub(&stubSpace_));
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -4830,16 +4773,7 @@ BaselineCompiler::emit_JSOP_REST()
|
|||
{
|
||||
frame.syncStack(0);
|
||||
|
||||
ArrayObject* templateObject =
|
||||
ObjectGroup::newArrayObject(cx, nullptr, 0, TenuredObject,
|
||||
ObjectGroup::NewArrayKind::UnknownIndex);
|
||||
if (!templateObject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Call IC.
|
||||
ICRest_Fallback::Compiler compiler(cx, templateObject);
|
||||
if (!emitOpIC(compiler.getStub(&stubSpace_))) {
|
||||
if (!emitNextIC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -262,8 +262,6 @@ class BaselineCompiler final
|
|||
BytecodeAnalysis analysis_;
|
||||
FrameInfo frame;
|
||||
|
||||
FallbackICStubSpace stubSpace_;
|
||||
js::Vector<ICEntry, 16, SystemAllocPolicy> icEntries_;
|
||||
js::Vector<RetAddrEntry, 16, SystemAllocPolicy> retAddrEntries_;
|
||||
|
||||
// Stores the native code offset for a bytecode pc.
|
||||
|
@ -280,15 +278,8 @@ class BaselineCompiler final
|
|||
|
||||
js::Vector<PCMappingEntry, 16, SystemAllocPolicy> pcMappingEntries_;
|
||||
|
||||
// Labels for the 'movWithPatch' for loading IC entry pointers in
|
||||
// the generated IC-calling code in the main jitcode. These need
|
||||
// to be patched with the actual icEntry offsets after the BaselineScript
|
||||
// has been allocated.
|
||||
struct ICLoadLabel {
|
||||
size_t icEntry;
|
||||
CodeOffset label;
|
||||
};
|
||||
js::Vector<ICLoadLabel, 16, SystemAllocPolicy> icLoadLabels_;
|
||||
// Index of the current ICEntry in the script's ICScript.
|
||||
uint32_t icEntryIndex_;
|
||||
|
||||
uint32_t pushedBeforeCall_;
|
||||
#ifdef DEBUG
|
||||
|
@ -351,18 +342,6 @@ class BaselineCompiler final
|
|||
return true;
|
||||
}
|
||||
|
||||
bool addICLoadLabel(CodeOffset label) {
|
||||
MOZ_ASSERT(!icEntries_.empty());
|
||||
ICLoadLabel loadLabel;
|
||||
loadLabel.label = label;
|
||||
loadLabel.icEntry = icEntries_.length() - 1;
|
||||
if (!icLoadLabels_.append(loadLabel)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
JSFunction* function() const {
|
||||
// Not delazifying here is ok as the function is guaranteed to have
|
||||
// been delazified before compilation started.
|
||||
|
@ -420,14 +399,7 @@ class BaselineCompiler final
|
|||
MOZ_MUST_USE bool emitPrologue();
|
||||
MOZ_MUST_USE bool emitEpilogue();
|
||||
MOZ_MUST_USE bool emitOutOfLinePostBarrierSlot();
|
||||
MOZ_MUST_USE bool emitIC(ICStub* stub, bool isForOp);
|
||||
MOZ_MUST_USE bool emitOpIC(ICStub* stub) {
|
||||
return emitIC(stub, true);
|
||||
}
|
||||
MOZ_MUST_USE bool emitNonOpIC(ICStub* stub) {
|
||||
return emitIC(stub, false);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool emitNextIC();
|
||||
MOZ_MUST_USE bool emitStackCheck();
|
||||
MOZ_MUST_USE bool emitInterruptCheck();
|
||||
MOZ_MUST_USE bool emitWarmUpCounterIncrement(bool allowOsr=true);
|
||||
|
|
|
@ -23,8 +23,6 @@ struct DebugModeOSREntry
|
|||
{
|
||||
JSScript* script;
|
||||
BaselineScript* oldBaselineScript;
|
||||
ICStub* oldStub;
|
||||
ICStub* newStub;
|
||||
BaselineDebugModeOSRInfo* recompInfo;
|
||||
uint32_t pcOffset;
|
||||
RetAddrEntry::Kind frameKind;
|
||||
|
@ -32,8 +30,6 @@ struct DebugModeOSREntry
|
|||
explicit DebugModeOSREntry(JSScript* script)
|
||||
: script(script),
|
||||
oldBaselineScript(script->baselineScript()),
|
||||
oldStub(nullptr),
|
||||
newStub(nullptr),
|
||||
recompInfo(nullptr),
|
||||
pcOffset(uint32_t(-1)),
|
||||
frameKind(RetAddrEntry::Kind::Invalid)
|
||||
|
@ -42,8 +38,6 @@ struct DebugModeOSREntry
|
|||
DebugModeOSREntry(JSScript* script, uint32_t pcOffset)
|
||||
: script(script),
|
||||
oldBaselineScript(script->baselineScript()),
|
||||
oldStub(nullptr),
|
||||
newStub(nullptr),
|
||||
recompInfo(nullptr),
|
||||
pcOffset(pcOffset),
|
||||
frameKind(RetAddrEntry::Kind::Invalid)
|
||||
|
@ -52,8 +46,6 @@ struct DebugModeOSREntry
|
|||
DebugModeOSREntry(JSScript* script, const RetAddrEntry& retAddrEntry)
|
||||
: script(script),
|
||||
oldBaselineScript(script->baselineScript()),
|
||||
oldStub(nullptr),
|
||||
newStub(nullptr),
|
||||
recompInfo(nullptr),
|
||||
pcOffset(retAddrEntry.pcOffset()),
|
||||
frameKind(retAddrEntry.kind())
|
||||
|
@ -67,8 +59,6 @@ struct DebugModeOSREntry
|
|||
DebugModeOSREntry(JSScript* script, BaselineDebugModeOSRInfo* info)
|
||||
: script(script),
|
||||
oldBaselineScript(script->baselineScript()),
|
||||
oldStub(nullptr),
|
||||
newStub(nullptr),
|
||||
recompInfo(nullptr),
|
||||
pcOffset(script->pcToOffset(info->pc)),
|
||||
frameKind(info->frameKind)
|
||||
|
@ -82,8 +72,6 @@ struct DebugModeOSREntry
|
|||
DebugModeOSREntry(DebugModeOSREntry&& other)
|
||||
: script(other.script),
|
||||
oldBaselineScript(other.oldBaselineScript),
|
||||
oldStub(other.oldStub),
|
||||
newStub(other.newStub),
|
||||
recompInfo(other.recompInfo ? other.takeRecompInfo() : nullptr),
|
||||
pcOffset(other.pcOffset),
|
||||
frameKind(other.frameKind)
|
||||
|
@ -132,12 +120,6 @@ struct DebugModeOSREntry
|
|||
recompInfo = cx->new_<BaselineDebugModeOSRInfo>(pc, kind);
|
||||
return !!recompInfo;
|
||||
}
|
||||
|
||||
ICFallbackStub* fallbackStub() const {
|
||||
MOZ_ASSERT(script);
|
||||
MOZ_ASSERT(oldStub);
|
||||
return script->baselineScript()->icEntryFromPCOffset(pcOffset).fallbackStub();
|
||||
}
|
||||
};
|
||||
|
||||
typedef Vector<DebugModeOSREntry> DebugModeOSREntryVector;
|
||||
|
@ -184,7 +166,6 @@ static bool
|
|||
CollectJitStackScripts(JSContext* cx, const Debugger::ExecutionObservableSet& obs,
|
||||
const ActivationIterator& activation, DebugModeOSREntryVector& entries)
|
||||
{
|
||||
ICStub* prevFrameStubPtr = nullptr;
|
||||
bool needsRecompileHandler = false;
|
||||
for (OnlyJSJitFrameIter iter(activation); !iter.done(); ++iter) {
|
||||
const JSJitFrameIter& frame = iter.frame();
|
||||
|
@ -193,7 +174,6 @@ CollectJitStackScripts(JSContext* cx, const Debugger::ExecutionObservableSet& ob
|
|||
JSScript* script = frame.script();
|
||||
|
||||
if (!obs.shouldRecompileOrInvalidate(script)) {
|
||||
prevFrameStubPtr = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -235,14 +215,10 @@ CollectJitStackScripts(JSContext* cx, const Debugger::ExecutionObservableSet& ob
|
|||
|
||||
needsRecompileHandler |= true;
|
||||
}
|
||||
entries.back().oldStub = prevFrameStubPtr;
|
||||
prevFrameStubPtr = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
case FrameType::BaselineStub:
|
||||
prevFrameStubPtr =
|
||||
reinterpret_cast<BaselineStubFrameLayout*>(frame.fp())->maybeStubPtr();
|
||||
break;
|
||||
|
||||
case FrameType::IonJS: {
|
||||
|
@ -346,14 +322,6 @@ SpewPatchBaselineFrameFromExceptionHandler(uint8_t* oldReturnAddress, uint8_t* n
|
|||
script->column(), CodeName[(JSOp)*pc]);
|
||||
}
|
||||
|
||||
static void
|
||||
SpewPatchStubFrame(ICStub* oldStub, ICStub* newStub)
|
||||
{
|
||||
JitSpew(JitSpew_BaselineDebugModeOSR,
|
||||
"Patch stub %p -> %p on BaselineStub frame (%s)",
|
||||
oldStub, newStub, newStub ? ICStub::KindString(newStub->kind()) : "exception handler");
|
||||
}
|
||||
|
||||
static void
|
||||
PatchBaselineFramesForDebugMode(JSContext* cx,
|
||||
const Debugger::ExecutionObservableSet& obs,
|
||||
|
@ -368,7 +336,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx,
|
|||
// script.
|
||||
//
|
||||
// Off to On:
|
||||
// A. From a "can call" stub.
|
||||
// A. From a "can call" IC stub.
|
||||
// B. From a VM call.
|
||||
// H. From inside HandleExceptionBaseline
|
||||
// I. From inside the interrupt handler via the prologue stack check.
|
||||
|
@ -424,13 +392,9 @@ PatchBaselineFramesForDebugMode(JSContext* cx,
|
|||
if (kind == RetAddrEntry::Kind::IC) {
|
||||
// Case A above.
|
||||
//
|
||||
// Patching these cases needs to patch both the stub frame and
|
||||
// the baseline frame. The stub frame is patched below. For
|
||||
// the baseline frame here, we resume right after the IC
|
||||
// returns.
|
||||
//
|
||||
// Since we're using the same IC stub code, we can resume
|
||||
// directly to the IC resume address.
|
||||
// For the baseline frame here, we resume right after the IC
|
||||
// returns. Since we're using the same IC stubs and stub code,
|
||||
// we don't have to patch the stub or stub frame.
|
||||
RetAddrEntry& retAddrEntry = bl->retAddrEntryFromPCOffset(pcOffset, kind);
|
||||
uint8_t* retAddr = bl->returnAddressForEntry(retAddrEntry);
|
||||
SpewPatchBaselineFrame(prev->returnAddress(), retAddr, script, kind, pc);
|
||||
|
@ -590,51 +554,6 @@ PatchBaselineFramesForDebugMode(JSContext* cx,
|
|||
break;
|
||||
}
|
||||
|
||||
case FrameType::BaselineStub: {
|
||||
JSJitFrameIter prev(iter.frame());
|
||||
++prev;
|
||||
BaselineFrame* prevFrame = prev.baselineFrame();
|
||||
if (!obs.shouldRecompileOrInvalidate(prevFrame->script())) {
|
||||
break;
|
||||
}
|
||||
|
||||
DebugModeOSREntry& entry = entries[entryIndex];
|
||||
|
||||
// If the script wasn't recompiled, there's nothing to patch.
|
||||
if (!entry.recompiled()) {
|
||||
break;
|
||||
}
|
||||
|
||||
BaselineStubFrameLayout* layout =
|
||||
reinterpret_cast<BaselineStubFrameLayout*>(frame.fp());
|
||||
MOZ_ASSERT(layout->maybeStubPtr() == entry.oldStub);
|
||||
|
||||
// Patch baseline stub frames for case A above.
|
||||
//
|
||||
// We need to patch the stub frame to point to an ICStub belonging
|
||||
// to the recompiled baseline script. These stubs are allocated up
|
||||
// front in CloneOldBaselineStub. They share the same JitCode as
|
||||
// the old baseline script's stubs, so we don't need to patch the
|
||||
// exit frame's return address.
|
||||
//
|
||||
// Subtlety here: the debug trap handler of case C above pushes a
|
||||
// stub frame with a null stub pointer. This handler will exist
|
||||
// across recompiling the script, so we don't patch anything for
|
||||
// such stub frames. We will return to that handler, which takes
|
||||
// care of cleaning up the stub frame.
|
||||
//
|
||||
// Note that for stub pointers that are already on the C stack
|
||||
// (i.e. fallback calls), we need to check for recompilation using
|
||||
// DebugModeOSRVolatileStub.
|
||||
if (layout->maybeStubPtr()) {
|
||||
MOZ_ASSERT(entry.newStub || prevFrame->isHandlingException());
|
||||
SpewPatchStubFrame(entry.oldStub, entry.newStub);
|
||||
layout->setStubPtr(entry.newStub);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case FrameType::IonJS: {
|
||||
// Nothing to patch.
|
||||
InlineFrameIterator inlineIter(cx, &frame);
|
||||
|
@ -712,113 +631,6 @@ RecompileBaselineScriptForDebugMode(JSContext* cx, JSScript* script,
|
|||
return true;
|
||||
}
|
||||
|
||||
#define PATCHABLE_ICSTUB_KIND_LIST(_) \
|
||||
_(CacheIR_Monitored) \
|
||||
_(CacheIR_Regular) \
|
||||
_(CacheIR_Updated) \
|
||||
_(Call_Scripted) \
|
||||
_(Call_AnyScripted) \
|
||||
_(Call_Native) \
|
||||
_(Call_ClassHook) \
|
||||
_(Call_ScriptedApplyArray) \
|
||||
_(Call_ScriptedApplyArguments) \
|
||||
_(Call_ScriptedFunCall)
|
||||
|
||||
static bool
|
||||
CloneOldBaselineStub(JSContext* cx, DebugModeOSREntryVector& entries, size_t entryIndex)
|
||||
{
|
||||
DebugModeOSREntry& entry = entries[entryIndex];
|
||||
if (!entry.oldStub) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ICStub* oldStub = entry.oldStub;
|
||||
MOZ_ASSERT(oldStub->makesGCCalls());
|
||||
|
||||
// If this script was not recompiled (because it already had the correct
|
||||
// debug instrumentation), don't clone to avoid attaching duplicate stubs.
|
||||
if (!entry.recompiled()) {
|
||||
entry.newStub = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entry.frameKind == RetAddrEntry::Kind::Invalid) {
|
||||
// The exception handler can modify the frame's override pc while
|
||||
// unwinding scopes. This is fine, but if we have a stub frame, the code
|
||||
// code below will get confused: the entry's pcOffset doesn't match the
|
||||
// stub that's still on the stack. To prevent that, we just set the new
|
||||
// stub to nullptr as we will never return to this stub frame anyway.
|
||||
entry.newStub = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the new fallback stub from the recompiled baseline script.
|
||||
ICFallbackStub* fallbackStub = entry.fallbackStub();
|
||||
|
||||
// Some stubs are monitored, get the first stub in the monitor chain from
|
||||
// the new fallback stub if so. We do this before checking for fallback
|
||||
// stubs below, to ensure monitored fallback stubs have a type monitor
|
||||
// chain.
|
||||
ICStub* firstMonitorStub;
|
||||
if (fallbackStub->isMonitoredFallback()) {
|
||||
ICMonitoredFallbackStub* monitored = fallbackStub->toMonitoredFallbackStub();
|
||||
ICTypeMonitor_Fallback* fallback = monitored->getFallbackMonitorStub(cx, entry.script);
|
||||
if (!fallback) {
|
||||
return false;
|
||||
}
|
||||
firstMonitorStub = fallback->firstMonitorStub();
|
||||
} else {
|
||||
firstMonitorStub = nullptr;
|
||||
}
|
||||
|
||||
// We don't need to clone fallback stubs, as they are guaranteed to
|
||||
// exist. Furthermore, their JitCode is cached and should be the same even
|
||||
// across the recompile.
|
||||
if (oldStub->isFallback()) {
|
||||
MOZ_ASSERT(oldStub->jitCode() == fallbackStub->jitCode());
|
||||
entry.newStub = fallbackStub;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if we have already cloned the stub on a younger frame. Ignore
|
||||
// frames that entered the exception handler (entries[i].newStub is nullptr
|
||||
// in that case, see above).
|
||||
for (size_t i = 0; i < entryIndex; i++) {
|
||||
if (oldStub == entries[i].oldStub && entries[i].frameKind != RetAddrEntry::Kind::Invalid) {
|
||||
MOZ_ASSERT(entries[i].newStub);
|
||||
entry.newStub = entries[i].newStub;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ICStubSpace* stubSpace = ICStubCompiler::StubSpaceForStub(oldStub->makesGCCalls(),
|
||||
entry.script);
|
||||
|
||||
// Clone the existing stub into the recompiled IC.
|
||||
//
|
||||
// Note that since JitCode is a GC thing, cloning an ICStub with the same
|
||||
// JitCode ensures it won't be collected.
|
||||
switch (oldStub->kind()) {
|
||||
#define CASE_KIND(kindName) \
|
||||
case ICStub::kindName: \
|
||||
entry.newStub = IC##kindName::Clone(cx, stubSpace, firstMonitorStub, \
|
||||
*oldStub->to##kindName()); \
|
||||
break;
|
||||
PATCHABLE_ICSTUB_KIND_LIST(CASE_KIND)
|
||||
#undef CASE_KIND
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Bad stub kind");
|
||||
}
|
||||
|
||||
if (!entry.newStub) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fallbackStub->addNewStub(entry.newStub);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
InvalidateScriptsInZone(JSContext* cx, Zone* zone, const Vector<DebugModeOSREntry>& entries)
|
||||
{
|
||||
|
@ -918,9 +730,7 @@ jit::RecompileOnStackBaselineScriptsForDebugMode(JSContext* cx,
|
|||
for (size_t i = 0; i < entries.length(); i++) {
|
||||
JSScript* script = entries[i].script;
|
||||
AutoRealm ar(cx, script);
|
||||
if (!RecompileBaselineScriptForDebugMode(cx, script, observing) ||
|
||||
!CloneOldBaselineStub(cx, entries, i))
|
||||
{
|
||||
if (!RecompileBaselineScriptForDebugMode(cx, script, observing)) {
|
||||
UndoRecompileBaselineScriptsForDebugMode(cx, entries);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -21,55 +21,6 @@ namespace jit {
|
|||
// on-stack recompilation. This is to be distinguished from ordinary
|
||||
// Baseline->Ion OSR, which is used to jump into compiled loops.
|
||||
|
||||
//
|
||||
// A volatile location due to recompilation of an on-stack baseline script
|
||||
// (e.g., for debug mode toggling).
|
||||
//
|
||||
// It is usually used in fallback stubs which may trigger on-stack
|
||||
// recompilation by calling out into the VM. Example use:
|
||||
//
|
||||
// DebugModeOSRVolatileStub<FallbackStubT*> stub(frame, stub_)
|
||||
//
|
||||
// // Call out to the VM
|
||||
// // Other effectful operations like TypeScript::Monitor
|
||||
//
|
||||
// if (stub.invalid()) {
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// // First use of stub after VM call.
|
||||
//
|
||||
template <typename T>
|
||||
class DebugModeOSRVolatileStub
|
||||
{
|
||||
T stub_;
|
||||
BaselineFrame* frame_;
|
||||
uint32_t pcOffset_;
|
||||
|
||||
public:
|
||||
DebugModeOSRVolatileStub(BaselineFrame* frame, ICFallbackStub* stub)
|
||||
: stub_(static_cast<T>(stub)),
|
||||
frame_(frame),
|
||||
pcOffset_(stub->icEntry()->pcOffset())
|
||||
{ }
|
||||
|
||||
bool invalid() const {
|
||||
MOZ_ASSERT(!frame_->isHandlingException());
|
||||
ICEntry& entry = frame_->script()->baselineScript()->icEntryFromPCOffset(pcOffset_);
|
||||
return stub_ != entry.fallbackStub();
|
||||
}
|
||||
|
||||
operator const T&() const { MOZ_ASSERT(!invalid()); return stub_; }
|
||||
T operator->() const { MOZ_ASSERT(!invalid()); return stub_; }
|
||||
T* address() { MOZ_ASSERT(!invalid()); return &stub_; }
|
||||
const T* address() const { MOZ_ASSERT(!invalid()); return &stub_; }
|
||||
T& get() { MOZ_ASSERT(!invalid()); return stub_; }
|
||||
const T& get() const { MOZ_ASSERT(!invalid()); return stub_; }
|
||||
|
||||
bool operator!=(const T& other) const { MOZ_ASSERT(!invalid()); return stub_ != other; }
|
||||
bool operator==(const T& other) const { MOZ_ASSERT(!invalid()); return stub_ == other; }
|
||||
};
|
||||
|
||||
//
|
||||
// A frame iterator that updates internal JSJitFrameIter in case of
|
||||
// recompilation of an on-stack baseline script.
|
||||
|
|
|
@ -123,6 +123,335 @@ ICEntry::trace(JSTracer* trc)
|
|||
}
|
||||
}
|
||||
|
||||
/* static */ UniquePtr<ICScript>
|
||||
ICScript::create(JSContext* cx, JSScript* script)
|
||||
{
|
||||
FallbackICStubSpace stubSpace;
|
||||
js::Vector<ICEntry, 16, SystemAllocPolicy> icEntries;
|
||||
|
||||
auto addIC = [cx, &icEntries, script](jsbytecode* pc, ICStub* stub) {
|
||||
if (!stub) {
|
||||
MOZ_ASSERT(cx->isExceptionPending());
|
||||
return false;
|
||||
}
|
||||
uint32_t offset = pc ? script->pcToOffset(pc) : ICEntry::NonOpPCOffset;
|
||||
if (!icEntries.emplaceBack(stub, offset)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// Add ICEntries and fallback stubs for this/argument type checks.
|
||||
// Note: we pass a nullptr pc to indicate this is a non-op IC.
|
||||
// See ICEntry::NonOpPCOffset.
|
||||
if (JSFunction* fun = script->functionNonDelazifying()) {
|
||||
ICTypeMonitor_Fallback::Compiler compiler(cx, uint32_t(0));
|
||||
if (!addIC(nullptr, compiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < fun->nargs(); i++) {
|
||||
ICTypeMonitor_Fallback::Compiler compiler(cx, i + 1);
|
||||
if (!addIC(nullptr, compiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jsbytecode const* pcEnd = script->codeEnd();
|
||||
|
||||
// Add ICEntries and fallback stubs for JOF_IC bytecode ops.
|
||||
for (jsbytecode* pc = script->code(); pc < pcEnd; pc = GetNextPc(pc)) {
|
||||
JSOp op = JSOp(*pc);
|
||||
if (!BytecodeOpHasIC(op)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case JSOP_NOT:
|
||||
case JSOP_AND:
|
||||
case JSOP_OR:
|
||||
case JSOP_IFEQ:
|
||||
case JSOP_IFNE: {
|
||||
ICToBool_Fallback::Compiler stubCompiler(cx);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_BITNOT:
|
||||
case JSOP_NEG: {
|
||||
ICUnaryArith_Fallback::Compiler stubCompiler(cx);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_BITOR:
|
||||
case JSOP_BITXOR:
|
||||
case JSOP_BITAND:
|
||||
case JSOP_LSH:
|
||||
case JSOP_RSH:
|
||||
case JSOP_URSH:
|
||||
case JSOP_ADD:
|
||||
case JSOP_SUB:
|
||||
case JSOP_MUL:
|
||||
case JSOP_DIV:
|
||||
case JSOP_MOD:
|
||||
case JSOP_POW: {
|
||||
ICBinaryArith_Fallback::Compiler stubCompiler(cx);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_EQ:
|
||||
case JSOP_NE:
|
||||
case JSOP_LT:
|
||||
case JSOP_LE:
|
||||
case JSOP_GT:
|
||||
case JSOP_GE:
|
||||
case JSOP_STRICTEQ:
|
||||
case JSOP_STRICTNE: {
|
||||
ICCompare_Fallback::Compiler stubCompiler(cx);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_POS: {
|
||||
ICToNumber_Fallback::Compiler stubCompiler(cx);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_LOOPENTRY: {
|
||||
ICWarmUpCounter_Fallback::Compiler stubCompiler(cx);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_NEWARRAY: {
|
||||
ObjectGroup* group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
|
||||
if (!group) {
|
||||
return nullptr;
|
||||
}
|
||||
ICNewArray_Fallback::Compiler stubCompiler(cx, group);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_NEWOBJECT:
|
||||
case JSOP_NEWINIT: {
|
||||
ICNewObject_Fallback::Compiler stubCompiler(cx);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_INITELEM:
|
||||
case JSOP_INITHIDDENELEM:
|
||||
case JSOP_INITELEM_ARRAY:
|
||||
case JSOP_INITELEM_INC:
|
||||
case JSOP_SETELEM:
|
||||
case JSOP_STRICTSETELEM: {
|
||||
ICSetElem_Fallback::Compiler stubCompiler(cx);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_INITPROP:
|
||||
case JSOP_INITLOCKEDPROP:
|
||||
case JSOP_INITHIDDENPROP:
|
||||
case JSOP_SETALIASEDVAR:
|
||||
case JSOP_INITGLEXICAL:
|
||||
case JSOP_INITALIASEDLEXICAL:
|
||||
case JSOP_SETPROP:
|
||||
case JSOP_STRICTSETPROP:
|
||||
case JSOP_SETNAME:
|
||||
case JSOP_STRICTSETNAME:
|
||||
case JSOP_SETGNAME:
|
||||
case JSOP_STRICTSETGNAME: {
|
||||
ICSetProp_Fallback::Compiler compiler(cx);
|
||||
if (!addIC(pc, compiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_GETPROP:
|
||||
case JSOP_CALLPROP:
|
||||
case JSOP_LENGTH:
|
||||
case JSOP_GETPROP_SUPER:
|
||||
case JSOP_GETBOUNDNAME: {
|
||||
bool hasReceiver = (op == JSOP_GETPROP_SUPER);
|
||||
ICGetProp_Fallback::Compiler compiler(cx, hasReceiver);
|
||||
if (!addIC(pc, compiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_GETELEM:
|
||||
case JSOP_CALLELEM:
|
||||
case JSOP_GETELEM_SUPER: {
|
||||
bool hasReceiver = (op == JSOP_GETELEM_SUPER);
|
||||
ICGetElem_Fallback::Compiler stubCompiler(cx, hasReceiver);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_IN: {
|
||||
ICIn_Fallback::Compiler stubCompiler(cx);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_HASOWN: {
|
||||
ICHasOwn_Fallback::Compiler stubCompiler(cx);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_GETNAME:
|
||||
case JSOP_GETGNAME: {
|
||||
ICGetName_Fallback::Compiler stubCompiler(cx);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_BINDNAME:
|
||||
case JSOP_BINDGNAME: {
|
||||
ICBindName_Fallback::Compiler stubCompiler(cx);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_GETALIASEDVAR:
|
||||
case JSOP_GETIMPORT: {
|
||||
ICTypeMonitor_Fallback::Compiler compiler(cx, nullptr);
|
||||
if (!addIC(pc, compiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_GETINTRINSIC: {
|
||||
ICGetIntrinsic_Fallback::Compiler stubCompiler(cx);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_CALL:
|
||||
case JSOP_CALL_IGNORES_RV:
|
||||
case JSOP_CALLITER:
|
||||
case JSOP_SUPERCALL:
|
||||
case JSOP_FUNCALL:
|
||||
case JSOP_FUNAPPLY:
|
||||
case JSOP_NEW:
|
||||
case JSOP_EVAL:
|
||||
case JSOP_STRICTEVAL: {
|
||||
bool construct = JSOp(*pc) == JSOP_NEW || JSOp(*pc) == JSOP_SUPERCALL;
|
||||
ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ construct,
|
||||
/* isSpread = */ false);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_SPREADCALL:
|
||||
case JSOP_SPREADSUPERCALL:
|
||||
case JSOP_SPREADNEW:
|
||||
case JSOP_SPREADEVAL:
|
||||
case JSOP_STRICTSPREADEVAL: {
|
||||
bool construct = JSOp(*pc) == JSOP_SPREADNEW || JSOp(*pc) == JSOP_SPREADSUPERCALL;
|
||||
ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ construct,
|
||||
/* isSpread = */ true);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_INSTANCEOF: {
|
||||
ICInstanceOf_Fallback::Compiler stubCompiler(cx);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_TYPEOF:
|
||||
case JSOP_TYPEOFEXPR: {
|
||||
ICTypeOf_Fallback::Compiler stubCompiler(cx);
|
||||
if (!addIC(pc, stubCompiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_ITER: {
|
||||
ICGetIterator_Fallback::Compiler compiler(cx);
|
||||
if (!addIC(pc, compiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_MOREITER: {
|
||||
ICIteratorMore_Fallback::Compiler compiler(cx);
|
||||
if (!addIC(pc, compiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_ENDITER: {
|
||||
ICIteratorClose_Fallback::Compiler compiler(cx);
|
||||
if (!addIC(pc, compiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_REST: {
|
||||
ArrayObject* templateObject =
|
||||
ObjectGroup::newArrayObject(cx, nullptr, 0, TenuredObject,
|
||||
ObjectGroup::NewArrayKind::UnknownIndex);
|
||||
if (!templateObject) {
|
||||
return nullptr;
|
||||
}
|
||||
ICRest_Fallback::Compiler compiler(cx, templateObject);
|
||||
if (!addIC(pc, compiler.getStub(&stubSpace))) {
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("JOF_IC op not handled");
|
||||
}
|
||||
}
|
||||
|
||||
UniquePtr<ICScript> icScript(
|
||||
script->zone()->pod_malloc_with_extra<ICScript, ICEntry>(icEntries.length()));
|
||||
if (!icScript) {
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
new (icScript.get()) ICScript(icEntries.length());
|
||||
|
||||
// Adopt fallback stubs into the ICScript.
|
||||
icScript->fallbackStubSpace_.adoptFrom(&stubSpace);
|
||||
|
||||
if (icEntries.length() > 0) {
|
||||
icScript->initICEntries(script, &icEntries[0]);
|
||||
}
|
||||
|
||||
return icScript;
|
||||
}
|
||||
|
||||
ICStubConstIterator&
|
||||
ICStubConstIterator::operator++()
|
||||
{
|
||||
|
@ -717,7 +1046,7 @@ ICMonitoredFallbackStub::initMonitoringChain(JSContext* cx, JSScript* script)
|
|||
MOZ_ASSERT(fallbackMonitorStub_ == nullptr);
|
||||
|
||||
ICTypeMonitor_Fallback::Compiler compiler(cx, this);
|
||||
ICStubSpace* space = script->baselineScript()->fallbackStubSpace();
|
||||
ICStubSpace* space = script->icScript()->fallbackStubSpace();
|
||||
ICTypeMonitor_Fallback* stub = compiler.getStub(space);
|
||||
if (!stub) {
|
||||
return false;
|
||||
|
@ -752,6 +1081,15 @@ ICUpdatedStub::initUpdatingChain(JSContext* cx, ICStubSpace* space)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* static */ ICStubSpace*
|
||||
ICStubCompiler::StubSpaceForStub(bool makesGCCalls, JSScript* script)
|
||||
{
|
||||
if (makesGCCalls) {
|
||||
return script->icScript()->fallbackStubSpace();
|
||||
}
|
||||
return script->zone()->jitZone()->optimizedStubSpace();
|
||||
}
|
||||
|
||||
JitCode*
|
||||
ICStubCompiler::getStubCode()
|
||||
{
|
||||
|
@ -891,9 +1229,8 @@ ICStubCompiler::PushStubPayload(MacroAssembler& masm, Register scratch)
|
|||
masm.adjustFrame(sizeof(intptr_t));
|
||||
}
|
||||
|
||||
//
|
||||
void
|
||||
BaselineScript::noteAccessedGetter(uint32_t pcOffset)
|
||||
ICScript::noteAccessedGetter(uint32_t pcOffset)
|
||||
{
|
||||
ICEntry& entry = icEntryFromPCOffset(pcOffset);
|
||||
ICFallbackStub* stub = entry.fallbackStub();
|
||||
|
@ -1698,11 +2035,9 @@ StripPreliminaryObjectStubs(JSContext* cx, ICFallbackStub* stub)
|
|||
//
|
||||
|
||||
static bool
|
||||
DoGetElemFallback(JSContext* cx, BaselineFrame* frame, ICGetElem_Fallback* stub_, HandleValue lhs,
|
||||
DoGetElemFallback(JSContext* cx, BaselineFrame* frame, ICGetElem_Fallback* stub, HandleValue lhs,
|
||||
HandleValue rhs, MutableHandleValue res)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICGetElem_Fallback*> stub(frame, stub_);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
RootedScript script(cx, frame->script());
|
||||
|
@ -1765,11 +2100,6 @@ DoGetElemFallback(JSContext* cx, BaselineFrame* frame, ICGetElem_Fallback* stub_
|
|||
TypeScript::Monitor(cx, script, pc, types, res);
|
||||
}
|
||||
|
||||
// Check if debug mode toggling made the stub invalid.
|
||||
if (stub.invalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add a type monitor stub for the resulting value.
|
||||
if (!stub->addMonitorStubForValue(cx, frame, types, res)) {
|
||||
return false;
|
||||
|
@ -1790,12 +2120,10 @@ DoGetElemFallback(JSContext* cx, BaselineFrame* frame, ICGetElem_Fallback* stub_
|
|||
}
|
||||
|
||||
static bool
|
||||
DoGetElemSuperFallback(JSContext* cx, BaselineFrame* frame, ICGetElem_Fallback* stub_,
|
||||
DoGetElemSuperFallback(JSContext* cx, BaselineFrame* frame, ICGetElem_Fallback* stub,
|
||||
HandleValue lhs, HandleValue rhs, HandleValue receiver,
|
||||
MutableHandleValue res)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICGetElem_Fallback*> stub(frame, stub_);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
RootedScript script(cx, frame->script());
|
||||
|
@ -1843,11 +2171,6 @@ DoGetElemSuperFallback(JSContext* cx, BaselineFrame* frame, ICGetElem_Fallback*
|
|||
}
|
||||
TypeScript::Monitor(cx, script, pc, types, res);
|
||||
|
||||
// Check if debug mode toggling made the stub invalid.
|
||||
if (stub.invalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add a type monitor stub for the resulting value.
|
||||
if (!stub->addMonitorStubForValue(cx, frame, types, res)) {
|
||||
return false;
|
||||
|
@ -1931,11 +2254,9 @@ SetUpdateStubData(ICCacheIR_Updated* stub, const PropertyTypeCheckInfo* info)
|
|||
}
|
||||
|
||||
static bool
|
||||
DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_, Value* stack,
|
||||
DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub, Value* stack,
|
||||
HandleValue objv, HandleValue index, HandleValue rhs)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICSetElem_Fallback*> stub(frame, stub_);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
RootedScript script(cx, frame->script());
|
||||
|
@ -2034,11 +2355,6 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
|
|||
MOZ_ASSERT(stack[2] == objv);
|
||||
stack[2] = rhs;
|
||||
|
||||
// Check if debug mode toggling made the stub invalid.
|
||||
if (stub.invalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (attached) {
|
||||
return true;
|
||||
}
|
||||
|
@ -2122,7 +2438,7 @@ ICSetElem_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
}
|
||||
|
||||
void
|
||||
BaselineScript::noteHasDenseAdd(uint32_t pcOffset)
|
||||
ICScript::noteHasDenseAdd(uint32_t pcOffset)
|
||||
{
|
||||
ICEntry& entry = icEntryFromPCOffset(pcOffset);
|
||||
ICFallbackStub* stub = entry.fallbackStub();
|
||||
|
@ -2222,11 +2538,9 @@ StoreToTypedArray(JSContext* cx, MacroAssembler& masm, Scalar::Type type,
|
|||
//
|
||||
|
||||
static bool
|
||||
DoInFallback(JSContext* cx, BaselineFrame* frame, ICIn_Fallback* stub_,
|
||||
DoInFallback(JSContext* cx, BaselineFrame* frame, ICIn_Fallback* stub,
|
||||
HandleValue key, HandleValue objValue, MutableHandleValue res)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICIn_Fallback*> stub(frame, stub_);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
FallbackICSpew(cx, stub, "In");
|
||||
|
@ -2276,11 +2590,9 @@ ICIn_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
//
|
||||
|
||||
static bool
|
||||
DoHasOwnFallback(JSContext* cx, BaselineFrame* frame, ICHasOwn_Fallback* stub_,
|
||||
DoHasOwnFallback(JSContext* cx, BaselineFrame* frame, ICHasOwn_Fallback* stub,
|
||||
HandleValue keyValue, HandleValue objValue, MutableHandleValue res)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICIn_Fallback*> stub(frame, stub_);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
FallbackICSpew(cx, stub, "HasOwn");
|
||||
|
@ -2327,11 +2639,9 @@ ICHasOwn_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
//
|
||||
|
||||
static bool
|
||||
DoGetNameFallback(JSContext* cx, BaselineFrame* frame, ICGetName_Fallback* stub_,
|
||||
DoGetNameFallback(JSContext* cx, BaselineFrame* frame, ICGetName_Fallback* stub,
|
||||
HandleObject envChain, MutableHandleValue res)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICGetName_Fallback*> stub(frame, stub_);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
RootedScript script(cx, frame->script());
|
||||
|
@ -2360,11 +2670,6 @@ DoGetNameFallback(JSContext* cx, BaselineFrame* frame, ICGetName_Fallback* stub_
|
|||
StackTypeSet* types = TypeScript::BytecodeTypes(script, pc);
|
||||
TypeScript::Monitor(cx, script, pc, types, res);
|
||||
|
||||
// Check if debug mode toggling made the stub invalid.
|
||||
if (stub.invalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add a type monitor stub for the resulting value.
|
||||
if (!stub->addMonitorStubForValue(cx, frame, types, res)) {
|
||||
return false;
|
||||
|
@ -2445,11 +2750,9 @@ ICBindName_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
//
|
||||
|
||||
static bool
|
||||
DoGetIntrinsicFallback(JSContext* cx, BaselineFrame* frame, ICGetIntrinsic_Fallback* stub_,
|
||||
DoGetIntrinsicFallback(JSContext* cx, BaselineFrame* frame, ICGetIntrinsic_Fallback* stub,
|
||||
MutableHandleValue res)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICGetIntrinsic_Fallback*> stub(frame, stub_);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
RootedScript script(cx, frame->script());
|
||||
|
@ -2469,11 +2772,6 @@ DoGetIntrinsicFallback(JSContext* cx, BaselineFrame* frame, ICGetIntrinsic_Fallb
|
|||
|
||||
TypeScript::Monitor(cx, script, pc, res);
|
||||
|
||||
// Check if debug mode toggling made the stub invalid.
|
||||
if (stub.invalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
TryAttachStub<GetIntrinsicIRGenerator>("GetIntrinsic", cx, frame, stub, BaselineCacheIRStubKind::Regular, res);
|
||||
|
||||
return true;
|
||||
|
@ -2533,15 +2831,13 @@ ComputeGetPropResult(JSContext* cx, BaselineFrame* frame, JSOp op, HandlePropert
|
|||
}
|
||||
|
||||
static bool
|
||||
DoGetPropFallback(JSContext* cx, BaselineFrame* frame, ICGetProp_Fallback* stub_,
|
||||
DoGetPropFallback(JSContext* cx, BaselineFrame* frame, ICGetProp_Fallback* stub,
|
||||
MutableHandleValue val, MutableHandleValue res)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICGetProp_Fallback*> stub(frame, stub_);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
RootedScript script(cx, frame->script());
|
||||
jsbytecode* pc = stub_->icEntry()->pc(script);
|
||||
jsbytecode* pc = stub->icEntry()->pc(script);
|
||||
JSOp op = JSOp(*pc);
|
||||
FallbackICSpew(cx, stub, "GetProp(%s)", CodeName[op]);
|
||||
|
||||
|
@ -2593,11 +2889,6 @@ DoGetPropFallback(JSContext* cx, BaselineFrame* frame, ICGetProp_Fallback* stub_
|
|||
StackTypeSet* types = TypeScript::BytecodeTypes(script, pc);
|
||||
TypeScript::Monitor(cx, script, pc, types, res);
|
||||
|
||||
// Check if debug mode toggling made the stub invalid.
|
||||
if (stub.invalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add a type monitor stub for the resulting value.
|
||||
if (!stub->addMonitorStubForValue(cx, frame, types, res)) {
|
||||
return false;
|
||||
|
@ -2606,15 +2897,13 @@ DoGetPropFallback(JSContext* cx, BaselineFrame* frame, ICGetProp_Fallback* stub_
|
|||
}
|
||||
|
||||
static bool
|
||||
DoGetPropSuperFallback(JSContext* cx, BaselineFrame* frame, ICGetProp_Fallback* stub_,
|
||||
DoGetPropSuperFallback(JSContext* cx, BaselineFrame* frame, ICGetProp_Fallback* stub,
|
||||
HandleValue receiver, MutableHandleValue val, MutableHandleValue res)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICGetProp_Fallback*> stub(frame, stub_);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
RootedScript script(cx, frame->script());
|
||||
jsbytecode* pc = stub_->icEntry()->pc(script);
|
||||
jsbytecode* pc = stub->icEntry()->pc(script);
|
||||
FallbackICSpew(cx, stub, "GetPropSuper(%s)", CodeName[JSOp(*pc)]);
|
||||
|
||||
MOZ_ASSERT(JSOp(*pc) == JSOP_GETPROP_SUPER);
|
||||
|
@ -2664,11 +2953,6 @@ DoGetPropSuperFallback(JSContext* cx, BaselineFrame* frame, ICGetProp_Fallback*
|
|||
StackTypeSet* types = TypeScript::BytecodeTypes(script, pc);
|
||||
TypeScript::Monitor(cx, script, pc, types, res);
|
||||
|
||||
// Check if debug mode toggling made the stub invalid.
|
||||
if (stub.invalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add a type monitor stub for the resulting value.
|
||||
if (!stub->addMonitorStubForValue(cx, frame, types, res)) {
|
||||
return false;
|
||||
|
@ -2754,11 +3038,9 @@ ICGetProp_Fallback::Compiler::postGenerateStubCode(MacroAssembler& masm, Handle<
|
|||
//
|
||||
|
||||
static bool
|
||||
DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_, Value* stack,
|
||||
DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub, Value* stack,
|
||||
HandleValue lhs, HandleValue rhs)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICSetProp_Fallback*> stub(frame, stub_);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
RootedScript script(cx, frame->script());
|
||||
|
@ -2878,11 +3160,6 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_
|
|||
MOZ_ASSERT(stack[1] == lhs);
|
||||
stack[1] = rhs;
|
||||
|
||||
// Check if debug mode toggling made the stub invalid.
|
||||
if (stub.invalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (attached) {
|
||||
return true;
|
||||
}
|
||||
|
@ -3570,11 +3847,9 @@ TryAttachConstStringSplit(JSContext* cx, ICCall_Fallback* stub, HandleScript scr
|
|||
}
|
||||
|
||||
static bool
|
||||
DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_, uint32_t argc,
|
||||
DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub, uint32_t argc,
|
||||
Value* vp, MutableHandleValue res)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICCall_Fallback*> stub(frame, stub_);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
RootedScript script(cx, frame->script());
|
||||
|
@ -3675,11 +3950,6 @@ DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_, uint
|
|||
StackTypeSet* types = TypeScript::BytecodeTypes(script, pc);
|
||||
TypeScript::Monitor(cx, script, pc, types, res);
|
||||
|
||||
// Check if debug mode toggling made the stub invalid.
|
||||
if (stub.invalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add a type monitor stub for the resulting value.
|
||||
if (!stub->addMonitorStubForValue(cx, frame, types, res)) {
|
||||
return false;
|
||||
|
@ -3709,11 +3979,9 @@ DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_, uint
|
|||
}
|
||||
|
||||
static bool
|
||||
DoSpreadCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_, Value* vp,
|
||||
DoSpreadCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub, Value* vp,
|
||||
MutableHandleValue res)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICCall_Fallback*> stub(frame, stub_);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
RootedScript script(cx, frame->script());
|
||||
|
@ -3743,11 +4011,6 @@ DoSpreadCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub_
|
|||
return false;
|
||||
}
|
||||
|
||||
// Check if debug mode toggling made the stub invalid.
|
||||
if (stub.invalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add a type monitor stub for the resulting value.
|
||||
StackTypeSet* types = TypeScript::BytecodeTypes(script, pc);
|
||||
if (!stub->addMonitorStubForValue(cx, frame, types, res)) {
|
||||
|
@ -5141,11 +5404,9 @@ ICGetIterator_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
//
|
||||
|
||||
static bool
|
||||
DoIteratorMoreFallback(JSContext* cx, BaselineFrame* frame, ICIteratorMore_Fallback* stub_,
|
||||
DoIteratorMoreFallback(JSContext* cx, BaselineFrame* frame, ICIteratorMore_Fallback* stub,
|
||||
HandleObject iterObj, MutableHandleValue res)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICIteratorMore_Fallback*> stub(frame, stub_);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
FallbackICSpew(cx, stub, "IteratorMore");
|
||||
|
@ -5154,11 +5415,6 @@ DoIteratorMoreFallback(JSContext* cx, BaselineFrame* frame, ICIteratorMore_Fallb
|
|||
return false;
|
||||
}
|
||||
|
||||
// Check if debug mode toggling made the stub invalid.
|
||||
if (stub.invalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!res.isMagic(JS_NO_ITER_VALUE) && !res.isString()) {
|
||||
stub->setHasNonStringResult();
|
||||
}
|
||||
|
@ -5275,11 +5531,9 @@ ICIteratorClose_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
//
|
||||
|
||||
static bool
|
||||
DoInstanceOfFallback(JSContext* cx, BaselineFrame* frame, ICInstanceOf_Fallback* stub_,
|
||||
DoInstanceOfFallback(JSContext* cx, BaselineFrame* frame, ICInstanceOf_Fallback* stub,
|
||||
HandleValue lhs, HandleValue rhs, MutableHandleValue res)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICInstanceOf_Fallback*> stub(frame, stub_);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
FallbackICSpew(cx, stub, "InstanceOf");
|
||||
|
@ -5297,11 +5551,6 @@ DoInstanceOfFallback(JSContext* cx, BaselineFrame* frame, ICInstanceOf_Fallback*
|
|||
|
||||
res.setBoolean(cond);
|
||||
|
||||
// Check if debug mode toggling made the stub invalid.
|
||||
if (stub.invalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!obj->is<JSFunction>()) {
|
||||
// ensure we've recorded at least one failure, so we can detect there was a non-optimizable case
|
||||
if (!stub->state().hasFailures()) {
|
||||
|
@ -5406,21 +5655,6 @@ ICCall_Scripted::ICCall_Scripted(JitCode* stubCode, ICStub* firstMonitorStub,
|
|||
pcOffset_(pcOffset)
|
||||
{ }
|
||||
|
||||
/* static */ ICCall_Scripted*
|
||||
ICCall_Scripted::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
|
||||
ICCall_Scripted& other)
|
||||
{
|
||||
return New<ICCall_Scripted>(cx, space, other.jitCode(), firstMonitorStub, other.callee_,
|
||||
other.templateObject_, other.pcOffset_);
|
||||
}
|
||||
|
||||
/* static */ ICCall_AnyScripted*
|
||||
ICCall_AnyScripted::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
|
||||
ICCall_AnyScripted& other)
|
||||
{
|
||||
return New<ICCall_AnyScripted>(cx, space, other.jitCode(), firstMonitorStub, other.pcOffset_);
|
||||
}
|
||||
|
||||
ICCall_Native::ICCall_Native(JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
JSFunction* callee, JSObject* templateObject,
|
||||
uint32_t pcOffset)
|
||||
|
@ -5438,14 +5672,6 @@ ICCall_Native::ICCall_Native(JitCode* stubCode, ICStub* firstMonitorStub,
|
|||
#endif
|
||||
}
|
||||
|
||||
/* static */ ICCall_Native*
|
||||
ICCall_Native::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
|
||||
ICCall_Native& other)
|
||||
{
|
||||
return New<ICCall_Native>(cx, space, other.jitCode(), firstMonitorStub, other.callee_,
|
||||
other.templateObject_, other.pcOffset_);
|
||||
}
|
||||
|
||||
ICCall_ClassHook::ICCall_ClassHook(JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
const Class* clasp, Native native,
|
||||
JSObject* templateObject, uint32_t pcOffset)
|
||||
|
@ -5463,45 +5689,6 @@ ICCall_ClassHook::ICCall_ClassHook(JitCode* stubCode, ICStub* firstMonitorStub,
|
|||
#endif
|
||||
}
|
||||
|
||||
/* static */ ICCall_ClassHook*
|
||||
ICCall_ClassHook::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
|
||||
ICCall_ClassHook& other)
|
||||
{
|
||||
ICCall_ClassHook* res = New<ICCall_ClassHook>(cx, space, other.jitCode(), firstMonitorStub,
|
||||
other.clasp(), nullptr, other.templateObject_,
|
||||
other.pcOffset_);
|
||||
if (res) {
|
||||
res->native_ = other.native();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* static */ ICCall_ScriptedApplyArray*
|
||||
ICCall_ScriptedApplyArray::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
|
||||
ICCall_ScriptedApplyArray& other)
|
||||
{
|
||||
return New<ICCall_ScriptedApplyArray>(cx, space, other.jitCode(), firstMonitorStub,
|
||||
other.pcOffset_);
|
||||
}
|
||||
|
||||
/* static */ ICCall_ScriptedApplyArguments*
|
||||
ICCall_ScriptedApplyArguments::Clone(JSContext* cx,
|
||||
ICStubSpace* space,
|
||||
ICStub* firstMonitorStub,
|
||||
ICCall_ScriptedApplyArguments& other)
|
||||
{
|
||||
return New<ICCall_ScriptedApplyArguments>(cx, space, other.jitCode(), firstMonitorStub,
|
||||
other.pcOffset_);
|
||||
}
|
||||
|
||||
/* static */ ICCall_ScriptedFunCall*
|
||||
ICCall_ScriptedFunCall::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
|
||||
ICCall_ScriptedFunCall& other)
|
||||
{
|
||||
return New<ICCall_ScriptedFunCall>(cx, space, other.jitCode(), firstMonitorStub,
|
||||
other.pcOffset_);
|
||||
}
|
||||
|
||||
//
|
||||
// Rest_Fallback
|
||||
//
|
||||
|
@ -5548,8 +5735,6 @@ static bool
|
|||
DoUnaryArithFallback(JSContext* cx, BaselineFrame* frame, ICUnaryArith_Fallback* stub,
|
||||
HandleValue val, MutableHandleValue res)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICUnaryArith_Fallback*> debug_stub(frame, stub);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
RootedScript script(cx, frame->script());
|
||||
|
@ -5577,11 +5762,6 @@ DoUnaryArithFallback(JSContext* cx, BaselineFrame* frame, ICUnaryArith_Fallback*
|
|||
MOZ_CRASH("Unexpected op");
|
||||
}
|
||||
|
||||
// Check if debug mode toggling made the stub invalid.
|
||||
if (debug_stub.invalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (res.isDouble()) {
|
||||
stub->setSawDoubleResult();
|
||||
}
|
||||
|
@ -5620,11 +5800,9 @@ ICUnaryArith_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
//
|
||||
|
||||
static bool
|
||||
DoBinaryArithFallback(JSContext* cx, BaselineFrame* frame, ICBinaryArith_Fallback* stub_,
|
||||
DoBinaryArithFallback(JSContext* cx, BaselineFrame* frame, ICBinaryArith_Fallback* stub,
|
||||
HandleValue lhs, HandleValue rhs, MutableHandleValue ret)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICBinaryArith_Fallback*> stub(frame, stub_);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
RootedScript script(cx, frame->script());
|
||||
|
@ -5712,11 +5890,6 @@ DoBinaryArithFallback(JSContext* cx, BaselineFrame* frame, ICBinaryArith_Fallbac
|
|||
MOZ_CRASH("Unhandled baseline arith op");
|
||||
}
|
||||
|
||||
// Check if debug mode toggling made the stub invalid.
|
||||
if (stub.invalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ret.isDouble()) {
|
||||
stub->setSawDoubleResult();
|
||||
}
|
||||
|
@ -5756,11 +5929,9 @@ ICBinaryArith_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
// Compare_Fallback
|
||||
//
|
||||
static bool
|
||||
DoCompareFallback(JSContext* cx, BaselineFrame* frame, ICCompare_Fallback* stub_, HandleValue lhs,
|
||||
DoCompareFallback(JSContext* cx, BaselineFrame* frame, ICCompare_Fallback* stub, HandleValue lhs,
|
||||
HandleValue rhs, MutableHandleValue ret)
|
||||
{
|
||||
// This fallback stub may trigger debug mode toggling.
|
||||
DebugModeOSRVolatileStub<ICCompare_Fallback*> stub(frame, stub_);
|
||||
stub->incrementEnteredCount();
|
||||
|
||||
RootedScript script(cx, frame->script());
|
||||
|
@ -5824,11 +5995,6 @@ DoCompareFallback(JSContext* cx, BaselineFrame* frame, ICCompare_Fallback* stub_
|
|||
|
||||
ret.setBoolean(out);
|
||||
|
||||
// Check if debug mode toggling made the stub invalid.
|
||||
if (stub.invalid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
TryAttachStub<CompareIRGenerator>("Compare", cx, frame, stub, BaselineCacheIRStubKind::Regular, op, lhs, rhs);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -222,19 +222,18 @@ class ICEntry
|
|||
ICStub* firstStub_;
|
||||
|
||||
// The PC of this IC's bytecode op within the JSScript.
|
||||
uint32_t pcOffset_ : 31;
|
||||
uint32_t isForOp_ : 1;
|
||||
uint32_t pcOffset_;
|
||||
|
||||
public:
|
||||
ICEntry(ICStub* firstStub, uint32_t pcOffset, bool isForOp)
|
||||
: firstStub_(firstStub), pcOffset_(pcOffset), isForOp_(uint32_t(isForOp))
|
||||
{
|
||||
// The offset must fit in at least 31 bits, since we shave off 1 for
|
||||
// the isForOp_ flag.
|
||||
MOZ_ASSERT(pcOffset_ == pcOffset);
|
||||
JS_STATIC_ASSERT(BaselineMaxScriptLength <= (1u << 31) - 1);
|
||||
MOZ_ASSERT(pcOffset <= BaselineMaxScriptLength);
|
||||
}
|
||||
// Non-op ICs are Baseline ICs used for function argument/this type
|
||||
// monitoring in the script's prologue. All other ICs are "for op" ICs.
|
||||
// Note: the last bytecode op in a script is always a return so UINT32_MAX
|
||||
// is never a valid bytecode offset.
|
||||
static constexpr uint32_t NonOpPCOffset = UINT32_MAX;
|
||||
|
||||
ICEntry(ICStub* firstStub, uint32_t pcOffset)
|
||||
: firstStub_(firstStub), pcOffset_(pcOffset)
|
||||
{}
|
||||
|
||||
ICStub* firstStub() const {
|
||||
MOZ_ASSERT(firstStub_);
|
||||
|
@ -248,10 +247,10 @@ class ICEntry
|
|||
}
|
||||
|
||||
uint32_t pcOffset() const {
|
||||
return pcOffset_;
|
||||
return pcOffset_ == NonOpPCOffset ? 0 : pcOffset_;
|
||||
}
|
||||
jsbytecode* pc(JSScript* script) const {
|
||||
return script->offsetToPC(pcOffset_);
|
||||
return script->offsetToPC(pcOffset());
|
||||
}
|
||||
|
||||
static inline size_t offsetOfFirstStub() {
|
||||
|
@ -263,12 +262,111 @@ class ICEntry
|
|||
}
|
||||
|
||||
bool isForOp() const {
|
||||
return !!isForOp_;
|
||||
return pcOffset_ != NonOpPCOffset;
|
||||
}
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
};
|
||||
|
||||
// [SMDOC] ICScript
|
||||
//
|
||||
// ICScript contains IC data used by Baseline (Ion has its own IC chains, stored
|
||||
// in IonScript).
|
||||
//
|
||||
// For each IC we store an ICEntry, which points to the first ICStub in the
|
||||
// chain. Note that multiple stubs in the same zone can share Baseline IC code.
|
||||
// This works because the stub data is stored in the ICStub instead of baked in
|
||||
// in the stub code.
|
||||
//
|
||||
// Storing this separate from BaselineScript simplifies debug mode OSR because
|
||||
// the ICScript can be reused when we replace the BaselineScript. It also makes
|
||||
// it easier to experiment with interpreter ICs in the future because the
|
||||
// interpreter and Baseline JIT will be able to use exactly the same IC data.
|
||||
//
|
||||
// ICScript contains the following:
|
||||
//
|
||||
// * Fallback stub space: this stores all fallback stubs and the "can GC" stubs.
|
||||
// These stubs are never purged before destroying the ICScript. (Other stubs
|
||||
// are stored in the optimized stub space stored in JitZone and can be
|
||||
// discarded more eagerly. See ICScript::purgeOptimizedStubs.)
|
||||
//
|
||||
// * List of IC entries, in the following order:
|
||||
//
|
||||
// - Type monitor IC for |this|.
|
||||
// - Type monitor IC for each formal argument.
|
||||
// - IC for each JOF_IC bytecode op.
|
||||
//
|
||||
// ICScript is stored in TypeScript and allocated/destroyed at the same time.
|
||||
class ICScript
|
||||
{
|
||||
// Allocated space for fallback stubs.
|
||||
FallbackICStubSpace fallbackStubSpace_ = {};
|
||||
|
||||
uint32_t numICEntries_;
|
||||
|
||||
explicit ICScript(uint32_t numICEntries)
|
||||
: numICEntries_(numICEntries)
|
||||
{}
|
||||
|
||||
ICEntry* icEntryList() {
|
||||
return (ICEntry*)(reinterpret_cast<uint8_t*>(this) + sizeof(ICScript));
|
||||
}
|
||||
|
||||
void initICEntries(JSScript* script, const ICEntry* entries);
|
||||
|
||||
public:
|
||||
static MOZ_MUST_USE js::UniquePtr<ICScript> create(JSContext* cx, JSScript* script);
|
||||
|
||||
~ICScript() {
|
||||
// The contents of the fallback stub space are removed and freed
|
||||
// separately after the next minor GC. See prepareForDestruction.
|
||||
MOZ_ASSERT(fallbackStubSpace_.isEmpty());
|
||||
}
|
||||
void prepareForDestruction(Zone* zone) {
|
||||
// When the script contains pointers to nursery things, the store buffer can
|
||||
// contain entries that point into the fallback stub space. Since we can
|
||||
// destroy scripts outside the context of a GC, this situation could result
|
||||
// in us trying to mark invalid store buffer entries.
|
||||
//
|
||||
// Defer freeing any allocated blocks until after the next minor GC.
|
||||
fallbackStubSpace_.freeAllAfterMinorGC(zone);
|
||||
}
|
||||
|
||||
FallbackICStubSpace* fallbackStubSpace() {
|
||||
return &fallbackStubSpace_;
|
||||
}
|
||||
|
||||
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, size_t* data,
|
||||
size_t* fallbackStubs) const {
|
||||
*data += mallocSizeOf(this);
|
||||
|
||||
// |data| already includes the ICStubSpace itself, so use
|
||||
// sizeOfExcludingThis.
|
||||
*fallbackStubs += fallbackStubSpace_.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
size_t numICEntries() const {
|
||||
return numICEntries_;
|
||||
}
|
||||
|
||||
ICEntry& icEntry(size_t index) {
|
||||
MOZ_ASSERT(index < numICEntries());
|
||||
return icEntryList()[index];
|
||||
}
|
||||
|
||||
void noteAccessedGetter(uint32_t pcOffset);
|
||||
void noteHasDenseAdd(uint32_t pcOffset);
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
void purgeOptimizedStubs(Zone* zone);
|
||||
|
||||
ICEntry* maybeICEntryFromPCOffset(uint32_t pcOffset);
|
||||
ICEntry* maybeICEntryFromPCOffset(uint32_t pcOffset, ICEntry* prevLookedUpEntry);
|
||||
|
||||
ICEntry& icEntryFromPCOffset(uint32_t pcOffset);
|
||||
ICEntry& icEntryFromPCOffset(uint32_t pcOffset, ICEntry* prevLookedUpEntry);
|
||||
};
|
||||
|
||||
class ICMonitoredStub;
|
||||
class ICMonitoredFallbackStub;
|
||||
class ICUpdatedStub;
|
||||
|
@ -782,9 +880,6 @@ class ICCacheIR_Regular : public ICStub, public ICCacheIR_Trait<ICCacheIR_Regula
|
|||
ICCacheIR_Trait(stubInfo)
|
||||
{}
|
||||
|
||||
static ICCacheIR_Regular* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
|
||||
ICCacheIR_Regular& other);
|
||||
|
||||
void notePreliminaryObject() {
|
||||
extra_ = 1;
|
||||
}
|
||||
|
@ -835,9 +930,6 @@ class ICCacheIR_Monitored : public ICMonitoredStub, public ICCacheIR_Trait<ICCac
|
|||
ICCacheIR_Trait(stubInfo)
|
||||
{}
|
||||
|
||||
static ICCacheIR_Monitored* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
|
||||
ICCacheIR_Monitored& other);
|
||||
|
||||
void notePreliminaryObject() {
|
||||
extra_ = 1;
|
||||
}
|
||||
|
@ -930,9 +1022,6 @@ class ICCacheIR_Updated : public ICUpdatedStub, public ICCacheIR_Trait<ICCacheIR
|
|||
updateStubId_(JSID_EMPTY)
|
||||
{}
|
||||
|
||||
static ICCacheIR_Updated* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
|
||||
ICCacheIR_Updated& other);
|
||||
|
||||
GCPtrObjectGroup& updateStubGroup() {
|
||||
return updateStubGroup_;
|
||||
}
|
||||
|
@ -1051,12 +1140,8 @@ class ICStubCompiler
|
|||
public:
|
||||
virtual ICStub* getStub(ICStubSpace* space) = 0;
|
||||
|
||||
static ICStubSpace* StubSpaceForStub(bool makesGCCalls, JSScript* outerScript) {
|
||||
if (makesGCCalls) {
|
||||
return outerScript->baselineScript()->fallbackStubSpace();
|
||||
}
|
||||
return outerScript->zone()->jitZone()->optimizedStubSpace();
|
||||
}
|
||||
static ICStubSpace* StubSpaceForStub(bool makesGCCalls, JSScript* script);
|
||||
|
||||
ICStubSpace* getStubSpace(JSScript* outerScript) {
|
||||
return StubSpaceForStub(ICStub::NonCacheIRStubMakesGCCalls(kind), outerScript);
|
||||
}
|
||||
|
@ -2114,9 +2199,6 @@ class ICCall_Scripted : public ICMonitoredStub
|
|||
uint32_t pcOffset);
|
||||
|
||||
public:
|
||||
static ICCall_Scripted* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
|
||||
ICCall_Scripted& other);
|
||||
|
||||
GCPtrFunction& callee() {
|
||||
return callee_;
|
||||
}
|
||||
|
@ -2145,9 +2227,6 @@ class ICCall_AnyScripted : public ICMonitoredStub
|
|||
{ }
|
||||
|
||||
public:
|
||||
static ICCall_AnyScripted* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
|
||||
ICCall_AnyScripted& other);
|
||||
|
||||
static size_t offsetOfPCOffset() {
|
||||
return offsetof(ICCall_AnyScripted, pcOffset_);
|
||||
}
|
||||
|
@ -2226,9 +2305,6 @@ class ICCall_Native : public ICMonitoredStub
|
|||
uint32_t pcOffset);
|
||||
|
||||
public:
|
||||
static ICCall_Native* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
|
||||
ICCall_Native& other);
|
||||
|
||||
GCPtrFunction& callee() {
|
||||
return callee_;
|
||||
}
|
||||
|
@ -2308,9 +2384,6 @@ class ICCall_ClassHook : public ICMonitoredStub
|
|||
uint32_t pcOffset);
|
||||
|
||||
public:
|
||||
static ICCall_ClassHook* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
|
||||
ICCall_ClassHook& other);
|
||||
|
||||
const Class* clasp() {
|
||||
return clasp_;
|
||||
}
|
||||
|
@ -2386,11 +2459,6 @@ class ICCall_ScriptedApplyArray : public ICMonitoredStub
|
|||
{}
|
||||
|
||||
public:
|
||||
static ICCall_ScriptedApplyArray* Clone(JSContext* cx,
|
||||
ICStubSpace* space,
|
||||
ICStub* firstMonitorStub,
|
||||
ICCall_ScriptedApplyArray& other);
|
||||
|
||||
static size_t offsetOfPCOffset() {
|
||||
return offsetof(ICCall_ScriptedApplyArray, pcOffset_);
|
||||
}
|
||||
|
@ -2429,11 +2497,6 @@ class ICCall_ScriptedApplyArguments : public ICMonitoredStub
|
|||
{}
|
||||
|
||||
public:
|
||||
static ICCall_ScriptedApplyArguments* Clone(JSContext* cx,
|
||||
ICStubSpace* space,
|
||||
ICStub* firstMonitorStub,
|
||||
ICCall_ScriptedApplyArguments& other);
|
||||
|
||||
static size_t offsetOfPCOffset() {
|
||||
return offsetof(ICCall_ScriptedApplyArguments, pcOffset_);
|
||||
}
|
||||
|
@ -2473,9 +2536,6 @@ class ICCall_ScriptedFunCall : public ICMonitoredStub
|
|||
{}
|
||||
|
||||
public:
|
||||
static ICCall_ScriptedFunCall* Clone(JSContext* cx, ICStubSpace* space,
|
||||
ICStub* firstMonitorStub, ICCall_ScriptedFunCall& other);
|
||||
|
||||
static size_t offsetOfPCOffset() {
|
||||
return offsetof(ICCall_ScriptedFunCall, pcOffset_);
|
||||
}
|
||||
|
|
|
@ -236,6 +236,36 @@ GetCacheIRReceiverForUnboxedProperty(ICCacheIR_Updated* stub, ReceiverGuard* rec
|
|||
return true;
|
||||
}
|
||||
|
||||
ICScript*
|
||||
BaselineInspector::icScript() const
|
||||
{
|
||||
return script->icScript();
|
||||
}
|
||||
|
||||
ICEntry&
|
||||
BaselineInspector::icEntryFromPC(jsbytecode* pc)
|
||||
{
|
||||
ICEntry* entry = maybeICEntryFromPC(pc);
|
||||
MOZ_ASSERT(entry);
|
||||
return *entry;
|
||||
}
|
||||
|
||||
ICEntry*
|
||||
BaselineInspector::maybeICEntryFromPC(jsbytecode* pc)
|
||||
{
|
||||
MOZ_ASSERT(hasICScript());
|
||||
MOZ_ASSERT(isValidPC(pc));
|
||||
ICEntry* ent =
|
||||
icScript()->maybeICEntryFromPCOffset(script->pcToOffset(pc), prevLookedUpEntry);
|
||||
if (!ent) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(ent->isForOp());
|
||||
prevLookedUpEntry = ent;
|
||||
return ent;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers,
|
||||
ObjectGroupVector& convertUnboxedGroups)
|
||||
|
@ -248,7 +278,7 @@ BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receiv
|
|||
MOZ_ASSERT(receivers.empty());
|
||||
MOZ_ASSERT(convertUnboxedGroups.empty());
|
||||
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -299,7 +329,7 @@ BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receiv
|
|||
ICStub*
|
||||
BaselineInspector::monomorphicStub(jsbytecode* pc)
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -324,7 +354,7 @@ BaselineInspector::monomorphicStub(jsbytecode* pc)
|
|||
bool
|
||||
BaselineInspector::dimorphicStub(jsbytecode* pc, ICStub** pfirst, ICStub** psecond)
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -683,7 +713,7 @@ TryToSpecializeBinaryArithOp(ICStub** stubs,
|
|||
MIRType
|
||||
BaselineInspector::expectedBinaryArithSpecialization(jsbytecode* pc)
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return MIRType::None;
|
||||
}
|
||||
|
||||
|
@ -716,7 +746,7 @@ BaselineInspector::expectedBinaryArithSpecialization(jsbytecode* pc)
|
|||
bool
|
||||
BaselineInspector::hasSeenNegativeIndexGetElement(jsbytecode* pc)
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -732,7 +762,7 @@ BaselineInspector::hasSeenNegativeIndexGetElement(jsbytecode* pc)
|
|||
bool
|
||||
BaselineInspector::hasSeenAccessedGetter(jsbytecode* pc)
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -750,7 +780,7 @@ BaselineInspector::hasSeenNonStringIterMore(jsbytecode* pc)
|
|||
{
|
||||
MOZ_ASSERT(JSOp(*pc) == JSOP_MOREITER);
|
||||
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -763,7 +793,7 @@ BaselineInspector::hasSeenNonStringIterMore(jsbytecode* pc)
|
|||
bool
|
||||
BaselineInspector::hasSeenDoubleResult(jsbytecode* pc)
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -782,7 +812,7 @@ BaselineInspector::hasSeenDoubleResult(jsbytecode* pc)
|
|||
JSObject*
|
||||
BaselineInspector::getTemplateObject(jsbytecode* pc)
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -811,7 +841,7 @@ BaselineInspector::getTemplateObject(jsbytecode* pc)
|
|||
ObjectGroup*
|
||||
BaselineInspector::getTemplateObjectGroup(jsbytecode* pc)
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -833,7 +863,7 @@ BaselineInspector::getSingleCallee(jsbytecode* pc)
|
|||
{
|
||||
MOZ_ASSERT(*pc == JSOP_NEW);
|
||||
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -854,7 +884,7 @@ BaselineInspector::getSingleCallee(jsbytecode* pc)
|
|||
JSObject*
|
||||
BaselineInspector::getTemplateObjectForNative(jsbytecode* pc, Native native)
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -872,7 +902,7 @@ bool
|
|||
BaselineInspector::isOptimizableConstStringSplit(jsbytecode* pc, JSString** strOut,
|
||||
JSString** sepOut, ArrayObject** objOut)
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -897,7 +927,7 @@ BaselineInspector::isOptimizableConstStringSplit(jsbytecode* pc, JSString** strO
|
|||
JSObject*
|
||||
BaselineInspector::getTemplateObjectForClassHook(jsbytecode* pc, const Class* clasp)
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -914,11 +944,11 @@ BaselineInspector::getTemplateObjectForClassHook(jsbytecode* pc, const Class* cl
|
|||
LexicalEnvironmentObject*
|
||||
BaselineInspector::templateNamedLambdaObject()
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!script->hasBaselineScript()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSObject* res = baselineScript()->templateEnvironment();
|
||||
JSObject* res = script->baselineScript()->templateEnvironment();
|
||||
if (script->bodyScope()->hasEnvironment()) {
|
||||
res = res->enclosingEnvironment();
|
||||
}
|
||||
|
@ -930,11 +960,11 @@ BaselineInspector::templateNamedLambdaObject()
|
|||
CallObject*
|
||||
BaselineInspector::templateCallObject()
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!script->hasBaselineScript()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSObject* res = baselineScript()->templateEnvironment();
|
||||
JSObject* res = script->baselineScript()->templateEnvironment();
|
||||
MOZ_ASSERT(res);
|
||||
|
||||
return &res->as<CallObject>();
|
||||
|
@ -1222,7 +1252,7 @@ BaselineInspector::commonGetPropFunction(jsbytecode* pc, bool innerized,
|
|||
ReceiverVector& receivers,
|
||||
ObjectGroupVector& convertUnboxedGroups)
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1291,7 +1321,7 @@ bool
|
|||
BaselineInspector::megamorphicGetterSetterFunction(jsbytecode* pc, bool isGetter,
|
||||
JSFunction** getterOrSetter)
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1448,7 +1478,7 @@ BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shap
|
|||
ReceiverVector& receivers,
|
||||
ObjectGroupVector& convertUnboxedGroups)
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1548,7 +1578,7 @@ BaselineInspector::maybeInfoForProtoReadSlot(jsbytecode* pc, ReceiverVector& rec
|
|||
MOZ_ASSERT(convertUnboxedGroups.empty());
|
||||
MOZ_ASSERT(!*holder);
|
||||
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1613,7 +1643,7 @@ GetCacheIRExpectedInputType(ICCacheIR_Monitored* stub)
|
|||
MIRType
|
||||
BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc)
|
||||
{
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return MIRType::Value;
|
||||
}
|
||||
|
||||
|
@ -1653,7 +1683,7 @@ BaselineInspector::instanceOfData(jsbytecode* pc, Shape** shape, uint32_t* slot,
|
|||
JSObject** prototypeObject)
|
||||
{
|
||||
MOZ_ASSERT(*pc == JSOP_INSTANCEOF);
|
||||
if (!hasBaselineScript()) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,13 +52,11 @@ class BaselineInspector
|
|||
MOZ_ASSERT(script);
|
||||
}
|
||||
|
||||
bool hasBaselineScript() const {
|
||||
return script->hasBaselineScript();
|
||||
bool hasICScript() const {
|
||||
return script->hasICScript();
|
||||
}
|
||||
|
||||
BaselineScript* baselineScript() const {
|
||||
return script->baselineScript();
|
||||
}
|
||||
ICScript* icScript() const;
|
||||
|
||||
private:
|
||||
#ifdef DEBUG
|
||||
|
@ -67,33 +65,13 @@ class BaselineInspector
|
|||
}
|
||||
#endif
|
||||
|
||||
ICEntry& icEntryFromPC(jsbytecode* pc) {
|
||||
MOZ_ASSERT(hasBaselineScript());
|
||||
MOZ_ASSERT(isValidPC(pc));
|
||||
ICEntry& ent =
|
||||
baselineScript()->icEntryFromPCOffset(script->pcToOffset(pc), prevLookedUpEntry);
|
||||
MOZ_ASSERT(ent.isForOp());
|
||||
prevLookedUpEntry = &ent;
|
||||
return ent;
|
||||
}
|
||||
|
||||
ICEntry* maybeICEntryFromPC(jsbytecode* pc) {
|
||||
MOZ_ASSERT(hasBaselineScript());
|
||||
MOZ_ASSERT(isValidPC(pc));
|
||||
ICEntry* ent =
|
||||
baselineScript()->maybeICEntryFromPCOffset(script->pcToOffset(pc), prevLookedUpEntry);
|
||||
if (!ent) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(ent->isForOp());
|
||||
prevLookedUpEntry = ent;
|
||||
return ent;
|
||||
}
|
||||
ICEntry& icEntryFromPC(jsbytecode* pc);
|
||||
ICEntry* maybeICEntryFromPC(jsbytecode* pc);
|
||||
|
||||
template <typename ICInspectorType>
|
||||
ICInspectorType makeICInspector(jsbytecode* pc, ICStub::Kind expectedFallbackKind) {
|
||||
ICEntry* ent = nullptr;
|
||||
if (hasBaselineScript()) {
|
||||
if (hasICScript()) {
|
||||
ent = &icEntryFromPC(pc);
|
||||
MOZ_ASSERT(ent->fallbackStub()->kind() == expectedFallbackKind);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "jit/IonControlFlow.h"
|
||||
#include "jit/JitCommon.h"
|
||||
#include "jit/JitSpewer.h"
|
||||
#include "util/StructuredSpewer.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
@ -352,7 +353,6 @@ BaselineScript::New(JSScript* jsscript,
|
|||
uint32_t debugOsrEpilogueOffset,
|
||||
uint32_t profilerEnterToggleOffset,
|
||||
uint32_t profilerExitToggleOffset,
|
||||
size_t icEntries,
|
||||
size_t retAddrEntries,
|
||||
size_t pcMappingIndexEntries, size_t pcMappingSize,
|
||||
size_t bytecodeTypeMapEntries,
|
||||
|
@ -361,14 +361,12 @@ BaselineScript::New(JSScript* jsscript,
|
|||
{
|
||||
static const unsigned DataAlignment = sizeof(uintptr_t);
|
||||
|
||||
size_t icEntriesSize = icEntries * sizeof(ICEntry);
|
||||
size_t retAddrEntriesSize = retAddrEntries * sizeof(RetAddrEntry);
|
||||
size_t pcMappingIndexEntriesSize = pcMappingIndexEntries * sizeof(PCMappingIndexEntry);
|
||||
size_t bytecodeTypeMapSize = bytecodeTypeMapEntries * sizeof(uint32_t);
|
||||
size_t resumeEntriesSize = resumeEntries * sizeof(uintptr_t);
|
||||
size_t tlEntriesSize = traceLoggerToggleOffsetEntries * sizeof(uint32_t);
|
||||
|
||||
size_t paddedICEntriesSize = AlignBytes(icEntriesSize, DataAlignment);
|
||||
size_t paddedRetAddrEntriesSize = AlignBytes(retAddrEntriesSize, DataAlignment);
|
||||
size_t paddedPCMappingIndexEntriesSize = AlignBytes(pcMappingIndexEntriesSize, DataAlignment);
|
||||
size_t paddedPCMappingSize = AlignBytes(pcMappingSize, DataAlignment);
|
||||
|
@ -376,8 +374,7 @@ BaselineScript::New(JSScript* jsscript,
|
|||
size_t paddedResumeEntriesSize = AlignBytes(resumeEntriesSize, DataAlignment);
|
||||
size_t paddedTLEntriesSize = AlignBytes(tlEntriesSize, DataAlignment);
|
||||
|
||||
size_t allocBytes = paddedICEntriesSize +
|
||||
paddedRetAddrEntriesSize +
|
||||
size_t allocBytes = paddedRetAddrEntriesSize +
|
||||
paddedPCMappingIndexEntriesSize +
|
||||
paddedPCMappingSize +
|
||||
paddedBytecodeTypesMapSize +
|
||||
|
@ -397,10 +394,6 @@ BaselineScript::New(JSScript* jsscript,
|
|||
size_t offsetCursor = sizeof(BaselineScript);
|
||||
MOZ_ASSERT(offsetCursor == AlignBytes(sizeof(BaselineScript), DataAlignment));
|
||||
|
||||
script->icEntriesOffset_ = offsetCursor;
|
||||
script->icEntries_ = icEntries;
|
||||
offsetCursor += paddedICEntriesSize;
|
||||
|
||||
script->retAddrEntriesOffset_ = offsetCursor;
|
||||
script->retAddrEntries_ = retAddrEntries;
|
||||
offsetCursor += paddedRetAddrEntriesSize;
|
||||
|
@ -432,7 +425,11 @@ BaselineScript::trace(JSTracer* trc)
|
|||
{
|
||||
TraceEdge(trc, &method_, "baseline-method");
|
||||
TraceNullableEdge(trc, &templateEnv_, "baseline-template-environment");
|
||||
}
|
||||
|
||||
void
|
||||
ICScript::trace(JSTracer* trc)
|
||||
{
|
||||
// Mark all IC stub codes hanging off the IC stub entries.
|
||||
for (size_t i = 0; i < numICEntries(); i++) {
|
||||
ICEntry& ent = icEntry(i);
|
||||
|
@ -463,16 +460,6 @@ BaselineScript::Destroy(FreeOp* fop, BaselineScript* script)
|
|||
|
||||
script->unlinkDependentWasmImports(fop);
|
||||
|
||||
/*
|
||||
* When the script contains pointers to nursery things, the store buffer can
|
||||
* contain entries that point into the fallback stub space. Since we can
|
||||
* destroy scripts outside the context of a GC, this situation could result
|
||||
* in us trying to mark invalid store buffer entries.
|
||||
*
|
||||
* Defer freeing any allocated blocks until after the next minor GC.
|
||||
*/
|
||||
script->fallbackStubSpace_.freeAllAfterMinorGC(script->method()->zone());
|
||||
|
||||
fop->delete_(script);
|
||||
}
|
||||
|
||||
|
@ -534,13 +521,6 @@ BaselineScript::removeDependentWasmImport(wasm::Instance& instance, uint32_t idx
|
|||
}
|
||||
}
|
||||
|
||||
ICEntry&
|
||||
BaselineScript::icEntry(size_t index)
|
||||
{
|
||||
MOZ_ASSERT(index < numICEntries());
|
||||
return icEntryList()[index];
|
||||
}
|
||||
|
||||
RetAddrEntry&
|
||||
BaselineScript::retAddrEntry(size_t index)
|
||||
{
|
||||
|
@ -572,15 +552,15 @@ struct ICEntries
|
|||
{
|
||||
using EntryT = ICEntry;
|
||||
|
||||
BaselineScript* const baseline_;
|
||||
ICScript* const icScript_;
|
||||
|
||||
explicit ICEntries(BaselineScript* baseline) : baseline_(baseline) {}
|
||||
explicit ICEntries(ICScript* icScript) : icScript_(icScript) {}
|
||||
|
||||
size_t numEntries() const {
|
||||
return baseline_->numICEntries();
|
||||
return icScript_->numICEntries();
|
||||
}
|
||||
ICEntry& operator[](size_t index) const {
|
||||
return baseline_->icEntry(index);
|
||||
return icScript_->icEntry(index);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -627,11 +607,11 @@ BaselineScript::retAddrEntryFromReturnOffset(CodeOffset returnOffset)
|
|||
return retAddrEntry(loc);
|
||||
}
|
||||
|
||||
template <typename Entries>
|
||||
template <typename Entries, typename ScriptT>
|
||||
static inline bool
|
||||
ComputeBinarySearchMid(BaselineScript* baseline, uint32_t pcOffset, size_t* loc)
|
||||
ComputeBinarySearchMid(ScriptT* script, uint32_t pcOffset, size_t* loc)
|
||||
{
|
||||
Entries entries(baseline);
|
||||
Entries entries(script);
|
||||
return BinarySearchIf(entries, 0, entries.numEntries(),
|
||||
[pcOffset](typename Entries::EntryT& entry) {
|
||||
uint32_t entryOffset = entry.pcOffset();
|
||||
|
@ -653,7 +633,7 @@ BaselineScript::returnAddressForEntry(const RetAddrEntry& ent)
|
|||
}
|
||||
|
||||
ICEntry*
|
||||
BaselineScript::maybeICEntryFromPCOffset(uint32_t pcOffset)
|
||||
ICScript::maybeICEntryFromPCOffset(uint32_t pcOffset)
|
||||
{
|
||||
// Multiple IC entries can have the same PC offset, but this method only looks for
|
||||
// those which have isForOp() set.
|
||||
|
@ -687,7 +667,7 @@ BaselineScript::maybeICEntryFromPCOffset(uint32_t pcOffset)
|
|||
}
|
||||
|
||||
ICEntry&
|
||||
BaselineScript::icEntryFromPCOffset(uint32_t pcOffset)
|
||||
ICScript::icEntryFromPCOffset(uint32_t pcOffset)
|
||||
{
|
||||
ICEntry* entry = maybeICEntryFromPCOffset(pcOffset);
|
||||
MOZ_RELEASE_ASSERT(entry);
|
||||
|
@ -695,7 +675,7 @@ BaselineScript::icEntryFromPCOffset(uint32_t pcOffset)
|
|||
}
|
||||
|
||||
ICEntry*
|
||||
BaselineScript::maybeICEntryFromPCOffset(uint32_t pcOffset, ICEntry* prevLookedUpEntry)
|
||||
ICScript::maybeICEntryFromPCOffset(uint32_t pcOffset, ICEntry* prevLookedUpEntry)
|
||||
{
|
||||
// Do a linear forward search from the last queried PC offset, or fallback to a
|
||||
// binary search if the last offset is too far away.
|
||||
|
@ -718,7 +698,7 @@ BaselineScript::maybeICEntryFromPCOffset(uint32_t pcOffset, ICEntry* prevLookedU
|
|||
}
|
||||
|
||||
ICEntry&
|
||||
BaselineScript::icEntryFromPCOffset(uint32_t pcOffset, ICEntry* prevLookedUpEntry)
|
||||
ICScript::icEntryFromPCOffset(uint32_t pcOffset, ICEntry* prevLookedUpEntry)
|
||||
{
|
||||
ICEntry* entry = maybeICEntryFromPCOffset(pcOffset, prevLookedUpEntry);
|
||||
MOZ_RELEASE_ASSERT(entry);
|
||||
|
@ -802,13 +782,13 @@ BaselineScript::computeResumeNativeOffsets(JSScript* script)
|
|||
}
|
||||
|
||||
void
|
||||
BaselineScript::copyICEntries(JSScript* script, const ICEntry* entries)
|
||||
ICScript::initICEntries(JSScript* script, const ICEntry* entries)
|
||||
{
|
||||
// Fix up the return offset in the IC entries and copy them in.
|
||||
// Also write out the IC entry ptrs in any fallback stubs that were added.
|
||||
for (uint32_t i = 0; i < numICEntries(); i++) {
|
||||
ICEntry& realEntry = icEntry(i);
|
||||
realEntry = entries[i];
|
||||
new (&realEntry) ICEntry(entries[i]);
|
||||
|
||||
// If the attached stub is a fallback stub, then fix it up with
|
||||
// a pointer to the (now available) realEntry.
|
||||
|
@ -831,12 +811,6 @@ BaselineScript::copyRetAddrEntries(JSScript* script, const RetAddrEntry* entries
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
BaselineScript::adoptFallbackStubs(FallbackICStubSpace* stubSpace)
|
||||
{
|
||||
fallbackStubSpace_.adoptFrom(stubSpace);
|
||||
}
|
||||
|
||||
void
|
||||
BaselineScript::copyPCMappingEntries(const CompactBufferWriter& entries)
|
||||
{
|
||||
|
@ -1106,7 +1080,7 @@ BaselineScript::toggleProfilerInstrumentation(bool enable)
|
|||
}
|
||||
|
||||
void
|
||||
BaselineScript::purgeOptimizedStubs(Zone* zone)
|
||||
ICScript::purgeOptimizedStubs(Zone* zone)
|
||||
{
|
||||
JitSpew(JitSpew_BaselineIC, "Purging optimized stubs");
|
||||
|
||||
|
@ -1162,7 +1136,7 @@ BaselineScript::purgeOptimizedStubs(Zone* zone)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef JS_JITSPEW
|
||||
#ifdef JS_STRUCTURED_SPEW
|
||||
static bool
|
||||
GetStubEnteredCount(ICStub* stub, uint32_t* count)
|
||||
{
|
||||
|
@ -1181,48 +1155,67 @@ GetStubEnteredCount(ICStub* stub, uint32_t* count)
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
HasEnteredCounters(ICEntry& entry)
|
||||
{
|
||||
ICStub* stub = entry.firstStub();
|
||||
while (stub && !stub->isFallback()) {
|
||||
uint32_t count;
|
||||
if (GetStubEnteredCount(stub, &count)) {
|
||||
return true;
|
||||
}
|
||||
stub = stub->next();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
jit::JitSpewBaselineICStats(JSScript* script, const char* dumpReason)
|
||||
{
|
||||
MOZ_ASSERT(script->hasBaselineScript());
|
||||
BaselineScript* blScript = script->baselineScript();
|
||||
|
||||
if (!JitSpewEnabled(JitSpew_BaselineIC_Statistics)) {
|
||||
MOZ_ASSERT(script->hasICScript());
|
||||
JSContext* cx = TlsContext.get();
|
||||
AutoStructuredSpewer spew(cx, SpewChannel::BaselineICStats, script);
|
||||
if (!spew) {
|
||||
return;
|
||||
}
|
||||
|
||||
Fprinter& out = JitSpewPrinter();
|
||||
|
||||
out.printf("[BaselineICStats] Dumping IC info for %s script %s:%d:%d\n",
|
||||
dumpReason, script->filename(), script->lineno(),
|
||||
script->column());
|
||||
|
||||
for (size_t i = 0; i < blScript->numICEntries(); i++) {
|
||||
ICEntry& entry = blScript->icEntry(i);
|
||||
ICScript* icScript = script->icScript();
|
||||
spew->property("reason", dumpReason);
|
||||
spew->beginListProperty("entries");
|
||||
for (size_t i = 0; i < icScript->numICEntries(); i++) {
|
||||
ICEntry& entry = icScript->icEntry(i);
|
||||
if (!HasEnteredCounters(entry)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t pcOffset = entry.pcOffset();
|
||||
jsbytecode* pc = entry.pc(script);
|
||||
|
||||
unsigned column;
|
||||
unsigned int line = PCToLineNumber(script, pc, &column);
|
||||
out.printf("[BaselineICStats] %s - pc=%u line=%u col=%u\n",
|
||||
CodeName[*pc], pcOffset, line, column);
|
||||
|
||||
spew->beginObject();
|
||||
spew->property("op", CodeName[*pc]);
|
||||
spew->property("pc", pcOffset);
|
||||
spew->property("line", line);
|
||||
spew->property("column", column);
|
||||
|
||||
spew->beginListProperty("counts");
|
||||
ICStub* stub = entry.firstStub();
|
||||
out.printf("[BaselineICStats] ");
|
||||
while (stub) {
|
||||
while (stub && !stub->isFallback()) {
|
||||
uint32_t count;
|
||||
if (GetStubEnteredCount(stub, &count)) {
|
||||
out.printf("%u -> ", count);
|
||||
} else if (stub->isFallback()) {
|
||||
out.printf("(fb) %u", stub->toFallbackStub()->enteredCount());
|
||||
spew->value(count);
|
||||
} else {
|
||||
out.printf(" ?? -> ");
|
||||
spew->value("?");
|
||||
}
|
||||
stub = stub->next();
|
||||
}
|
||||
out.printf("\n");
|
||||
spew->endList();
|
||||
spew->property("fallback_count", entry.fallbackStub()->enteredCount());
|
||||
spew->endObject();
|
||||
}
|
||||
spew->endList();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1235,10 +1228,6 @@ jit::FinishDiscardBaselineScript(FreeOp* fop, JSScript* script)
|
|||
}
|
||||
|
||||
if (script->baselineScript()->active()) {
|
||||
// Script is live on the stack. Keep the BaselineScript, but destroy
|
||||
// stubs allocated in the optimized stub space.
|
||||
script->baselineScript()->purgeOptimizedStubs(script->zone());
|
||||
|
||||
// Reset |active| flag so that we don't need a separate script
|
||||
// iteration to unmark them.
|
||||
script->baselineScript()->resetActive();
|
||||
|
@ -1258,8 +1247,13 @@ void
|
|||
jit::AddSizeOfBaselineData(JSScript* script, mozilla::MallocSizeOf mallocSizeOf, size_t* data,
|
||||
size_t* fallbackStubs)
|
||||
{
|
||||
if (script->hasICScript()) {
|
||||
// ICScript is stored in TypeScript but we report its size here and not
|
||||
// in TypeScript::sizeOfIncludingThis.
|
||||
script->icScript()->addSizeOfIncludingThis(mallocSizeOf, data, fallbackStubs);
|
||||
}
|
||||
if (script->hasBaselineScript()) {
|
||||
script->baselineScript()->addSizeOfIncludingThis(mallocSizeOf, data, fallbackStubs);
|
||||
script->baselineScript()->addSizeOfIncludingThis(mallocSizeOf, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -245,9 +245,6 @@ struct BaselineScript final
|
|||
// scope).
|
||||
HeapPtr<EnvironmentObject*> templateEnv_ = nullptr;
|
||||
|
||||
// Allocated space for fallback stubs.
|
||||
FallbackICStubSpace fallbackStubSpace_ = {};
|
||||
|
||||
// If non-null, the list of wasm::Modules that contain an optimized call
|
||||
// directly to this script.
|
||||
Vector<DependentWasmImport>* dependentWasmImports_ = nullptr;
|
||||
|
@ -313,9 +310,6 @@ struct BaselineScript final
|
|||
private:
|
||||
void trace(JSTracer* trc);
|
||||
|
||||
uint32_t icEntriesOffset_ = 0;
|
||||
uint32_t icEntries_ = 0;
|
||||
|
||||
uint32_t retAddrEntriesOffset_ = 0;
|
||||
uint32_t retAddrEntries_ = 0;
|
||||
|
||||
|
@ -370,19 +364,12 @@ struct BaselineScript final
|
|||
{ }
|
||||
|
||||
public:
|
||||
~BaselineScript() {
|
||||
// The contents of the fallback stub space are removed and freed
|
||||
// separately after the next minor GC. See BaselineScript::Destroy.
|
||||
MOZ_ASSERT(fallbackStubSpace_.isEmpty());
|
||||
}
|
||||
|
||||
static BaselineScript* New(JSScript* jsscript,
|
||||
uint32_t bailoutPrologueOffset,
|
||||
uint32_t debugOsrPrologueOffset,
|
||||
uint32_t debugOsrEpilogueOffset,
|
||||
uint32_t profilerEnterToggleOffset,
|
||||
uint32_t profilerExitToggleOffset,
|
||||
size_t icEntries,
|
||||
size_t retAddrEntries,
|
||||
size_t pcMappingIndexEntries, size_t pcMappingSize,
|
||||
size_t bytecodeTypeMapEntries,
|
||||
|
@ -392,19 +379,12 @@ struct BaselineScript final
|
|||
static void Trace(JSTracer* trc, BaselineScript* script);
|
||||
static void Destroy(FreeOp* fop, BaselineScript* script);
|
||||
|
||||
void purgeOptimizedStubs(Zone* zone);
|
||||
|
||||
static inline size_t offsetOfMethod() {
|
||||
return offsetof(BaselineScript, method_);
|
||||
}
|
||||
|
||||
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, size_t* data,
|
||||
size_t* fallbackStubs) const {
|
||||
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, size_t* data) const {
|
||||
*data += mallocSizeOf(this);
|
||||
|
||||
// |data| already includes the ICStubSpace itself, so use
|
||||
// sizeOfExcludingThis.
|
||||
*fallbackStubs += fallbackStubSpace_.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
bool active() const {
|
||||
|
@ -458,9 +438,6 @@ struct BaselineScript final
|
|||
return method_->raw() + debugOsrEpilogueOffset_;
|
||||
}
|
||||
|
||||
ICEntry* icEntryList() {
|
||||
return (ICEntry*)(reinterpret_cast<uint8_t*>(this) + icEntriesOffset_);
|
||||
}
|
||||
RetAddrEntry* retAddrEntryList() {
|
||||
return (RetAddrEntry*)(reinterpret_cast<uint8_t*>(this) + retAddrEntriesOffset_);
|
||||
}
|
||||
|
@ -473,9 +450,6 @@ struct BaselineScript final
|
|||
uint8_t* pcMappingData() {
|
||||
return reinterpret_cast<uint8_t*>(this) + pcMappingOffset_;
|
||||
}
|
||||
FallbackICStubSpace* fallbackStubSpace() {
|
||||
return &fallbackStubSpace_;
|
||||
}
|
||||
|
||||
JitCode* method() const {
|
||||
return method_;
|
||||
|
@ -497,14 +471,6 @@ struct BaselineScript final
|
|||
return method()->raw() <= addr && addr <= method()->raw() + method()->instructionsSize();
|
||||
}
|
||||
|
||||
ICEntry* maybeICEntryFromPCOffset(uint32_t pcOffset);
|
||||
ICEntry* maybeICEntryFromPCOffset(uint32_t pcOffset,
|
||||
ICEntry* prevLookedUpEntry);
|
||||
|
||||
ICEntry& icEntry(size_t index);
|
||||
ICEntry& icEntryFromPCOffset(uint32_t pcOffset);
|
||||
ICEntry& icEntryFromPCOffset(uint32_t pcOffset, ICEntry* prevLookedUpEntry);
|
||||
|
||||
uint8_t* returnAddressForEntry(const RetAddrEntry& ent);
|
||||
|
||||
RetAddrEntry& retAddrEntry(size_t index);
|
||||
|
@ -513,19 +479,12 @@ struct BaselineScript final
|
|||
RetAddrEntry& retAddrEntryFromReturnOffset(CodeOffset returnOffset);
|
||||
RetAddrEntry& retAddrEntryFromReturnAddress(uint8_t* returnAddr);
|
||||
|
||||
size_t numICEntries() const {
|
||||
return icEntries_;
|
||||
}
|
||||
|
||||
size_t numRetAddrEntries() const {
|
||||
return retAddrEntries_;
|
||||
}
|
||||
|
||||
void copyICEntries(JSScript* script, const ICEntry* entries);
|
||||
void copyRetAddrEntries(JSScript* script, const RetAddrEntry* entries);
|
||||
|
||||
void adoptFallbackStubs(FallbackICStubSpace* stubSpace);
|
||||
|
||||
// Copy resumeOffsets list from |script| and convert the pcOffsets
|
||||
// to native addresses in the Baseline code.
|
||||
void computeResumeNativeOffsets(JSScript* script);
|
||||
|
@ -586,9 +545,6 @@ struct BaselineScript final
|
|||
}
|
||||
#endif
|
||||
|
||||
void noteAccessedGetter(uint32_t pcOffset);
|
||||
void noteHasDenseAdd(uint32_t pcOffset);
|
||||
|
||||
static size_t offsetOfFlags() {
|
||||
return offsetof(BaselineScript, flags_);
|
||||
}
|
||||
|
@ -766,7 +722,7 @@ MarkActiveBaselineScripts(Zone* zone);
|
|||
MethodStatus
|
||||
BaselineCompile(JSContext* cx, JSScript* script, bool forceDebugInstrumentation = false);
|
||||
|
||||
#ifdef JS_JITSPEW
|
||||
#ifdef JS_STRUCTURED_SPEW
|
||||
void
|
||||
JitSpewBaselineICStats(JSScript* script, const char* dumpReason);
|
||||
#endif
|
||||
|
|
|
@ -943,55 +943,6 @@ CacheIRStubInfo::stubDataSize() const
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
CacheIRStubInfo::copyStubData(ICStub* src, ICStub* dest) const
|
||||
{
|
||||
uint8_t* srcBytes = reinterpret_cast<uint8_t*>(src);
|
||||
uint8_t* destBytes = reinterpret_cast<uint8_t*>(dest);
|
||||
|
||||
size_t field = 0;
|
||||
size_t offset = 0;
|
||||
while (true) {
|
||||
StubField::Type type = fieldType(field);
|
||||
switch (type) {
|
||||
case StubField::Type::RawWord:
|
||||
*reinterpret_cast<uintptr_t*>(destBytes + offset) =
|
||||
*reinterpret_cast<uintptr_t*>(srcBytes + offset);
|
||||
break;
|
||||
case StubField::Type::RawInt64:
|
||||
case StubField::Type::DOMExpandoGeneration:
|
||||
*reinterpret_cast<uint64_t*>(destBytes + offset) =
|
||||
*reinterpret_cast<uint64_t*>(srcBytes + offset);
|
||||
break;
|
||||
case StubField::Type::Shape:
|
||||
getStubField<ICStub, Shape*>(dest, offset).init(getStubField<ICStub, Shape*>(src, offset));
|
||||
break;
|
||||
case StubField::Type::JSObject:
|
||||
getStubField<ICStub, JSObject*>(dest, offset).init(getStubField<ICStub, JSObject*>(src, offset));
|
||||
break;
|
||||
case StubField::Type::ObjectGroup:
|
||||
getStubField<ICStub, ObjectGroup*>(dest, offset).init(getStubField<ICStub, ObjectGroup*>(src, offset));
|
||||
break;
|
||||
case StubField::Type::Symbol:
|
||||
getStubField<ICStub, JS::Symbol*>(dest, offset).init(getStubField<ICStub, JS::Symbol*>(src, offset));
|
||||
break;
|
||||
case StubField::Type::String:
|
||||
getStubField<ICStub, JSString*>(dest, offset).init(getStubField<ICStub, JSString*>(src, offset));
|
||||
break;
|
||||
case StubField::Type::Id:
|
||||
getStubField<ICStub, jsid>(dest, offset).init(getStubField<ICStub, jsid>(src, offset));
|
||||
break;
|
||||
case StubField::Type::Value:
|
||||
getStubField<ICStub, Value>(dest, offset).init(getStubField<ICStub, Value>(src, offset));
|
||||
break;
|
||||
case StubField::Type::Limit:
|
||||
return; // Done.
|
||||
}
|
||||
field++;
|
||||
offset += StubField::sizeInBytes(type);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static GCPtr<T>*
|
||||
AsGCPtr(uintptr_t* ptr)
|
||||
|
|
|
@ -983,8 +983,6 @@ class CacheIRStubInfo
|
|||
}
|
||||
|
||||
uintptr_t getStubRawWord(ICStub* stub, uint32_t field) const;
|
||||
|
||||
void copyStubData(ICStub* src, ICStub* dest) const;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -3302,6 +3302,10 @@ jit::TraceJitScripts(JSTracer* trc, JSScript* script)
|
|||
if (script->hasBaselineScript()) {
|
||||
jit::BaselineScript::Trace(trc, script->baselineScript());
|
||||
}
|
||||
|
||||
if (script->hasICScript()) {
|
||||
script->icScript()->trace(trc);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -782,7 +782,7 @@ IonBuilder::build()
|
|||
{
|
||||
// Spew IC info for inlined script, but only when actually compiling,
|
||||
// not when analyzing it.
|
||||
#ifdef JS_JITSPEW
|
||||
#ifdef JS_STRUCTURED_SPEW
|
||||
if (!info().isAnalysis()) {
|
||||
JitSpewBaselineICStats(script(), "To-Be-Compiled");
|
||||
}
|
||||
|
@ -983,7 +983,7 @@ IonBuilder::buildInline(IonBuilder* callerBuilder, MResumePoint* callerResumePoi
|
|||
|
||||
// Spew IC info for inlined script, but only when actually compiling,
|
||||
// not when analyzing it.
|
||||
#ifdef JS_JITSPEW
|
||||
#ifdef JS_STRUCTURED_SPEW
|
||||
if (!info().isAnalysis()) {
|
||||
JitSpewBaselineICStats(script(), "To-Be-Inlined");
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "jit/MIRGenerator.h"
|
||||
#include "jit/MIRGraph.h"
|
||||
#include "threading/LockGuard.h"
|
||||
#include "util/Text.h"
|
||||
#include "vm/HelperThreads.h"
|
||||
#include "vm/MutexIDs.h"
|
||||
|
||||
|
@ -372,21 +373,6 @@ jit::JitSpewPrinter()
|
|||
return out;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
ContainsFlag(const char* str, const char* flag)
|
||||
{
|
||||
size_t flaglen = strlen(flag);
|
||||
const char* index = strstr(str, flag);
|
||||
while (index) {
|
||||
if ((index == str || index[-1] == ',') && (index[flaglen] == 0 || index[flaglen] == ',')) {
|
||||
return true;
|
||||
}
|
||||
index = strstr(index + flaglen, flag);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
jit::CheckLogging()
|
||||
{
|
||||
|
|
|
@ -31,16 +31,13 @@ EmitRepushTailCallReg(MacroAssembler& masm)
|
|||
}
|
||||
|
||||
inline void
|
||||
EmitCallIC(MacroAssembler& masm, CodeOffset* patchOffset, CodeOffset* callOffset)
|
||||
EmitCallIC(MacroAssembler& masm, const ICEntry* entry, CodeOffset* callOffset)
|
||||
{
|
||||
// Move ICEntry offset into ICStubReg
|
||||
CodeOffset offset = masm.movWithPatch(ImmWord(-1), ICStubReg);
|
||||
*patchOffset = offset;
|
||||
// Load stub pointer into ICStubReg.
|
||||
masm.loadPtr(AbsoluteAddress(entry).offset(ICEntry::offsetOfFirstStub()),
|
||||
ICStubReg);
|
||||
|
||||
// Load stub pointer into ICStubReg
|
||||
masm.loadPtr(Address(ICStubReg, ICEntry::offsetOfFirstStub()), ICStubReg);
|
||||
|
||||
// Load stubcode pointer from BaselineStubEntry.
|
||||
// Load stubcode pointer from the ICStub.
|
||||
// R2 won't be active when we call ICs, so we can use r0.
|
||||
MOZ_ASSERT(R2 == ValueOperand(r1, r0));
|
||||
masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), r0);
|
||||
|
|
|
@ -31,16 +31,13 @@ EmitRepushTailCallReg(MacroAssembler& masm)
|
|||
}
|
||||
|
||||
inline void
|
||||
EmitCallIC(MacroAssembler& masm, CodeOffset* patchOffset, CodeOffset* callOffset)
|
||||
EmitCallIC(MacroAssembler& masm, const ICEntry* entry, CodeOffset* callOffset)
|
||||
{
|
||||
// Move ICEntry offset into ICStubReg
|
||||
CodeOffset offset = masm.movWithPatch(ImmWord(-1), ICStubReg);
|
||||
*patchOffset = offset;
|
||||
// Load stub pointer into ICStubReg.
|
||||
masm.loadPtr(AbsoluteAddress(entry).offset(ICEntry::offsetOfFirstStub()),
|
||||
ICStubReg);
|
||||
|
||||
// Load stub pointer into ICStubReg
|
||||
masm.loadPtr(Address(ICStubReg, ICEntry::offsetOfFirstStub()), ICStubReg);
|
||||
|
||||
// Load stubcode pointer from BaselineStubEntry.
|
||||
// Load stubcode pointer from the ICStub.
|
||||
// R2 won't be active when we call ICs, so we can use r0.
|
||||
MOZ_ASSERT(R2 == ValueOperand(r0));
|
||||
masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), r0);
|
||||
|
|
|
@ -43,16 +43,13 @@ EmitRepushTailCallReg(MacroAssembler& masm)
|
|||
}
|
||||
|
||||
inline void
|
||||
EmitCallIC(MacroAssembler& masm, CodeOffset* patchOffset, CodeOffset* callOffset)
|
||||
EmitCallIC(MacroAssembler& masm, const ICEntry* entry, CodeOffset* callOffset)
|
||||
{
|
||||
// Move ICEntry offset into ICStubReg.
|
||||
CodeOffset offset = masm.movWithPatch(ImmWord(-1), ICStubReg);
|
||||
*patchOffset = offset;
|
||||
|
||||
// Load stub pointer into ICStubReg.
|
||||
masm.loadPtr(Address(ICStubReg, ICEntry::offsetOfFirstStub()), ICStubReg);
|
||||
masm.loadPtr(AbsoluteAddress(entry).offset(ICEntry::offsetOfFirstStub()),
|
||||
ICStubReg);
|
||||
|
||||
// Load stubcode pointer from BaselineStubEntry.
|
||||
// Load stubcode pointer from the ICStub.
|
||||
// R2 won't be active when we call ICs, so we can use it as scratch.
|
||||
masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), R2.scratchReg());
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ static const size_t ICStackValueOffset = 0;
|
|||
|
||||
inline void EmitRestoreTailCallReg(MacroAssembler&) { MOZ_CRASH(); }
|
||||
inline void EmitRepushTailCallReg(MacroAssembler&) { MOZ_CRASH(); }
|
||||
inline void EmitCallIC(MacroAssembler&, CodeOffset*, CodeOffset*) { MOZ_CRASH(); }
|
||||
inline void EmitCallIC(MacroAssembler&, const ICEntry*, CodeOffset*) { MOZ_CRASH(); }
|
||||
inline void EmitEnterTypeMonitorIC(MacroAssembler&, size_t v = 0) { MOZ_CRASH(); }
|
||||
inline void EmitReturnFromIC(MacroAssembler&) { MOZ_CRASH(); }
|
||||
inline void EmitBaselineLeaveStubFrame(MacroAssembler&, bool v = false) { MOZ_CRASH(); }
|
||||
|
|
|
@ -31,14 +31,10 @@ EmitRepushTailCallReg(MacroAssembler& masm)
|
|||
}
|
||||
|
||||
inline void
|
||||
EmitCallIC(MacroAssembler& masm, CodeOffset* patchOffset, CodeOffset* callOffset)
|
||||
EmitCallIC(MacroAssembler& masm, const ICEntry* entry, CodeOffset* callOffset)
|
||||
{
|
||||
// Move ICEntry offset into ICStubReg
|
||||
CodeOffset offset = masm.movWithPatch(ImmWord(-1), ICStubReg);
|
||||
*patchOffset = offset;
|
||||
|
||||
// Load stub pointer into ICStubReg
|
||||
masm.loadPtr(Address(ICStubReg, (int32_t) ICEntry::offsetOfFirstStub()),
|
||||
// Load stub pointer into ICStubReg.
|
||||
masm.loadPtr(AbsoluteAddress(entry).offset(ICEntry::offsetOfFirstStub()),
|
||||
ICStubReg);
|
||||
|
||||
// Call the stubcode.
|
||||
|
|
|
@ -31,18 +31,13 @@ EmitRepushTailCallReg(MacroAssembler& masm)
|
|||
}
|
||||
|
||||
inline void
|
||||
EmitCallIC(MacroAssembler& masm, CodeOffset* patchOffset, CodeOffset* callOffset)
|
||||
EmitCallIC(MacroAssembler& masm, const ICEntry* entry, CodeOffset* callOffset)
|
||||
{
|
||||
// Move ICEntry offset into ICStubReg
|
||||
CodeOffset offset = masm.movWithPatch(ImmWord(-1), ICStubReg);
|
||||
*patchOffset = offset;
|
||||
|
||||
// Load stub pointer into ICStubReg
|
||||
masm.loadPtr(Address(ICStubReg, (int32_t) ICEntry::offsetOfFirstStub()),
|
||||
// Load stub pointer into ICStubReg.
|
||||
masm.loadPtr(AbsoluteAddress(entry).offset(ICEntry::offsetOfFirstStub()),
|
||||
ICStubReg);
|
||||
|
||||
// Load stubcode pointer from BaselineStubEntry into ICTailCallReg
|
||||
// ICTailCallReg will always be unused in the contexts where ICs are called.
|
||||
// Call the stubcode.
|
||||
masm.call(Address(ICStubReg, ICStub::offsetOfStubCode()));
|
||||
*callOffset = CodeOffset(masm.currentOffset());
|
||||
}
|
||||
|
|
|
@ -17,9 +17,11 @@ if CONFIG['NIGHTLY_BUILD']:
|
|||
if CONFIG['JS_CODEGEN_X64'] or CONFIG['JS_CODEGEN_ARM64']:
|
||||
DEFINES['WASM_HUGE_MEMORY'] = True
|
||||
|
||||
# Enables CACHEIR_LOGS to diagnose IC coverage.
|
||||
# Enables CACHEIR_LOGS to diagnose IC coverage, and
|
||||
# Structured spewer for diagnostics
|
||||
if CONFIG['MOZ_DEBUG'] or CONFIG['NIGHTLY_BUILD']:
|
||||
DEFINES['JS_CACHEIR_SPEW'] = True
|
||||
DEFINES['JS_STRUCTURED_SPEW'] = True
|
||||
|
||||
# CTypes
|
||||
if CONFIG['JS_HAS_CTYPES']:
|
||||
|
|
|
@ -240,6 +240,7 @@ UNIFIED_SOURCES += [
|
|||
'util/NativeStack.cpp',
|
||||
'util/Printf.cpp',
|
||||
'util/StringBuffer.cpp',
|
||||
'util/StructuredSpewer.cpp',
|
||||
'util/Text.cpp',
|
||||
'util/Unicode.cpp',
|
||||
'vm/ArgumentsObject.cpp',
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifdef JS_STRUCTURED_SPEW
|
||||
|
||||
#include "util/StructuredSpewer.h"
|
||||
|
||||
#include "mozilla/Sprintf.h"
|
||||
|
||||
#include "util/Text.h"
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/JSScript.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
const StructuredSpewer::NameArray StructuredSpewer::names_ =
|
||||
{
|
||||
#define STRUCTURED_CHANNEL(name) #name,
|
||||
STRUCTURED_CHANNEL_LIST(STRUCTURED_CHANNEL)
|
||||
#undef STRUCTURED_CHANNEL
|
||||
};
|
||||
|
||||
|
||||
// Choose a sensible default spew directory.
|
||||
//
|
||||
// The preference here is to use the current working directory,
|
||||
// except on Android.
|
||||
#ifndef DEFAULT_SPEW_DIRECTORY
|
||||
# if defined(_WIN32)
|
||||
# define DEFAULT_SPEW_DIRECTORY "."
|
||||
# elif defined(__ANDROID__)
|
||||
# define DEFAULT_SPEW_DIRECTORY "/data/local/tmp"
|
||||
# else
|
||||
# define DEFAULT_SPEW_DIRECTORY "."
|
||||
# endif
|
||||
#endif
|
||||
|
||||
void
|
||||
StructuredSpewer::ensureInitializationAttempted()
|
||||
{
|
||||
if (!outputInitializationAttempted_) {
|
||||
// We cannot call getenv during record replay, so disable
|
||||
// the spewer.
|
||||
if (!mozilla::recordreplay::IsRecordingOrReplaying()) {
|
||||
char filename[2048] = {0};
|
||||
// For ease of use with Treeherder
|
||||
if (getenv("SPEW_UPLOAD") && getenv("MOZ_UPLOAD_DIR")) {
|
||||
SprintfLiteral(filename, "%s/spew_output", getenv("MOZ_UPLOAD_DIR"));
|
||||
} else if (getenv("SPEW_FILE")) {
|
||||
SprintfLiteral(filename, "%s", getenv("SPEW_FILE"));
|
||||
} else {
|
||||
SprintfLiteral(filename, "%s/spew_output", DEFAULT_SPEW_DIRECTORY);
|
||||
}
|
||||
tryToInitializeOutput(filename);
|
||||
}
|
||||
// We can't use the intialization state of the Fprinter, as it is not
|
||||
// marked as initialized in a case where we cannot open the output, so
|
||||
// we track the attempt separately.
|
||||
outputInitializationAttempted_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StructuredSpewer::tryToInitializeOutput(const char* path)
|
||||
{
|
||||
static mozilla::Atomic<uint32_t,
|
||||
mozilla::ReleaseAcquire,
|
||||
mozilla::recordreplay::Behavior::DontPreserve> threadCounter;
|
||||
|
||||
char suffix_path[2048] = {0};
|
||||
SprintfLiteral(suffix_path, "%s.%d.%d", path, getpid(), threadCounter++);
|
||||
|
||||
if (!output_.init(suffix_path)) {
|
||||
// Returning here before we've emplaced the JSONPrinter
|
||||
// means this is effectively disabled, but fail earlier
|
||||
// we also disable all the bits
|
||||
selectedChannels_.disableAll();
|
||||
return;
|
||||
}
|
||||
|
||||
// These logs are structured as a JSON array.
|
||||
output_.put("[");
|
||||
json_.emplace(output_);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Treat pattern like a glob, and return true if pattern exists
|
||||
// in the script's name or filename or line number.
|
||||
//
|
||||
// This is the most basic matching I can imagine
|
||||
static bool
|
||||
MatchJSScript(JSScript* script, const char* pattern)
|
||||
{
|
||||
if (!pattern) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char signature[2048] = {0};
|
||||
SprintfLiteral(signature, "%s:%d:%d", script->filename(),
|
||||
script->lineno(),
|
||||
script->column());
|
||||
|
||||
// Trivial containment match.
|
||||
char* result = strstr(signature, pattern);
|
||||
|
||||
return result != nullptr;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
StructuredSpewer::enabled(JSScript* script)
|
||||
{
|
||||
// We cannot call getenv under record/replay.
|
||||
if (mozilla::recordreplay::IsRecordingOrReplaying()) {
|
||||
return false;
|
||||
}
|
||||
static const char* pattern = getenv("SPEW_FILTER");
|
||||
if (!pattern || MatchJSScript(script, pattern)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
StructuredSpewer::enabled(JSContext* cx, const JSScript* script, SpewChannel channel) const
|
||||
{
|
||||
return script->spewEnabled() && cx->spewer().filter().enabled(channel);
|
||||
}
|
||||
|
||||
// Attempt to setup a common header for objects based on script/channel.
|
||||
//
|
||||
// Returns true if the spewer is prepared for more input
|
||||
void
|
||||
StructuredSpewer::startObject(JSContext* cx, const JSScript* script, SpewChannel channel)
|
||||
{
|
||||
MOZ_ASSERT(json_.isSome());
|
||||
|
||||
JSONPrinter& json = json_.ref();
|
||||
|
||||
json.beginObject();
|
||||
json.property("channel", getName(channel));
|
||||
json.beginObjectProperty("location");
|
||||
{
|
||||
json.property("filename", script->filename());
|
||||
json.property("line", script->lineno());
|
||||
json.property("column", script->column());
|
||||
}
|
||||
json.endObject();
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
StructuredSpewer::spew(JSContext* cx, SpewChannel channel, const char* fmt, ...)
|
||||
{
|
||||
// Because we don't have a script here, use the singleton's
|
||||
// filter to determine if the channel is active.
|
||||
if (!cx->spewer().filter().enabled(channel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
cx->spewer().ensureInitializationAttempted();
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
MOZ_ASSERT(cx->spewer().json_.isSome());
|
||||
|
||||
JSONPrinter& json = cx->spewer().json_.ref();
|
||||
|
||||
json.beginObject();
|
||||
json.property("channel", getName(channel));
|
||||
json.formatProperty("message", fmt, ap);
|
||||
json.endObject();
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
// Currently uses the exact spew flag representation as text.
|
||||
void
|
||||
StructuredSpewer::parseSpewFlags(const char* flags) {
|
||||
// If '*' or 'all' are in the list, enable all spew.
|
||||
bool star = ContainsFlag(flags, "*") || ContainsFlag(flags, "all");
|
||||
#define CHECK_CHANNEL(name) \
|
||||
if (ContainsFlag(flags, #name) || star) { \
|
||||
selectedChannels_.enableChannel(SpewChannel:: name); \
|
||||
}
|
||||
|
||||
STRUCTURED_CHANNEL_LIST(CHECK_CHANNEL)
|
||||
|
||||
#undef CHECK_CHANNEL
|
||||
|
||||
}
|
||||
|
||||
AutoStructuredSpewer::AutoStructuredSpewer(JSContext* cx,
|
||||
SpewChannel channel,
|
||||
JSScript* script)
|
||||
: printer_(mozilla::Nothing())
|
||||
{
|
||||
if (!cx->spewer().enabled(cx, script, channel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
cx->spewer().ensureInitializationAttempted();
|
||||
|
||||
cx->spewer().startObject(cx, script, channel);
|
||||
printer_.emplace(&cx->spewer().json_.ref());
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,255 @@
|
|||
/* -*- 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_StructuredSpewer_h
|
||||
#define jit_StructuredSpewer_h
|
||||
|
||||
#ifdef JS_STRUCTURED_SPEW
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EnumeratedArray.h"
|
||||
#include "mozilla/EnumSet.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
|
||||
#include "vm/JSONPrinter.h"
|
||||
#include "vm/Printer.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include <process.h>
|
||||
#define getpid _getpid
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
// [SMDOC] JSON Structured Spewer
|
||||
//
|
||||
// This spewer design has two goals:
|
||||
//
|
||||
// 1. Provide a spew mechanism that has first-class support for slicing and
|
||||
// dicing output. This means that filtering by script and channel should be
|
||||
// the dominant output mechanism.
|
||||
// 2. Provide a simple powerful mechanism for getting information out of the
|
||||
// compiler and into tools. I'm inspired by tools like CacheIR analyzer,
|
||||
// IR Hydra, and the upcoming tracelogger integration into perf.html.
|
||||
//
|
||||
// The spewer has four main control knobs, all currently set as
|
||||
// environment variables. All but the first are optional.
|
||||
//
|
||||
// SPEW: Activates the spewer. The value provided is interpreted as a comma
|
||||
// separated list that selects channels by name. Currently there's no
|
||||
// mapping between internal and external names, so the channel names
|
||||
// are exactly those described in STRUCTURED_CHANNEL_LIST below.
|
||||
//
|
||||
// SPEW_FILE: Selects the file to write to. An absolute path.
|
||||
//
|
||||
// SPEW_FILTER: A string which is matched against 'signature' constructed or a
|
||||
// JSScript, currently connsisting of filename:line:col.
|
||||
//
|
||||
// Matching in this version is merely finding the string in
|
||||
// in question in the 'signature'
|
||||
//
|
||||
// SPEW_UPLOAD: If this variable is set as well as MOZ_UPLOAD_DIR, output goes
|
||||
// to $MOZ_UPLOAD_DIR/spew_output* to ease usage with Treeherder.
|
||||
//
|
||||
// Other notes:
|
||||
// - Thread safety is provided by opening a new spewer file for every thread.
|
||||
// - Each file is prefixed with the PID to handle multiple processes.
|
||||
// - Files are opened lazily, just before the first write to them.
|
||||
|
||||
class JSScript;
|
||||
|
||||
namespace js {
|
||||
|
||||
#define STRUCTURED_CHANNEL_LIST(_) \
|
||||
_(BaselineICStats)
|
||||
|
||||
// Structured spew channels
|
||||
enum class SpewChannel {
|
||||
#define STRUCTURED_CHANNEL(name) name,
|
||||
STRUCTURED_CHANNEL_LIST(STRUCTURED_CHANNEL)
|
||||
#undef STRUCTURED_CHANNEL
|
||||
Count
|
||||
};
|
||||
|
||||
// A filter is used to select what channels are enabled
|
||||
//
|
||||
// To save memory, JSScripts do not have their own filters, but instead have
|
||||
// a single bit which tracks if that script has opted into spewing.
|
||||
class StructuredSpewFilter
|
||||
{
|
||||
// Packed set of bits indicating what spew channels
|
||||
// are enabled.
|
||||
mozilla::EnumSet<SpewChannel> bits_;
|
||||
|
||||
public:
|
||||
// Default construct to all bits disabled.
|
||||
StructuredSpewFilter()
|
||||
: bits_()
|
||||
{}
|
||||
|
||||
// Return true iff spew is enabled for this channel for
|
||||
// the script this was created for.
|
||||
bool enabled(SpewChannel x) const {
|
||||
return bits_.contains(x);
|
||||
}
|
||||
|
||||
void enableChannel(SpewChannel x) {
|
||||
bits_ += x;
|
||||
}
|
||||
|
||||
void disableAll() {
|
||||
bits_.clear();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class StructuredSpewer
|
||||
{
|
||||
public:
|
||||
StructuredSpewer()
|
||||
: outputInitializationAttempted_(false),
|
||||
json_(mozilla::Nothing()),
|
||||
selectedChannels_()
|
||||
{
|
||||
// If we are recording or replaying, we cannot use getenv
|
||||
if (mozilla::recordreplay::IsRecordingOrReplaying()) {
|
||||
return;
|
||||
}
|
||||
if (getenv("SPEW")) {
|
||||
parseSpewFlags(getenv("SPEW"));
|
||||
}
|
||||
}
|
||||
|
||||
~StructuredSpewer() {
|
||||
if (json_.isSome()) {
|
||||
json_->endList();
|
||||
output_.flush();
|
||||
output_.finish();
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the spewer is enabled for a particular script, used to power
|
||||
// script level filtering.
|
||||
static bool enabled(JSScript* script);
|
||||
|
||||
// A generic printf like spewer that logs the formatted string.
|
||||
static void spew(JSContext* cx, SpewChannel channel, const char* fmt, ...) MOZ_FORMAT_PRINTF(3,4);
|
||||
|
||||
private:
|
||||
// In order to support lazy initialization, and simultaneously support a
|
||||
// failure to open a log file being non-fatal (as lazily reporting failure
|
||||
// would be hard, we have an akward set of states to represent.
|
||||
//
|
||||
// We need to handle:
|
||||
// - Output file not initialized, and not yet attempted
|
||||
// - Output file not intialized, attempted, and failed.
|
||||
// - Output file initialized, JSON writer ready for input.
|
||||
//
|
||||
// Because Fprinter doesn't record whether or not its initialization was
|
||||
// attempted, we keep track of that here.
|
||||
//
|
||||
// The contract we require is that ensureInitializationAttempted() be called
|
||||
// just before any attempte to write. This will ensure the file open is
|
||||
// attemped in the right place.
|
||||
bool outputInitializationAttempted_;
|
||||
Fprinter output_;
|
||||
mozilla::Maybe<JSONPrinter> json_;
|
||||
|
||||
// Globally selected channels.
|
||||
StructuredSpewFilter selectedChannels_;
|
||||
|
||||
using NameArray = mozilla::EnumeratedArray<SpewChannel,
|
||||
SpewChannel::Count,
|
||||
const char*>;
|
||||
// Channel Names
|
||||
static NameArray const names_;
|
||||
|
||||
// Return the global filter.
|
||||
StructuredSpewFilter& filter() {
|
||||
return selectedChannels_;
|
||||
}
|
||||
|
||||
// Get channel name
|
||||
static const char* getName(SpewChannel channel) {
|
||||
return names_[channel];
|
||||
}
|
||||
|
||||
// Call just before writes to the output are expected.
|
||||
//
|
||||
// Avoids opening files that will remain empty.
|
||||
void ensureInitializationAttempted();
|
||||
|
||||
void tryToInitializeOutput(const char* path);
|
||||
|
||||
// Using flags, choose the enabled channels for this spewer.
|
||||
void parseSpewFlags(const char* flags);
|
||||
|
||||
// Returns true iff the channels is enabled for the given script.
|
||||
bool enabled(JSContext* cx, const JSScript* script, SpewChannel channel) const;
|
||||
|
||||
// Start a record
|
||||
void startObject(JSContext* cx, const JSScript* script, SpewChannel channel);
|
||||
|
||||
friend class AutoStructuredSpewer;
|
||||
};
|
||||
|
||||
// An RAII class for accessing the structured spewer.
|
||||
//
|
||||
// This class prefixes the spew with channel and location information.
|
||||
//
|
||||
// Before writing with this Spewer, it must be checked: ie.
|
||||
//
|
||||
// {
|
||||
// AutoSpew x(...);
|
||||
// if (x) {
|
||||
// x->property("lalala", y);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// As the selected channel may not be enabled.
|
||||
//
|
||||
// Note: If the lifespan of two AutoSpewers overlap, then the output
|
||||
// may not be well defined JSON. These spewers should be given as
|
||||
// short a lifespan as possible.
|
||||
//
|
||||
// As well, this class cannot be copied or assigned to ensure the
|
||||
// correct number of destructors fire.
|
||||
class MOZ_RAII AutoStructuredSpewer {
|
||||
mozilla::Maybe<JSONPrinter*> printer_;
|
||||
AutoStructuredSpewer(const AutoStructuredSpewer&) = delete;
|
||||
void operator=(AutoStructuredSpewer&) = delete;
|
||||
public:
|
||||
|
||||
explicit AutoStructuredSpewer(JSContext* cx, SpewChannel channel, JSScript* script);
|
||||
|
||||
~AutoStructuredSpewer() {
|
||||
if (printer_.isSome()) {
|
||||
printer_.ref()->endObject();
|
||||
}
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return printer_.isSome();
|
||||
}
|
||||
|
||||
JSONPrinter* operator->() {
|
||||
MOZ_ASSERT(printer_.isSome());
|
||||
return printer_.ref();
|
||||
}
|
||||
|
||||
JSONPrinter& operator*() {
|
||||
MOZ_ASSERT(printer_.isSome());
|
||||
return *printer_.ref();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif
|
||||
#endif /* jit_StructuredSpewer_h */
|
|
@ -288,6 +288,20 @@ js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, c
|
|||
return n;
|
||||
}
|
||||
|
||||
bool
|
||||
js::ContainsFlag(const char* str, const char* flag)
|
||||
{
|
||||
size_t flaglen = strlen(flag);
|
||||
const char* index = strstr(str, flag);
|
||||
while (index) {
|
||||
if ((index == str || index[-1] == ',') && (index[flaglen] == 0 || index[flaglen] == ',')) {
|
||||
return true;
|
||||
}
|
||||
index = strstr(index + flaglen, flag);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template size_t
|
||||
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const Latin1Char* chars,
|
||||
size_t length, uint32_t quote);
|
||||
|
|
|
@ -226,6 +226,10 @@ FileEscapedString(FILE* fp, const char* chars, size_t length, uint32_t quote)
|
|||
JSString*
|
||||
EncodeURI(JSContext* cx, const char* chars, size_t length);
|
||||
|
||||
// Return true if input string contains a given flag in a comma separated list.
|
||||
bool
|
||||
ContainsFlag(const char* str, const char* flag);
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // util_Text_h
|
||||
|
|
|
@ -1863,8 +1863,8 @@ SetObjectElementOperation(JSContext* cx, HandleObject obj, HandleId id, HandleVa
|
|||
int32_t i = JSID_TO_INT(id);
|
||||
if ((uint32_t)i >= length) {
|
||||
// Annotate script if provided with information (e.g. baseline)
|
||||
if (script && script->hasBaselineScript() && IsSetElemPC(pc)) {
|
||||
script->baselineScript()->noteHasDenseAdd(script->pcToOffset(pc));
|
||||
if (script && script->hasICScript() && IsSetElemPC(pc)) {
|
||||
script->icScript()->noteHasDenseAdd(script->pcToOffset(pc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1375,6 +1375,9 @@ JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options)
|
|||
canSkipEnqueuingJobs(false),
|
||||
promiseRejectionTrackerCallback(nullptr),
|
||||
promiseRejectionTrackerCallbackData(nullptr)
|
||||
#ifdef JS_STRUCTURED_SPEW
|
||||
, structuredSpewer_()
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(static_cast<JS::RootingContext*>(this) ==
|
||||
JS::RootingContext::get(this));
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "js/Utility.h"
|
||||
#include "js/Vector.h"
|
||||
#include "threading/ProtectedData.h"
|
||||
#include "util/StructuredSpewer.h"
|
||||
#include "vm/ErrorReporting.h"
|
||||
#include "vm/MallocProvider.h"
|
||||
#include "vm/Runtime.h"
|
||||
|
@ -959,6 +960,15 @@ struct JSContext : public JS::RootingContext,
|
|||
template <class... Args> inline void check(const Args&... args);
|
||||
template <class... Args> inline void releaseCheck(const Args&... args);
|
||||
template <class... Args> MOZ_ALWAYS_INLINE void debugOnlyCheck(const Args&... args);
|
||||
|
||||
#ifdef JS_STRUCTURED_SPEW
|
||||
private:
|
||||
// Spewer for this thread
|
||||
js::ThreadData<js::StructuredSpewer> structuredSpewer_;
|
||||
public:
|
||||
js::StructuredSpewer& spewer() { return structuredSpewer_.ref(); }
|
||||
#endif
|
||||
|
||||
}; /* struct JSContext */
|
||||
|
||||
inline JS::Result<>
|
||||
|
|
|
@ -119,6 +119,14 @@ JSONPrinter::formatProperty(const char* name, const char* format, ...)
|
|||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
JSONPrinter::formatProperty(const char* name, const char* format, va_list ap)
|
||||
{
|
||||
beginStringProperty(name);
|
||||
out_.vprintf(format, ap);
|
||||
endStringProperty();
|
||||
}
|
||||
|
||||
void
|
||||
JSONPrinter::value(const char* format, ...)
|
||||
{
|
||||
|
|
|
@ -62,6 +62,7 @@ class JSONPrinter
|
|||
#endif
|
||||
|
||||
void formatProperty(const char* name, const char* format, ...) MOZ_FORMAT_PRINTF(3, 4);
|
||||
void formatProperty(const char* name, const char* format, va_list ap);
|
||||
|
||||
// JSON requires decimals to be separated by periods, but the LC_NUMERIC
|
||||
// setting may cause printf to use commas in some locales.
|
||||
|
|
|
@ -229,4 +229,11 @@ JSScript::trackRecordReplayProgress() const
|
|||
&& mozilla::recordreplay::ShouldUpdateProgressCounter(filename());
|
||||
}
|
||||
|
||||
inline js::jit::ICScript*
|
||||
JSScript::icScript() const
|
||||
{
|
||||
MOZ_ASSERT(hasICScript());
|
||||
return types_->icScript();
|
||||
}
|
||||
|
||||
#endif /* vm_JSScript_inl_h */
|
||||
|
|
|
@ -3517,6 +3517,11 @@ JSScript::fullyInitFromEmitter(JSContext* cx, HandleScript script, frontend::Byt
|
|||
initFromModuleContext(script);
|
||||
}
|
||||
|
||||
#ifdef JS_STRUCTURED_SPEW
|
||||
// We want this to happen after line number initialization to allow filtering to work.
|
||||
script->setSpewEnabled(StructuredSpewer::enabled(script));
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
script->assertValidJumpTargets();
|
||||
#endif
|
||||
|
@ -3629,7 +3634,7 @@ JSScript::finalize(FreeOp* fop)
|
|||
fop->runtime()->geckoProfiler().onScriptFinalized(this);
|
||||
|
||||
if (types_) {
|
||||
types_->destroy();
|
||||
types_->destroy(zone());
|
||||
}
|
||||
|
||||
jit::DestroyJitScripts(fop, this);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "js/UbiNode.h"
|
||||
#include "js/UniquePtr.h"
|
||||
#include "js/Utility.h"
|
||||
#include "util/StructuredSpewer.h"
|
||||
#include "vm/BytecodeIterator.h"
|
||||
#include "vm/BytecodeLocation.h"
|
||||
#include "vm/BytecodeUtil.h"
|
||||
|
@ -52,6 +53,7 @@ namespace js {
|
|||
|
||||
namespace jit {
|
||||
struct BaselineScript;
|
||||
class ICScript;
|
||||
struct IonScriptCounts;
|
||||
} // namespace jit
|
||||
|
||||
|
@ -1776,6 +1778,9 @@ class JSScript : public js::gc::TenuredCell
|
|||
|
||||
// Set if the debugger's onNewScript hook has not yet been called.
|
||||
HideScriptFromDebugger = 1 << 19,
|
||||
|
||||
// Set if the script has opted into spew
|
||||
SpewEnabled = 1 << 20,
|
||||
};
|
||||
private:
|
||||
// Note: don't make this a bitfield! It makes it hard to read these flags
|
||||
|
@ -2188,6 +2193,13 @@ class JSScript : public js::gc::TenuredCell
|
|||
clearFlag(MutableFlags::HideScriptFromDebugger);
|
||||
}
|
||||
|
||||
bool spewEnabled() const {
|
||||
return hasFlag(MutableFlags::SpewEnabled);
|
||||
}
|
||||
void setSpewEnabled(bool enabled) {
|
||||
setFlag(MutableFlags::SpewEnabled, enabled);
|
||||
}
|
||||
|
||||
bool needsHomeObject() const {
|
||||
return hasFlag(ImmutableFlags::NeedsHomeObject);
|
||||
}
|
||||
|
@ -2299,6 +2311,14 @@ class JSScript : public js::gc::TenuredCell
|
|||
}
|
||||
inline void setBaselineScript(JSRuntime* rt, js::jit::BaselineScript* baselineScript);
|
||||
|
||||
inline js::jit::ICScript* icScript() const;
|
||||
|
||||
bool hasICScript() const {
|
||||
// ICScript is stored in TypeScript so we have an ICScript iff we have a
|
||||
// TypeScript.
|
||||
return !!types_;
|
||||
}
|
||||
|
||||
void updateJitCodeRaw(JSRuntime* rt);
|
||||
|
||||
static size_t offsetOfBaselineScript() {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "mozilla/DebugOnly.h"
|
||||
|
||||
#include "gc/Marking.h"
|
||||
#include "jit/BaselineIC.h"
|
||||
#include "js/CharacterEncoding.h"
|
||||
#include "js/Value.h"
|
||||
#include "vm/Debugger.h"
|
||||
|
@ -22,6 +23,7 @@
|
|||
#include "vm/ArrayObject-inl.h"
|
||||
#include "vm/EnvironmentObject-inl.h"
|
||||
#include "vm/JSObject-inl.h"
|
||||
#include "vm/JSScript-inl.h"
|
||||
#include "vm/Shape-inl.h"
|
||||
#include "vm/TypeInference-inl.h"
|
||||
#include "vm/UnboxedObject-inl.h"
|
||||
|
@ -2339,12 +2341,12 @@ GetExistingProperty(JSContext* cx,
|
|||
{
|
||||
jsbytecode* pc;
|
||||
JSScript* script = cx->currentScript(&pc);
|
||||
if (script && script->hasBaselineScript()) {
|
||||
if (script && script->hasICScript()) {
|
||||
switch (JSOp(*pc)) {
|
||||
case JSOP_GETPROP:
|
||||
case JSOP_CALLPROP:
|
||||
case JSOP_LENGTH:
|
||||
script->baselineScript()->noteAccessedGetter(script->pcToOffset(pc));
|
||||
script->icScript()->noteAccessedGetter(script->pcToOffset(pc));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -823,20 +823,6 @@ TraceLoggerThreadState::~TraceLoggerThreadState()
|
|||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
ContainsFlag(const char* str, const char* flag)
|
||||
{
|
||||
size_t flaglen = strlen(flag);
|
||||
const char* index = strstr(str, flag);
|
||||
while (index) {
|
||||
if ((index == str || index[-1] == ',') && (index[flaglen] == 0 || index[flaglen] == ',')) {
|
||||
return true;
|
||||
}
|
||||
index = strstr(index + flaglen, flag);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
TraceLoggerThreadState::init()
|
||||
{
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "builtin/String.h"
|
||||
|
||||
#include "gc/HashUtil.h"
|
||||
#include "jit/BaselineIC.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/CompileInfo.h"
|
||||
#include "jit/Ion.h"
|
||||
|
@ -171,7 +172,7 @@ TypeSet::ObjectGroupString(const ObjectGroup* group)
|
|||
#ifdef DEBUG
|
||||
|
||||
bool
|
||||
js::InferSpewActive(SpewChannel channel)
|
||||
js::InferSpewActive(TypeSpewChannel channel)
|
||||
{
|
||||
static bool active[SPEW_COUNT];
|
||||
static bool checked = false;
|
||||
|
@ -3747,6 +3748,16 @@ JSScript::makeTypes(JSContext* cx)
|
|||
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
||||
UniquePtr<jit::ICScript> icScript(jit::ICScript::create(cx, this));
|
||||
if (!icScript) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need to call prepareForDestruction on ICScript before we |delete| it.
|
||||
auto prepareForDestruction = mozilla::MakeScopeExit([&] {
|
||||
icScript->prepareForDestruction(cx->zone());
|
||||
});
|
||||
|
||||
unsigned count = TypeScript::NumTypeSets(this);
|
||||
|
||||
size_t size = TypeScript::SizeIncludingTypeArray(count);
|
||||
|
@ -3755,6 +3766,9 @@ JSScript::makeTypes(JSContext* cx)
|
|||
return false;
|
||||
}
|
||||
|
||||
prepareForDestruction.release();
|
||||
typeScript->icScript_ = std::move(icScript);
|
||||
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
{
|
||||
StackTypeSet* typeArray = typeScript->typeArray();
|
||||
|
@ -4909,7 +4923,7 @@ JSScript::maybeReleaseTypes()
|
|||
|
||||
MOZ_ASSERT(!hasIonScript());
|
||||
|
||||
types_->destroy();
|
||||
types_->destroy(zone());
|
||||
types_ = nullptr;
|
||||
|
||||
// Freeze constraints on stack type sets need to be regenerated the
|
||||
|
@ -4918,8 +4932,10 @@ JSScript::maybeReleaseTypes()
|
|||
}
|
||||
|
||||
void
|
||||
TypeScript::destroy()
|
||||
TypeScript::destroy(Zone* zone)
|
||||
{
|
||||
icScript_->prepareForDestruction(zone);
|
||||
|
||||
js_delete(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ class HeapTypeSetKey;
|
|||
|
||||
namespace jit {
|
||||
|
||||
class ICScript;
|
||||
struct IonScript;
|
||||
class TempAllocator;
|
||||
|
||||
|
@ -234,6 +235,10 @@ class TypeScript
|
|||
// them as well.
|
||||
RecompileInfoVector inlinedCompilations_;
|
||||
|
||||
// ICScript and TypeScript have the same lifetimes, so we store a pointer to
|
||||
// ICScript here to not increase sizeof(JSScript).
|
||||
js::UniquePtr<js::jit::ICScript> icScript_;
|
||||
|
||||
// Variable-size array
|
||||
StackTypeSet typeArray_[1];
|
||||
|
||||
|
@ -248,6 +253,11 @@ class TypeScript
|
|||
return inlinedCompilations_.append(info);
|
||||
}
|
||||
|
||||
jit::ICScript* icScript() const {
|
||||
MOZ_ASSERT(icScript_);
|
||||
return icScript_.get();
|
||||
}
|
||||
|
||||
/* Array of type sets for variables and JOF_TYPESET ops. */
|
||||
StackTypeSet* typeArray() const {
|
||||
// Ensure typeArray_ is the last data member of TypeScript.
|
||||
|
@ -314,9 +324,10 @@ class TypeScript
|
|||
|
||||
static void Purge(JSContext* cx, HandleScript script);
|
||||
|
||||
void destroy();
|
||||
void destroy(Zone* zone);
|
||||
|
||||
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
|
||||
// Note: icScript_ size is reported in jit::AddSizeOfBaselineData.
|
||||
return mallocSizeOf(this);
|
||||
}
|
||||
|
||||
|
@ -435,7 +446,7 @@ class TypeZone
|
|||
}
|
||||
};
|
||||
|
||||
enum SpewChannel {
|
||||
enum TypeSpewChannel {
|
||||
ISpewOps, /* ops: New constraints and types. */
|
||||
ISpewResult, /* result: Final type sets. */
|
||||
SPEW_COUNT
|
||||
|
@ -443,7 +454,7 @@ enum SpewChannel {
|
|||
|
||||
#ifdef DEBUG
|
||||
|
||||
bool InferSpewActive(SpewChannel channel);
|
||||
bool InferSpewActive(TypeSpewChannel channel);
|
||||
const char * InferSpewColorReset();
|
||||
const char * InferSpewColor(TypeConstraint* constraint);
|
||||
const char * InferSpewColor(TypeSet* types);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "gc/Nursery-inl.h"
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
#include "vm/JSObject-inl.h"
|
||||
#include "vm/JSScript-inl.h"
|
||||
#include "vm/Shape-inl.h"
|
||||
#include "vm/TypeInference-inl.h"
|
||||
|
||||
|
@ -649,8 +650,8 @@ UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group)
|
|||
realm.replaceAllocationSiteGroup(script, pc, JSProto_Object, replacementGroup);
|
||||
|
||||
// Clear any baseline information at this opcode which might use the old group.
|
||||
if (script->hasBaselineScript()) {
|
||||
jit::ICEntry& entry = script->baselineScript()->icEntryFromPCOffset(script->pcToOffset(pc));
|
||||
if (script->hasICScript()) {
|
||||
jit::ICEntry& entry = script->icScript()->icEntryFromPCOffset(script->pcToOffset(pc));
|
||||
jit::ICFallbackStub* fallback = entry.fallbackStub();
|
||||
for (jit::ICStubIterator iter = fallback->beginChain(); !iter.atEnd(); iter++) {
|
||||
iter.unlink(cx);
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html reftest-async-scroll>
|
||||
<div style="transform: translateY(10px); margin-top: 90px">
|
||||
<div style="overflow:scroll; height: 400px; width: 400px; background-color: yellow"
|
||||
reftest-displayport-x="0"
|
||||
reftest-displayport-y="0"
|
||||
reftest-displayport-w="400"
|
||||
reftest-displayport-h="800"
|
||||
reftest-async-scroll-x="0"
|
||||
reftest-async-scroll-y="120">
|
||||
<div style="height: 800px">
|
||||
<div style="position:sticky; top: 0px; height: 20px; background-color: green">sticky</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html reftest-async-scroll>
|
||||
<div style="transform: translateY(90px); margin-top: 10px">
|
||||
<div style="overflow:scroll; height: 400px; width: 400px; background-color: yellow"
|
||||
reftest-displayport-x="0"
|
||||
reftest-displayport-y="0"
|
||||
reftest-displayport-w="400"
|
||||
reftest-displayport-h="800"
|
||||
reftest-async-scroll-x="0"
|
||||
reftest-async-scroll-y="120">
|
||||
<div style="height: 800px">
|
||||
<div style="position:sticky; top: 0px; height: 20px; background-color: green">sticky</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<div style="margin-top: 100px">
|
||||
<div id="scroller" style="overflow:scroll; height: 400px; width: 400px; background-color: yellow">
|
||||
<div style="height: 800px">
|
||||
<div style="position: relative; top: 120px; height: 20px; background-color: green">sticky</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.getElementById('scroller').scrollTop = 120;
|
||||
</script>
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<div id="scroller" style="overflow:scroll; height: 400px; width: 400px">
|
||||
<div style="transform: translateY(10px); margin-top: 90px; background-color: yellow; height: 400px">
|
||||
<div style="position: relative; top: 30px; height: 20px; background-color: green">sticky</div>
|
||||
</div>
|
||||
<div style="height: 400px">spacer</div>
|
||||
</div>
|
||||
<script>
|
||||
document.getElementById('scroller').scrollTop = 120;
|
||||
</script>
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html reftest-async-scroll>
|
||||
<div style="overflow:scroll; height: 400px; width: 400px"
|
||||
reftest-displayport-x="0"
|
||||
reftest-displayport-y="0"
|
||||
reftest-displayport-w="400"
|
||||
reftest-displayport-h="890"
|
||||
reftest-async-scroll-x="0"
|
||||
reftest-async-scroll-y="120">
|
||||
<div style="transform: translateY(10px); margin-top: 90px; background-color: yellow; height: 400px">
|
||||
<div style="position:sticky; top: 0px; height: 20px; background-color: green">sticky</div>
|
||||
</div>
|
||||
<div style="height: 400px">spacer</div>
|
||||
</div>
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<div id="scroller" style="overflow:scroll; height: 400px; width: 400px">
|
||||
<div style="margin-top: 120px; background-color: yellow; height: 380px">
|
||||
<div style="height: 90px"></div>
|
||||
<div style="height: 20px; background-color: green">sticky</div>
|
||||
</div>
|
||||
<div style="height: 310px"></div>
|
||||
</div>
|
||||
<script>
|
||||
document.getElementById('scroller').scrollTop = 120;
|
||||
</script>
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html reftest-async-scroll>
|
||||
<div style="overflow:scroll; height: 400px; width: 400px"
|
||||
reftest-displayport-x="0"
|
||||
reftest-displayport-y="0"
|
||||
reftest-displayport-w="400"
|
||||
reftest-displayport-h="890"
|
||||
reftest-async-scroll-x="0"
|
||||
reftest-async-scroll-y="120">
|
||||
<div style="transform: translateY(90px); margin-top: 10px; background-color: yellow; height: 400px">
|
||||
<div style="position:sticky; top: 0px; height: 20px; background-color: green">sticky</div>
|
||||
</div>
|
||||
<div style="height: 400px">spacer</div>
|
||||
</div>
|
|
@ -70,6 +70,10 @@ fuzzy-if(Android,0-6,0-4) skip-if(!asyncPan) == position-sticky-scrolled-clip-1.
|
|||
fuzzy-if(Android,0-6,0-4) skip == position-sticky-scrolled-clip-2.html position-sticky-scrolled-clip-2-ref.html # bug ?????? - incorrectly applying clip to sticky contents
|
||||
fuzzy-if(Android,0-2,0-4) skip-if(!asyncPan) == curtain-effect-1.html curtain-effect-1-ref.html
|
||||
fuzzy-if(Android,0-1,0-4) skip-if(!asyncPan) == transformed-1.html transformed-1-ref.html
|
||||
fuzzy-if(Android,2-2,4-4) skip-if(!asyncPan) == position-sticky-transformed-in-scrollframe-1.html position-sticky-transformed-in-scrollframe-1-ref.html
|
||||
fuzzy-if(Android,3-3,4-4) skip-if(!asyncPan) == position-sticky-transformed-in-scrollframe-2.html position-sticky-transformed-in-scrollframe-2-ref.html
|
||||
fuzzy-if(Android,3-3,4-4) skip-if(!asyncPan) == position-sticky-in-transformed-scrollframe-1.html position-sticky-in-transformed-scrollframe-ref.html
|
||||
fuzzy-if(Android,3-3,4-4) skip-if(!asyncPan) == position-sticky-in-transformed-scrollframe-2.html position-sticky-in-transformed-scrollframe-ref.html
|
||||
|
||||
# for the following tests, we want to disable the low-precision buffer
|
||||
# as it will expand the displayport beyond what the test specifies in
|
||||
|
|
|
@ -238,12 +238,6 @@ var validGradientAndElementValues = [
|
|||
"radial-gradient(at left calc(100px + -25%), red, blue)",
|
||||
"radial-gradient(at calc(100px + -25px) top, red, blue)",
|
||||
"radial-gradient(at left calc(100px + -25px), red, blue)",
|
||||
|
||||
"-webkit-linear-gradient(top, red, blue)",
|
||||
"-moz-linear-gradient(top, red, blue)",
|
||||
"-moz-linear-gradient(center 0%, red, blue)",
|
||||
"-moz-linear-gradient(50% top, red, blue)",
|
||||
"-moz-linear-gradient(50% 0%, red, blue)",
|
||||
];
|
||||
var invalidGradientAndElementValues = [
|
||||
"-moz-element(#a:1)",
|
||||
|
@ -647,6 +641,7 @@ if (IsCSSPropertyPrefEnabled("layout.css.prefixes.webkit")) {
|
|||
"-webkit-radial-gradient(contain ellipse, red, blue)",
|
||||
|
||||
// Initial side/corner/point (valid only for -moz/-webkit prefixed):
|
||||
"-webkit-linear-gradient(top, red, blue)",
|
||||
"-webkit-linear-gradient(left, red, blue)",
|
||||
"-webkit-linear-gradient(bottom, red, blue)",
|
||||
"-webkit-linear-gradient(right top, red, blue)",
|
||||
|
@ -850,6 +845,11 @@ if (IsCSSPropertyPrefEnabled("layout.css.prefixes.gradients")) {
|
|||
"-moz-linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
|
||||
"-moz-linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
|
||||
|
||||
"-moz-linear-gradient(top, red, blue)",
|
||||
"-moz-linear-gradient(center 0%, red, blue)",
|
||||
"-moz-linear-gradient(50% top, red, blue)",
|
||||
"-moz-linear-gradient(50% 0%, red, blue)",
|
||||
|
||||
"-moz-linear-gradient(to top, red, blue)",
|
||||
"-moz-linear-gradient(to bottom, red, blue)",
|
||||
"-moz-linear-gradient(to left, red, blue)",
|
||||
|
|
|
@ -116,6 +116,7 @@ nrappkit copyright:
|
|||
#include "nsIPrefBranch.h"
|
||||
#include "nsISocketFilter.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
|
@ -2160,6 +2161,10 @@ NrSocketBase::CreateSocket(nr_transport_addr *addr,
|
|||
{
|
||||
int r, _status;
|
||||
|
||||
if (IsForbiddenAddress(addr)) {
|
||||
ABORT(R_REJECTED);
|
||||
}
|
||||
|
||||
// create IPC bridge for content process
|
||||
if (XRE_IsParentProcess()) {
|
||||
*sock = new NrSocket();
|
||||
|
@ -2196,6 +2201,26 @@ abort:
|
|||
return _status;
|
||||
}
|
||||
|
||||
// static
|
||||
bool NrSocketBase::IsForbiddenAddress(nr_transport_addr *addr) {
|
||||
int r, port;
|
||||
|
||||
r = nr_transport_addr_get_port(addr, &port);
|
||||
if (r) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// allow auto assigned ports
|
||||
if (port != 0) {
|
||||
// Don't need to check an override scheme
|
||||
nsresult rv = NS_CheckPortSafety(port, nullptr);
|
||||
if(NS_FAILED(rv)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int nr_socket_local_destroy(void **objp) {
|
||||
if(!objp || !*objp)
|
||||
|
|
|
@ -103,6 +103,7 @@ public:
|
|||
static int CreateSocket(nr_transport_addr *addr,
|
||||
RefPtr<NrSocketBase> *sock,
|
||||
const std::shared_ptr<NrSocketProxyConfig>& config);
|
||||
static bool IsForbiddenAddress(nr_transport_addr *addr);
|
||||
|
||||
// the nr_socket APIs
|
||||
virtual int create(nr_transport_addr *addr) = 0;
|
||||
|
|
|
@ -462,6 +462,47 @@ class TestNrSocketTest : public MtransportTest {
|
|||
|
||||
using mozilla::TestNrSocketTest;
|
||||
using mozilla::TestNat;
|
||||
using mozilla::NrSocketBase;
|
||||
|
||||
TEST_F(TestNrSocketTest, UnsafePortRejectedUDP) {
|
||||
nr_transport_addr address;
|
||||
ASSERT_FALSE(nr_str_port_to_transport_addr("127.0.0.1",
|
||||
// ssh
|
||||
22,
|
||||
IPPROTO_UDP,
|
||||
&address));
|
||||
ASSERT_TRUE(NrSocketBase::IsForbiddenAddress(&address));
|
||||
}
|
||||
|
||||
TEST_F(TestNrSocketTest, UnsafePortRejectedTCP) {
|
||||
nr_transport_addr address;
|
||||
ASSERT_FALSE(nr_str_port_to_transport_addr("127.0.0.1",
|
||||
// ssh
|
||||
22,
|
||||
IPPROTO_TCP,
|
||||
&address));
|
||||
ASSERT_TRUE(NrSocketBase::IsForbiddenAddress(&address));
|
||||
}
|
||||
|
||||
TEST_F(TestNrSocketTest, SafePortAcceptedUDP) {
|
||||
nr_transport_addr address;
|
||||
ASSERT_FALSE(nr_str_port_to_transport_addr("127.0.0.1",
|
||||
// stuns
|
||||
5349,
|
||||
IPPROTO_UDP,
|
||||
&address));
|
||||
ASSERT_FALSE(NrSocketBase::IsForbiddenAddress(&address));
|
||||
}
|
||||
|
||||
TEST_F(TestNrSocketTest, SafePortAcceptedTCP) {
|
||||
nr_transport_addr address;
|
||||
ASSERT_FALSE(nr_str_port_to_transport_addr("127.0.0.1",
|
||||
// turns
|
||||
5349,
|
||||
IPPROTO_TCP,
|
||||
&address));
|
||||
ASSERT_FALSE(NrSocketBase::IsForbiddenAddress(&address));
|
||||
}
|
||||
|
||||
TEST_F(TestNrSocketTest, PublicConnectivity) {
|
||||
CreatePublicAddrs(2);
|
||||
|
|
|
@ -1673,7 +1673,6 @@ public:
|
|||
mTrack.get(),
|
||||
mSource.get()));
|
||||
|
||||
mSource->AdvanceKnownTracksTime(STREAM_TIME_MAX);
|
||||
mSource->AddTrackListener(this, mTrackId);
|
||||
}
|
||||
|
||||
|
@ -1681,7 +1680,7 @@ public:
|
|||
{
|
||||
if (!mListening) {
|
||||
mListening = true;
|
||||
mSource->SetPullEnabled(true);
|
||||
mSource->SetPullingEnabled(mTrackId, true);
|
||||
mMaybeTrackNeedsUnmute = true;
|
||||
}
|
||||
}
|
||||
|
@ -1690,7 +1689,7 @@ public:
|
|||
{
|
||||
if (mListening) {
|
||||
mListening = false;
|
||||
mSource->SetPullEnabled(false);
|
||||
mSource->SetPullingEnabled(mTrackId, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -154,7 +154,9 @@ public final class GeckoLoader {
|
|||
putenv("CACHE_DIRECTORY=" + f.getPath());
|
||||
|
||||
f = context.getExternalFilesDir(null);
|
||||
putenv("PUBLIC_STORAGE=" + f.getPath());
|
||||
if (f != null) {
|
||||
putenv("PUBLIC_STORAGE=" + f.getPath());
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 17) {
|
||||
android.os.UserManager um = (android.os.UserManager)context.getSystemService(Context.USER_SERVICE);
|
||||
|
|
|
@ -714,12 +714,18 @@ VARCACHE_PREF(
|
|||
bool, true
|
||||
)
|
||||
|
||||
// Is -moz-prefixed gradient functions enabled?
|
||||
// Are -moz-prefixed gradient functions enabled?
|
||||
#ifdef EARLY_BETA_OR_EARLIER
|
||||
# define PREF_VALUE false
|
||||
#else
|
||||
# define PREF_VALUE true
|
||||
#endif
|
||||
VARCACHE_PREF(
|
||||
"layout.css.prefixes.gradients",
|
||||
layout_css_prefixes_gradients,
|
||||
bool, true
|
||||
bool, PREF_VALUE
|
||||
)
|
||||
#undef PREF_VALUE
|
||||
|
||||
// Whether the offset-* logical property aliases are enabled.
|
||||
VARCACHE_PREF(
|
||||
|
|
|
@ -216,57 +216,6 @@ ReauthenticateUserWindows(const nsACString& aPrompt,
|
|||
}
|
||||
#endif // XP_WIN
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <Security/Security.h>
|
||||
|
||||
static nsresult
|
||||
ReauthenticateUserMacOS(const nsACString& aPrompt,
|
||||
/* out */ bool& aReauthenticated)
|
||||
{
|
||||
// The idea here is that we ask to be authorized to unlock the user's session.
|
||||
// This should cause a prompt to come up for the user asking them for their
|
||||
// password. If they correctly enter it, we'll return a successful result. If
|
||||
// they cancel the prompt or otherwise fail to provide their password, we
|
||||
// return a failing result.
|
||||
AuthorizationItem authorizationItems[] = {
|
||||
{ "system.login.screensaver", 0, NULL, 0 },
|
||||
};
|
||||
AuthorizationRights authorizationRights = {
|
||||
ArrayLength(authorizationItems),
|
||||
authorizationItems,
|
||||
};
|
||||
const nsCString& promptFlat = PromiseFlatCString(aPrompt);
|
||||
// All "kAuthorization..." constants come from the MacOS SDK.
|
||||
AuthorizationItem environmentItems[] = {
|
||||
{ kAuthorizationEnvironmentPrompt,
|
||||
promptFlat.Length(),
|
||||
(void*)promptFlat.get(),
|
||||
0
|
||||
},
|
||||
};
|
||||
AuthorizationEnvironment environment = {
|
||||
ArrayLength(environmentItems),
|
||||
environmentItems,
|
||||
};
|
||||
AuthorizationFlags flags = kAuthorizationFlagDefaults |
|
||||
kAuthorizationFlagInteractionAllowed |
|
||||
kAuthorizationFlagExtendRights |
|
||||
kAuthorizationFlagPreAuthorize |
|
||||
kAuthorizationFlagDestroyRights;
|
||||
AuthorizationRef authorizationRef = nullptr;
|
||||
OSStatus result = AuthorizationCreate(&authorizationRights,
|
||||
&environment,
|
||||
flags,
|
||||
&authorizationRef);
|
||||
aReauthenticated = result == errAuthorizationSuccess;
|
||||
if (authorizationRef) {
|
||||
AuthorizationFree(authorizationRef, kAuthorizationFlagDestroyRights);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
#endif // XP_MACOSX
|
||||
|
||||
static nsresult
|
||||
ReauthenticateUser(const nsACString& prompt, /* out */ bool& reauthenticated)
|
||||
{
|
||||
|
|
|
@ -23,4 +23,10 @@ private:
|
|||
virtual ~OSReauthenticator() = default;
|
||||
};
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
nsresult
|
||||
ReauthenticateUserMacOS(const nsACString& aPrompt,
|
||||
/* out */ bool& aReauthenticated);
|
||||
#endif // XP_MACOSX
|
||||
|
||||
#endif // OSReauthenticator_h
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "OSReauthenticator.h"
|
||||
|
||||
#include "nsCocoaUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <LocalAuthentication/LocalAuthentication.h>
|
||||
|
||||
nsresult
|
||||
ReauthenticateUserMacOS(const nsACString& aPrompt,
|
||||
/* out */ bool& aReauthenticated)
|
||||
{
|
||||
// The idea here is that we ask to be authorized to unlock the user's session.
|
||||
// This should cause a prompt to come up for the user asking them for their
|
||||
// password. If they correctly enter it, we'll set aReauthenticated to true.
|
||||
|
||||
LAContext* context = [[LAContext alloc] init];
|
||||
NSString* prompt = nsCocoaUtils::ToNSString(NS_ConvertUTF8toUTF16(aPrompt));
|
||||
|
||||
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
||||
|
||||
__block BOOL biometricSuccess; // mark variable r/w across the block
|
||||
|
||||
// Note: This is an async callback in an already-async Promise chain.
|
||||
[context evaluatePolicy:LAPolicyDeviceOwnerAuthentication
|
||||
localizedReason:prompt
|
||||
reply:^(BOOL success, NSError *error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// error is not particularly useful in this context, and we have no
|
||||
// mechanism to really return it. We could use it to set the nsresult,
|
||||
// but this is a best-effort mechanism and there's no particular case for
|
||||
// propagating up XPCOM.
|
||||
biometricSuccess = success;
|
||||
dispatch_semaphore_signal(sema);
|
||||
});
|
||||
}];
|
||||
|
||||
// What we want to do here is convert this into a blocking call, since
|
||||
// our calling methods expect us to block and set aReauthenticated on return.
|
||||
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
|
||||
dispatch_release(sema);
|
||||
sema = NULL;
|
||||
|
||||
aReauthenticated = biometricSuccess;
|
||||
|
||||
[context release];
|
||||
return NS_OK;
|
||||
}
|
|
@ -151,9 +151,11 @@ if CONFIG['MOZ_LIB_SECRET']:
|
|||
if CONFIG['OS_ARCH'] == 'Darwin':
|
||||
UNIFIED_SOURCES += [
|
||||
'KeychainSecret.cpp',
|
||||
'OSReauthenticatorDarwin.mm',
|
||||
]
|
||||
OS_LIBS += [
|
||||
'-framework Security'
|
||||
'-framework LocalAuthentication',
|
||||
'-framework Security',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
|
|
|
@ -674,6 +674,87 @@ SandboxBroker::SetSecurityLevelForGPUProcess(int32_t aSandboxLevel)
|
|||
return false; \
|
||||
} while (0)
|
||||
|
||||
bool
|
||||
SandboxBroker::SetSecurityLevelForRDDProcess()
|
||||
{
|
||||
if (!mPolicy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto result = SetJobLevel(mPolicy, sandbox::JOB_LOCKDOWN,
|
||||
0 /* ui_exceptions */);
|
||||
SANDBOX_ENSURE_SUCCESS(result,
|
||||
"SetJobLevel should never fail with these arguments, what happened?");
|
||||
|
||||
result = mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
|
||||
sandbox::USER_LOCKDOWN);
|
||||
SANDBOX_ENSURE_SUCCESS(result,
|
||||
"SetTokenLevel should never fail with these arguments, what happened?");
|
||||
|
||||
result = mPolicy->SetAlternateDesktop(true);
|
||||
if (NS_WARN_IF(result != sandbox::SBOX_ALL_OK)) {
|
||||
LOG_W("SetAlternateDesktop failed, result: %i, last error: %x",
|
||||
result, ::GetLastError());
|
||||
}
|
||||
|
||||
result = mPolicy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
|
||||
SANDBOX_ENSURE_SUCCESS(result,
|
||||
"SetIntegrityLevel should never fail with these arguments, what happened?");
|
||||
|
||||
result =
|
||||
mPolicy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED);
|
||||
SANDBOX_ENSURE_SUCCESS(result,
|
||||
"SetDelayedIntegrityLevel should never fail with these arguments, what happened?");
|
||||
|
||||
sandbox::MitigationFlags mitigations =
|
||||
sandbox::MITIGATION_BOTTOM_UP_ASLR |
|
||||
sandbox::MITIGATION_HEAP_TERMINATE |
|
||||
sandbox::MITIGATION_SEHOP |
|
||||
sandbox::MITIGATION_EXTENSION_POINT_DISABLE |
|
||||
sandbox::MITIGATION_DEP_NO_ATL_THUNK |
|
||||
sandbox::MITIGATION_DEP |
|
||||
sandbox::MITIGATION_DYNAMIC_CODE_DISABLE |
|
||||
sandbox::MITIGATION_IMAGE_LOAD_PREFER_SYS32;
|
||||
|
||||
result = mPolicy->SetProcessMitigations(mitigations);
|
||||
SANDBOX_ENSURE_SUCCESS(result,
|
||||
"Invalid flags for SetProcessMitigations.");
|
||||
|
||||
mitigations =
|
||||
sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
|
||||
sandbox::MITIGATION_DLL_SEARCH_ORDER;
|
||||
|
||||
result = mPolicy->SetDelayedProcessMitigations(mitigations);
|
||||
SANDBOX_ENSURE_SUCCESS(result,
|
||||
"Invalid flags for SetDelayedProcessMitigations.");
|
||||
|
||||
// Add the policy for the client side of a pipe. It is just a file
|
||||
// in the \pipe\ namespace. We restrict it to pipes that start with
|
||||
// "chrome." so the sandboxed process cannot connect to system services.
|
||||
result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
|
||||
sandbox::TargetPolicy::FILES_ALLOW_ANY,
|
||||
L"\\??\\pipe\\chrome.*");
|
||||
SANDBOX_ENSURE_SUCCESS(result,
|
||||
"With these static arguments AddRule should never fail, what happened?");
|
||||
|
||||
// Add the policy for the client side of the crash server pipe.
|
||||
result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
|
||||
sandbox::TargetPolicy::FILES_ALLOW_ANY,
|
||||
L"\\??\\pipe\\gecko-crash-server-pipe.*");
|
||||
SANDBOX_ENSURE_SUCCESS(result,
|
||||
"With these static arguments AddRule should never fail, what happened?");
|
||||
|
||||
// The process needs to be able to duplicate shared memory handles,
|
||||
// which are Section handles, to the content processes.
|
||||
result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES,
|
||||
sandbox::TargetPolicy::HANDLES_DUP_ANY,
|
||||
L"Section");
|
||||
SANDBOX_ENSURE_SUCCESS(result,
|
||||
"With these static arguments AddRule should never fail, what happened?");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SandboxBroker::SetSecurityLevelForPluginProcess(int32_t aSandboxLevel)
|
||||
{
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
#endif
|
||||
|
||||
void SetSecurityLevelForGPUProcess(int32_t aSandboxLevel);
|
||||
bool SetSecurityLevelForRDDProcess();
|
||||
|
||||
bool SetSecurityLevelForPluginProcess(int32_t aSandboxLevel);
|
||||
enum SandboxLevel {
|
||||
|
|
|
@ -284,6 +284,8 @@ def run_tests(config, test_paths, product, **kwargs):
|
|||
logger.suite_end()
|
||||
if repeat_until_unexpected and unexpected_total > 0:
|
||||
break
|
||||
if len(test_loader.test_ids) == skipped_tests:
|
||||
break;
|
||||
|
||||
if test_total == 0:
|
||||
if skipped_tests > 0:
|
||||
|
|
|
@ -32,6 +32,13 @@ const PROXY_TYPES_MAP = new Map([
|
|||
["autoConfig", proxySvc.PROXYCONFIG_PAC],
|
||||
]);
|
||||
|
||||
const DEFAULT_PORTS = new Map([
|
||||
["http", 80],
|
||||
["ssl", 443],
|
||||
["ftp", 21],
|
||||
["socks", 1080],
|
||||
]);
|
||||
|
||||
ExtensionPreferencesManager.addSetting("proxy.settings", {
|
||||
prefNames: [
|
||||
"network.proxy.type",
|
||||
|
@ -66,8 +73,8 @@ ExtensionPreferencesManager.addSetting("proxy.settings", {
|
|||
if (value[prop]) {
|
||||
let url = new URL(`http://${value[prop]}`);
|
||||
prefs[`network.proxy.${prop}`] = url.hostname;
|
||||
let port = parseInt(url.port, 10);
|
||||
prefs[`network.proxy.${prop}_port`] = isNaN(port) ? 0 : port;
|
||||
let port = parseInt(url.port, 10) || DEFAULT_PORTS.get(prop);
|
||||
prefs[`network.proxy.${prop}_port`] = port;
|
||||
} else {
|
||||
prefs[`network.proxy.${prop}`] = undefined;
|
||||
prefs[`network.proxy.${prop}_port`] = undefined;
|
||||
|
|
|
@ -88,7 +88,8 @@
|
|||
},
|
||||
"headerURL": {
|
||||
"$ref": "ImageDataOrExtensionURL",
|
||||
"optional": true
|
||||
"optional": true,
|
||||
"deprecated": "Please use <em>theme.images.theme_frame</em>, this alias will be removed in Firefox 69."
|
||||
},
|
||||
"theme_frame": {
|
||||
"$ref": "ImageDataOrExtensionURL",
|
||||
|
@ -107,7 +108,8 @@
|
|||
},
|
||||
"accentcolor": {
|
||||
"$ref": "ThemeColor",
|
||||
"optional": true
|
||||
"optional": true,
|
||||
"deprecated": "Please use <em>theme.colors.frame</em>, this alias will be removed in Firefox 69."
|
||||
},
|
||||
"frame": {
|
||||
"$ref": "ThemeColor",
|
||||
|
@ -119,7 +121,8 @@
|
|||
},
|
||||
"textcolor": {
|
||||
"$ref": "ThemeColor",
|
||||
"optional": true
|
||||
"optional": true,
|
||||
"deprecated": "Please use <em>theme.colors.tab_background_text</em>, this alias will be removed in Firefox 69."
|
||||
},
|
||||
"tab_background_text": {
|
||||
"$ref": "ThemeColor",
|
||||
|
@ -147,7 +150,8 @@
|
|||
},
|
||||
"toolbar_text": {
|
||||
"$ref": "ThemeColor",
|
||||
"optional": true
|
||||
"optional": true,
|
||||
"deprecated": "Please use <em>theme.colors.bookmark_text</em>, this alias will be removed in Firefox 69."
|
||||
},
|
||||
"bookmark_text": {
|
||||
"$ref": "ThemeColor",
|
||||
|
|
|
@ -17,7 +17,7 @@ add_task(async function test_management_themes() {
|
|||
"description": "test theme",
|
||||
"theme": {
|
||||
"images": {
|
||||
"headerURL": "image1.png",
|
||||
"theme_frame": "image1.png",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
/* globals InspectorUtils */
|
||||
|
||||
// Case 1 - When there is a headerURL image and additional_backgrounds_alignment is not specified.
|
||||
// Case 1 - When there is a theme_frame image and additional_backgrounds_alignment is not specified.
|
||||
// So background-position should default to "right top"
|
||||
add_task(async function test_default_additional_backgrounds_alignment() {
|
||||
const RIGHT_TOP = "100% 0%";
|
||||
|
@ -11,12 +11,12 @@ add_task(async function test_default_additional_backgrounds_alignment() {
|
|||
manifest: {
|
||||
"theme": {
|
||||
"images": {
|
||||
"headerURL": "image1.png",
|
||||
"theme_frame": "image1.png",
|
||||
"additional_backgrounds": ["image1.png", "image1.png"],
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR,
|
||||
"textcolor": TEXT_COLOR,
|
||||
"frame": ACCENT_COLOR,
|
||||
"tab_background_text": TEXT_COLOR,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -34,7 +34,7 @@ add_task(async function test_default_additional_backgrounds_alignment() {
|
|||
Assert.equal(
|
||||
rootCS.getPropertyValue("background-position"),
|
||||
RIGHT_TOP,
|
||||
"root only contains headerURL alignment property"
|
||||
"root only contains theme_frame alignment property"
|
||||
);
|
||||
|
||||
|
||||
|
@ -51,7 +51,7 @@ add_task(async function test_default_additional_backgrounds_alignment() {
|
|||
});
|
||||
|
||||
|
||||
// Case 2 - When there is a headerURL image and additional_backgrounds_alignment is specified.
|
||||
// Case 2 - When there is a theme_frame image and additional_backgrounds_alignment is specified.
|
||||
add_task(async function test_additional_backgrounds_alignment() {
|
||||
const LEFT_BOTTOM = "0% 100%";
|
||||
const CENTER_CENTER = "50% 50%";
|
||||
|
@ -61,12 +61,12 @@ add_task(async function test_additional_backgrounds_alignment() {
|
|||
manifest: {
|
||||
"theme": {
|
||||
"images": {
|
||||
"headerURL": "image1.png",
|
||||
"theme_frame": "image1.png",
|
||||
"additional_backgrounds": ["image1.png", "image1.png", "image1.png"],
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR,
|
||||
"textcolor": TEXT_COLOR,
|
||||
"frame": ACCENT_COLOR,
|
||||
"tab_background_text": TEXT_COLOR,
|
||||
},
|
||||
"properties": {
|
||||
additional_backgrounds_alignment: ["left bottom", "center center", "right top"],
|
||||
|
@ -87,7 +87,7 @@ add_task(async function test_additional_backgrounds_alignment() {
|
|||
Assert.equal(
|
||||
rootCS.getPropertyValue("background-position"),
|
||||
RIGHT_TOP,
|
||||
"root only contains headerURL alignment property"
|
||||
"root only contains theme_frame alignment property"
|
||||
);
|
||||
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
"use strict";
|
||||
|
||||
add_task(async function test_alpha_accentcolor() {
|
||||
add_task(async function test_alpha_frame_color() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"theme": {
|
||||
"images": {
|
||||
"headerURL": "image1.png",
|
||||
"theme_frame": "image1.png",
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": "rgba(230, 128, 0, 0.1)",
|
||||
"textcolor": TEXT_COLOR,
|
||||
"frame": "rgba(230, 128, 0, 0.1)",
|
||||
"tab_background_text": TEXT_COLOR,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -24,11 +24,11 @@ add_task(async function test_popup_styling(browser, accDoc) {
|
|||
manifest: {
|
||||
"theme": {
|
||||
"images": {
|
||||
"headerURL": "image1.png",
|
||||
"theme_frame": "image1.png",
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR,
|
||||
"textcolor": TEXT_COLOR,
|
||||
"frame": ACCENT_COLOR,
|
||||
"tab_background_text": TEXT_COLOR,
|
||||
"popup": POPUP_BACKGROUND_COLOR,
|
||||
"popup_text": POPUP_TEXT_COLOR,
|
||||
"popup_border": POPUP_BORDER_COLOR,
|
||||
|
|
|
@ -80,11 +80,11 @@ add_task(async function test_popup_url() {
|
|||
manifest: {
|
||||
"theme": {
|
||||
"images": {
|
||||
"headerURL": "image1.png",
|
||||
"theme_frame": "image1.png",
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR,
|
||||
"textcolor": TEXT_COLOR,
|
||||
"frame": ACCENT_COLOR,
|
||||
"tab_background_text": TEXT_COLOR,
|
||||
"popup": POPUP_COLOR,
|
||||
"popup_border": POPUP_BORDER_COLOR,
|
||||
"popup_text": POPUP_TEXT_COLOR_DARK,
|
||||
|
@ -179,11 +179,11 @@ add_task(async function test_popup_url() {
|
|||
manifest: {
|
||||
"theme": {
|
||||
"images": {
|
||||
"headerURL": "image1.png",
|
||||
"theme_frame": "image1.png",
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR,
|
||||
"textcolor": TEXT_COLOR,
|
||||
"frame": ACCENT_COLOR,
|
||||
"tab_background_text": TEXT_COLOR,
|
||||
"popup": POPUP_COLOR,
|
||||
"popup_text": POPUP_TEXT_COLOR_BRIGHT,
|
||||
"popup_highlight": POPUP_SELECTED_COLOR,
|
||||
|
|
|
@ -19,21 +19,21 @@ add_task(async function test_get_current() {
|
|||
|
||||
const theme1 = {
|
||||
"images": {
|
||||
"headerURL": "image1.png",
|
||||
"theme_frame": "image1.png",
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR_1,
|
||||
"textcolor": TEXT_COLOR_1,
|
||||
"frame": ACCENT_COLOR_1,
|
||||
"tab_background_text": TEXT_COLOR_1,
|
||||
},
|
||||
};
|
||||
|
||||
const theme2 = {
|
||||
"images": {
|
||||
"headerURL": "image2.png",
|
||||
"theme_frame": "image2.png",
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR_2,
|
||||
"textcolor": TEXT_COLOR_2,
|
||||
"frame": ACCENT_COLOR_2,
|
||||
"tab_background_text": TEXT_COLOR_2,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -61,26 +61,26 @@ add_task(async function test_get_current() {
|
|||
|
||||
function testTheme1(returnedTheme) {
|
||||
browser.test.assertTrue(
|
||||
returnedTheme.images.headerURL.includes("image1.png"),
|
||||
"Theme 1 header URL should be applied");
|
||||
returnedTheme.images.theme_frame.includes("image1.png"),
|
||||
"Theme 1 theme_frame image should be applied");
|
||||
browser.test.assertEq(
|
||||
ACCENT_COLOR_1, returnedTheme.colors.accentcolor,
|
||||
"Theme 1 accent color should be applied");
|
||||
ACCENT_COLOR_1, returnedTheme.colors.frame,
|
||||
"Theme 1 frame color should be applied");
|
||||
browser.test.assertEq(
|
||||
TEXT_COLOR_1, returnedTheme.colors.textcolor,
|
||||
"Theme 1 text color should be applied");
|
||||
TEXT_COLOR_1, returnedTheme.colors.tab_background_text,
|
||||
"Theme 1 tab_background_text color should be applied");
|
||||
}
|
||||
|
||||
function testTheme2(returnedTheme) {
|
||||
browser.test.assertTrue(
|
||||
returnedTheme.images.headerURL.includes("image2.png"),
|
||||
"Theme 2 header URL should be applied");
|
||||
returnedTheme.images.theme_frame.includes("image2.png"),
|
||||
"Theme 2 theme_frame image should be applied");
|
||||
browser.test.assertEq(
|
||||
ACCENT_COLOR_2, returnedTheme.colors.accentcolor,
|
||||
"Theme 2 accent color should be applied");
|
||||
ACCENT_COLOR_2, returnedTheme.colors.frame,
|
||||
"Theme 2 frame color should be applied");
|
||||
browser.test.assertEq(
|
||||
TEXT_COLOR_2, returnedTheme.colors.textcolor,
|
||||
"Theme 2 text color should be applied");
|
||||
TEXT_COLOR_2, returnedTheme.colors.tab_background_text,
|
||||
"Theme 2 tab_background_text color should be applied");
|
||||
}
|
||||
|
||||
function testEmptyTheme(returnedTheme) {
|
||||
|
|
|
@ -19,46 +19,46 @@ add_task(async function test_on_updated() {
|
|||
|
||||
const theme1 = {
|
||||
"images": {
|
||||
"headerURL": "image1.png",
|
||||
"theme_frame": "image1.png",
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR_1,
|
||||
"textcolor": TEXT_COLOR_1,
|
||||
"frame": ACCENT_COLOR_1,
|
||||
"tab_background_text": TEXT_COLOR_1,
|
||||
},
|
||||
};
|
||||
|
||||
const theme2 = {
|
||||
"images": {
|
||||
"headerURL": "image2.png",
|
||||
"theme_frame": "image2.png",
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR_2,
|
||||
"textcolor": TEXT_COLOR_2,
|
||||
"frame": ACCENT_COLOR_2,
|
||||
"tab_background_text": TEXT_COLOR_2,
|
||||
},
|
||||
};
|
||||
|
||||
function testTheme1(returnedTheme) {
|
||||
browser.test.assertTrue(
|
||||
returnedTheme.images.headerURL.includes("image1.png"),
|
||||
"Theme 1 header URL should be applied");
|
||||
returnedTheme.images.theme_frame.includes("image1.png"),
|
||||
"Theme 1 theme_frame image should be applied");
|
||||
browser.test.assertEq(
|
||||
ACCENT_COLOR_1, returnedTheme.colors.accentcolor,
|
||||
"Theme 1 accent color should be applied");
|
||||
ACCENT_COLOR_1, returnedTheme.colors.frame,
|
||||
"Theme 1 frame color should be applied");
|
||||
browser.test.assertEq(
|
||||
TEXT_COLOR_1, returnedTheme.colors.textcolor,
|
||||
"Theme 1 text color should be applied");
|
||||
TEXT_COLOR_1, returnedTheme.colors.tab_background_text,
|
||||
"Theme 1 tab_background_text color should be applied");
|
||||
}
|
||||
|
||||
function testTheme2(returnedTheme) {
|
||||
browser.test.assertTrue(
|
||||
returnedTheme.images.headerURL.includes("image2.png"),
|
||||
"Theme 2 header URL should be applied");
|
||||
returnedTheme.images.theme_frame.includes("image2.png"),
|
||||
"Theme 2 theme_frame image should be applied");
|
||||
browser.test.assertEq(
|
||||
ACCENT_COLOR_2, returnedTheme.colors.accentcolor,
|
||||
"Theme 2 accent color should be applied");
|
||||
ACCENT_COLOR_2, returnedTheme.colors.frame,
|
||||
"Theme 2 frame color should be applied");
|
||||
browser.test.assertEq(
|
||||
TEXT_COLOR_2, returnedTheme.colors.textcolor,
|
||||
"Theme 2 text color should be applied");
|
||||
TEXT_COLOR_2, returnedTheme.colors.tab_background_text,
|
||||
"Theme 2 tab_background_text color should be applied");
|
||||
}
|
||||
|
||||
const firstWin = await browser.windows.getCurrent();
|
||||
|
|
|
@ -65,11 +65,11 @@ add_task(async function test_dynamic_theme_updates() {
|
|||
|
||||
extension.sendMessage("update-theme", {
|
||||
"images": {
|
||||
"headerURL": "image1.png",
|
||||
"theme_frame": "image1.png",
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR_1,
|
||||
"textcolor": TEXT_COLOR_1,
|
||||
"frame": ACCENT_COLOR_1,
|
||||
"tab_background_text": TEXT_COLOR_1,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -77,13 +77,15 @@ add_task(async function test_dynamic_theme_updates() {
|
|||
|
||||
validateTheme("image1.png", ACCENT_COLOR_1, TEXT_COLOR_1, true);
|
||||
|
||||
// Check with the LWT aliases (to update on Firefox 69, because the
|
||||
// LWT aliases are going to be removed).
|
||||
extension.sendMessage("update-theme", {
|
||||
"images": {
|
||||
"headerURL": "image2.png",
|
||||
"theme_frame": "image2.png",
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR_2,
|
||||
"textcolor": TEXT_COLOR_2,
|
||||
"frame": ACCENT_COLOR_2,
|
||||
"tab_background_text": TEXT_COLOR_2,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -129,11 +131,11 @@ add_task(async function test_dynamic_theme_updates_with_data_url() {
|
|||
|
||||
extension.sendMessage("update-theme", {
|
||||
"images": {
|
||||
"headerURL": BACKGROUND_1,
|
||||
"theme_frame": BACKGROUND_1,
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR_1,
|
||||
"textcolor": TEXT_COLOR_1,
|
||||
"frame": ACCENT_COLOR_1,
|
||||
"tab_background_text": TEXT_COLOR_1,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -143,11 +145,11 @@ add_task(async function test_dynamic_theme_updates_with_data_url() {
|
|||
|
||||
extension.sendMessage("update-theme", {
|
||||
"images": {
|
||||
"headerURL": BACKGROUND_2,
|
||||
"theme_frame": BACKGROUND_2,
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR_2,
|
||||
"textcolor": TEXT_COLOR_2,
|
||||
"frame": ACCENT_COLOR_2,
|
||||
"tab_background_text": TEXT_COLOR_2,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -10,13 +10,13 @@ add_task(async function test_support_toolbar_properties_on_findbar() {
|
|||
manifest: {
|
||||
"theme": {
|
||||
"images": {
|
||||
"headerURL": "image1.png",
|
||||
"theme_frame": "image1.png",
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR,
|
||||
"textcolor": TEXT_COLOR,
|
||||
"frame": ACCENT_COLOR,
|
||||
"tab_background_text": TEXT_COLOR,
|
||||
"toolbar": TOOLBAR_COLOR,
|
||||
"toolbar_text": TOOLBAR_TEXT_COLOR,
|
||||
"bookmark_text": TOOLBAR_TEXT_COLOR,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -54,11 +54,11 @@ add_task(async function test_support_toolbar_field_properties_on_findbar() {
|
|||
manifest: {
|
||||
"theme": {
|
||||
"images": {
|
||||
"headerURL": "image1.png",
|
||||
"theme_frame": "image1.png",
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR,
|
||||
"textcolor": TEXT_COLOR,
|
||||
"frame": ACCENT_COLOR,
|
||||
"tab_background_text": TEXT_COLOR,
|
||||
"toolbar_field": TOOLBAR_FIELD_COLOR,
|
||||
"toolbar_field_text": TOOLBAR_FIELD_TEXT_COLOR,
|
||||
"toolbar_field_border": TOOLBAR_FIELD_BORDER_COLOR,
|
||||
|
|
|
@ -8,11 +8,11 @@ add_task(async function test_getcurrent() {
|
|||
manifest: {
|
||||
"theme": {
|
||||
"images": {
|
||||
"headerURL": "image1.png",
|
||||
"theme_frame": "image1.png",
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR,
|
||||
"textcolor": TEXT_COLOR,
|
||||
"frame": ACCENT_COLOR,
|
||||
"tab_background_text": TEXT_COLOR,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -37,12 +37,12 @@ add_task(async function test_getcurrent() {
|
|||
let updatedPromise = extension.awaitMessage("theme-updated");
|
||||
await theme.startup();
|
||||
let receivedTheme = await updatedPromise;
|
||||
Assert.ok(receivedTheme.images.headerURL.includes("image1.png"),
|
||||
"getCurrent returns correct headerURL");
|
||||
Assert.equal(receivedTheme.colors.accentcolor, ACCENT_COLOR,
|
||||
"getCurrent returns correct accentcolor");
|
||||
Assert.equal(receivedTheme.colors.textcolor, TEXT_COLOR,
|
||||
"getCurrent returns correct textcolor");
|
||||
Assert.ok(receivedTheme.images.theme_frame.includes("image1.png"),
|
||||
"getCurrent returns correct theme_frame image");
|
||||
Assert.equal(receivedTheme.colors.frame, ACCENT_COLOR,
|
||||
"getCurrent returns correct frame color");
|
||||
Assert.equal(receivedTheme.colors.tab_background_text, TEXT_COLOR,
|
||||
"getCurrent returns correct tab_background_text color");
|
||||
|
||||
info("Testing getCurrent after static theme unload");
|
||||
updatedPromise = extension.awaitMessage("theme-updated");
|
||||
|
|
|
@ -5,12 +5,12 @@ add_task(async function test_support_backgrounds_position() {
|
|||
manifest: {
|
||||
"theme": {
|
||||
"images": {
|
||||
"headerURL": "face1.png",
|
||||
"theme_frame": "face1.png",
|
||||
"additional_backgrounds": ["face2.png", "face2.png", "face2.png"],
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": `rgb(${FRAME_COLOR.join(",")})`,
|
||||
"textcolor": `rgb(${TAB_BACKGROUND_TEXT_COLOR.join(",")})`,
|
||||
"frame": `rgb(${FRAME_COLOR.join(",")})`,
|
||||
"tab_background_text": `rgb(${TAB_BACKGROUND_TEXT_COLOR.join(",")})`,
|
||||
},
|
||||
"properties": {
|
||||
"additional_backgrounds_alignment": ["left top", "center top", "right bottom"],
|
||||
|
|
|
@ -87,8 +87,8 @@ add_task(async function test_support_ntp_colors() {
|
|||
await BrowserTestUtils.withNewTab({gBrowser, url}, async browser => {
|
||||
await test_ntp_theme({
|
||||
colors: {
|
||||
accentcolor: ACCENT_COLOR,
|
||||
textcolor: TEXT_COLOR,
|
||||
frame: ACCENT_COLOR,
|
||||
tab_background_text: TEXT_COLOR,
|
||||
ntp_background: "#add8e6",
|
||||
ntp_text: "#00008b",
|
||||
},
|
||||
|
@ -96,8 +96,8 @@ add_task(async function test_support_ntp_colors() {
|
|||
|
||||
await test_ntp_theme({
|
||||
colors: {
|
||||
accentcolor: ACCENT_COLOR,
|
||||
textcolor: TEXT_COLOR,
|
||||
frame: ACCENT_COLOR,
|
||||
tab_background_text: TEXT_COLOR,
|
||||
ntp_background: "#00008b",
|
||||
ntp_text: "#add8e6",
|
||||
},
|
||||
|
|
|
@ -103,8 +103,8 @@ add_task(async function test_per_window_ntp_theme() {
|
|||
|
||||
const darkTextTheme = {
|
||||
colors: {
|
||||
accentcolor: "#add8e6",
|
||||
textcolor: "#000",
|
||||
frame: "#add8e6",
|
||||
tab_background_text: "#000",
|
||||
ntp_background: "#add8e6",
|
||||
ntp_text: "#000",
|
||||
},
|
||||
|
@ -112,8 +112,8 @@ add_task(async function test_per_window_ntp_theme() {
|
|||
|
||||
const brightTextTheme = {
|
||||
colors: {
|
||||
accentcolor: "#00008b",
|
||||
textcolor: "#add8e6",
|
||||
frame: "#00008b",
|
||||
tab_background_text: "#add8e6",
|
||||
ntp_background: "#00008b",
|
||||
ntp_text: "#add8e6",
|
||||
},
|
||||
|
|
|
@ -8,11 +8,11 @@ add_task(async function test_multiple_windows() {
|
|||
manifest: {
|
||||
"theme": {
|
||||
"images": {
|
||||
"headerURL": "image1.png",
|
||||
"theme_frame": "image1.png",
|
||||
},
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR,
|
||||
"textcolor": TEXT_COLOR,
|
||||
"frame": ACCENT_COLOR,
|
||||
"tab_background_text": TEXT_COLOR,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -8,9 +8,9 @@ add_task(async function test_sanitization_invalid() {
|
|||
manifest: {
|
||||
"theme": {
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR,
|
||||
"textcolor": TEXT_COLOR,
|
||||
"toolbar_text": "ntimsfavoriteblue",
|
||||
"frame": ACCENT_COLOR,
|
||||
"tab_background_text": TEXT_COLOR,
|
||||
"bookmark_text": "ntimsfavoriteblue",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -34,9 +34,9 @@ add_task(async function test_sanitization_css_variables() {
|
|||
manifest: {
|
||||
"theme": {
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR,
|
||||
"textcolor": TEXT_COLOR,
|
||||
"toolbar_text": "var(--arrowpanel-dimmed)",
|
||||
"frame": ACCENT_COLOR,
|
||||
"tab_background_text": TEXT_COLOR,
|
||||
"bookmark_text": "var(--arrowpanel-dimmed)",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -60,8 +60,8 @@ add_task(async function test_sanitization_transparent() {
|
|||
manifest: {
|
||||
"theme": {
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR,
|
||||
"textcolor": TEXT_COLOR,
|
||||
"frame": ACCENT_COLOR,
|
||||
"tab_background_text": TEXT_COLOR,
|
||||
"toolbar_top_separator": "transparent",
|
||||
},
|
||||
},
|
||||
|
@ -79,14 +79,14 @@ add_task(async function test_sanitization_transparent() {
|
|||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function test_sanitization_transparent_accentcolor() {
|
||||
// This test checks whether transparent accentcolor falls back to white.
|
||||
add_task(async function test_sanitization_transparent_frame_color() {
|
||||
// This test checks whether transparent frame color falls back to white.
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"theme": {
|
||||
"colors": {
|
||||
"accentcolor": "transparent",
|
||||
"textcolor": TEXT_COLOR,
|
||||
"frame": "transparent",
|
||||
"tab_background_text": TEXT_COLOR,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -104,14 +104,14 @@ add_task(async function test_sanitization_transparent_accentcolor() {
|
|||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function test_sanitization_transparent_textcolor() {
|
||||
add_task(async function test_sanitization_transparent_tab_background_text_color() {
|
||||
// This test checks whether transparent textcolor falls back to black.
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"theme": {
|
||||
"colors": {
|
||||
"accentcolor": ACCENT_COLOR,
|
||||
"textcolor": "transparent",
|
||||
"frame": ACCENT_COLOR,
|
||||
"tab_background_text": "transparent",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче