Merge mozilla-central to mozilla-inbound. a=merge on a CLOSED TREE

This commit is contained in:
Razvan Maries 2018-11-29 23:46:52 +02:00
Родитель 9aeecaa75e b38ee74e4d
Коммит d696b8eb57
117 изменённых файлов: 2053 добавлений и 1408 удалений

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

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

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