Merge mozilla-central and inbound

This commit is contained in:
Ed Morley 2014-04-29 18:23:29 +01:00
Родитель 1c7287b8b1 781111c6d3
Коммит e41a3e1c8a
140 изменённых файлов: 3337 добавлений и 1402 удалений

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

@ -31,6 +31,7 @@
gestures.forEach(AccessFuTest.addSequence); gestures.forEach(AccessFuTest.addSequence);
AccessFuTest.addFunc(stopGestureTracker); AccessFuTest.addFunc(stopGestureTracker);
AccessFuTest.waitForExplicitFinish(); AccessFuTest.waitForExplicitFinish();
Logger.logLevel = Logger.DEBUG;
AccessFuTest.runTests(); AccessFuTest.runTests();
}); });
} }

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

@ -156,11 +156,6 @@ pref("browser.search.suggest.enabled", true);
// tell the search service that we don't really expose the "current engine" // tell the search service that we don't really expose the "current engine"
pref("browser.search.noCurrentEngine", true); pref("browser.search.noCurrentEngine", true);
// Enable sparse localization by setting a few package locale overrides
pref("chrome.override_package.global", "b2g-l10n");
pref("chrome.override_package.mozapps", "b2g-l10n");
pref("chrome.override_package.passwordmgr", "b2g-l10n");
// enable xul error pages // enable xul error pages
pref("browser.xul.error_pages.enabled", true); pref("browser.xul.error_pages.enabled", true);
@ -899,9 +894,9 @@ pref("osfile.reset_worker_delay", 5000);
pref("apz.asyncscroll.throttle", 40); pref("apz.asyncscroll.throttle", 40);
pref("apz.pan_repaint_interval", 16); pref("apz.pan_repaint_interval", 16);
// Maximum fling velocity in inches/ms. Slower devices may need to reduce this // APZ physics settings, tuned by UX designers
// to avoid checkerboarding. Note, float value must be set as a string. pref("apz.max_velocity_inches_per_ms", "0.07");
pref("apz.max_velocity_inches_per_ms", "0.0375"); pref("apz.fling_friction", "0.003");
// Tweak default displayport values to reduce the risk of running out of // Tweak default displayport values to reduce the risk of running out of
// memory when zooming in // memory when zooming in

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

@ -5,3 +5,8 @@
#filter substitution #filter substitution
pref("general.useragent.locale", "@AB_CD@"); pref("general.useragent.locale", "@AB_CD@");
// Enable sparse localization by setting a few package locale overrides
pref("chrome.override_package.global", "b2g-l10n");
pref("chrome.override_package.mozapps", "b2g-l10n");
pref("chrome.override_package.passwordmgr", "b2g-l10n");

Двоичные данные
build/pgo/certs/cert8.db

Двоичный файл не отображается.

Двоичные данные
build/pgo/certs/key3.db

Двоичный файл не отображается.

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

@ -212,3 +212,5 @@ http://example.cn:80 privileged
http://example.co.jp:80 privileged http://example.co.jp:80 privileged
http://example.fi:80 privileged http://example.fi:80 privileged
# Hosts for testing marketplace apps installations
https://marketplace.firefox.com:443 privileged

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

@ -5964,18 +5964,6 @@ if test "$MOZ_GAMEPAD"; then
MOZ_GAMEPAD_BACKEND=cocoa MOZ_GAMEPAD_BACKEND=cocoa
;; ;;
WINNT) WINNT)
if test -z "$MOZ_HAS_WINSDK_WITH_D3D"; then
if test -n "$MOZ_DIRECTX_SDK_PATH" ; then
if ! test -f "$MOZ_DIRECTX_SDK_PATH"/lib/$MOZ_DIRECTX_SDK_CPU_SUFFIX/dxguid.lib ; then
MOZ_GAMEPAD=
fi
elif test "$GCC" != "yes"; then
MOZ_GAMEPAD=
fi
fi
if test -z "$MOZ_GAMEPAD"; then
AC_MSG_ERROR([Couldn't find the DirectX SDK, needed for gamepad support. Please install it or, reconfigure with --disable-gamepad to disable gamepad support.])
fi
MOZ_GAMEPAD_BACKEND=windows MOZ_GAMEPAD_BACKEND=windows
;; ;;
Linux) Linux)

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

@ -3209,7 +3209,7 @@ nsObjectLoadingContent::LegacyCall(JSContext* aCx,
} }
for (size_t i = 0; i < args.length(); i++) { for (size_t i = 0; i < args.length(); i++) {
if (!JS_WrapValue(aCx, args.handleAt(i))) { if (!JS_WrapValue(aCx, args[i])) {
aRv.Throw(NS_ERROR_UNEXPECTED); aRv.Throw(NS_ERROR_UNEXPECTED);
return JS::UndefinedValue(); return JS::UndefinedValue();
} }

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

@ -32,7 +32,7 @@ public:
virtual ReentrantMonitor& GetReentrantMonitor() MOZ_OVERRIDE; virtual ReentrantMonitor& GetReentrantMonitor() MOZ_OVERRIDE;
virtual bool IsShutdown() const MOZ_FINAL MOZ_OVERRIDE; virtual bool IsShutdown() const MOZ_OVERRIDE;
virtual bool OnStateMachineThread() const MOZ_OVERRIDE; virtual bool OnStateMachineThread() const MOZ_OVERRIDE;
@ -40,11 +40,11 @@ public:
virtual MediaResource* GetResource() const MOZ_OVERRIDE; virtual MediaResource* GetResource() const MOZ_OVERRIDE;
virtual void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) MOZ_FINAL MOZ_OVERRIDE; virtual void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) MOZ_OVERRIDE;
virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) MOZ_FINAL MOZ_OVERRIDE; virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) MOZ_OVERRIDE;
virtual int64_t GetEndMediaTime() const MOZ_FINAL MOZ_OVERRIDE; virtual int64_t GetEndMediaTime() const MOZ_OVERRIDE;
virtual int64_t GetMediaDuration() MOZ_OVERRIDE; virtual int64_t GetMediaDuration() MOZ_OVERRIDE;
@ -56,25 +56,25 @@ public:
virtual void SetTransportSeekable(bool aTransportSeekable) MOZ_OVERRIDE; virtual void SetTransportSeekable(bool aTransportSeekable) MOZ_OVERRIDE;
virtual VideoFrameContainer* GetVideoFrameContainer() MOZ_FINAL MOZ_OVERRIDE; virtual VideoFrameContainer* GetVideoFrameContainer() MOZ_OVERRIDE;
virtual layers::ImageContainer* GetImageContainer() MOZ_OVERRIDE; virtual layers::ImageContainer* GetImageContainer() MOZ_OVERRIDE;
virtual bool IsTransportSeekable() MOZ_FINAL MOZ_OVERRIDE; virtual bool IsTransportSeekable() MOZ_OVERRIDE;
virtual bool IsMediaSeekable() MOZ_FINAL MOZ_OVERRIDE; virtual bool IsMediaSeekable() MOZ_OVERRIDE;
virtual void MetadataLoaded(int aChannels, int aRate, bool aHasAudio, bool aHasVideo, MetadataTags* aTags) MOZ_FINAL MOZ_OVERRIDE; virtual void MetadataLoaded(int aChannels, int aRate, bool aHasAudio, bool aHasVideo, MetadataTags* aTags) MOZ_OVERRIDE;
virtual void QueueMetadata(int64_t aTime, int aChannels, int aRate, bool aHasAudio, bool aHasVideo, MetadataTags* aTags) MOZ_FINAL MOZ_OVERRIDE; virtual void QueueMetadata(int64_t aTime, int aChannels, int aRate, bool aHasAudio, bool aHasVideo, MetadataTags* aTags) MOZ_OVERRIDE;
virtual void SetMediaEndTime(int64_t aTime) MOZ_FINAL MOZ_OVERRIDE; virtual void SetMediaEndTime(int64_t aTime) MOZ_OVERRIDE;
virtual void UpdatePlaybackPosition(int64_t aTime) MOZ_FINAL MOZ_OVERRIDE; virtual void UpdatePlaybackPosition(int64_t aTime) MOZ_OVERRIDE;
virtual void OnReadMetadataCompleted() MOZ_FINAL MOZ_OVERRIDE; virtual void OnReadMetadataCompleted() MOZ_OVERRIDE;
virtual MediaDecoderOwner* GetOwner() MOZ_OVERRIDE; virtual MediaDecoderOwner* GetOwner() MOZ_OVERRIDE;
virtual void NotifyWaitingForResourcesStatusChanged() MOZ_FINAL MOZ_OVERRIDE; virtual void NotifyWaitingForResourcesStatusChanged() MOZ_OVERRIDE;
protected: protected:
// This monitor object is not really used to synchronize access to anything. // This monitor object is not really used to synchronize access to anything.

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

@ -164,6 +164,14 @@ VideoTrackEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
if (!chunk.IsNull()) { if (!chunk.IsNull()) {
gfx::IntSize imgsize = chunk.mFrame.GetImage()->GetSize(); gfx::IntSize imgsize = chunk.mFrame.GetImage()->GetSize();
gfxIntSize intrinsicSize = chunk.mFrame.GetIntrinsicSize(); gfxIntSize intrinsicSize = chunk.mFrame.GetIntrinsicSize();
#ifdef MOZ_WIDGET_GONK
// Block the video frames come from video source.
if (chunk.mFrame.GetImage()->GetFormat() != ImageFormat::PLANAR_YCBCR) {
LOG("Can't encode this ImageFormat %x", chunk.mFrame.GetImage()->GetFormat());
NotifyCancel();
break;
}
#endif
nsresult rv = Init(imgsize.width, imgsize.height, nsresult rv = Init(imgsize.width, imgsize.height,
intrinsicSize.width, intrinsicSize.height, intrinsicSize.width, intrinsicSize.height,
aTrackRate); aTrackRate);

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

@ -89,7 +89,9 @@ public:
return false; return false;
} }
MaybeSwitchVideoReaders(aTimeThreshold); if (MaybeSwitchVideoReaders(aTimeThreshold)) {
GetVideoReader()->DecodeToTarget(aTimeThreshold);
}
bool rv = GetVideoReader()->DecodeVideoFrame(aKeyFrameSkip, aTimeThreshold); bool rv = GetVideoReader()->DecodeVideoFrame(aKeyFrameSkip, aTimeThreshold);
@ -129,7 +131,7 @@ public:
void CallDecoderInitialization(); void CallDecoderInitialization();
private: private:
void MaybeSwitchVideoReaders(int64_t aTimeThreshold) { bool MaybeSwitchVideoReaders(int64_t aTimeThreshold) {
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
MOZ_ASSERT(mActiveVideoDecoder != -1); MOZ_ASSERT(mActiveVideoDecoder != -1);
@ -146,10 +148,11 @@ private:
MSE_DEBUG("%p MSR::DecodeVF switching to %d", this, mActiveVideoDecoder); MSE_DEBUG("%p MSR::DecodeVF switching to %d", this, mActiveVideoDecoder);
GetVideoReader()->SetActive(); GetVideoReader()->SetActive();
GetVideoReader()->DecodeToTarget(aTimeThreshold); return true;
break;
} }
} }
return false;
} }
MediaDecoderReader* GetAudioReader() { MediaDecoderReader* GetAudioReader() {

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

@ -66,6 +66,12 @@ SubBufferDecoder::GetResource() const
return static_cast<SourceBufferResource*>(mResource.get()); return static_cast<SourceBufferResource*>(mResource.get());
} }
void
SubBufferDecoder::NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded)
{
return mParentDecoder->NotifyDecodedFrames(aParsed, aDecoded);
}
void void
SubBufferDecoder::SetMediaDuration(int64_t aDuration) SubBufferDecoder::SetMediaDuration(int64_t aDuration)
{ {
@ -192,12 +198,8 @@ SourceBuffer::GetBuffered(ErrorResult& aRv)
return nullptr; return nullptr;
} }
nsRefPtr<TimeRanges> ranges = new TimeRanges(); nsRefPtr<TimeRanges> ranges = new TimeRanges();
for (uint32_t i = 0; i < mDecoders.Length(); ++i) { if (mDecoder) {
nsRefPtr<TimeRanges> r = new TimeRanges(); mDecoder->GetBuffered(ranges);
mDecoders[i]->GetBuffered(r);
if (r->Length() > 0) {
ranges->Add(r->GetStartTime(), r->GetEndTime());
}
} }
ranges->Normalize(); ranges->Normalize();
return ranges.forget(); return ranges.forget();
@ -264,10 +266,10 @@ SourceBuffer::Abort(ErrorResult& aRv)
mAppendWindowStart = 0; mAppendWindowStart = 0;
mAppendWindowEnd = PositiveInfinity<double>(); mAppendWindowEnd = PositiveInfinity<double>();
MSE_DEBUG("%p Abort: Discarding decoders.", this); MSE_DEBUG("%p Abort: Discarding decoder.", this);
if (mCurrentDecoder) { if (mDecoder) {
mCurrentDecoder->GetResource()->Ended(); mDecoder->GetResource()->Ended();
mCurrentDecoder = nullptr; mDecoder = nullptr;
} }
} }
@ -294,16 +296,15 @@ void
SourceBuffer::Detach() SourceBuffer::Detach()
{ {
Ended(); Ended();
mDecoders.Clear(); mDecoder = nullptr;
mCurrentDecoder = nullptr;
mMediaSource = nullptr; mMediaSource = nullptr;
} }
void void
SourceBuffer::Ended() SourceBuffer::Ended()
{ {
for (uint32_t i = 0; i < mDecoders.Length(); ++i) { if (mDecoder) {
mDecoders[i]->GetResource()->Ended(); mDecoder->GetResource()->Ended();
} }
} }
@ -316,6 +317,7 @@ SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
, mTimestampOffset(0) , mTimestampOffset(0)
, mAppendMode(SourceBufferAppendMode::Segments) , mAppendMode(SourceBufferAppendMode::Segments)
, mUpdating(false) , mUpdating(false)
, mDecoderInit(false)
{ {
MOZ_ASSERT(aMediaSource); MOZ_ASSERT(aMediaSource);
if (mType.EqualsIgnoreCase("video/webm") || mType.EqualsIgnoreCase("audio/webm")) { if (mType.EqualsIgnoreCase("video/webm") || mType.EqualsIgnoreCase("audio/webm")) {
@ -324,6 +326,8 @@ SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
// XXX: Plug in parsers for MPEG4, etc. here. // XXX: Plug in parsers for MPEG4, etc. here.
mParser = new ContainerParser(); mParser = new ContainerParser();
} }
MSE_DEBUG("%p SourceBuffer: Creating initial decoder.", this);
InitNewDecoder();
} }
already_AddRefed<SourceBuffer> already_AddRefed<SourceBuffer>
@ -335,8 +339,8 @@ SourceBuffer::Create(MediaSource* aMediaSource, const nsACString& aType)
SourceBuffer::~SourceBuffer() SourceBuffer::~SourceBuffer()
{ {
for (uint32_t i = 0; i < mDecoders.Length(); ++i) { if (mDecoder) {
mDecoders[i]->GetResource()->Ended(); mDecoder->GetResource()->Ended();
} }
} }
@ -375,11 +379,7 @@ SourceBuffer::InitNewDecoder()
if (!decoder) { if (!decoder) {
return false; return false;
} }
mDecoders.AppendElement(decoder); mDecoder = decoder;
// XXX: At this point, we really want to push through any remaining
// processing for the old decoder and discard it, rather than hanging on
// to all of them in mDecoders.
mCurrentDecoder = decoder;
return true; return true;
} }
@ -424,21 +424,24 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
// TODO: Test buffer full flag. // TODO: Test buffer full flag.
StartUpdating(); StartUpdating();
// TODO: Run buffer append algorithm asynchronously (would call StopUpdating()). // TODO: Run buffer append algorithm asynchronously (would call StopUpdating()).
if (mParser->IsInitSegmentPresent(aData, aLength) || !mCurrentDecoder) { if (!mDecoder || mParser->IsInitSegmentPresent(aData, aLength)) {
MSE_DEBUG("%p AppendBuffer: New initialization segment, switching decoders.", this); if (!mDecoder || mDecoderInit) {
if (mCurrentDecoder) { MSE_DEBUG("%p AppendBuffer: New initialization segment, creating decoder.", this);
mCurrentDecoder->GetResource()->Ended(); mDecoder->GetResource()->Ended();
}
if (!InitNewDecoder()) { if (!InitNewDecoder()) {
aRv.Throw(NS_ERROR_FAILURE); // XXX: Review error handling. aRv.Throw(NS_ERROR_FAILURE); // XXX: Review error handling.
return; return;
} }
} }
MSE_DEBUG("%p AppendBuffer: Decoder marked as initialized.", this);
mDecoderInit = true;
}
// XXX: For future reference: NDA call must run on the main thread. // XXX: For future reference: NDA call must run on the main thread.
mCurrentDecoder->NotifyDataArrived(reinterpret_cast<const char*>(aData), mDecoder->NotifyDataArrived(reinterpret_cast<const char*>(aData),
aLength, aLength,
mCurrentDecoder->GetResource()->GetLength()); mDecoder->GetResource()->GetLength());
mCurrentDecoder->GetResource()->AppendData(aData, aLength); mDecoder->GetResource()->AppendData(aData, aLength);
// Eviction uses a byte threshold. If the buffer is greater than the // Eviction uses a byte threshold. If the buffer is greater than the
// number of bytes then data is evicted. The time range for this // number of bytes then data is evicted. The time range for this
@ -446,7 +449,7 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
// evict data before that range across all SourceBuffer's it knows // evict data before that range across all SourceBuffer's it knows
// about. // about.
const int evict_threshold = 1000000; const int evict_threshold = 1000000;
bool evicted = mCurrentDecoder->GetResource()->EvictData(evict_threshold); bool evicted = mDecoder->GetResource()->EvictData(evict_threshold);
if (evicted) { if (evicted) {
double start = 0.0; double start = 0.0;
double end = 0.0; double end = 0.0;
@ -479,14 +482,15 @@ SourceBuffer::GetBufferedStartEndTime(double* aStart, double* aEnd)
void void
SourceBuffer::Evict(double aStart, double aEnd) SourceBuffer::Evict(double aStart, double aEnd)
{ {
for (uint32_t i = 0; i < mDecoders.Length(); ++i) { if (!mDecoder) {
// Need to map time to byte offset then evict return;
int64_t end = mDecoders[i]->ConvertToByteOffset(aEnd);
if (end <= 0) {
NS_WARNING("SourceBuffer::Evict failed");
continue;
} }
mDecoders[i]->GetResource()->EvictBefore(end); // Need to map time to byte offset then evict
int64_t end = mDecoder->ConvertToByteOffset(aEnd);
if (end > 0) {
mDecoder->GetResource()->EvictBefore(end);
} else {
NS_WARNING("SourceBuffer::Evict failed");
} }
} }

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

@ -140,10 +140,7 @@ private:
nsAutoPtr<ContainerParser> mParser; nsAutoPtr<ContainerParser> mParser;
// XXX: We only want to keep the current decoder alive, but need a way to nsRefPtr<SubBufferDecoder> mDecoder;
// query @buffered for everything this SourceBuffer is responsible for.
nsTArray<nsRefPtr<SubBufferDecoder>> mDecoders;
nsRefPtr<SubBufferDecoder> mCurrentDecoder;
double mAppendWindowStart; double mAppendWindowStart;
double mAppendWindowEnd; double mAppendWindowEnd;
@ -152,6 +149,8 @@ private:
SourceBufferAppendMode mAppendMode; SourceBufferAppendMode mAppendMode;
bool mUpdating; bool mUpdating;
bool mDecoderInit;
}; };
} // namespace dom } // namespace dom

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

@ -40,6 +40,7 @@ public:
virtual bool OnStateMachineThread() const MOZ_OVERRIDE; virtual bool OnStateMachineThread() const MOZ_OVERRIDE;
virtual bool OnDecodeThread() const MOZ_OVERRIDE; virtual bool OnDecodeThread() const MOZ_OVERRIDE;
virtual SourceBufferResource* GetResource() const MOZ_OVERRIDE; virtual SourceBufferResource* GetResource() const MOZ_OVERRIDE;
virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) MOZ_OVERRIDE;
virtual void SetMediaDuration(int64_t aDuration) MOZ_OVERRIDE; virtual void SetMediaDuration(int64_t aDuration) MOZ_OVERRIDE;
virtual void UpdateEstimatedMediaDuration(int64_t aDuration) MOZ_OVERRIDE; virtual void UpdateEstimatedMediaDuration(int64_t aDuration) MOZ_OVERRIDE;
virtual void SetMediaSeekable(bool aMediaSeekable) MOZ_OVERRIDE; virtual void SetMediaSeekable(bool aMediaSeekable) MOZ_OVERRIDE;

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

@ -678,6 +678,7 @@ MediaEngineWebRTCVideoSource::Shutdown()
void void
MediaEngineWebRTCVideoSource::AllocImpl() { MediaEngineWebRTCVideoSource::AllocImpl() {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
mCameraControl = ICameraControl::Create(mCaptureIndex); mCameraControl = ICameraControl::Create(mCaptureIndex);
if (mCameraControl) { if (mCameraControl) {
@ -818,6 +819,7 @@ MediaEngineWebRTCVideoSource::OnError(CameraErrorContext aContext, CameraError a
void void
MediaEngineWebRTCVideoSource::OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType) MediaEngineWebRTCVideoSource::OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
{ {
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
mLastCapture = mLastCapture =
static_cast<nsIDOMFile*>(new nsDOMMemoryFile(static_cast<void*>(aData), static_cast<nsIDOMFile*>(new nsDOMMemoryFile(static_cast<void*>(aData),
static_cast<uint64_t>(aLength), static_cast<uint64_t>(aLength),

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

@ -2244,8 +2244,7 @@ this.DOMApplicationRegistry = {
queuedDownload: {}, queuedDownload: {},
queuedPackageDownload: {}, queuedPackageDownload: {},
onInstallSuccessAck: function onInstallSuccessAck(aManifestURL, onInstallSuccessAck: function(aManifestURL, aDontNeedNetwork) {
aDontNeedNetwork) {
// If we are offline, register to run when we'll be online. // If we are offline, register to run when we'll be online.
if ((Services.io.offline) && !aDontNeedNetwork) { if ((Services.io.offline) && !aDontNeedNetwork) {
let onlineWrapper = { let onlineWrapper = {
@ -2345,7 +2344,7 @@ onInstallSuccessAck: function onInstallSuccessAck(aManifestURL,
let dir = this._getAppDir(aId).path; let dir = this._getAppDir(aId).path;
let manFile = OS.Path.join(dir, manifestName); let manFile = OS.Path.join(dir, manifestName);
this._writeFile(manFile, JSON.stringify(aJsonManifest)); return this._writeFile(manFile, JSON.stringify(aJsonManifest));
}, },
// Add an app that is already installed to the registry. // Add an app that is already installed to the registry.
@ -2418,7 +2417,7 @@ onInstallSuccessAck: function onInstallSuccessAck(aManifestURL,
}); });
}), }),
confirmInstall: function(aData, aProfileDir, aInstallSuccessCallback) { confirmInstall: Task.async(function*(aData, aProfileDir, aInstallSuccessCallback) {
debug("confirmInstall"); debug("confirmInstall");
let origin = Services.io.newURI(aData.app.origin, null, null); let origin = Services.io.newURI(aData.app.origin, null, null);
@ -2443,7 +2442,7 @@ onInstallSuccessAck: function onInstallSuccessAck(aManifestURL,
let app = this._setupApp(aData, id); let app = this._setupApp(aData, id);
let jsonManifest = aData.isPackage ? app.updateManifest : app.manifest; let jsonManifest = aData.isPackage ? app.updateManifest : app.manifest;
this._writeManifestFile(id, aData.isPackage, jsonManifest); yield this._writeManifestFile(id, aData.isPackage, jsonManifest);
debug("app.origin: " + app.origin); debug("app.origin: " + app.origin);
let manifest = new ManifestHelper(jsonManifest, app.origin); let manifest = new ManifestHelper(jsonManifest, app.origin);
@ -2477,42 +2476,15 @@ onInstallSuccessAck: function onInstallSuccessAck(aManifestURL,
aData.app[prop] = appObject[prop]; aData.app[prop] = appObject[prop];
} }
let dontNeedNetwork = false;
if (manifest.appcache_path) { if (manifest.appcache_path) {
this.queuedDownload[app.manifestURL] = { this.queuedDownload[app.manifestURL] = {
manifest: manifest, manifest: manifest,
app: appObject, app: appObject,
profileDir: aProfileDir profileDir: aProfileDir
} }
} } else if (manifest.package_path) {
// We notify about the successful installation via mgmt.oninstall and the
// corresponging DOMRequest.onsuccess event as soon as the app is properly
// saved in the registry.
this._saveApps().then(() => {
this.broadcastMessage("Webapps:AddApp", { id: id, app: appObject });
if (aData.isPackage && aData.autoInstall) {
// Skip directly to onInstallSuccessAck, since there isn't
// a WebappsRegistry to receive Webapps:Install:Return:OK and respond
// Webapps:Install:Return:Ack when an app is being auto-installed.
this.onInstallSuccessAck(app.manifestURL);
} else {
// Broadcast Webapps:Install:Return:OK so the WebappsRegistry can notify
// the installing page about the successful install, after which it'll
// respond Webapps:Install:Return:Ack, which calls onInstallSuccessAck.
this.broadcastMessage("Webapps:Install:Return:OK", aData);
}
if (!aData.isPackage) {
this.updateAppHandlers(null, app.manifest, app);
if (aInstallSuccessCallback) {
aInstallSuccessCallback(app.manifest);
}
}
Services.obs.notifyObservers(null, "webapps-installed",
JSON.stringify({ manifestURL: app.manifestURL }));
});
let dontNeedNetwork = false;
if (manifest.package_path) {
// If it is a local app then it must been installed from a local file // If it is a local app then it must been installed from a local file
// instead of web. // instead of web.
#ifdef MOZ_ANDROID_SYNTHAPKS #ifdef MOZ_ANDROID_SYNTHAPKS
@ -2537,12 +2509,40 @@ onInstallSuccessAck: function onInstallSuccessAck(aManifestURL,
}; };
} }
// We notify about the successful installation via mgmt.oninstall and the
// corresponding DOMRequest.onsuccess event as soon as the app is properly
// saved in the registry.
yield this._saveApps();
this.broadcastMessage("Webapps:AddApp", { id: id, app: appObject });
if (aData.isPackage && aData.autoInstall) {
// Skip directly to onInstallSuccessAck, since there isn't
// a WebappsRegistry to receive Webapps:Install:Return:OK and respond
// Webapps:Install:Return:Ack when an app is being auto-installed.
this.onInstallSuccessAck(app.manifestURL);
} else {
// Broadcast Webapps:Install:Return:OK so the WebappsRegistry can notify
// the installing page about the successful install, after which it'll
// respond Webapps:Install:Return:Ack, which calls onInstallSuccessAck.
this.broadcastMessage("Webapps:Install:Return:OK", aData);
}
if (!aData.isPackage) {
this.updateAppHandlers(null, app.manifest, app);
if (aInstallSuccessCallback) {
aInstallSuccessCallback(app.manifest);
}
}
Services.obs.notifyObservers(null, "webapps-installed",
JSON.stringify({ manifestURL: app.manifestURL }));
if (aData.forceSuccessAck) { if (aData.forceSuccessAck) {
// If it's a local install, there's no content process so just // If it's a local install, there's no content process so just
// ack the install. // ack the install.
this.onInstallSuccessAck(app.manifestURL, dontNeedNetwork); this.onInstallSuccessAck(app.manifestURL, dontNeedNetwork);
} }
}, }),
/** /**
* Install the package after successfully downloading it * Install the package after successfully downloading it
@ -3104,7 +3104,10 @@ onInstallSuccessAck: function onInstallSuccessAck(aManifestURL,
throw "CERTDB_ERROR"; throw "CERTDB_ERROR";
} }
let [result, zipReader] = yield this._openSignedPackage(aZipFile, certDb); let [result, zipReader] = yield this._openSignedPackage(aApp.installOrigin,
aApp.manifestURL,
aZipFile,
certDb);
// We cannot really know if the system date is correct or // We cannot really know if the system date is correct or
// not. What we can know is if it's after the build date or not, // not. What we can know is if it's after the build date or not,
@ -3147,11 +3150,39 @@ onInstallSuccessAck: function onInstallSuccessAck(aManifestURL,
}).bind(this)); }).bind(this));
}, },
_openSignedPackage: function(aZipFile, aCertDb) { _openSignedPackage: function(aInstallOrigin, aManifestURL, aZipFile, aCertDb) {
let deferred = Promise.defer(); let deferred = Promise.defer();
let root = TrustedRootCertificate.index;
let useReviewerCerts = false;
try {
useReviewerCerts = Services.prefs.
getBoolPref("dom.mozApps.use_reviewer_certs");
} catch (ex) { }
// We'll use the reviewer and dev certificates only if the pref is set to
// true.
if (useReviewerCerts) {
let manifestPath = Services.io.newURI(aManifestURL, null, null).path;
switch (aInstallOrigin) {
case "https://marketplace.firefox.com":
root = manifestPath.startsWith("/reviewers/")
? Ci.nsIX509CertDB.AppMarketplaceProdReviewersRoot
: Ci.nsIX509CertDB.AppMarketplaceProdPublicRoot;
break;
case "https://marketplace-dev.allizom.org":
root = manifestPath.startsWith("/reviewers/")
? Ci.nsIX509CertDB.AppMarketplaceDevReviewersRoot
: Ci.nsIX509CertDB.AppMarketplaceDevPublicRoot;
break;
}
}
aCertDb.openSignedAppFileAsync( aCertDb.openSignedAppFileAsync(
TrustedRootCertificate.index, aZipFile, root, aZipFile,
function(aRv, aZipReader) { function(aRv, aZipReader) {
deferred.resolve([aRv, aZipReader]); deferred.resolve([aRv, aZipReader]);
} }

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

@ -0,0 +1,28 @@
{
"version" : "2.0",
"name" : "Flashlight (Linterna)",
"description" : "Simple Flashlight that you can use everywhere without internet connection and also with cool modes: * Flashlight mode - * Disco mode - * Colors mode",
"launch_path" : "/index.html",
"icons": {
"16": "/img/icons/mortar-16.png",
"48": "/img/icons/mortar-48.png",
"60": "/img/icons/mortar-60.png",
"128": "/img/icons/mortar-128.png"
},
"developer": {
"name": "William Vargas",
"url" : "https://twitter.com/tecnowilliam"
},
"installs_allowed_from": ["*"],
"locales": {
"es": {
"description": "Una simple linterna que puedes utilizar en cualquier lugar sin conexión a internet y con opciones geniales: * Modo Linterna - * Modo Disco - * Modo Colores",
"developer": {
"name": "William Vargas",
"url" : "https://twitter.com/tecnowilliam"
}
}
},
"default_locale": "en",
"package_path": "marketplace_app.zip"
}

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

@ -0,0 +1 @@
Content-Type: application/x-web-app-manifest+json

Двоичные данные
dom/apps/tests/marketplace/marketplace_app.zip Normal file

Двоичный файл не отображается.

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

@ -0,0 +1,50 @@
{
"version": "0.2.2",
"name": "KitchenSink",
"description": "Tests and report APIs available on the device",
"launch_path": "/index.html",
"developer": {
"name": "Piotr Zalewa",
"url": "http://www.mozillalabs.com"
},
"icons": {
"16": "/img/icons/logo-16.png",
"32": "/img/icons/logo-32.png",
"64": "/img/icons/logo-64.png",
"128": "/img/icons/logo-128.png",
"256": "/img/icons/logo-256.png"
},
"type": "privileged",
"permissions": {
"alarms": {
"description": "Testing"
},
"browser": {
"description": "Testing"
},
"geolocation": {
"description": "Testing"
},
"contacts": {
"access": "readwrite",
"description": "Testing"
},
"device-storage:sdcard": {
"access": "readwrite",
"description": "Testing"
},
"fmradio": {
"description": "Testing"
},
"storage": {
"description": "Testing"
},
"systemXHR": {
"description": "Testing"
},
"tcp-socket": {
"description": "Testing"
}
},
"package_path": "marketplace_privileged_app.zip"
}

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

@ -0,0 +1 @@
Content-Type: application/x-web-app-manifest+json

Двоичные данные
dom/apps/tests/marketplace/marketplace_privileged_app.zip Normal file

Двоичный файл не отображается.

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

@ -0,0 +1,20 @@
{
"name": "Stopwatch",
"description": "Simple stopwatch",
"launch_path": "/index.html",
"icons": {
"128": "/static/img/icon.png"
},
"developer": {
"name": "Andy McKay",
"url": "http://www.agmweb.ca/blog/andy/"
},
"locales": {
"fr": {
"description": "Simple chronomètre"
}
},
"installs_allowed_from": ["*"],
"default_locale": "en",
"package_path": "marketplace_reviewers_app.zip"
}

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

@ -0,0 +1 @@
Content-Type: application/x-web-app-manifest+json

Двоичные данные
dom/apps/tests/marketplace/marketplace_reviewers_app.zip Normal file

Двоичный файл не отображается.

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

@ -14,10 +14,14 @@ support-files =
signed_app_template.webapp signed_app_template.webapp
signed/* signed/*
test_packaged_app_common.js test_packaged_app_common.js
marketplace/*
pkg_install_iframe.html
[test_app_update.html] [test_app_update.html]
[test_bug_795164.html] [test_bug_795164.html]
[test_install_receipts.html] [test_install_receipts.html]
[test_marketplace_pkg_install.html]
skip-if = buildapp == "b2g" || toolkit == "android" # see bug 989806
[test_packaged_app_install.html] [test_packaged_app_install.html]
[test_packaged_app_update.html] [test_packaged_app_update.html]
[test_receipt_operations.html] [test_receipt_operations.html]

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

@ -0,0 +1,26 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Cross Origin Helper</title>
</head>
<body>
<script type="application/javascript">
window.addEventListener("message", function onMessage(event) {
window.removeEventListener("message", onMessage, false);
var request = navigator.mozApps.installPackage(event.data);
request.onerror = function() {
parent.postMessage("Error: " + this.error.name, "*");
};
request.onsuccess = function() {
parent.postMessage("Application installed", "*");
};
}, false);
</script>
</body>
</html>

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

@ -102,7 +102,7 @@ function readFile(path) {
function makeResource(templatePath, version, packagePath, packageSize, function makeResource(templatePath, version, packagePath, packageSize,
appName, developerName, developerUrl) { appName, developerName, developerUrl) {
var res = readFile(templatePath, false). var res = readFile(templatePath).
replace(/VERSIONTOKEN/g, version). replace(/VERSIONTOKEN/g, version).
replace(/PACKAGEPATHTOKEN/g, packagePath). replace(/PACKAGEPATHTOKEN/g, packagePath).
replace(/PACKAGESIZETOKEN/g, packageSize). replace(/PACKAGESIZETOKEN/g, packageSize).

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

@ -0,0 +1,198 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=989806
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 989806</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="test_packaged_app_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=989806">Mozilla Bug 989806</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
"use strict";
let gApp = null;
let gExternalInstallOrigin = "http://mochi.test:8888/";
let gExternalAppsPath = gExternalInstallOrigin + "tests/dom/apps/tests/marketplace/";
let gMarketplaceInstallOrigin = "https://marketplace.firefox.com/";
let gMarketplaceAppsPath = gMarketplaceInstallOrigin + "tests/dom/apps/tests/marketplace/";
SimpleTest.waitForExplicitFinish();
function checkAppOnInstallSuccess(aExpected) {
navigator.mozApps.mgmt.oninstall = function(evt) {
info("Got oninstall event");
gApp = evt.application;
gApp.ondownloaderror = function() {
ok(false, "Download should succeed (got error: " +
gApp.downloadError.name + ")");
PackagedTestHelper.finish();
};
gApp.ondownloadsuccess = function() {
info("App downloaded");
PackagedTestHelper.checkAppState(gApp, aExpected.version, aExpected,
true, true, PackagedTestHelper.next);
};
};
}
function checkAppOnInstallError(aExpectedError) {
navigator.mozApps.mgmt.oninstall = function(evt) {
info("Got oninstall event");
gApp = evt.application;
gApp.ondownloaderror = function() {
is(gApp.downloadError.name, aExpectedError,
"Download fails with expected error: " + aExpectedError);
if (gApp.downloadError.name != aExpectedError) {
PackagedTestHelper.finish();
} else {
PackagedTestHelper.next();
}
};
gApp.ondownloadsuccess = function() {
ok(false, "App download should fail");
PackagedTestHelper.finish();
};
};
}
function checkUninstallApp(aApp) {
let req = navigator.mozApps.mgmt.uninstall(aApp);
req.onsuccess = function() {
info("App uninstalled");
aApp.ondownloadsuccess = null;
aApp.ondownloaderror = null;
aApp.onprogress = null;
PackagedTestHelper.next();
};
req.onerror = function(evt) {
ok(false, "App uninstallation should succeed (got unexpected " +
evt.target.error.name + ")");
PackagedTestHelper.finish();
};
}
function installApp(installOrigin, manifestURL) {
let domParent = document.getElementById('container');
let ifr = document.createElement('iframe');
ifr.setAttribute('mozbrowser', 'true');
ifr.setAttribute("src", installOrigin + "tests/dom/apps/tests/pkg_install_iframe.html");
ifr.addEventListener("load", function onIFrameLoad() {
ifr.removeEventListener("load", onIFrameLoad, false);
ifr.contentWindow.postMessage(manifestURL, "*");
}, false);
ifr.addEventListener("mozbrowsererror", function onCertError(e) {
ifr.removeEventListener("mozbrowsererror", onCertError);
ok(false, "mozbrowsererror: " + e.detail.type);
domParent.removeChild(ifr);
PackagedTestHelper.finish();
});
window.addEventListener("message", function onMessage(event) {
window.removeEventListener("message", onMessage);
is(event.data, "Application installed", "Application installed");
domParent.removeChild(ifr);
});
domParent.appendChild(ifr);
}
PackagedTestHelper.setSteps([
function() {
SpecialPowers.setAllAppsLaunchable(true);
SpecialPowers.addPermission("webapps-manage", true, document);
SpecialPowers.addPermission("browser", true, document);
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.pushPrefEnv({set: [["dom.mozBrowserFramesEnabled", true]]},
PackagedTestHelper.next));
},
function() {
info("== TEST == Marketplace packaged app from https://marketplace.firefox.com/");
let miniManifestURL = gMarketplaceAppsPath + "marketplace_app.webapp"
let expected = {
name: "Flashlight (Linterna)",
manifestURL: miniManifestURL,
installOrigin: gMarketplaceInstallOrigin.slice(0, -1),
progress: 0,
installState: "installed",
downloadAvailable: false,
downloading: false,
readyToApplyDownload: false,
launch_path: "/index.html",
version: "2.0",
};
checkAppOnInstallSuccess(expected);
installApp(gMarketplaceInstallOrigin, miniManifestURL);
},
function() {
info("== TEST == Marketplace privileged app from https://marketplace.firefox.com/");
let miniManifestURL = gMarketplaceAppsPath + "marketplace_privileged_app.webapp"
let expected = {
name: "KitchenSink",
manifestURL: miniManifestURL,
installOrigin: gMarketplaceInstallOrigin.slice(0, -1),
progress: 0,
installState: "installed",
downloadAvailable: false,
downloading: false,
readyToApplyDownload: false,
launch_path: "/index.html",
version: "0.2.2",
};
checkAppOnInstallSuccess(expected);
installApp(gMarketplaceInstallOrigin, miniManifestURL);
},
function() {
info("== TEST == Marketplace reviewers packaged app from https://marketplace.firefox.com/");
checkAppOnInstallError("INVALID_SIGNATURE");
installApp(gMarketplaceInstallOrigin, gMarketplaceAppsPath + "marketplace_reviewers_app.webapp");
},
function() {
info("== TEST == Marketplace packaged app not from https://marketplace.firefox.com/");
checkAppOnInstallError("INSTALL_FROM_DENIED");
installApp(gExternalInstallOrigin, gExternalAppsPath + "marketplace_app.webapp");
},
function() {
info("== TEST == Marketplace privileged app not from https://marketplace.firefox.com/");
checkAppOnInstallError("INSTALL_FROM_DENIED");
installApp(gExternalInstallOrigin, gExternalAppsPath + "marketplace_privileged_app.webapp");
},
function() {
info("== TEST == Marketplace reviewers packaged app not from https://marketplace.firefox.com/");
checkAppOnInstallError("INVALID_SIGNATURE");
installApp(gExternalInstallOrigin, gExternalAppsPath + "marketplace_reviewers_app.webapp");
},
function() {
PackagedTestHelper.finish();
}
]);
addLoadEvent(PackagedTestHelper.start);
</script>
</pre>
<div id="container"></div>
</body>
</html>

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

@ -12,31 +12,18 @@ var PackagedTestHelper = (function PackagedTestHelper() {
var gAppName = "appname"; var gAppName = "appname";
var gApp = null; var gApp = null;
var gInstallOrigin = "http://mochi.test:8888"; var gInstallOrigin = "http://mochi.test:8888";
var timeoutID;
function timeoutError() {
ok(false, "Timeout! Probably waiting on a app installation event");
info("Finishing this test suite!");
finish();
}
function debug(aMsg) { function debug(aMsg) {
//dump("== PackageTestHelper debug == " + aMsg + "\n"); //dump("== PackageTestHelper debug == " + aMsg + "\n");
} }
function next() { function next() {
if (timeoutID) {
clearTimeout(timeoutID);
}
index += 1; index += 1;
if (index >= steps.length) { if (index >= steps.length) {
ok(false, "Shouldn't get here!"); ok(false, "Shouldn't get here!");
return; return;
} }
try { try {
// There's nothing here that should take more than 30 seconds, even on
// heavy loads. So there's no need to stop further tests for five minutes.
timeoutID = setTimeout(timeoutError, 30000);
steps[index](); steps[index]();
} catch(ex) { } catch(ex) {
ok(false, "Caught exception", ex); ok(false, "Caught exception", ex);
@ -48,10 +35,8 @@ var PackagedTestHelper = (function PackagedTestHelper() {
} }
function finish() { function finish() {
if (timeoutID) {
clearTimeout(timeoutID);
}
SpecialPowers.removePermission("webapps-manage", document); SpecialPowers.removePermission("webapps-manage", document);
SpecialPowers.removePermission("browser", document);
SimpleTest.finish(); SimpleTest.finish();
} }
@ -165,7 +150,7 @@ var PackagedTestHelper = (function PackagedTestHelper() {
is(aApp.manifest.size, aExpectedApp.size, "Check size"); is(aApp.manifest.size, aExpectedApp.size, "Check size");
} }
if (aApp.manifest) { if (aApp.manifest) {
is(aApp.manifest.launch_path, gSJSPath, "Check launch path"); is(aApp.manifest.launch_path, aExpectedApp.launch_path || gSJSPath, "Check launch path");
} }
if (aExpectedApp.manifestURL) { if (aExpectedApp.manifestURL) {
is(aApp.manifestURL, aExpectedApp.manifestURL, "Check manifestURL"); is(aApp.manifestURL, aExpectedApp.manifestURL, "Check manifestURL");

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

@ -476,10 +476,7 @@ private:
arguments.AppendElement(value); arguments.AppendElement(value);
} }
console->ProfileMethod(cx, mAction, arguments, error); console->ProfileMethod(cx, mAction, arguments);
if (error.Failed()) {
NS_WARNING("Failed to call call profile() method to the ConsoleAPI.");
}
} }
private: private:
@ -662,23 +659,20 @@ Console::TimeEnd(JSContext* aCx, const JS::Handle<JS::Value> aTime)
} }
void void
Console::Profile(JSContext* aCx, const Sequence<JS::Value>& aData, Console::Profile(JSContext* aCx, const Sequence<JS::Value>& aData)
ErrorResult& aRv)
{ {
ProfileMethod(aCx, NS_LITERAL_STRING("profile"), aData, aRv); ProfileMethod(aCx, NS_LITERAL_STRING("profile"), aData);
} }
void void
Console::ProfileEnd(JSContext* aCx, const Sequence<JS::Value>& aData, Console::ProfileEnd(JSContext* aCx, const Sequence<JS::Value>& aData)
ErrorResult& aRv)
{ {
ProfileMethod(aCx, NS_LITERAL_STRING("profileEnd"), aData, aRv); ProfileMethod(aCx, NS_LITERAL_STRING("profileEnd"), aData);
} }
void void
Console::ProfileMethod(JSContext* aCx, const nsAString& aAction, Console::ProfileMethod(JSContext* aCx, const nsAString& aAction,
const Sequence<JS::Value>& aData, const Sequence<JS::Value>& aData)
ErrorResult& aRv)
{ {
if (!NS_IsMainThread()) { if (!NS_IsMainThread()) {
// Here we are in a worker thread. // Here we are in a worker thread.
@ -688,6 +682,8 @@ Console::ProfileMethod(JSContext* aCx, const nsAString& aAction,
return; return;
} }
ClearException ce(aCx);
RootedDictionary<ConsoleProfileEvent> event(aCx); RootedDictionary<ConsoleProfileEvent> event(aCx);
event.mAction = aAction; event.mAction = aAction;
@ -700,15 +696,14 @@ Console::ProfileMethod(JSContext* aCx, const nsAString& aAction,
JS::Rooted<JS::Value> eventValue(aCx); JS::Rooted<JS::Value> eventValue(aCx);
if (!event.ToObject(aCx, &eventValue)) { if (!event.ToObject(aCx, &eventValue)) {
aRv.Throw(NS_ERROR_FAILURE);
return; return;
} }
JS::Rooted<JSObject*> eventObj(aCx, &eventValue.toObject()); JS::Rooted<JSObject*> eventObj(aCx, &eventValue.toObject());
MOZ_ASSERT(eventObj); MOZ_ASSERT(eventObj);
if (!JS_DefineProperty(aCx, eventObj, "wrappedJSObject", eventValue, JSPROP_ENUMERATE)) { if (!JS_DefineProperty(aCx, eventObj, "wrappedJSObject", eventValue,
aRv.Throw(NS_ERROR_FAILURE); JSPROP_ENUMERATE)) {
return; return;
} }
@ -717,7 +712,6 @@ Console::ProfileMethod(JSContext* aCx, const nsAString& aAction,
const nsIID& iid = NS_GET_IID(nsISupports); const nsIID& iid = NS_GET_IID(nsISupports);
if (NS_FAILED(xpc->WrapJS(aCx, eventObj, iid, getter_AddRefs(wrapper)))) { if (NS_FAILED(xpc->WrapJS(aCx, eventObj, iid, getter_AddRefs(wrapper)))) {
aRv.Throw(NS_ERROR_FAILURE);
return; return;
} }
@ -836,13 +830,14 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
ConsoleCallData* callData = new ConsoleCallData(); ConsoleCallData* callData = new ConsoleCallData();
mQueuedCalls.insertBack(callData); mQueuedCalls.insertBack(callData);
ClearException ce(aCx);
callData->Initialize(aCx, aMethodName, aMethodString, aData); callData->Initialize(aCx, aMethodName, aMethodString, aData);
RAII raii(mQueuedCalls); RAII raii(mQueuedCalls);
if (mWindow) { if (mWindow) {
nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(mWindow); nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(mWindow);
if (!webNav) { if (!webNav) {
Throw(aCx, NS_ERROR_FAILURE);
return; return;
} }
@ -857,7 +852,6 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
nsCOMPtr<nsIStackFrame> stack = CreateStack(aCx, maxDepth); nsCOMPtr<nsIStackFrame> stack = CreateStack(aCx, maxDepth);
if (!stack) { if (!stack) {
Throw(aCx, NS_ERROR_FAILURE);
return; return;
} }
@ -866,7 +860,6 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
uint32_t language; uint32_t language;
nsresult rv = stack->GetLanguage(&language); nsresult rv = stack->GetLanguage(&language);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
Throw(aCx, rv);
return; return;
} }
@ -877,7 +870,6 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
callData->mTopStackFrame.ref(), callData->mTopStackFrame.ref(),
language); language);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
Throw(aCx, rv);
return; return;
} }
@ -887,7 +879,6 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
nsCOMPtr<nsIStackFrame> caller; nsCOMPtr<nsIStackFrame> caller;
rv = stack->GetCaller(getter_AddRefs(caller)); rv = stack->GetCaller(getter_AddRefs(caller));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
Throw(aCx, rv);
return; return;
} }
@ -902,7 +893,6 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
callData->mReifiedStack.construct(); callData->mReifiedStack.construct();
nsresult rv = ReifyStack(stack, callData->mReifiedStack.ref()); nsresult rv = ReifyStack(stack, callData->mReifiedStack.ref());
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
Throw(aCx, rv);
return; return;
} }
} }
@ -915,7 +905,6 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
ErrorResult rv; ErrorResult rv;
nsRefPtr<nsPerformance> performance = win->GetPerformance(rv); nsRefPtr<nsPerformance> performance = win->GetPerformance(rv);
if (rv.Failed()) { if (rv.Failed()) {
Throw(aCx, rv.ErrorCode());
return; return;
} }
@ -1111,7 +1100,6 @@ Console::ProcessCallData(ConsoleCallData* aData)
JS::Rooted<JS::Value> eventValue(cx); JS::Rooted<JS::Value> eventValue(cx);
if (!event.ToObject(cx, &eventValue)) { if (!event.ToObject(cx, &eventValue)) {
Throw(cx, NS_ERROR_FAILURE);
return; return;
} }

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

@ -87,12 +87,10 @@ public:
TimeEnd(JSContext* aCx, const JS::Handle<JS::Value> aTime); TimeEnd(JSContext* aCx, const JS::Handle<JS::Value> aTime);
void void
Profile(JSContext* aCx, const Sequence<JS::Value>& aData, Profile(JSContext* aCx, const Sequence<JS::Value>& aData);
ErrorResult& aRv);
void void
ProfileEnd(JSContext* aCx, const Sequence<JS::Value>& aData, ProfileEnd(JSContext* aCx, const Sequence<JS::Value>& aData);
ErrorResult& aRv);
void void
Assert(JSContext* aCx, bool aCondition, const Sequence<JS::Value>& aData); Assert(JSContext* aCx, bool aCondition, const Sequence<JS::Value>& aData);
@ -181,8 +179,7 @@ private:
void void
ProfileMethod(JSContext* aCx, const nsAString& aAction, ProfileMethod(JSContext* aCx, const nsAString& aAction,
const Sequence<JS::Value>& aData, const Sequence<JS::Value>& aData);
ErrorResult& aRv);
JS::Value JS::Value
IncreaseCounter(JSContext* aCx, const ConsoleStackEntry& aFrame, IncreaseCounter(JSContext* aCx, const ConsoleStackEntry& aFrame,

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

@ -1975,11 +1975,11 @@ BaseStubConstructor(nsIWeakReference* aWeakOwner,
nsCOMPtr<nsIDOMWindow> currentWin(do_GetInterface(currentInner)); nsCOMPtr<nsIDOMWindow> currentWin(do_GetInterface(currentInner));
rv = WrapNative(cx, currentWin, &NS_GET_IID(nsIDOMWindow), rv = WrapNative(cx, currentWin, &NS_GET_IID(nsIDOMWindow),
true, argv.handleAt(0)); true, argv[0]);
for (size_t i = 1; i < argc; ++i) { for (size_t i = 1; i < argc; ++i) {
argv[i] = args[i - 1]; argv[i].set(args[i - 1]);
if (!JS_WrapValue(cx, argv.handleAt(i))) if (!JS_WrapValue(cx, argv[i]))
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }

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

@ -1002,7 +1002,7 @@ nsJSContext::SetProperty(JS::Handle<JSObject*> aTarget, const char* aPropName, n
// got the arguments, now attach them. // got the arguments, now attach them.
for (uint32_t i = 0; i < args.length(); ++i) { for (uint32_t i = 0; i < args.length(); ++i) {
if (!JS_WrapValue(mContext, args.handleAt(i))) { if (!JS_WrapValue(mContext, args[i])) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
} }
@ -1066,7 +1066,7 @@ nsJSContext::ConvertSupportsTojsvals(nsISupports* aArgs,
if (argsArray) { if (argsArray) {
for (uint32_t argCtr = 0; argCtr < argCount && NS_SUCCEEDED(rv); argCtr++) { for (uint32_t argCtr = 0; argCtr < argCount && NS_SUCCEEDED(rv); argCtr++) {
nsCOMPtr<nsISupports> arg; nsCOMPtr<nsISupports> arg;
JS::MutableHandle<JS::Value> thisVal = aArgsOut.handleAt(argCtr); JS::MutableHandle<JS::Value> thisVal = aArgsOut[argCtr];
argsArray->QueryElementAt(argCtr, NS_GET_IID(nsISupports), argsArray->QueryElementAt(argCtr, NS_GET_IID(nsISupports),
getter_AddRefs(arg)); getter_AddRefs(arg));
if (!arg) { if (!arg) {
@ -1099,7 +1099,7 @@ nsJSContext::ConvertSupportsTojsvals(nsISupports* aArgs,
} else { } else {
nsCOMPtr<nsIVariant> variant = do_QueryInterface(aArgs); nsCOMPtr<nsIVariant> variant = do_QueryInterface(aArgs);
if (variant) { if (variant) {
rv = xpc->VariantToJS(cx, aScope, variant, aArgsOut.handleAt(0)); rv = xpc->VariantToJS(cx, aScope, variant, aArgsOut[0]);
} else { } else {
NS_ERROR("Not an array, not an interface?"); NS_ERROR("Not an array, not an interface?");
rv = NS_ERROR_UNEXPECTED; rv = NS_ERROR_UNEXPECTED;

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

@ -2054,7 +2054,7 @@ inline bool
AddStringToIDVector(JSContext* cx, JS::AutoIdVector& vector, const char* name) AddStringToIDVector(JSContext* cx, JS::AutoIdVector& vector, const char* name)
{ {
return vector.growBy(1) && return vector.growBy(1) &&
InternJSString(cx, vector[vector.length() - 1], name); InternJSString(cx, *(vector[vector.length() - 1]).address(), name);
} }
// Implementation of the bits that XrayWrapper needs // Implementation of the bits that XrayWrapper needs

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

@ -12525,8 +12525,8 @@ class CallbackMember(CGNativeMember):
{ {
'result': result, 'result': result,
'successCode': "continue;\n" if arg.variadic else "break;\n", 'successCode': "continue;\n" if arg.variadic else "break;\n",
'jsvalRef': "argv.handleAt(%s)" % jsvalIndex, 'jsvalRef': "argv[%s]" % jsvalIndex,
'jsvalHandle': "argv.handleAt(%s)" % jsvalIndex, 'jsvalHandle': "argv[%s]" % jsvalIndex,
# XXXbz we don't have anything better to use for 'obj', # XXXbz we don't have anything better to use for 'obj',
# really... It's OK to use CallbackPreserveColor because # really... It's OK to use CallbackPreserveColor because
# CallSetup already handled the unmark-gray bits for us. # CallSetup already handled the unmark-gray bits for us.
@ -12558,7 +12558,7 @@ class CallbackMember(CGNativeMember):
// This is our current trailing argument; reduce argc // This is our current trailing argument; reduce argc
--argc; --argc;
} else { } else {
argv[${i}] = JS::UndefinedValue(); argv[${i}].setUndefined();
} }
""", """,
argName=arg.identifier.name, argName=arg.identifier.name,
@ -12816,7 +12816,7 @@ class CallbackSetter(CallbackAccessor):
return fill( return fill(
""" """
MOZ_ASSERT(argv.length() == 1); MOZ_ASSERT(argv.length() == 1);
if (!JS_SetProperty(cx, CallbackPreserveColor(), "${attrName}", argv.handleAt(0))) { if (!JS_SetProperty(cx, CallbackPreserveColor(), "${attrName}", argv[0])) {
aRv.Throw(NS_ERROR_UNEXPECTED); aRv.Throw(NS_ERROR_UNEXPECTED);
return${errorReturn}; return${errorReturn};
} }

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

@ -244,7 +244,7 @@ ToJSValue(JSContext* aCx,
return false; return false;
} }
for (size_t i = 0; i < aLength; ++i) { for (size_t i = 0; i < aLength; ++i) {
if (!ToJSValue(aCx, aArguments[i], v.handleAt(i))) { if (!ToJSValue(aCx, aArguments[i], v[i])) {
return false; return false;
} }
} }

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

@ -22,6 +22,19 @@ enum GamepadMappingType
StandardMapping = 1 StandardMapping = 1
}; };
// Per spec:
// https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#remapping
const int kStandardGamepadButtons = 17;
const int kStandardGamepadAxes = 4;
const int kButtonLeftTrigger = 6;
const int kButtonRightTrigger = 7;
const int kLeftStickXAxis = 0;
const int kLeftStickYAxis = 1;
const int kRightStickXAxis = 2;
const int kRightStickYAxis = 3;
class Gamepad : public nsISupports, class Gamepad : public nsISupports,
public nsWrapperCache public nsWrapperCache
{ {

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

@ -97,7 +97,9 @@ function createMediaElement(type, label) {
* The error callback if the stream fails to be retrieved * The error callback if the stream fails to be retrieved
*/ */
function getUserMedia(constraints, onSuccess, onError) { function getUserMedia(constraints, onSuccess, onError) {
if (!("fake" in constraints)) {
constraints["fake"] = FAKE_ENABLED; constraints["fake"] = FAKE_ENABLED;
}
info("Call getUserMedia for " + JSON.stringify(constraints)); info("Call getUserMedia for " + JSON.stringify(constraints));
navigator.mozGetUserMedia(constraints, onSuccess, onError); navigator.mozGetUserMedia(constraints, onSuccess, onError);

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

@ -131,7 +131,7 @@ MobileMessageManager::Send(JSContext* aCx, JS::Handle<JSObject*> aGlobal,
uint32_t aServiceId, uint32_t aServiceId,
JS::Handle<JSString*> aNumber, JS::Handle<JSString*> aNumber,
const nsAString& aMessage, const nsAString& aMessage,
JS::Value* aRequest) JS::MutableHandle<JS::Value> aRequest)
{ {
nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID); nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(smsService, NS_ERROR_FAILURE); NS_ENSURE_TRUE(smsService, NS_ERROR_FAILURE);
@ -149,16 +149,14 @@ MobileMessageManager::Send(JSContext* aCx, JS::Handle<JSObject*> aGlobal,
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
js::AssertSameCompartment(aCx, aGlobal); js::AssertSameCompartment(aCx, aGlobal);
JS::Rooted<JS::Value> rval(aCx);
rv = nsContentUtils::WrapNative(aCx, rv = nsContentUtils::WrapNative(aCx,
static_cast<nsIDOMDOMRequest*>(request.get()), static_cast<nsIDOMDOMRequest*>(request.get()),
&rval); aRequest);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
NS_ERROR("Failed to create the js value!"); NS_ERROR("Failed to create the js value!");
return rv; return rv;
} }
*aRequest = rval;
return NS_OK; return NS_OK;
} }
@ -208,7 +206,7 @@ MobileMessageManager::Send(JS::Handle<JS::Value> aNumber,
if (aNumber.isString()) { if (aNumber.isString()) {
JS::Rooted<JSString*> str(aCx, aNumber.toString()); JS::Rooted<JSString*> str(aCx, aNumber.toString());
return Send(aCx, global, serviceId, str, aMessage, aReturn.address()); return Send(aCx, global, serviceId, str, aMessage, aReturn);
} }
// Must be an array then. // Must be an array then.
@ -236,7 +234,7 @@ MobileMessageManager::Send(JS::Handle<JS::Value> aNumber,
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
nsresult rv = Send(aCx, global, serviceId, str, aMessage, &requests[i]); nsresult rv = Send(aCx, global, serviceId, str, aMessage, requests[i]);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }

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

@ -38,7 +38,7 @@ private:
uint32_t aServiceId, uint32_t aServiceId,
JS::Handle<JSString*> aNumber, JS::Handle<JSString*> aNumber,
const nsAString& aMessage, const nsAString& aMessage,
JS::Value* aRequest); JS::MutableHandle<JS::Value> aRequest);
nsresult DispatchTrustedSmsEventToSelf(const char* aTopic, nsresult DispatchTrustedSmsEventToSelf(const char* aTopic,
const nsAString& aEventName, const nsAString& aEventName,

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

@ -272,6 +272,7 @@ let NotificationDB = {
var id = data.id; var id = data.id;
if (!this.notifications[origin]) { if (!this.notifications[origin]) {
if (DEBUG) { debug("No notifications found for origin: " + origin); } if (DEBUG) { debug("No notifications found for origin: " + origin); }
callback();
return; return;
} }
@ -279,6 +280,7 @@ let NotificationDB = {
var oldNotification = this.notifications[origin][id]; var oldNotification = this.notifications[origin][id];
if (!oldNotification) { if (!oldNotification) {
if (DEBUG) { debug("No notification found with id: " + id); } if (DEBUG) { debug("No notification found with id: " + id); }
callback();
return; return;
} }

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

@ -34,3 +34,4 @@ LOCAL_INCLUDES += [
'/dom/ipc', '/dom/ipc',
] ]
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']

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

@ -0,0 +1,338 @@
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
let systemNotification = {
origin: "app://system.gaiamobile.org/manifest.webapp",
id: "{2bc883bf-2809-4432-b0f4-f54e10372764}",
title: "SystemNotification:" + Date.now(),
dir: "auto",
lang: "",
body: "System notification body",
tag: "",
icon: "icon.png"
};
let calendarNotification = {
origin: "app://calendar.gaiamobile.org/manifest.webapp",
id: "{d8d11299-a58e-429b-9a9a-57c562982fbf}",
title: "CalendarNotification:" + Date.now(),
dir: "auto",
lang: "",
body: "Calendar notification body",
tag: "",
icon: "icon.png"
};
function run_test() {
do_get_profile();
Cu.import("resource://gre/modules/NotificationDB.jsm");
run_next_test();
}
// Helper function to add a listener, send message and treat the reply
function addAndSend(msg, reply, callback, payload, runNext = true) {
let handler = {
receiveMessage: function(message) {
if (message.name === reply) {
cpmm.removeMessageListener(reply, handler);
callback(message);
if (runNext) {
run_next_test();
}
}
}
};
cpmm.addMessageListener(reply, handler);
cpmm.sendAsyncMessage(msg, payload);
}
// helper fonction, comparing two notifications
function compareNotification(notif1, notif2) {
// retrieved notification should be the second one sent
for (let prop in notif1) {
// compare each property
do_check_eq(notif1[prop], notif2[prop]);
}
}
// Get one notification, none exists
add_test(function test_get_none() {
let requestID = 0;
let msgReply = "Notification:GetAll:Return:OK";
let msgHandler = function(message) {
do_check_eq(requestID, message.data.requestID);
do_check_eq(0, message.data.notifications.length);
};
addAndSend("Notification:GetAll", msgReply, msgHandler, {
origin: systemNotification.origin,
requestID: requestID
});
});
// Store one notification
add_test(function test_send_one() {
let requestID = 1;
let msgReply = "Notification:Save:Return:OK";
let msgHandler = function(message) {
do_check_eq(requestID, message.data.requestID);
};
addAndSend("Notification:Save", msgReply, msgHandler, {
origin: systemNotification.origin,
notification: systemNotification,
requestID: requestID
});
});
// Get one notification, one exists
add_test(function test_get_one() {
let requestID = 2;
let msgReply = "Notification:GetAll:Return:OK";
let msgHandler = function(message) {
do_check_eq(requestID, message.data.requestID);
do_check_eq(1, message.data.notifications.length);
// compare the content
compareNotification(systemNotification, message.data.notifications[0]);
};
addAndSend("Notification:GetAll", msgReply, msgHandler, {
origin: systemNotification.origin,
requestID: requestID
});
});
// Delete one notification
add_test(function test_delete_one() {
let requestID = 3;
let msgReply = "Notification:Delete:Return:OK";
let msgHandler = function(message) {
do_check_eq(requestID, message.data.requestID);
};
addAndSend("Notification:Delete", msgReply, msgHandler, {
origin: systemNotification.origin,
id: systemNotification.id,
requestID: requestID
});
});
// Get one notification, none exists
add_test(function test_get_none_again() {
let requestID = 4;
let msgReply = "Notification:GetAll:Return:OK";
let msgHandler = function(message) {
do_check_eq(requestID, message.data.requestID);
do_check_eq(0, message.data.notifications.length);
};
addAndSend("Notification:GetAll", msgReply, msgHandler, {
origin: systemNotification.origin,
requestID: requestID
});
});
// Delete one notification that do not exists anymore
add_test(function test_delete_one_nonexistent() {
let requestID = 5;
let msgReply = "Notification:Delete:Return:OK";
let msgHandler = function(message) {
do_check_eq(requestID, message.data.requestID);
};
addAndSend("Notification:Delete", msgReply, msgHandler, {
origin: systemNotification.origin,
id: systemNotification.id,
requestID: requestID
});
});
// Store two notifications with the same id
add_test(function test_send_two_get_one() {
let requestID = 6;
let calls = 0;
let msgGetReply = "Notification:GetAll:Return:OK";
let msgGetHandler = function(message) {
do_check_eq(requestID + 2, message.data.requestID);
do_check_eq(1, message.data.notifications.length);
// compare the content
compareNotification(systemNotification, message.data.notifications[0]);
};
let msgSaveReply = "Notification:Save:Return:OK";
let msgSaveHandler = function(message) {
calls += 1;
if (calls === 2) {
addAndSend("Notification:GetAll", msgGetReply, msgGetHandler, {
origin: systemNotification.origin,
requestID: (requestID + 2)
});
}
};
addAndSend("Notification:Save", msgSaveReply, msgSaveHandler, {
origin: systemNotification.origin,
notification: systemNotification,
requestID: requestID
}, false);
addAndSend("Notification:Save", msgSaveReply, msgSaveHandler, {
origin: systemNotification.origin,
notification: systemNotification,
requestID: (requestID + 1)
}, false);
});
// Delete previous notification
add_test(function test_delete_previous() {
let requestID = 8;
let msgReply = "Notification:Delete:Return:OK";
let msgHandler = function(message) {
do_check_eq(requestID, message.data.requestID);
};
addAndSend("Notification:Delete", msgReply, msgHandler, {
origin: systemNotification.origin,
id: systemNotification.id,
requestID: requestID
});
});
// Store two notifications from same origin with the same tag
add_test(function test_send_two_get_one() {
let requestID = 10;
let tag = "voicemail";
let systemNotification1 = systemNotification;
systemNotification1.id = "{f271f9ee-3955-4c10-b1f2-af552fb270ee}";
systemNotification1.tag = tag;
let systemNotification2 = systemNotification;
systemNotification2.id = "{8ef9a628-f0f4-44b4-820d-c117573c33e3}";
systemNotification2.tag = tag;
let msgGetReply = "Notification:GetAll:Return:OK";
let msgGetNotifHandler = {
receiveMessage: function(message) {
if (message.name === msgGetReply) {
cpmm.removeMessageListener(msgGetReply, msgGetNotifHandler);
let notifications = message.data.notifications;
// same tag, so replaced
do_check_eq(1, notifications.length);
// compare the content
compareNotification(systemNotification2, notifications[0]);
run_next_test();
}
}
};
cpmm.addMessageListener(msgGetReply, msgGetNotifHandler);
let msgSaveReply = "Notification:Save:Return:OK";
let msgSaveCalls = 0;
let msgSaveHandler = function(message) {
msgSaveCalls++;
// Once both request have been sent, trigger getall
if (msgSaveCalls === 2) {
cpmm.sendAsyncMessage("Notification:GetAll", {
origin: systemNotification1.origin,
requestID: message.data.requestID + 2 // 12, 13
});
}
};
addAndSend("Notification:Save", msgSaveReply, msgSaveHandler, {
origin: systemNotification1.origin,
notification: systemNotification1,
requestID: requestID // 10
}, false);
addAndSend("Notification:Save", msgSaveReply, msgSaveHandler, {
origin: systemNotification2.origin,
notification: systemNotification2,
requestID: (requestID + 1) // 11
}, false);
});
// Store two notifications from two origins with the same tag
add_test(function test_send_two_get_two() {
let requestID = 20;
let tag = "voicemail";
let systemNotification1 = systemNotification;
systemNotification1.tag = tag;
let calendarNotification2 = calendarNotification;
calendarNotification2.tag = tag;
let msgGetReply = "Notification:GetAll:Return:OK";
let msgGetCalls = 0;
let msgGetHandler = {
receiveMessage: function(message) {
if (message.name === msgGetReply) {
msgGetCalls++;
let notifications = message.data.notifications;
// one notification per origin
do_check_eq(1, notifications.length);
// first call should be system notification
if (msgGetCalls === 1) {
compareNotification(systemNotification1, notifications[0]);
}
// second and last call should be calendar notification
if (msgGetCalls === 2) {
cpmm.removeMessageListener(msgGetReply, msgGetHandler);
compareNotification(calendarNotification2, notifications[0]);
run_next_test();
}
}
}
};
cpmm.addMessageListener(msgGetReply, msgGetHandler);
let msgSaveReply = "Notification:Save:Return:OK";
let msgSaveCalls = 0;
let msgSaveHandler = {
receiveMessage: function(message) {
if (message.name === msgSaveReply) {
msgSaveCalls++;
if (msgSaveCalls === 2) {
cpmm.removeMessageListener(msgSaveReply, msgSaveHandler);
// Trigger getall for each origin
cpmm.sendAsyncMessage("Notification:GetAll", {
origin: systemNotification1.origin,
requestID: message.data.requestID + 1 // 22
});
cpmm.sendAsyncMessage("Notification:GetAll", {
origin: calendarNotification2.origin,
requestID: message.data.requestID + 2 // 23
});
}
}
}
};
cpmm.addMessageListener(msgSaveReply, msgSaveHandler);
cpmm.sendAsyncMessage("Notification:Save", {
origin: systemNotification1.origin,
notification: systemNotification1,
requestID: requestID // 20
});
cpmm.sendAsyncMessage("Notification:Save", {
origin: calendarNotification2.origin,
notification: calendarNotification2,
requestID: (requestID + 1) // 21
});
});

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

@ -0,0 +1,5 @@
[DEFAULT]
head =
tail =
[test_notificationdb.js]

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

@ -20,10 +20,7 @@ interface Console {
void time(optional any time); void time(optional any time);
void timeEnd(optional any time); void timeEnd(optional any time);
[Throws]
void profile(any... data); void profile(any... data);
[Throws]
void profileEnd(any... data); void profileEnd(any... data);
void assert(boolean condition, any... data); void assert(boolean condition, any... data);

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

@ -728,7 +728,7 @@ APZCTreeManager::HandOffFling(AsyncPanZoomController* aPrev, ScreenPoint aVeloci
// otherwise built on touch-start and cleared on touch-end, and a fling // otherwise built on touch-start and cleared on touch-end, and a fling
// happens after touch-end. Note that, unlike DispatchScroll() which is // happens after touch-end. Note that, unlike DispatchScroll() which is
// called on every touch-move during overscroll panning, // called on every touch-move during overscroll panning,
// HandleFlingOverscroll() is only called once during a fling handoff, // HandOffFling() is only called once during a fling handoff,
// so it's not worth trying to avoid building the handoff chain here. // so it's not worth trying to avoid building the handoff chain here.
BuildOverscrollHandoffChain(aPrev); BuildOverscrollHandoffChain(aPrev);

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

@ -66,7 +66,7 @@
#define APZC_LOG_FM(fm, prefix, ...) \ #define APZC_LOG_FM(fm, prefix, ...) \
APZC_LOG(prefix ":" \ APZC_LOG(prefix ":" \
" i=(%ld %lld) cb=(%d %d %d %d) rcs=(%.3f %.3f) dp=(%.3f %.3f %.3f %.3f) dpm=(%.3f %.3f %.3f %.3f) um=%d " \ " i=(%ld %lld) cb=(%d %d %d %d) rcs=(%.3f %.3f) dp=(%.3f %.3f %.3f %.3f) dpm=(%.3f %.3f %.3f %.3f) um=%d " \
"v=(%.3f %.3f %.3f %.3f) s=(%.3f %.3f) sr=(%.3f %.3f %.3f %.3f) z=(%.3f %.3f %.3f %.3f) u=(%d %lu)\n", \ "v=(%.3f %.3f %.3f %.3f) s=(%.3f %.3f) sr=(%.3f %.3f %.3f %.3f) z(ld=%.3f r=%.3f cr=%.3f z=%.3f ts=%.3f) u=(%d %lu)\n", \
__VA_ARGS__, \ __VA_ARGS__, \
fm.mPresShellId, fm.GetScrollId(), \ fm.mPresShellId, fm.GetScrollId(), \
fm.mCompositionBounds.x, fm.mCompositionBounds.y, fm.mCompositionBounds.width, fm.mCompositionBounds.height, \ fm.mCompositionBounds.x, fm.mCompositionBounds.y, fm.mCompositionBounds.width, fm.mCompositionBounds.height, \
@ -77,7 +77,7 @@
fm.mViewport.x, fm.mViewport.y, fm.mViewport.width, fm.mViewport.height, \ fm.mViewport.x, fm.mViewport.y, fm.mViewport.width, fm.mViewport.height, \
fm.GetScrollOffset().x, fm.GetScrollOffset().y, \ fm.GetScrollOffset().x, fm.GetScrollOffset().y, \
fm.mScrollableRect.x, fm.mScrollableRect.y, fm.mScrollableRect.width, fm.mScrollableRect.height, \ fm.mScrollableRect.x, fm.mScrollableRect.y, fm.mScrollableRect.width, fm.mScrollableRect.height, \
fm.mDevPixelsPerCSSPixel.scale, fm.mResolution.scale, fm.mCumulativeResolution.scale, fm.GetZoom().scale, \ fm.mDevPixelsPerCSSPixel.scale, fm.mResolution.scale, fm.mCumulativeResolution.scale, fm.GetZoom().scale, fm.mTransformScale.scale, \
fm.GetScrollOffsetUpdated(), fm.GetScrollGeneration()); \ fm.GetScrollOffsetUpdated(), fm.GetScrollGeneration()); \
// Static helper functions // Static helper functions
@ -163,6 +163,20 @@ typedef GeckoContentController::APZStateChange APZStateChange;
* generated displayport's size is beyond that of the scrollable rect on the * generated displayport's size is beyond that of the scrollable rect on the
* opposite axis. * opposite axis.
* *
* "apz.fling_accel_interval_ms"
* The time in milliseconds that determines whether a second fling will be
* treated as accelerated. If two flings are started within this interval,
* the second one will be accelerated. Setting an interval of 0 means that
* acceleration will be disabled.
*
* "apz.fling_accel_base_mult"
* "apz.fling_accel_supplemental_mult"
* When applying an acceleration on a fling, the new computed velocity is
* (new_fling_velocity * base_mult) + (old_velocity * supplemental_mult).
* The base_mult and supplemental_mult multiplier values are controlled by
* these prefs. Note that "old_velocity" here is the initial velocity of the
* previous fling _after_ acceleration was applied to it (if applicable).
*
* "apz.fling_friction" * "apz.fling_friction"
* Amount of friction applied during flings. * Amount of friction applied during flings.
* *
@ -330,10 +344,40 @@ GetFrameTime() {
class FlingAnimation: public AsyncPanZoomAnimation { class FlingAnimation: public AsyncPanZoomAnimation {
public: public:
FlingAnimation(AsyncPanZoomController& aApzc) FlingAnimation(AsyncPanZoomController& aApzc, bool aApplyAcceleration)
: AsyncPanZoomAnimation(TimeDuration::FromMilliseconds(gfxPrefs::APZFlingRepaintInterval())) : AsyncPanZoomAnimation(TimeDuration::FromMilliseconds(gfxPrefs::APZFlingRepaintInterval()))
, mApzc(aApzc) , mApzc(aApzc)
{} {
TimeStamp now = GetFrameTime();
ScreenPoint velocity(mApzc.mX.GetVelocity(), mApzc.mY.GetVelocity());
// If the last fling was very recent and in the same direction as this one,
// boost the velocity to be the sum of the two. Check separate axes separately
// because we could have two vertical flings with small horizontal components
// on the opposite side of zero, and we still want the y-fling to get accelerated.
// Note that the acceleration code is only applied on the APZC that receives the
// actual touch event; the accelerated velocities are then handed off using the
// normal HandOffFling codepath.
if (aApplyAcceleration && !mApzc.mLastFlingTime.IsNull()
&& (now - mApzc.mLastFlingTime).ToMilliseconds() < gfxPrefs::APZFlingAccelInterval()) {
if (SameDirection(velocity.x, mApzc.mLastFlingVelocity.x)) {
velocity.x = Accelerate(velocity.x, mApzc.mLastFlingVelocity.x);
APZC_LOG("%p Applying fling x-acceleration from %f to %f (delta %f)\n",
&mApzc, mApzc.mX.GetVelocity(), velocity.x, mApzc.mLastFlingVelocity.x);
mApzc.mX.SetVelocity(velocity.x);
}
if (SameDirection(velocity.y, mApzc.mLastFlingVelocity.y)) {
velocity.y = Accelerate(velocity.y, mApzc.mLastFlingVelocity.y);
APZC_LOG("%p Applying fling y-acceleration from %f to %f (delta %f)\n",
&mApzc, mApzc.mY.GetVelocity(), velocity.y, mApzc.mLastFlingVelocity.y);
mApzc.mY.SetVelocity(velocity.y);
}
}
mApzc.mLastFlingTime = now;
mApzc.mLastFlingVelocity = velocity;
}
/** /**
* Advances a fling by an interpolated amount based on the passed in |aDelta|. * Advances a fling by an interpolated amount based on the passed in |aDelta|.
* This should be called whenever sampling the content transform for this * This should be called whenever sampling the content transform for this
@ -344,6 +388,19 @@ public:
const TimeDuration& aDelta); const TimeDuration& aDelta);
private: private:
static bool SameDirection(float aVelocity1, float aVelocity2)
{
return (aVelocity1 == 0.0f)
|| (aVelocity2 == 0.0f)
|| (IsNegative(aVelocity1) == IsNegative(aVelocity2));
}
static float Accelerate(float aBase, float aSupplemental)
{
return (aBase * gfxPrefs::APZFlingAccelBaseMultiplier())
+ (aSupplemental * gfxPrefs::APZFlingAccelSupplementalMultiplier());
}
AsyncPanZoomController& mApzc; AsyncPanZoomController& mApzc;
}; };
@ -755,7 +812,7 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
mX.EndTouch(); mX.EndTouch();
mY.EndTouch(); mY.EndTouch();
SetState(FLING); SetState(FLING);
StartAnimation(new FlingAnimation(*this)); StartAnimation(new FlingAnimation(*this, true));
return nsEventStatus_eConsumeNoDefault; return nsEventStatus_eConsumeNoDefault;
case PINCHING: case PINCHING:
@ -1183,7 +1240,7 @@ void AsyncPanZoomController::TakeOverFling(ScreenPoint aVelocity) {
mX.SetVelocity(mX.GetVelocity() + aVelocity.x); mX.SetVelocity(mX.GetVelocity() + aVelocity.x);
mY.SetVelocity(mY.GetVelocity() + aVelocity.y); mY.SetVelocity(mY.GetVelocity() + aVelocity.y);
SetState(FLING); SetState(FLING);
StartAnimation(new FlingAnimation(*this)); StartAnimation(new FlingAnimation(*this, false));
} }
void AsyncPanZoomController::CallDispatchScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint, void AsyncPanZoomController::CallDispatchScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint,
@ -1294,20 +1351,20 @@ bool FlingAnimation::Sample(FrameMetrics& aFrameMetrics,
velocity.y = 0; velocity.y = 0;
} }
// To hand off the fling, we call APZCTreeManager::HandleFlingOverscroll() // To hand off the fling, we call APZCTreeManager::HandOffFling()
// which starts a new fling in the next APZC in the handoff chain with // which starts a new fling in the next APZC in the handoff chain with
// the same velocity. For simplicity, the actual overscroll of the current // the same velocity. For simplicity, the actual overscroll of the current
// sample is discarded rather than being handed off. The compositor should // sample is discarded rather than being handed off. The compositor should
// sample animations sufficiently frequently that this is not noticeable. // sample animations sufficiently frequently that this is not noticeable.
// Make a local copy of the tree manager pointer and check if it's not // Make a local copy of the tree manager pointer and check if it's not
// null before calling HandleFlingOverscroll(). This is necessary because // null before calling HandOffFling(). This is necessary because
// Destroy(), which nulls out mTreeManager, could be called concurrently. // Destroy(), which nulls out mTreeManager, could be called concurrently.
APZCTreeManager* treeManagerLocal = mApzc.mTreeManager; APZCTreeManager* treeManagerLocal = mApzc.mTreeManager;
if (treeManagerLocal) { if (treeManagerLocal) {
// APZC is holding mMonitor, so directly calling HandleFlingOverscroll() // APZC is holding mMonitor, so directly calling HandOffFling()
// (which acquires the tree lock) would violate the lock ordering. Instead // (which acquires the tree lock) would violate the lock ordering. Instead
// we schedule HandleFlingOverscroll() to be called after mMonitor is // we schedule HandOffFling() to be called after mMonitor is
// released. // released.
mDeferredTasks.append(NewRunnableMethod(treeManagerLocal, mDeferredTasks.append(NewRunnableMethod(treeManagerLocal,
&APZCTreeManager::HandOffFling, &APZCTreeManager::HandOffFling,
@ -1718,11 +1775,11 @@ gfx3DMatrix AsyncPanZoomController::GetTransformToLastDispatchedPaint() {
void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint) { void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint) {
ReentrantMonitorAutoEnter lock(mMonitor); ReentrantMonitorAutoEnter lock(mMonitor);
bool isDefault = mFrameMetrics.IsDefault();
mLastContentPaintMetrics = aLayerMetrics; mLastContentPaintMetrics = aLayerMetrics;
UpdateTransformScale(); UpdateTransformScale();
bool isDefault = mFrameMetrics.IsDefault();
mFrameMetrics.mMayHaveTouchListeners = aLayerMetrics.mMayHaveTouchListeners; mFrameMetrics.mMayHaveTouchListeners = aLayerMetrics.mMayHaveTouchListeners;
APZC_LOG_FM(aLayerMetrics, "%p got a NotifyLayersUpdated with aIsFirstPaint=%d", this, aIsFirstPaint); APZC_LOG_FM(aLayerMetrics, "%p got a NotifyLayersUpdated with aIsFirstPaint=%d", this, aIsFirstPaint);

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

@ -294,12 +294,6 @@ public:
*/ */
void CancelAnimation(); void CancelAnimation();
/**
* Take over a fling with the given velocity from another APZC. Used for
* during overscroll handoff for a fling.
*/
void TakeOverFling(ScreenPoint aVelocity);
/** /**
* Returns allowed touch behavior for the given point on the scrollable layer. * Returns allowed touch behavior for the given point on the scrollable layer.
* Internally performs a kind of hit testing based on the regions constructed * Internally performs a kind of hit testing based on the regions constructed
@ -501,14 +495,6 @@ protected:
*/ */
void DispatchRepaintRequest(const FrameMetrics& aFrameMetrics); void DispatchRepaintRequest(const FrameMetrics& aFrameMetrics);
/**
* Advances a fling by an interpolated amount based on the passed in |aDelta|.
* This should be called whenever sampling the content transform for this
* frame. Returns true if the fling animation should be advanced by one frame,
* or false if there is no fling or the fling has ended.
*/
bool DoFling(const TimeDuration& aDelta);
/** /**
* Gets the current frame metrics. This is *not* the Gecko copy stored in the * Gets the current frame metrics. This is *not* the Gecko copy stored in the
* layers code. * layers code.
@ -777,7 +763,25 @@ private:
RefPtr<AsyncPanZoomAnimation> mAnimation; RefPtr<AsyncPanZoomAnimation> mAnimation;
friend class Axis; friend class Axis;
/* ===================================================================
* The functions and members in this section are used to manage
* fling animations.
*/
public:
/**
* Take over a fling with the given velocity from another APZC. Used for
* during overscroll handoff for a fling.
*/
void TakeOverFling(ScreenPoint aVelocity);
private:
friend class FlingAnimation; friend class FlingAnimation;
// The initial velocity of the most recent fling.
ScreenPoint mLastFlingVelocity;
// The time at which the most recent fling started.
TimeStamp mLastFlingTime;
/* =================================================================== /* ===================================================================

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

@ -111,6 +111,9 @@ private:
DECL_GFX_PREF(Live, "apz.content_response_timeout", APZContentResponseTimeout, int32_t, 300); DECL_GFX_PREF(Live, "apz.content_response_timeout", APZContentResponseTimeout, int32_t, 300);
DECL_GFX_PREF(Live, "apz.cross_slide.enabled", APZCrossSlideEnabled, bool, false); DECL_GFX_PREF(Live, "apz.cross_slide.enabled", APZCrossSlideEnabled, bool, false);
DECL_GFX_PREF(Live, "apz.enlarge_displayport_when_clipped", APZEnlargeDisplayPortWhenClipped, bool, false); DECL_GFX_PREF(Live, "apz.enlarge_displayport_when_clipped", APZEnlargeDisplayPortWhenClipped, bool, false);
DECL_GFX_PREF(Live, "apz.fling_accel_interval_ms", APZFlingAccelInterval, int32_t, 500);
DECL_GFX_PREF(Live, "apz.fling_accel_base_mult", APZFlingAccelBaseMultiplier, float, 1.0f);
DECL_GFX_PREF(Live, "apz.fling_accel_supplemental_mult", APZFlingAccelSupplementalMultiplier, float, 1.0f);
DECL_GFX_PREF(Once, "apz.fling_friction", APZFlingFriction, float, 0.002f); DECL_GFX_PREF(Once, "apz.fling_friction", APZFlingFriction, float, 0.002f);
DECL_GFX_PREF(Live, "apz.fling_repaint_interval", APZFlingRepaintInterval, int32_t, 75); DECL_GFX_PREF(Live, "apz.fling_repaint_interval", APZFlingRepaintInterval, int32_t, 75);
DECL_GFX_PREF(Once, "apz.fling_stopped_threshold", APZFlingStoppedThreshold, float, 0.01f); DECL_GFX_PREF(Once, "apz.fling_stopped_threshold", APZFlingStoppedThreshold, float, 0.01f);

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

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

@ -501,7 +501,7 @@ JavaScriptChild::AnswerCall(const ObjectId &objId, const nsTArray<JSParam> &argv
ContextOptionsRef(cx).setDontReportUncaught(true); ContextOptionsRef(cx).setDontReportUncaught(true);
HandleValueArray args = HandleValueArray::subarray(vals, 2, vals.length() - 2); HandleValueArray args = HandleValueArray::subarray(vals, 2, vals.length() - 2);
bool success = JS::Call(cx, vals.handleAt(1), vals.handleAt(0), args, &rval); bool success = JS::Call(cx, vals[1], vals[0], args, &rval);
if (!success) if (!success)
return fail(cx, rs); return fail(cx, rs);
} }
@ -536,7 +536,7 @@ JavaScriptChild::AnswerCall(const ObjectId &objId, const nsTArray<JSParam> &argv
// treat this as the outparam never having been set. // treat this as the outparam never having been set.
for (size_t i = 0; i < vals.length(); i++) { for (size_t i = 0; i < vals.length(); i++) {
JSVariant variant; JSVariant variant;
if (!toVariant(cx, vals.handleAt(i), &variant)) if (!toVariant(cx, vals[i], &variant))
return fail(cx, rs); return fail(cx, rs);
outparams->ReplaceElementAt(i, JSParam(variant)); outparams->ReplaceElementAt(i, JSParam(variant));
} }
@ -596,7 +596,7 @@ JavaScriptChild::AnswerGetPropertyNames(const ObjectId &objId, const uint32_t &f
for (size_t i = 0; i < props.length(); i++) { for (size_t i = 0; i < props.length(); i++) {
nsString name; nsString name;
if (!convertIdToGeckoString(cx, props.handleAt(i), &name)) if (!convertIdToGeckoString(cx, props[i], &name))
return fail(cx, rs); return fail(cx, rs);
names->AppendElement(name); names->AppendElement(name);

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

@ -236,7 +236,7 @@ typedef enum JSWhyMagic
JS_BLOCK_NEEDS_CLONE, /* value of static block object slot */ JS_BLOCK_NEEDS_CLONE, /* value of static block object slot */
JS_HASH_KEY_EMPTY, /* see class js::HashableValue */ JS_HASH_KEY_EMPTY, /* see class js::HashableValue */
JS_ION_ERROR, /* error while running Ion code */ JS_ION_ERROR, /* error while running Ion code */
JS_ION_BAILOUT, /* status code to signal EnterIon will OSR into Interpret */ JS_ION_BAILOUT, /* missing recover instruction result */
JS_OPTIMIZED_OUT, /* optimized out slot */ JS_OPTIMIZED_OUT, /* optimized out slot */
JS_GENERIC_MAGIC /* for local use */ JS_GENERIC_MAGIC /* for local use */
} JSWhyMagic; } JSWhyMagic;

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

@ -930,7 +930,7 @@ StructMetaTypeDescr::create(JSContext *cx,
// userFieldTypes[id] = typeObj // userFieldTypes[id] = typeObj
if (!JSObject::defineGeneric(cx, userFieldTypes, id, if (!JSObject::defineGeneric(cx, userFieldTypes, id,
fieldTypeObjs.handleAt(i), nullptr, nullptr, fieldTypeObjs[i], nullptr, nullptr,
JSPROP_READONLY | JSPROP_PERMANENT)) JSPROP_READONLY | JSPROP_PERMANENT))
return nullptr; return nullptr;

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

@ -1163,27 +1163,27 @@ InitTypeClasses(JSContext* cx, HandleObject parent)
if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto, if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto,
sPointerFunction, nullptr, sPointerProps, sPointerFunction, nullptr, sPointerProps,
sPointerInstanceFunctions, sPointerInstanceProps, sPointerInstanceFunctions, sPointerInstanceProps,
protos.handleAt(SLOT_POINTERPROTO), protos.handleAt(SLOT_POINTERDATAPROTO))) protos[SLOT_POINTERPROTO], protos[SLOT_POINTERDATAPROTO]))
return false; return false;
if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto, if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto,
sArrayFunction, nullptr, sArrayProps, sArrayFunction, nullptr, sArrayProps,
sArrayInstanceFunctions, sArrayInstanceProps, sArrayInstanceFunctions, sArrayInstanceProps,
protos.handleAt(SLOT_ARRAYPROTO), protos.handleAt(SLOT_ARRAYDATAPROTO))) protos[SLOT_ARRAYPROTO], protos[SLOT_ARRAYDATAPROTO]))
return false; return false;
if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto, if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto,
sStructFunction, sStructFunctions, sStructProps, sStructFunction, sStructFunctions, sStructProps,
sStructInstanceFunctions, nullptr, sStructInstanceFunctions, nullptr,
protos.handleAt(SLOT_STRUCTPROTO), protos.handleAt(SLOT_STRUCTDATAPROTO))) protos[SLOT_STRUCTPROTO], protos[SLOT_STRUCTDATAPROTO]))
return false; return false;
if (!InitTypeConstructor(cx, parent, CTypeProto, protos.handleAt(SLOT_POINTERDATAPROTO), if (!InitTypeConstructor(cx, parent, CTypeProto, protos[SLOT_POINTERDATAPROTO],
sFunctionFunction, nullptr, sFunctionProps, sFunctionInstanceFunctions, nullptr, sFunctionFunction, nullptr, sFunctionProps, sFunctionInstanceFunctions, nullptr,
protos.handleAt(SLOT_FUNCTIONPROTO), protos.handleAt(SLOT_FUNCTIONDATAPROTO))) protos[SLOT_FUNCTIONPROTO], protos[SLOT_FUNCTIONDATAPROTO]))
return false; return false;
protos[SLOT_CDATAPROTO] = CDataProto; protos[SLOT_CDATAPROTO].set(CDataProto);
// Create and attach the ctypes.{Int64,UInt64} constructors. // Create and attach the ctypes.{Int64,UInt64} constructors.
// Each of these has, respectively: // Each of these has, respectively:
@ -1193,18 +1193,18 @@ InitTypeClasses(JSContext* cx, HandleObject parent)
// * 'prototype' property: // * 'prototype' property:
// * [[Class]] {"Int64Proto","UInt64Proto"} // * [[Class]] {"Int64Proto","UInt64Proto"}
// * 'constructor' property === ctypes.{Int64,UInt64} // * 'constructor' property === ctypes.{Int64,UInt64}
protos[SLOT_INT64PROTO] = InitInt64Class(cx, parent, &sInt64ProtoClass, protos[SLOT_INT64PROTO].set(InitInt64Class(cx, parent, &sInt64ProtoClass,
Int64::Construct, sInt64Functions, sInt64StaticFunctions); Int64::Construct, sInt64Functions, sInt64StaticFunctions));
if (!protos[SLOT_INT64PROTO]) if (!protos[SLOT_INT64PROTO])
return false; return false;
protos[SLOT_UINT64PROTO] = InitInt64Class(cx, parent, &sUInt64ProtoClass, protos[SLOT_UINT64PROTO].set(InitInt64Class(cx, parent, &sUInt64ProtoClass,
UInt64::Construct, sUInt64Functions, sUInt64StaticFunctions); UInt64::Construct, sUInt64Functions, sUInt64StaticFunctions));
if (!protos[SLOT_UINT64PROTO]) if (!protos[SLOT_UINT64PROTO])
return false; return false;
// Finally, store a pointer to the global ctypes object. // Finally, store a pointer to the global ctypes object.
// Note that there is no other reliable manner of locating this object. // Note that there is no other reliable manner of locating this object.
protos[SLOT_CTYPES] = parent; protos[SLOT_CTYPES].set(parent);
// Attach the prototypes just created to each of ctypes.CType.prototype, // Attach the prototypes just created to each of ctypes.CType.prototype,
// and the special type constructors, so we can access them when constructing // and the special type constructors, so we can access them when constructing
@ -4827,7 +4827,7 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj_, JSObject* fieldsOb
Rooted<JSFlatString*> name(cx, ExtractStructField(cx, item, fieldType.address())); Rooted<JSFlatString*> name(cx, ExtractStructField(cx, item, fieldType.address()));
if (!name) if (!name)
return false; return false;
fieldRoots[i] = JS::ObjectValue(*fieldType); fieldRoots[i].setObject(*fieldType);
// Make sure each field name is unique // Make sure each field name is unique
FieldInfoHash::AddPtr entryPtr = fields->lookupForAdd(name); FieldInfoHash::AddPtr entryPtr = fields->lookupForAdd(name);
@ -5135,7 +5135,7 @@ StructType::BuildFieldsArray(JSContext* cx, JSObject* obj)
for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) { for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
const FieldInfoHash::Entry& entry = r.front(); const FieldInfoHash::Entry& entry = r.front();
// Add the field descriptor to the array. // Add the field descriptor to the array.
if (!AddFieldToArray(cx, &fieldsVec[entry.value().mIndex], if (!AddFieldToArray(cx, fieldsVec[entry.value().mIndex].address(),
entry.key(), entry.value().mType)) entry.key(), entry.value().mType))
return nullptr; return nullptr;
} }
@ -5620,7 +5620,7 @@ FunctionType::Create(JSContext* cx, unsigned argc, jsval* vp)
// Pull out the argument types from the array, if any. // Pull out the argument types from the array, if any.
JS_ASSERT_IF(argTypes.length(), arrayObj); JS_ASSERT_IF(argTypes.length(), arrayObj);
for (uint32_t i = 0; i < argTypes.length(); ++i) { for (uint32_t i = 0; i < argTypes.length(); ++i) {
if (!JS_GetElement(cx, arrayObj, i, argTypes.handleAt(i))) if (!JS_GetElement(cx, arrayObj, i, argTypes[i]))
return false; return false;
} }
@ -5946,7 +5946,7 @@ FunctionType::ArgTypesGetter(JSContext* cx, JS::CallArgs args)
return false; return false;
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i)
vec[i] = JS::ObjectValue(*fninfo->mArgTypes[i]); vec[i].setObject(*fninfo->mArgTypes[i]);
argTypes = JS_NewArrayObject(cx, vec); argTypes = JS_NewArrayObject(cx, vec);
if (!argTypes) if (!argTypes)
@ -6182,7 +6182,7 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData)
// Convert each argument, and have any CData objects created depend on // Convert each argument, and have any CData objects created depend on
// the existing buffers. // the existing buffers.
RootedObject argType(cx, fninfo->mArgTypes[i]); RootedObject argType(cx, fninfo->mArgTypes[i]);
if (!ConvertToJS(cx, argType, NullPtr(), args[i], false, false, &argv[i])) if (!ConvertToJS(cx, argType, NullPtr(), args[i], false, false, argv[i].address()))
return; return;
} }

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

@ -0,0 +1,72 @@
setJitCompilerOption("baseline.usecount.trigger", 10);
setJitCompilerOption("ion.usecount.trigger", 20);
var i;
// Check that we are able to remove the addition inside "ra" functions, when we
// inline the first version of uceFault, and ensure that the bailout is correct
// when uceFault is replaced (which cause an invalidation bailout)
var uceFault = function (i) {
if (i > 98)
uceFault = function (i) { return true; };
return false;
}
var uceFault_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_number'));
function ra_number(i) {
var x = 1 + i;
if (uceFault_number(i) || uceFault_number(i))
assertEq(x, 100 /* = 1 + 99 */);
return i;
}
var uceFault_float = eval(uneval(uceFault).replace('uceFault', 'uceFault_float'));
function ra_float(i) {
var t = Math.fround(1/3);
var fi = Math.fround(i);
var x = Math.fround(Math.fround(Math.fround(Math.fround(t + fi) + t) + fi) + t);
if (uceFault_float(i) || uceFault_float(i))
assertEq(x, 199); /* != 199.00000002980232 (when computed with double additions) */
return i;
}
var uceFault_string = eval(uneval(uceFault).replace('uceFault', 'uceFault_string'));
function ra_string(i) {
var x = "s" + i;
if (uceFault_string(i) || uceFault_string(i))
assertEq(x, "s99");
return i;
}
var uceFault_object = eval(uneval(uceFault).replace('uceFault', 'uceFault_object'));
function ra_object(i) {
var x = {} + i;
if (uceFault_object(i) || uceFault_object(i))
assertEq(x, "[object Object]99");
return i;
}
for (i = 0; i < 100; i++) {
ra_number(i);
ra_float(i);
ra_string(i);
ra_object(i);
}
// Test that we can refer multiple time to the same recover instruction, as well
// as chaining recover instructions.
function alignedAlloc($size, $alignment) {
var $1 = $size + 4 | 0;
var $2 = $alignment - 1 | 0;
var $3 = $1 + $2 | 0;
var $4 = malloc($3);
}
function malloc($bytes) {
var $189 = undefined;
var $198 = $189 + 8 | 0;
}
for (i = 0; i < 50; i++)
alignedAlloc(608, 16);

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

@ -239,7 +239,7 @@ ValidateFFI(JSContext *cx, AsmJSModule::Global &global, HandleValue importVal,
if (!v.isObject() || !v.toObject().is<JSFunction>()) if (!v.isObject() || !v.toObject().is<JSFunction>())
return LinkFail(cx, "FFI imports must be functions"); return LinkFail(cx, "FFI imports must be functions");
(*ffis)[global.ffiIndex()] = &v.toObject().as<JSFunction>(); (*ffis)[global.ffiIndex()].set(&v.toObject().as<JSFunction>());
return true; return true;
} }

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

@ -47,7 +47,8 @@ SnapshotIterator::SnapshotIterator(const IonBailoutIterator &iter)
iter.ionScript()->recoversSize()), iter.ionScript()->recoversSize()),
fp_(iter.jsFrame()), fp_(iter.jsFrame()),
machine_(iter.machineState()), machine_(iter.machineState()),
ionScript_(iter.ionScript()) ionScript_(iter.ionScript()),
instructionResults_(nullptr)
{ {
} }

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

@ -558,9 +558,6 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
if (callerPC == nullptr) { if (callerPC == nullptr) {
IonSpew(IonSpew_BaselineBailouts, " Setting SPS flag on top frame!"); IonSpew(IonSpew_BaselineBailouts, " Setting SPS flag on top frame!");
flags |= BaselineFrame::HAS_PUSHED_SPS_FRAME; flags |= BaselineFrame::HAS_PUSHED_SPS_FRAME;
} else if (js_JitOptions.profileInlineFrames) {
IonSpew(IonSpew_BaselineBailouts, " Setting SPS flag on inline frame!");
flags |= BaselineFrame::HAS_PUSHED_SPS_FRAME;
} }
} }
@ -674,7 +671,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
size_t argOffset = builder.framePushed() + IonJSFrameLayout::offsetOfActualArg(i); size_t argOffset = builder.framePushed() + IonJSFrameLayout::offsetOfActualArg(i);
*builder.valuePointerAtStackOffset(argOffset) = arg; *builder.valuePointerAtStackOffset(argOffset) = arg;
} else { } else {
startFrameFormals[i] = arg; startFrameFormals[i].set(arg);
} }
} }
} }
@ -758,7 +755,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
if (!savedCallerArgs.resize(inlined_args)) if (!savedCallerArgs.resize(inlined_args))
return false; return false;
for (uint32_t i = 0; i < inlined_args; i++) for (uint32_t i = 0; i < inlined_args; i++)
savedCallerArgs[i] = iter.read(); savedCallerArgs[i].set(iter.read());
if (IsSetPropPC(pc)) { if (IsSetPropPC(pc)) {
// We would love to just save all the arguments and leave them // We would love to just save all the arguments and leave them
@ -988,36 +985,6 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
blFrame->unsetPushedSPSFrame(); blFrame->unsetPushedSPSFrame();
if (cx->runtime()->spsProfiler.enabled()) { if (cx->runtime()->spsProfiler.enabled()) {
if (js_JitOptions.profileInlineFrames) {
// If SPS is enabled, there are two corner cases to handle:
// 1. If resuming into the prologue, and innermost frame is an inlined
// frame, and bailout is because of argument check failure, then:
// Top SPS profiler entry would be for caller frame.
// Ion would not have set the PC index field on that frame
// (since this bailout happens before MFunctionBoundary).
// Make sure that's done now.
// 2. If resuming into the prologue, and the bailout is NOT because of an
// argument check, then:
// Top SPS profiler entry would be for callee frame.
// Ion would already have pushed an SPS entry for this frame.
// The pc for this entry would be set to nullptr.
// Make sure it's set to script->pc.
if (caller && bailoutKind == Bailout_ArgumentCheck) {
IonSpew(IonSpew_BaselineBailouts, " Setting PCidx on innermost "
"inlined frame's parent's SPS entry (%s:%d) (pcIdx=%d)!",
caller->filename(), caller->lineno(),
caller->pcToOffset(callerPC));
cx->runtime()->spsProfiler.updatePC(caller, callerPC);
} else if (bailoutKind != Bailout_ArgumentCheck) {
IonSpew(IonSpew_BaselineBailouts,
" Popping SPS entry for innermost inlined frame");
cx->runtime()->spsProfiler.exit(script, fun);
}
} else {
// If not profiling inline frames, then this is logically simpler.
//
// 1. If resuming into inline code, then the top SPS entry will be // 1. If resuming into inline code, then the top SPS entry will be
// for the outermost caller, and will have an uninitialized PC. // for the outermost caller, and will have an uninitialized PC.
// This will be fixed up later in BailoutIonToBaseline. // This will be fixed up later in BailoutIonToBaseline.
@ -1038,7 +1005,6 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
cx->runtime()->spsProfiler.exit(script, fun); cx->runtime()->spsProfiler.exit(script, fun);
} }
} }
}
} else { } else {
opReturnAddr = nativeCodeForPC; opReturnAddr = nativeCodeForPC;
} }
@ -1370,8 +1336,12 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
return BAILOUT_RETURN_FATAL_ERROR; return BAILOUT_RETURN_FATAL_ERROR;
IonSpew(IonSpew_BaselineBailouts, " Incoming frame ptr = %p", builder.startFrame()); IonSpew(IonSpew_BaselineBailouts, " Incoming frame ptr = %p", builder.startFrame());
AutoValueVector instructionResults(cx);
SnapshotIterator snapIter(iter); SnapshotIterator snapIter(iter);
if (!snapIter.initIntructionResults(instructionResults))
return BAILOUT_RETURN_FATAL_ERROR;
RootedFunction callee(cx, iter.maybeCallee()); RootedFunction callee(cx, iter.maybeCallee());
RootedScript scr(cx, iter.script()); RootedScript scr(cx, iter.script());
if (callee) { if (callee) {
@ -1399,7 +1369,12 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
jsbytecode *topCallerPC = nullptr; jsbytecode *topCallerPC = nullptr;
while (true) { while (true) {
MOZ_ASSERT(snapIter.instruction()->isResumePoint()); if (!snapIter.instruction()->isResumePoint()) {
if (!snapIter.instruction()->recover(cx, snapIter))
return BAILOUT_RETURN_FATAL_ERROR;
snapIter.nextInstruction();
continue;
}
if (frameNo > 0) { if (frameNo > 0) {
TraceLogStartEvent(logger, TraceLogCreateTextId(logger, scr)); TraceLogStartEvent(logger, TraceLogCreateTextId(logger, scr));
@ -1453,10 +1428,9 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIt
} }
IonSpew(IonSpew_BaselineBailouts, " Done restoring frames"); IonSpew(IonSpew_BaselineBailouts, " Done restoring frames");
// If there were multiple inline frames unpacked, and inline frame profiling // If there were multiple inline frames unpacked, then the current top SPS frame
// is off, then the current top SPS frame is for the outermost caller, and // is for the outermost caller, and has an uninitialized PC. Initialize it now.
// has an uninitialized PC. Initialize it now. if (frameNo > 0)
if (frameNo > 0 && !js_JitOptions.profileInlineFrames)
cx->runtime()->spsProfiler.updatePC(topCaller, topCallerPC); cx->runtime()->spsProfiler.updatePC(topCaller, topCallerPC);
BailoutKind bailoutKind = snapIter.bailoutKind(); BailoutKind bailoutKind = snapIter.bailoutKind();

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

@ -2342,6 +2342,58 @@ BaselineCompiler::emit_JSOP_INITELEM_SETTER()
return emitInitElemGetterSetter(); return emitInitElemGetterSetter();
} }
bool
BaselineCompiler::emit_JSOP_INITELEM_INC()
{
// Keep the object and rhs on the stack.
frame.syncStack(0);
// Load object in R0, index in R1.
masm.loadValue(frame.addressOfStackValue(frame.peek(-3)), R0);
masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R1);
// Call IC.
ICSetElem_Fallback::Compiler stubCompiler(cx);
if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
return false;
// Pop the rhs
frame.pop();
// Increment index
Address indexAddr = frame.addressOfStackValue(frame.peek(-1));
masm.incrementInt32Value(indexAddr);
return true;
}
typedef bool (*SpreadFn)(JSContext *, HandleObject, HandleValue,
HandleValue, MutableHandleValue);
static const VMFunction SpreadInfo = FunctionInfo<SpreadFn>(js::SpreadOperation);
bool
BaselineCompiler::emit_JSOP_SPREAD()
{
// Load index and iterable in R0 and R1, but keep values on the stack for
// the decompiler.
frame.syncStack(0);
masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
prepareVMCall();
pushArg(R1);
pushArg(R0);
masm.extractObject(frame.addressOfStackValue(frame.peek(-3)), R0.scratchReg());
pushArg(R0.scratchReg());
if (!callVM(SpreadInfo))
return false;
frame.popn(2);
frame.push(R0);
return true;
}
bool bool
BaselineCompiler::emit_JSOP_GETLOCAL() BaselineCompiler::emit_JSOP_GETLOCAL()
{ {

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

@ -97,6 +97,8 @@ namespace jit {
_(JSOP_INITELEM) \ _(JSOP_INITELEM) \
_(JSOP_INITELEM_GETTER) \ _(JSOP_INITELEM_GETTER) \
_(JSOP_INITELEM_SETTER) \ _(JSOP_INITELEM_SETTER) \
_(JSOP_INITELEM_INC) \
_(JSOP_SPREAD) \
_(JSOP_MUTATEPROTO) \ _(JSOP_MUTATEPROTO) \
_(JSOP_INITPROP) \ _(JSOP_INITPROP) \
_(JSOP_INITPROP_GETTER) \ _(JSOP_INITPROP_GETTER) \

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

@ -111,7 +111,7 @@ BaselineFrame::copyRawFrameSlots(AutoValueVector *vec) const
mozilla::PodCopy(vec->begin(), argv(), nformals); mozilla::PodCopy(vec->begin(), argv(), nformals);
for (unsigned i = 0; i < nfixed; i++) for (unsigned i = 0; i < nfixed; i++)
(*vec)[nformals + i] = *valueSlot(i); (*vec)[nformals + i].set(*valueSlot(i));
return true; return true;
} }

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

@ -5002,7 +5002,8 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub_
JS_ASSERT(op == JSOP_SETELEM || JS_ASSERT(op == JSOP_SETELEM ||
op == JSOP_INITELEM || op == JSOP_INITELEM ||
op == JSOP_INITELEM_ARRAY); op == JSOP_INITELEM_ARRAY ||
op == JSOP_INITELEM_INC);
RootedObject obj(cx, ToObjectFromStack(cx, objv)); RootedObject obj(cx, ToObjectFromStack(cx, objv));
if (!obj) if (!obj)
@ -5025,6 +5026,9 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub_
JS_ASSERT(uint32_t(index.toInt32()) == GET_UINT24(pc)); JS_ASSERT(uint32_t(index.toInt32()) == GET_UINT24(pc));
if (!InitArrayElemOperation(cx, pc, obj, index.toInt32(), rhs)) if (!InitArrayElemOperation(cx, pc, obj, index.toInt32(), rhs))
return false; return false;
} else if (op == JSOP_INITELEM_INC) {
if (!InitArrayElemOperation(cx, pc, obj, index.toInt32(), rhs))
return false;
} else { } else {
if (!SetObjectElement(cx, obj, index, rhs, script->strict(), script, pc)) if (!SetObjectElement(cx, obj, index, rhs, script->strict(), script, pc))
return false; return false;

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

@ -1728,7 +1728,7 @@ CodeGenerator::visitTypeBarrierV(LTypeBarrierV *lir)
Register scratch = ToTempRegisterOrInvalid(lir->temp()); Register scratch = ToTempRegisterOrInvalid(lir->temp());
Label miss; Label miss;
masm.guardTypeSet(operand, lir->mir()->resultTypeSet(), scratch, &miss); masm.guardTypeSet(operand, lir->mir()->resultTypeSet(), lir->mir()->barrierKind(), scratch, &miss);
if (!bailoutFrom(&miss, lir->snapshot())) if (!bailoutFrom(&miss, lir->snapshot()))
return false; return false;
return true; return true;
@ -1737,6 +1737,8 @@ CodeGenerator::visitTypeBarrierV(LTypeBarrierV *lir)
bool bool
CodeGenerator::visitTypeBarrierO(LTypeBarrierO *lir) CodeGenerator::visitTypeBarrierO(LTypeBarrierO *lir)
{ {
MOZ_ASSERT(lir->mir()->barrierKind() != BarrierKind::TypeTagOnly);
Register obj = ToRegister(lir->object()); Register obj = ToRegister(lir->object());
Register scratch = ToTempRegisterOrInvalid(lir->temp()); Register scratch = ToTempRegisterOrInvalid(lir->temp());
@ -1754,7 +1756,7 @@ CodeGenerator::visitMonitorTypes(LMonitorTypes *lir)
Register scratch = ToTempUnboxRegister(lir->temp()); Register scratch = ToTempUnboxRegister(lir->temp());
Label matched, miss; Label matched, miss;
masm.guardTypeSet(operand, lir->mir()->typeSet(), scratch, &miss); masm.guardTypeSet(operand, lir->mir()->typeSet(), lir->mir()->barrierKind(), scratch, &miss);
if (!bailoutFrom(&miss, lir->snapshot())) if (!bailoutFrom(&miss, lir->snapshot()))
return false; return false;
return true; return true;
@ -2710,7 +2712,7 @@ CodeGenerator::generateArgumentsChecks(bool bailout)
// ... * sizeof(Value) - Scale by value size. // ... * sizeof(Value) - Scale by value size.
// ArgToStackOffset(...) - Compute displacement within arg vector. // ArgToStackOffset(...) - Compute displacement within arg vector.
int32_t offset = ArgToStackOffset((i - info.startArgSlot()) * sizeof(Value)); int32_t offset = ArgToStackOffset((i - info.startArgSlot()) * sizeof(Value));
masm.guardTypeSet(Address(StackPointer, offset), types, temp, &miss); masm.guardTypeSet(Address(StackPointer, offset), types, BarrierKind::TypeSet, temp, &miss);
} }
if (miss.used()) { if (miss.used()) {
@ -3186,7 +3188,7 @@ CodeGenerator::emitValueResultChecks(LInstruction *lir, MDefinition *mir)
if (mir->resultTypeSet() && !mir->resultTypeSet()->unknown()) { if (mir->resultTypeSet() && !mir->resultTypeSet()->unknown()) {
// We have a result TypeSet, assert this value is in it. // We have a result TypeSet, assert this value is in it.
Label miss, ok; Label miss, ok;
masm.guardTypeSet(output, mir->resultTypeSet(), temp1, &miss); masm.guardTypeSet(output, mir->resultTypeSet(), BarrierKind::TypeSet, temp1, &miss);
masm.jump(&ok); masm.jump(&ok);
masm.bind(&miss); masm.bind(&miss);
@ -8051,7 +8053,7 @@ CodeGenerator::visitProfilerStackOp(LProfilerStackOp *lir)
case MProfilerStackOp::Enter: case MProfilerStackOp::Enter:
if (gen->options.spsSlowAssertionsEnabled()) { if (gen->options.spsSlowAssertionsEnabled()) {
if (!inlinedFunction || js_JitOptions.profileInlineFrames) { if (!inlinedFunction) {
saveLive(lir); saveLive(lir);
pushArg(ImmGCPtr(lir->script())); pushArg(ImmGCPtr(lir->script()));
if (!callVM(SPSEnterInfo, lir)) if (!callVM(SPSEnterInfo, lir))
@ -8074,7 +8076,7 @@ CodeGenerator::visitProfilerStackOp(LProfilerStackOp *lir)
case MProfilerStackOp::Exit: case MProfilerStackOp::Exit:
if (gen->options.spsSlowAssertionsEnabled()) { if (gen->options.spsSlowAssertionsEnabled()) {
if (!inlinedFunction || js_JitOptions.profileInlineFrames) { if (!inlinedFunction) {
saveLive(lir); saveLive(lir);
pushArg(ImmGCPtr(lir->script())); pushArg(ImmGCPtr(lir->script()));
// Once we've exited, then we shouldn't emit instrumentation for // Once we've exited, then we shouldn't emit instrumentation for

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

@ -171,6 +171,9 @@ jit::EliminateDeadCode(MIRGenerator *mir, MIRGraph &graph)
!inst->hasUses() && !inst->isGuard() && !inst->hasUses() && !inst->isGuard() &&
!inst->isControlInstruction()) { !inst->isControlInstruction()) {
inst = block->discardAt(inst); inst = block->discardAt(inst);
} else if (!inst->hasLiveDefUses() && inst->canRecoverOnBailout()) {
inst->setRecoveredOnBailout();
inst++;
} else { } else {
inst++; inst++;
} }
@ -1382,11 +1385,6 @@ jit::AssertBasicGraphCoherency(MIRGraph &graph)
for (size_t i = 0; i < block->numPredecessors(); i++) for (size_t i = 0; i < block->numPredecessors(); i++)
JS_ASSERT(CheckPredecessorImpliesSuccessor(*block, block->getPredecessor(i))); JS_ASSERT(CheckPredecessorImpliesSuccessor(*block, block->getPredecessor(i)));
// Assert that use chains are valid for this instruction.
for (MDefinitionIterator iter(*block); iter; iter++) {
for (uint32_t i = 0, e = iter->numOperands(); i < e; i++)
JS_ASSERT(CheckOperandImpliesUse(*iter, iter->getOperand(i)));
}
for (MResumePointIterator iter(block->resumePointsBegin()); iter != block->resumePointsEnd(); iter++) { for (MResumePointIterator iter(block->resumePointsBegin()); iter != block->resumePointsEnd(); iter++) {
for (uint32_t i = 0, e = iter->numOperands(); i < e; i++) { for (uint32_t i = 0, e = iter->numOperands(); i < e; i++) {
if (iter->getUseFor(i)->hasProducer()) if (iter->getUseFor(i)->hasProducer())
@ -1395,11 +1393,16 @@ jit::AssertBasicGraphCoherency(MIRGraph &graph)
} }
for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) { for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
JS_ASSERT(phi->numOperands() == block->numPredecessors()); JS_ASSERT(phi->numOperands() == block->numPredecessors());
MOZ_ASSERT(!phi->isRecoveredOnBailout());
} }
for (MDefinitionIterator iter(*block); iter; iter++) { for (MDefinitionIterator iter(*block); iter; iter++) {
JS_ASSERT(iter->block() == *block); JS_ASSERT(iter->block() == *block);
for (MUseIterator i(iter->usesBegin()); i != iter->usesEnd(); i++)
JS_ASSERT(CheckUseImpliesOperand(*iter, *i)); // Assert that use chains are valid for this instruction.
for (uint32_t i = 0, end = iter->numOperands(); i < end; i++)
JS_ASSERT(CheckOperandImpliesUse(*iter, iter->getOperand(i)));
for (MUseIterator use(iter->usesBegin()); use != iter->usesEnd(); use++)
JS_ASSERT(CheckUseImpliesOperand(*iter, *use));
if (iter->isInstruction()) { if (iter->isInstruction()) {
if (MResumePoint *resume = iter->toInstruction()->resumePoint()) { if (MResumePoint *resume = iter->toInstruction()->resumePoint()) {
@ -1407,6 +1410,9 @@ jit::AssertBasicGraphCoherency(MIRGraph &graph)
JS_ASSERT(ins->block() == iter->block()); JS_ASSERT(ins->block() == iter->block());
} }
} }
if (iter->isRecoveredOnBailout())
MOZ_ASSERT(!iter->hasLiveDefUses());
} }
} }

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

@ -5049,7 +5049,7 @@ IonBuilder::jsop_funapplyarguments(uint32_t argc)
return false; return false;
types::TemporaryTypeSet *types = bytecodeTypes(pc); types::TemporaryTypeSet *types = bytecodeTypes(pc);
return pushTypeBarrier(apply, types, true); return pushTypeBarrier(apply, types, BarrierKind::TypeSet);
} }
// When inlining we have the arguments the function gets called with // When inlining we have the arguments the function gets called with
@ -5378,7 +5378,7 @@ IonBuilder::makeCall(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsit
if (call->isCallDOMNative()) if (call->isCallDOMNative())
return pushDOMTypeBarrier(call, types, call->getSingleTarget()); return pushDOMTypeBarrier(call, types, call->getSingleTarget());
return pushTypeBarrier(call, types, true); return pushTypeBarrier(call, types, BarrierKind::TypeSet);
} }
bool bool
@ -5426,7 +5426,7 @@ IonBuilder::jsop_eval(uint32_t argc)
if (!string->mightBeType(MIRType_String)) { if (!string->mightBeType(MIRType_String)) {
current->push(string); current->push(string);
types::TemporaryTypeSet *types = bytecodeTypes(pc); types::TemporaryTypeSet *types = bytecodeTypes(pc);
return pushTypeBarrier(string, types, true); return pushTypeBarrier(string, types, BarrierKind::TypeSet);
} }
current->pushSlot(info().thisSlot()); current->pushSlot(info().thisSlot());
@ -5465,7 +5465,7 @@ IonBuilder::jsop_eval(uint32_t argc)
current->push(ins); current->push(ins);
types::TemporaryTypeSet *types = bytecodeTypes(pc); types::TemporaryTypeSet *types = bytecodeTypes(pc);
return resumeAfter(ins) && pushTypeBarrier(ins, types, true); return resumeAfter(ins) && pushTypeBarrier(ins, types, BarrierKind::TypeSet);
} }
return jsop_call(argc, /* constructing = */ false); return jsop_call(argc, /* constructing = */ false);
@ -6274,7 +6274,7 @@ IonBuilder::testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton, Pr
// instruction replaces the top of the stack. // instruction replaces the top of the stack.
// (5) Lastly, a type barrier instruction replaces the top of the stack. // (5) Lastly, a type barrier instruction replaces the top of the stack.
bool bool
IonBuilder::pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, bool needsBarrier) IonBuilder::pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, BarrierKind kind)
{ {
// Barriers are never needed for instructions whose result will not be used. // Barriers are never needed for instructions whose result will not be used.
if (BytecodeIsPopped(pc)) if (BytecodeIsPopped(pc))
@ -6286,7 +6286,7 @@ IonBuilder::pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed,
// must be a resume point capturing the original def, and resuming // must be a resume point capturing the original def, and resuming
// to that point will explicitly monitor the new type. // to that point will explicitly monitor the new type.
if (!needsBarrier) { if (kind == BarrierKind::NoBarrier) {
MDefinition *replace = ensureDefiniteType(def, observed->getKnownMIRType()); MDefinition *replace = ensureDefiniteType(def, observed->getKnownMIRType());
if (replace != def) { if (replace != def) {
current->pop(); current->pop();
@ -6301,7 +6301,7 @@ IonBuilder::pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed,
current->pop(); current->pop();
MInstruction *barrier = MTypeBarrier::New(alloc(), def, observed); MInstruction *barrier = MTypeBarrier::New(alloc(), def, observed, kind);
current->add(barrier); current->add(barrier);
if (barrier->type() == MIRType_Undefined) if (barrier->type() == MIRType_Undefined)
@ -6342,7 +6342,8 @@ IonBuilder::pushDOMTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *obser
JS_ASSERT(barrier); JS_ASSERT(barrier);
} }
return pushTypeBarrier(replace, observed, barrier); return pushTypeBarrier(replace, observed,
barrier ? BarrierKind::TypeSet : BarrierKind::NoBarrier);
} }
MDefinition * MDefinition *
@ -6449,13 +6450,13 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc
} }
types::TemporaryTypeSet *types = bytecodeTypes(pc); types::TemporaryTypeSet *types = bytecodeTypes(pc);
bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), staticType, BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), staticType,
name, types, /* updateObserved = */ true); name, types, /* updateObserved = */ true);
JSObject *singleton = types->getSingleton(); JSObject *singleton = types->getSingleton();
MIRType knownType = types->getKnownMIRType(); MIRType knownType = types->getKnownMIRType();
if (!barrier) { if (barrier == BarrierKind::NoBarrier) {
if (singleton) { if (singleton) {
// Try to inline a known constant value. // Try to inline a known constant value.
if (testSingletonProperty(staticObject, name) == singleton) if (testSingletonProperty(staticObject, name) == singleton)
@ -6470,7 +6471,7 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc
MInstruction *obj = constant(ObjectValue(*staticObject)); MInstruction *obj = constant(ObjectValue(*staticObject));
MIRType rvalType = types->getKnownMIRType(); MIRType rvalType = types->getKnownMIRType();
if (barrier) if (barrier != BarrierKind::NoBarrier)
rvalType = MIRType_Value; rvalType = MIRType_Value;
return loadSlot(obj, property.maybeTypes()->definiteSlot(), NumFixedSlots(staticObject), return loadSlot(obj, property.maybeTypes()->definiteSlot(), NumFixedSlots(staticObject),
@ -6612,7 +6613,7 @@ IonBuilder::jsop_getname(PropertyName *name)
return false; return false;
types::TemporaryTypeSet *types = bytecodeTypes(pc); types::TemporaryTypeSet *types = bytecodeTypes(pc);
return pushTypeBarrier(ins, types, true); return pushTypeBarrier(ins, types, BarrierKind::TypeSet);
} }
bool bool
@ -6631,7 +6632,7 @@ IonBuilder::jsop_intrinsic(PropertyName *name)
if (!resumeAfter(ins)) if (!resumeAfter(ins))
return false; return false;
return pushTypeBarrier(ins, types, true); return pushTypeBarrier(ins, types, BarrierKind::TypeSet);
} }
// Bake in the intrinsic. Make sure that TI agrees with us on the type. // Bake in the intrinsic. Make sure that TI agrees with us on the type.
@ -6696,7 +6697,7 @@ IonBuilder::jsop_getelem()
return false; return false;
types::TemporaryTypeSet *types = bytecodeTypes(pc); types::TemporaryTypeSet *types = bytecodeTypes(pc);
return pushTypeBarrier(ins, types, true); return pushTypeBarrier(ins, types, BarrierKind::TypeSet);
} }
bool emitted = false; bool emitted = false;
@ -6738,7 +6739,7 @@ IonBuilder::jsop_getelem()
return false; return false;
types::TemporaryTypeSet *types = bytecodeTypes(pc); types::TemporaryTypeSet *types = bytecodeTypes(pc);
return pushTypeBarrier(ins, types, true); return pushTypeBarrier(ins, types, BarrierKind::TypeSet);
} }
bool bool
@ -7004,7 +7005,7 @@ IonBuilder::pushDerivedTypedObject(bool *emitted,
{ {
derivedTypedObj->setResultTypeSet(observedTypes); derivedTypedObj->setResultTypeSet(observedTypes);
} else { } else {
if (!pushTypeBarrier(derivedTypedObj, observedTypes, true)) if (!pushTypeBarrier(derivedTypedObj, observedTypes, BarrierKind::TypeSet))
return false; return false;
} }
@ -7186,7 +7187,7 @@ IonBuilder::getElemTryArguments(bool *emitted, MDefinition *obj, MDefinition *in
current->push(load); current->push(load);
types::TemporaryTypeSet *types = bytecodeTypes(pc); types::TemporaryTypeSet *types = bytecodeTypes(pc);
if (!pushTypeBarrier(load, types, true)) if (!pushTypeBarrier(load, types, BarrierKind::TypeSet))
return false; return false;
*emitted = true; *emitted = true;
@ -7255,18 +7256,19 @@ IonBuilder::getElemTryCache(bool *emitted, MDefinition *obj, MDefinition *index)
// Emit GetElementCache. // Emit GetElementCache.
types::TemporaryTypeSet *types = bytecodeTypes(pc); types::TemporaryTypeSet *types = bytecodeTypes(pc);
bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), obj, nullptr, types); BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), obj,
nullptr, types);
// Always add a barrier if the index might be a string, so that the cache // Always add a barrier if the index might be a string, so that the cache
// can attach stubs for particular properties. // can attach stubs for particular properties.
if (index->mightBeType(MIRType_String)) if (index->mightBeType(MIRType_String))
barrier = true; barrier = BarrierKind::TypeSet;
// See note about always needing a barrier in jsop_getprop. // See note about always needing a barrier in jsop_getprop.
if (needsToMonitorMissingProperties(types)) if (needsToMonitorMissingProperties(types))
barrier = true; barrier = BarrierKind::TypeSet;
MInstruction *ins = MGetElementCache::New(alloc(), obj, index, barrier); MInstruction *ins = MGetElementCache::New(alloc(), obj, index, barrier != BarrierKind::NoBarrier);
current->add(ins); current->add(ins);
current->push(ins); current->push(ins);
@ -7275,7 +7277,7 @@ IonBuilder::getElemTryCache(bool *emitted, MDefinition *obj, MDefinition *index)
return false; return false;
// Spice up type information. // Spice up type information.
if (index->type() == MIRType_Int32 && !barrier) { if (index->type() == MIRType_Int32 && barrier == BarrierKind::NoBarrier) {
bool needHoleCheck = !ElementAccessIsPacked(constraints(), obj); bool needHoleCheck = !ElementAccessIsPacked(constraints(), obj);
MIRType knownType = GetElemKnownType(needHoleCheck, types); MIRType knownType = GetElemKnownType(needHoleCheck, types);
@ -7302,7 +7304,8 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
AddObjectsForPropertyRead(obj, nullptr, types); AddObjectsForPropertyRead(obj, nullptr, types);
} }
bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), obj, nullptr, types); BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), obj,
nullptr, types);
bool needsHoleCheck = !ElementAccessIsPacked(constraints(), obj); bool needsHoleCheck = !ElementAccessIsPacked(constraints(), obj);
// Reads which are on holes in the object do not have to bail out if // Reads which are on holes in the object do not have to bail out if
@ -7313,7 +7316,7 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
!ElementAccessHasExtraIndexedProperty(constraints(), obj); !ElementAccessHasExtraIndexedProperty(constraints(), obj);
MIRType knownType = MIRType_Value; MIRType knownType = MIRType_Value;
if (!barrier) if (barrier == BarrierKind::NoBarrier)
knownType = GetElemKnownType(needsHoleCheck, types); knownType = GetElemKnownType(needsHoleCheck, types);
// Ensure index is an integer. // Ensure index is an integer.
@ -7341,7 +7344,7 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
ExecutionMode executionMode = info().executionMode(); ExecutionMode executionMode = info().executionMode();
bool loadDouble = bool loadDouble =
executionMode == SequentialExecution && executionMode == SequentialExecution &&
!barrier && barrier == BarrierKind::NoBarrier &&
loopDepth_ && loopDepth_ &&
!readOutOfBounds && !readOutOfBounds &&
!needsHoleCheck && !needsHoleCheck &&
@ -7392,7 +7395,7 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
// NB: we have not added a MConvertElementsToDoubles MIR, so we // NB: we have not added a MConvertElementsToDoubles MIR, so we
// cannot *assume* the result is a double. // cannot *assume* the result is a double.
if (executionMode == ParallelExecution && if (executionMode == ParallelExecution &&
barrier && barrier != BarrierKind::NoBarrier &&
types->getKnownMIRType() == MIRType_Int32 && types->getKnownMIRType() == MIRType_Int32 &&
objTypes && objTypes &&
objTypes->convertDoubleElements(constraints()) == types::TemporaryTypeSet::AlwaysConvertToDoubles) objTypes->convertDoubleElements(constraints()) == types::TemporaryTypeSet::AlwaysConvertToDoubles)
@ -7402,7 +7405,7 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
if (!types) if (!types)
return false; return false;
barrier = false; // Don't need a barrier anymore barrier = BarrierKind::NoBarrier; // Don't need a barrier anymore
} }
if (knownType != MIRType_Value) if (knownType != MIRType_Value)
@ -7561,7 +7564,7 @@ IonBuilder::jsop_getelem_typed(MDefinition *obj, MDefinition *index,
// observed (we've only read out-of-bounds values). Note that for // observed (we've only read out-of-bounds values). Note that for
// Uint32Array, we only check for int32: if allowDouble is false we // Uint32Array, we only check for int32: if allowDouble is false we
// will bailout when we read a double. // will bailout when we read a double.
bool needsBarrier = true; BarrierKind barrier = BarrierKind::TypeSet;
switch (arrayType) { switch (arrayType) {
case ScalarTypeDescr::TYPE_INT8: case ScalarTypeDescr::TYPE_INT8:
case ScalarTypeDescr::TYPE_UINT8: case ScalarTypeDescr::TYPE_UINT8:
@ -7571,12 +7574,12 @@ IonBuilder::jsop_getelem_typed(MDefinition *obj, MDefinition *index,
case ScalarTypeDescr::TYPE_INT32: case ScalarTypeDescr::TYPE_INT32:
case ScalarTypeDescr::TYPE_UINT32: case ScalarTypeDescr::TYPE_UINT32:
if (types->hasType(types::Type::Int32Type())) if (types->hasType(types::Type::Int32Type()))
needsBarrier = false; barrier = BarrierKind::NoBarrier;
break; break;
case ScalarTypeDescr::TYPE_FLOAT32: case ScalarTypeDescr::TYPE_FLOAT32:
case ScalarTypeDescr::TYPE_FLOAT64: case ScalarTypeDescr::TYPE_FLOAT64:
if (allowDouble) if (allowDouble)
needsBarrier = false; barrier = BarrierKind::NoBarrier;
break; break;
default: default:
MOZ_ASSUME_UNREACHABLE("Unknown typed array type"); MOZ_ASSUME_UNREACHABLE("Unknown typed array type");
@ -7590,7 +7593,7 @@ IonBuilder::jsop_getelem_typed(MDefinition *obj, MDefinition *index,
current->add(load); current->add(load);
current->push(load); current->push(load);
return pushTypeBarrier(load, types, needsBarrier); return pushTypeBarrier(load, types, barrier);
} }
} }
@ -8494,7 +8497,7 @@ IonBuilder::invalidatedIdempotentCache()
bool bool
IonBuilder::loadSlot(MDefinition *obj, size_t slot, size_t nfixed, MIRType rvalType, IonBuilder::loadSlot(MDefinition *obj, size_t slot, size_t nfixed, MIRType rvalType,
bool barrier, types::TemporaryTypeSet *types) BarrierKind barrier, types::TemporaryTypeSet *types)
{ {
if (slot < nfixed) { if (slot < nfixed) {
MLoadFixedSlot *load = MLoadFixedSlot::New(alloc(), obj, slot); MLoadFixedSlot *load = MLoadFixedSlot::New(alloc(), obj, slot);
@ -8518,7 +8521,7 @@ IonBuilder::loadSlot(MDefinition *obj, size_t slot, size_t nfixed, MIRType rvalT
bool bool
IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType, IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType,
bool barrier, types::TemporaryTypeSet *types) BarrierKind barrier, types::TemporaryTypeSet *types)
{ {
return loadSlot(obj, shape->slot(), shape->numFixedSlots(), rvalType, barrier, types); return loadSlot(obj, shape->slot(), shape->numFixedSlots(), rvalType, barrier, types);
} }
@ -8568,7 +8571,7 @@ IonBuilder::jsop_getprop(PropertyName *name)
return emitted; return emitted;
types::TemporaryTypeSet *types = bytecodeTypes(pc); types::TemporaryTypeSet *types = bytecodeTypes(pc);
bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
current->peek(-1), name, types); current->peek(-1), name, types);
// Always use a call if we are performing analysis and // Always use a call if we are performing analysis and
@ -8591,7 +8594,7 @@ IonBuilder::jsop_getprop(PropertyName *name)
current->pop(); current->pop();
current->push(call); current->push(call);
return resumeAfter(call) && pushTypeBarrier(call, types, true); return resumeAfter(call) && pushTypeBarrier(call, types, BarrierKind::TypeSet);
} }
// Try to hardcode known constants. // Try to hardcode known constants.
@ -8626,7 +8629,7 @@ IonBuilder::jsop_getprop(PropertyName *name)
if (!resumeAfter(call)) if (!resumeAfter(call))
return false; return false;
return pushTypeBarrier(call, types, true); return pushTypeBarrier(call, types, BarrierKind::TypeSet);
} }
bool bool
@ -8765,7 +8768,7 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
bool bool
IonBuilder::getPropTryDefiniteSlot(bool *emitted, PropertyName *name, IonBuilder::getPropTryDefiniteSlot(bool *emitted, PropertyName *name,
bool barrier, types::TemporaryTypeSet *types) BarrierKind barrier, types::TemporaryTypeSet *types)
{ {
JS_ASSERT(*emitted == false); JS_ASSERT(*emitted == false);
types::HeapTypeSetKey property; types::HeapTypeSetKey property;
@ -8781,7 +8784,7 @@ IonBuilder::getPropTryDefiniteSlot(bool *emitted, PropertyName *name,
} }
MLoadFixedSlot *fixed = MLoadFixedSlot::New(alloc(), useObj, property.maybeTypes()->definiteSlot()); MLoadFixedSlot *fixed = MLoadFixedSlot::New(alloc(), useObj, property.maybeTypes()->definiteSlot());
if (!barrier) if (barrier == BarrierKind::NoBarrier)
fixed->setResultType(types->getKnownMIRType()); fixed->setResultType(types->getKnownMIRType());
current->add(fixed); current->add(fixed);
@ -8903,7 +8906,7 @@ CanInlinePropertyOpShapes(const BaselineInspector::ShapeVector &shapes)
bool bool
IonBuilder::getPropTryInlineAccess(bool *emitted, PropertyName *name, IonBuilder::getPropTryInlineAccess(bool *emitted, PropertyName *name,
bool barrier, types::TemporaryTypeSet *types) BarrierKind barrier, types::TemporaryTypeSet *types)
{ {
JS_ASSERT(*emitted == false); JS_ASSERT(*emitted == false);
if (current->peek(-1)->type() != MIRType_Object) if (current->peek(-1)->type() != MIRType_Object)
@ -8917,7 +8920,7 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, PropertyName *name,
return true; return true;
MIRType rvalType = types->getKnownMIRType(); MIRType rvalType = types->getKnownMIRType();
if (barrier || IsNullOrUndefined(rvalType)) if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType))
rvalType = MIRType_Value; rvalType = MIRType_Value;
MDefinition *obj = current->pop(); MDefinition *obj = current->pop();
@ -8964,7 +8967,7 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, PropertyName *name,
bool bool
IonBuilder::getPropTryCache(bool *emitted, PropertyName *name, IonBuilder::getPropTryCache(bool *emitted, PropertyName *name,
bool barrier, types::TemporaryTypeSet *types) BarrierKind barrier, types::TemporaryTypeSet *types)
{ {
JS_ASSERT(*emitted == false); JS_ASSERT(*emitted == false);
@ -8981,18 +8984,19 @@ IonBuilder::getPropTryCache(bool *emitted, PropertyName *name,
// Since getters have no guaranteed return values, we must barrier in order to be // Since getters have no guaranteed return values, we must barrier in order to be
// able to attach stubs for them. // able to attach stubs for them.
if (inspector->hasSeenAccessedGetter(pc)) if (inspector->hasSeenAccessedGetter(pc))
barrier = true; barrier = BarrierKind::TypeSet;
if (needsToMonitorMissingProperties(types)) if (needsToMonitorMissingProperties(types))
barrier = true; barrier = BarrierKind::TypeSet;
// Caches can read values from prototypes, so update the barrier to // Caches can read values from prototypes, so update the barrier to
// reflect such possible values. // reflect such possible values.
if (!barrier) if (barrier == BarrierKind::NoBarrier)
barrier = PropertyReadOnPrototypeNeedsTypeBarrier(constraints(), obj, name, types); barrier = PropertyReadOnPrototypeNeedsTypeBarrier(constraints(), obj, name, types);
current->pop(); current->pop();
MGetPropertyCache *load = MGetPropertyCache::New(alloc(), obj, name, barrier); MGetPropertyCache *load = MGetPropertyCache::New(alloc(), obj, name,
barrier != BarrierKind::NoBarrier);
// Try to mark the cache as idempotent. // Try to mark the cache as idempotent.
// //
@ -9019,7 +9023,7 @@ IonBuilder::getPropTryCache(bool *emitted, PropertyName *name,
return false; return false;
MIRType rvalType = types->getKnownMIRType(); MIRType rvalType = types->getKnownMIRType();
if (barrier || IsNullOrUndefined(rvalType)) if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType))
rvalType = MIRType_Value; rvalType = MIRType_Value;
load->setResultType(rvalType); load->setResultType(rvalType);
@ -9863,7 +9867,7 @@ IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
current->push(load); current->push(load);
types::TemporaryTypeSet *types = bytecodeTypes(pc); types::TemporaryTypeSet *types = bytecodeTypes(pc);
return pushTypeBarrier(load, types, true); return pushTypeBarrier(load, types, BarrierKind::TypeSet);
} }
bool bool

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

@ -343,7 +343,7 @@ class IonBuilder : public MIRGenerator
// Add a guard which ensure that the set of type which goes through this // Add a guard which ensure that the set of type which goes through this
// generated code correspond to the observed types for the bytecode. // generated code correspond to the observed types for the bytecode.
bool pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, bool needBarrier); bool pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, BarrierKind kind);
// As pushTypeBarrier, but will compute the needBarrier boolean itself based // As pushTypeBarrier, but will compute the needBarrier boolean itself based
// on observed and the JSFunction that we're planning to call. The // on observed and the JSFunction that we're planning to call. The
@ -380,9 +380,9 @@ class IonBuilder : public MIRGenerator
bool hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall); bool hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall);
bool loadSlot(MDefinition *obj, size_t slot, size_t nfixed, MIRType rvalType, bool loadSlot(MDefinition *obj, size_t slot, size_t nfixed, MIRType rvalType,
bool barrier, types::TemporaryTypeSet *types); BarrierKind barrier, types::TemporaryTypeSet *types);
bool loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType, bool loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType,
bool barrier, types::TemporaryTypeSet *types); BarrierKind barrier, types::TemporaryTypeSet *types);
bool storeSlot(MDefinition *obj, size_t slot, size_t nfixed, bool storeSlot(MDefinition *obj, size_t slot, size_t nfixed,
MDefinition *value, bool needsBarrier, MDefinition *value, bool needsBarrier,
MIRType slotType = MIRType_None); MIRType slotType = MIRType_None);
@ -394,11 +394,11 @@ class IonBuilder : public MIRGenerator
bool getPropTryConstant(bool *emitted, PropertyName *name, bool getPropTryConstant(bool *emitted, PropertyName *name,
types::TemporaryTypeSet *types); types::TemporaryTypeSet *types);
bool getPropTryDefiniteSlot(bool *emitted, PropertyName *name, bool getPropTryDefiniteSlot(bool *emitted, PropertyName *name,
bool barrier, types::TemporaryTypeSet *types); BarrierKind barrier, types::TemporaryTypeSet *types);
bool getPropTryCommonGetter(bool *emitted, PropertyName *name, bool getPropTryCommonGetter(bool *emitted, PropertyName *name,
types::TemporaryTypeSet *types); types::TemporaryTypeSet *types);
bool getPropTryInlineAccess(bool *emitted, PropertyName *name, bool getPropTryInlineAccess(bool *emitted, PropertyName *name,
bool barrier, types::TemporaryTypeSet *types); BarrierKind barrier, types::TemporaryTypeSet *types);
bool getPropTryTypedObject(bool *emitted, PropertyName *name, bool getPropTryTypedObject(bool *emitted, PropertyName *name,
types::TemporaryTypeSet *resultTypes); types::TemporaryTypeSet *resultTypes);
bool getPropTryScalarPropOfTypedObject(bool *emitted, bool getPropTryScalarPropOfTypedObject(bool *emitted,
@ -411,7 +411,7 @@ class IonBuilder : public MIRGenerator
size_t fieldIndex, size_t fieldIndex,
types::TemporaryTypeSet *resultTypes); types::TemporaryTypeSet *resultTypes);
bool getPropTryCache(bool *emitted, PropertyName *name, bool getPropTryCache(bool *emitted, PropertyName *name,
bool barrier, types::TemporaryTypeSet *types); BarrierKind barrier, types::TemporaryTypeSet *types);
bool needsToMonitorMissingProperties(types::TemporaryTypeSet *types); bool needsToMonitorMissingProperties(types::TemporaryTypeSet *types);
// jsop_setprop() helpers. // jsop_setprop() helpers.

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

@ -1969,7 +1969,7 @@ GenerateSetSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att
Register scratchReg = object; Register scratchReg = object;
masm.push(scratchReg); masm.push(scratchReg);
masm.guardTypeSet(valReg, propTypes, scratchReg, &barrierFailure); masm.guardTypeSet(valReg, propTypes, BarrierKind::TypeSet, scratchReg, &barrierFailure);
masm.pop(object); masm.pop(object);
} }
} }
@ -2521,7 +2521,7 @@ GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att
JS_ASSERT(!propTypes->unknown()); JS_ASSERT(!propTypes->unknown());
Register scratchReg = object; Register scratchReg = object;
masm.guardTypeSet(valReg, propTypes, scratchReg, &failuresPopObject); masm.guardTypeSet(valReg, propTypes, BarrierKind::TypeSet, scratchReg, &failuresPopObject);
masm.loadPtr(Address(StackPointer, 0), object); masm.loadPtr(Address(StackPointer, 0), object);
} }

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

@ -631,9 +631,8 @@ HandleException(ResumeFromException *rfe)
if (invalidated) if (invalidated)
popSPSFrame = ionScript->hasSPSInstrumentation(); popSPSFrame = ionScript->hasSPSInstrumentation();
// If inline-frames are not profiled, then don't pop an SPS frame // Don't pop an SPS frame for inlined frames, since they are not instrumented.
// for them. if (frames.more())
if (frames.more() && !js_JitOptions.profileInlineFrames)
popSPSFrame = false; popSPSFrame = false;
// When profiling, each frame popped needs a notification that // When profiling, each frame popped needs a notification that
@ -1339,7 +1338,8 @@ SnapshotIterator::SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshot
ionScript->recoversSize()), ionScript->recoversSize()),
fp_(fp), fp_(fp),
machine_(machine), machine_(machine),
ionScript_(ionScript) ionScript_(ionScript),
instructionResults_(nullptr)
{ {
JS_ASSERT(snapshotOffset < ionScript->snapshotsListSize()); JS_ASSERT(snapshotOffset < ionScript->snapshotsListSize());
} }
@ -1354,7 +1354,8 @@ SnapshotIterator::SnapshotIterator(const JitFrameIterator &iter)
iter.ionScript()->recoversSize()), iter.ionScript()->recoversSize()),
fp_(iter.jsFrame()), fp_(iter.jsFrame()),
machine_(iter.machineState()), machine_(iter.machineState()),
ionScript_(iter.ionScript()) ionScript_(iter.ionScript()),
instructionResults_(nullptr)
{ {
} }
@ -1362,7 +1363,8 @@ SnapshotIterator::SnapshotIterator()
: snapshot_(nullptr, 0, 0, 0), : snapshot_(nullptr, 0, 0, 0),
recover_(snapshot_, nullptr, 0), recover_(snapshot_, nullptr, 0),
fp_(nullptr), fp_(nullptr),
ionScript_(nullptr) ionScript_(nullptr),
instructionResults_(nullptr)
{ {
} }
@ -1427,6 +1429,9 @@ SnapshotIterator::allocationReadable(const RValueAllocation &alloc)
return hasStack(alloc.stackOffset()); return hasStack(alloc.stackOffset());
#endif #endif
case RValueAllocation::RECOVER_INSTRUCTION:
return hasInstructionResult(alloc.index());
default: default:
return true; return true;
} }
@ -1532,6 +1537,9 @@ SnapshotIterator::allocationValue(const RValueAllocation &alloc)
} }
#endif #endif
case RValueAllocation::RECOVER_INSTRUCTION:
return fromInstructionResult(alloc.index());
default: default:
MOZ_ASSUME_UNREACHABLE("huh?"); MOZ_ASSUME_UNREACHABLE("huh?");
} }
@ -1546,7 +1554,7 @@ SnapshotIterator::resumePoint() const
uint32_t uint32_t
SnapshotIterator::numAllocations() const SnapshotIterator::numAllocations() const
{ {
return resumePoint()->numOperands(); return instruction()->numOperands();
} }
uint32_t uint32_t
@ -1565,6 +1573,43 @@ SnapshotIterator::skipInstruction()
nextInstruction(); nextInstruction();
} }
bool
SnapshotIterator::initIntructionResults(AutoValueVector &results)
{
MOZ_ASSERT(recover_.numInstructionsRead() == 1);
// The last instruction will always be a resume point, no need to allocate
// space for it.
if (recover_.numInstructions() == 1)
return true;
MOZ_ASSERT(recover_.numInstructions() > 1);
size_t numResults = recover_.numInstructions() - 1;
if (!results.reserve(numResults))
return false;
for (size_t i = 0; i < numResults; i++)
results.infallibleAppend(MagicValue(JS_ION_BAILOUT));
instructionResults_ = &results;
return true;
}
void
SnapshotIterator::storeInstructionResult(Value v)
{
uint32_t currIns = recover_.numInstructionsRead() - 1;
MOZ_ASSERT((*instructionResults_)[currIns].isMagic(JS_ION_BAILOUT));
(*instructionResults_)[currIns].set(v);
}
Value
SnapshotIterator::fromInstructionResult(uint32_t index) const
{
MOZ_ASSERT(!(*instructionResults_)[index].isMagic(JS_ION_BAILOUT));
return (*instructionResults_)[index];
}
void void
SnapshotIterator::nextFrame() SnapshotIterator::nextFrame()
{ {

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

@ -69,9 +69,10 @@ class TypeWrapper {
} /* anonymous namespace */ } /* anonymous namespace */
template <typename Source, typename TypeSet> void template <typename Source, typename TypeSet> void
MacroAssembler::guardTypeSet(const Source &address, const TypeSet *types, MacroAssembler::guardTypeSet(const Source &address, const TypeSet *types, BarrierKind kind,
Register scratch, Label *miss) Register scratch, Label *miss)
{ {
JS_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
JS_ASSERT(!types->unknown()); JS_ASSERT(!types->unknown());
Label matched; Label matched;
@ -126,8 +127,10 @@ MacroAssembler::guardTypeSet(const Source &address, const TypeSet *types,
// Test specific objects. // Test specific objects.
JS_ASSERT(scratch != InvalidReg); JS_ASSERT(scratch != InvalidReg);
branchTestObject(NotEqual, tag, miss); branchTestObject(NotEqual, tag, miss);
if (kind != BarrierKind::TypeTagOnly) {
Register obj = extractObject(address, scratch); Register obj = extractObject(address, scratch);
guardObjectType(obj, types, scratch, miss); guardObjectType(obj, types, scratch, miss);
}
bind(&matched); bind(&matched);
} }
@ -203,30 +206,30 @@ MacroAssembler::guardType(const Source &address, types::Type type,
Register scratch, Label *miss) Register scratch, Label *miss)
{ {
TypeWrapper wrapper(type); TypeWrapper wrapper(type);
guardTypeSet(address, &wrapper, scratch, miss); guardTypeSet(address, &wrapper, BarrierKind::TypeSet, scratch, miss);
} }
template void MacroAssembler::guardTypeSet(const Address &address, const types::TemporaryTypeSet *types, template void MacroAssembler::guardTypeSet(const Address &address, const types::TemporaryTypeSet *types,
Register scratch, Label *miss); BarrierKind kind, Register scratch, Label *miss);
template void MacroAssembler::guardTypeSet(const ValueOperand &value, const types::TemporaryTypeSet *types, template void MacroAssembler::guardTypeSet(const ValueOperand &value, const types::TemporaryTypeSet *types,
Register scratch, Label *miss); BarrierKind kind, Register scratch, Label *miss);
template void MacroAssembler::guardTypeSet(const Address &address, const types::HeapTypeSet *types, template void MacroAssembler::guardTypeSet(const Address &address, const types::HeapTypeSet *types,
Register scratch, Label *miss); BarrierKind kind, Register scratch, Label *miss);
template void MacroAssembler::guardTypeSet(const ValueOperand &value, const types::HeapTypeSet *types, template void MacroAssembler::guardTypeSet(const ValueOperand &value, const types::HeapTypeSet *types,
Register scratch, Label *miss); BarrierKind kind, Register scratch, Label *miss);
template void MacroAssembler::guardTypeSet(const TypedOrValueRegister &reg, const types::HeapTypeSet *types, template void MacroAssembler::guardTypeSet(const TypedOrValueRegister &reg, const types::HeapTypeSet *types,
Register scratch, Label *miss); BarrierKind kind, Register scratch, Label *miss);
template void MacroAssembler::guardTypeSet(const Address &address, const types::TypeSet *types, template void MacroAssembler::guardTypeSet(const Address &address, const types::TypeSet *types,
Register scratch, Label *miss); BarrierKind kind, Register scratch, Label *miss);
template void MacroAssembler::guardTypeSet(const ValueOperand &value, const types::TypeSet *types, template void MacroAssembler::guardTypeSet(const ValueOperand &value, const types::TypeSet *types,
Register scratch, Label *miss); BarrierKind kind, Register scratch, Label *miss);
template void MacroAssembler::guardTypeSet(const Address &address, const TypeWrapper *types, template void MacroAssembler::guardTypeSet(const Address &address, const TypeWrapper *types,
Register scratch, Label *miss); BarrierKind kind, Register scratch, Label *miss);
template void MacroAssembler::guardTypeSet(const ValueOperand &value, const TypeWrapper *types, template void MacroAssembler::guardTypeSet(const ValueOperand &value, const TypeWrapper *types,
Register scratch, Label *miss); BarrierKind kind, Register scratch, Label *miss);
template void MacroAssembler::guardObjectType(Register obj, const types::TemporaryTypeSet *types, template void MacroAssembler::guardObjectType(Register obj, const types::TemporaryTypeSet *types,
Register scratch, Label *miss); Register scratch, Label *miss);

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

@ -300,7 +300,7 @@ class MacroAssembler : public MacroAssemblerSpecific
// Emits a test of a value against all types in a TypeSet. A scratch // Emits a test of a value against all types in a TypeSet. A scratch
// register is required. // register is required.
template <typename Source, typename TypeSet> template <typename Source, typename TypeSet>
void guardTypeSet(const Source &address, const TypeSet *types, Register scratch, Label *miss); void guardTypeSet(const Source &address, const TypeSet *types, BarrierKind kind, Register scratch, Label *miss);
template <typename TypeSet> template <typename TypeSet>
void guardObjectType(Register obj, const TypeSet *types, Register scratch, Label *miss); void guardObjectType(Register obj, const TypeSet *types, Register scratch, Label *miss);
template <typename Source> template <typename Source>

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

@ -7,6 +7,8 @@
#ifndef jit_IonTypes_h #ifndef jit_IonTypes_h
#define jit_IonTypes_h #define jit_IonTypes_h
#include "mozilla/TypedEnum.h"
#include "jstypes.h" #include "jstypes.h"
#include "js/Value.h" #include "js/Value.h"
@ -324,6 +326,19 @@ enum ABIFunctionType
(ArgType_General << (ArgType_Shift * 2)) (ArgType_General << (ArgType_Shift * 2))
}; };
MOZ_BEGIN_ENUM_CLASS(BarrierKind, uint32_t)
// No barrier is needed.
NoBarrier,
// The barrier only has to check the value's type tag is in the TypeSet.
// Specific object types don't have to be checked.
TypeTagOnly,
// Check if the value is in the TypeSet, including the object type if it's
// an object.
TypeSet
MOZ_END_ENUM_CLASS(BarrierKind)
} // namespace jit } // namespace jit
} // namespace js } // namespace js

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

@ -258,6 +258,7 @@ class SnapshotIterator
IonJSFrameLayout *fp_; IonJSFrameLayout *fp_;
MachineState machine_; MachineState machine_;
IonScript *ionScript_; IonScript *ionScript_;
AutoValueVector *instructionResults_;
private: private:
// Read a spilled register from the machine state. // Read a spilled register from the machine state.
@ -281,6 +282,11 @@ class SnapshotIterator
} }
uintptr_t fromStack(int32_t offset) const; uintptr_t fromStack(int32_t offset) const;
bool hasInstructionResult(uint32_t index) const {
return instructionResults_;
}
Value fromInstructionResult(uint32_t index) const;
Value allocationValue(const RValueAllocation &a); Value allocationValue(const RValueAllocation &a);
bool allocationReadable(const RValueAllocation &a); bool allocationReadable(const RValueAllocation &a);
void warnUnreadableAllocation(); void warnUnreadableAllocation();
@ -338,6 +344,14 @@ class SnapshotIterator
return recover_.moreInstructions(); return recover_.moreInstructions();
} }
// Register a vector used for storing the results of the evaluation of
// recover instructions. This vector should be registered before the
// beginning of the iteration. This function is in charge of allocating
// enough space for all instructions results, and return false iff it fails.
bool initIntructionResults(AutoValueVector &results);
void storeInstructionResult(Value v);
public: public:
// Handle iterating over frames of the snapshots. // Handle iterating over frames of the snapshots.
void nextFrame(); void nextFrame();

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

@ -110,9 +110,6 @@ JitOptions::JitOptions()
// How many uses of a parallel kernel before we attempt compilation. // How many uses of a parallel kernel before we attempt compilation.
usesBeforeCompilePar = 1; usesBeforeCompilePar = 1;
// Whether to profile inlined functions in Ion or not.
profileInlineFrames = false;
} }
bool bool

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

@ -69,7 +69,6 @@ struct JitOptions
uint32_t osrPcMismatchesBeforeRecompile; uint32_t osrPcMismatchesBeforeRecompile;
uint32_t smallFunctionMaxBytecodeLength_; uint32_t smallFunctionMaxBytecodeLength_;
uint32_t usesBeforeCompilePar; uint32_t usesBeforeCompilePar;
bool profileInlineFrames;
JitOptions(); JitOptions();
bool isSmallFunction(JSScript *script) const; bool isSmallFunction(JSScript *script) const;

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

@ -111,11 +111,16 @@ LBlock::getExitMoveGroup(TempAllocator &alloc)
} }
static size_t static size_t
TotalOperandCount(MResumePoint *mir) TotalOperandCount(LRecoverInfo *recoverInfo)
{ {
size_t accum = mir->numOperands(); LRecoverInfo::OperandIter it(recoverInfo->begin());
while ((mir = mir->caller())) LRecoverInfo::OperandIter end(recoverInfo->end());
accum += mir->numOperands(); size_t accum = 0;
for (; it != end; ++it) {
if (!it->isRecoveredOnBailout())
accum++;
}
return accum; return accum;
} }
@ -137,28 +142,71 @@ LRecoverInfo::New(MIRGenerator *gen, MResumePoint *mir)
return recoverInfo; return recoverInfo;
} }
bool
LRecoverInfo::appendOperands(MNode *ins)
{
for (size_t i = 0, end = ins->numOperands(); i < end; i++) {
MDefinition *def = ins->getOperand(i);
// As there is no cycle in the data-flow (without MPhi), checking for
// isInWorkList implies that the definition is already in the
// instruction vector, and not processed by a caller of the current
// function.
if (def->isRecoveredOnBailout() && !def->isInWorklist()) {
if (!appendDefinition(def))
return false;
}
}
return true;
}
bool
LRecoverInfo::appendDefinition(MDefinition *def)
{
MOZ_ASSERT(def->isRecoveredOnBailout());
def->setInWorklist();
if (!appendOperands(def))
return false;
return instructions_.append(def);
}
bool
LRecoverInfo::appendResumePoint(MResumePoint *rp)
{
if (rp->caller() && !appendResumePoint(rp->caller()))
return false;
if (!appendOperands(rp))
return false;
return instructions_.append(rp);
}
bool bool
LRecoverInfo::init(MResumePoint *rp) LRecoverInfo::init(MResumePoint *rp)
{ {
MResumePoint *it = rp;
// Sort operations in the order in which we need to restore the stack. This // Sort operations in the order in which we need to restore the stack. This
// implies that outer frames, as well as operations needed to recover the // implies that outer frames, as well as operations needed to recover the
// current frame, are located before the current frame. The inner-most // current frame, are located before the current frame. The inner-most
// resume point should be the last element in the list. // resume point should be the last element in the list.
do { if (!appendResumePoint(rp))
if (!instructions_.append(it))
return false; return false;
it = it->caller();
} while (it);
Reverse(instructions_.begin(), instructions_.end()); // Remove temporary flags from all definitions.
for (MNode **it = begin(); it != end(); it++) {
if (!(*it)->isDefinition())
continue;
(*it)->toDefinition()->setNotInWorklist();
}
MOZ_ASSERT(mir() == rp); MOZ_ASSERT(mir() == rp);
return true; return true;
} }
LSnapshot::LSnapshot(LRecoverInfo *recoverInfo, BailoutKind kind) LSnapshot::LSnapshot(LRecoverInfo *recoverInfo, BailoutKind kind)
: numSlots_(TotalOperandCount(recoverInfo->mir()) * BOX_PIECES), : numSlots_(TotalOperandCount(recoverInfo) * BOX_PIECES),
slots_(nullptr), slots_(nullptr),
recoverInfo_(recoverInfo), recoverInfo_(recoverInfo),
snapshotOffset_(INVALID_SNAPSHOT_OFFSET), snapshotOffset_(INVALID_SNAPSHOT_OFFSET),
@ -368,8 +416,6 @@ LInstruction::dump(FILE *fp)
fprintf(fp, "} <- "); fprintf(fp, "} <- ");
printName(fp); printName(fp);
printInfo(fp); printInfo(fp);
if (numTemps()) { if (numTemps()) {
@ -381,13 +427,13 @@ LInstruction::dump(FILE *fp)
} }
fprintf(fp, ")"); fprintf(fp, ")");
} }
fprintf(fp, "\n");
} }
void void
LInstruction::dump() LInstruction::dump()
{ {
return dump(stderr); dump(stderr);
fprintf(stderr, "\n");
} }
void void

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

@ -879,7 +879,7 @@ class LCallInstructionHelper : public LInstructionHelper<Defs, Operands, Temps>
class LRecoverInfo : public TempObject class LRecoverInfo : public TempObject
{ {
public: public:
typedef Vector<MResumePoint *, 2, IonAllocPolicy> Instructions; typedef Vector<MNode *, 2, IonAllocPolicy> Instructions;
private: private:
// List of instructions needed to recover the stack frames. // List of instructions needed to recover the stack frames.
@ -892,12 +892,17 @@ class LRecoverInfo : public TempObject
LRecoverInfo(TempAllocator &alloc); LRecoverInfo(TempAllocator &alloc);
bool init(MResumePoint *mir); bool init(MResumePoint *mir);
// Fill the instruction vector such as all instructions needed for the
// recovery are pushed before the current instruction.
bool appendOperands(MNode *ins);
bool appendDefinition(MDefinition *def);
bool appendResumePoint(MResumePoint *rp);
public: public:
static LRecoverInfo *New(MIRGenerator *gen, MResumePoint *mir); static LRecoverInfo *New(MIRGenerator *gen, MResumePoint *mir);
// Resume point of the inner most function. // Resume point of the inner most function.
MResumePoint *mir() const { MResumePoint *mir() const {
return instructions_.back(); return instructions_.back()->toResumePoint();
} }
RecoverOffset recoverOffset() const { RecoverOffset recoverOffset() const {
return recoverOffset_; return recoverOffset_;
@ -907,12 +912,47 @@ class LRecoverInfo : public TempObject
recoverOffset_ = offset; recoverOffset_ = offset;
} }
MResumePoint **begin() { MNode **begin() {
return instructions_.begin(); return instructions_.begin();
} }
MResumePoint **end() { MNode **end() {
return instructions_.end(); return instructions_.end();
} }
size_t numInstructions() const {
return instructions_.length();
}
class OperandIter
{
private:
MNode **it_;
size_t op_;
public:
OperandIter(MNode **it)
: it_(it), op_(0)
{ }
MDefinition *operator *() {
return (*it_)->getOperand(op_);
}
MDefinition *operator ->() {
return (*it_)->getOperand(op_);
}
OperandIter &operator ++() {
++op_;
if (op_ == (*it_)->numOperands()) {
op_ = 0;
++it_;
}
return *this;
}
bool operator !=(const OperandIter &where) const {
return it_ != where.it_ || op_ != where.op_;
}
};
}; };
// An LSnapshot is the reflection of an MResumePoint in LIR. Unlike MResumePoints, // An LSnapshot is the reflection of an MResumePoint in LIR. Unlike MResumePoints,

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

@ -2303,7 +2303,8 @@ LIRGenerator::visitTypeBarrier(MTypeBarrier *ins)
} }
// Handle typebarrier with specific TypeObject/SingleObjects. // Handle typebarrier with specific TypeObject/SingleObjects.
if (inputType == MIRType_Object && !types->hasType(types::Type::AnyObjectType())) if (inputType == MIRType_Object && !types->hasType(types::Type::AnyObjectType()) &&
ins->barrierKind() != BarrierKind::TypeTagOnly)
{ {
LDefinition tmp = needTemp ? temp() : LDefinition::BogusTemp(); LDefinition tmp = needTemp ? temp() : LDefinition::BogusTemp();
LTypeBarrierO *barrier = new(alloc()) LTypeBarrierO(useRegister(ins->getOperand(0)), tmp); LTypeBarrierO *barrier = new(alloc()) LTypeBarrierO(useRegister(ins->getOperand(0)), tmp);
@ -3597,6 +3598,9 @@ SpewResumePoint(MBasicBlock *block, MInstruction *ins, MResumePoint *resumePoint
bool bool
LIRGenerator::visitInstruction(MInstruction *ins) LIRGenerator::visitInstruction(MInstruction *ins)
{ {
if (ins->isRecoveredOnBailout())
return true;
if (!gen->ensureBallast()) if (!gen->ensureBallast())
return false; return false;
if (!ins->accept(this)) if (!ins->accept(this))

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

@ -385,9 +385,9 @@ IonBuilder::inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode)
bool needsHoleCheck = thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED); bool needsHoleCheck = thisTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_NON_PACKED);
bool maybeUndefined = returnTypes->hasType(types::Type::UndefinedType()); bool maybeUndefined = returnTypes->hasType(types::Type::UndefinedType());
bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
callInfo.thisArg(), nullptr, returnTypes); callInfo.thisArg(), nullptr, returnTypes);
if (barrier) if (barrier != BarrierKind::NoBarrier)
returnType = MIRType_Value; returnType = MIRType_Value;
MArrayPopShift *ins = MArrayPopShift::New(alloc(), callInfo.thisArg(), mode, MArrayPopShift *ins = MArrayPopShift::New(alloc(), callInfo.thisArg(), mode,
@ -1231,7 +1231,7 @@ IonBuilder::inlineRegExpExec(CallInfo &callInfo)
if (!resumeAfter(exec)) if (!resumeAfter(exec))
return InliningStatus_Error; return InliningStatus_Error;
if (!pushTypeBarrier(exec, getInlineReturnTypeSet(), true)) if (!pushTypeBarrier(exec, getInlineReturnTypeSet(), BarrierKind::TypeSet))
return InliningStatus_Error; return InliningStatus_Error;
return InliningStatus_Inlined; return InliningStatus_Inlined;
@ -1782,7 +1782,7 @@ IonBuilder::inlineUnsafeGetReservedSlot(CallInfo &callInfo)
current->push(load); current->push(load);
// We don't track reserved slot types, so always emit a barrier. // We don't track reserved slot types, so always emit a barrier.
if (!pushTypeBarrier(load, getInlineReturnTypeSet(), true)) if (!pushTypeBarrier(load, getInlineReturnTypeSet(), BarrierKind::TypeSet))
return InliningStatus_Error; return InliningStatus_Error;
return InliningStatus_Inlined; return InliningStatus_Inlined;

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

@ -359,6 +359,20 @@ MDefinition::hasDefUses() const
return false; return false;
} }
bool
MDefinition::hasLiveDefUses() const
{
for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
MNode *ins = (*i)->consumer();
if (!ins->isDefinition())
continue;
if (!ins->toDefinition()->isRecoveredOnBailout())
return true;
}
return false;
}
MUseIterator MUseIterator
MDefinition::removeUse(MUseIterator use) MDefinition::removeUse(MUseIterator use)
{ {
@ -3089,7 +3103,7 @@ jit::DenseNativeElementType(types::CompilerConstraintList *constraints, MDefinit
return elementType; return elementType;
} }
static bool static BarrierKind
PropertyReadNeedsTypeBarrier(types::CompilerConstraintList *constraints, PropertyReadNeedsTypeBarrier(types::CompilerConstraintList *constraints,
types::TypeObjectKey *object, PropertyName *name, types::TypeObjectKey *object, PropertyName *name,
types::TypeSet *observed) types::TypeSet *observed)
@ -3105,13 +3119,22 @@ PropertyReadNeedsTypeBarrier(types::CompilerConstraintList *constraints,
if (object->unknownProperties() || observed->empty() || if (object->unknownProperties() || observed->empty() ||
object->clasp()->isProxy()) object->clasp()->isProxy())
{ {
return true; return BarrierKind::TypeSet;
} }
jsid id = name ? NameToId(name) : JSID_VOID; jsid id = name ? NameToId(name) : JSID_VOID;
types::HeapTypeSetKey property = object->property(id); types::HeapTypeSetKey property = object->property(id);
if (property.maybeTypes() && !TypeSetIncludes(observed, MIRType_Value, property.maybeTypes())) if (property.maybeTypes()) {
return true; if (!TypeSetIncludes(observed, MIRType_Value, property.maybeTypes())) {
// If all possible objects have been observed, we don't have to
// guard on the specific object types.
if (property.maybeTypes()->objectsAreSubset(observed)) {
property.freeze(constraints);
return BarrierKind::TypeTagOnly;
}
return BarrierKind::TypeSet;
}
}
// Type information for global objects is not required to reflect the // Type information for global objects is not required to reflect the
// initial 'undefined' value for properties, in particular global // initial 'undefined' value for properties, in particular global
@ -3121,15 +3144,15 @@ PropertyReadNeedsTypeBarrier(types::CompilerConstraintList *constraints,
if (name && types::CanHaveEmptyPropertyTypesForOwnProperty(obj) && if (name && types::CanHaveEmptyPropertyTypesForOwnProperty(obj) &&
(!property.maybeTypes() || property.maybeTypes()->empty())) (!property.maybeTypes() || property.maybeTypes()->empty()))
{ {
return true; return BarrierKind::TypeSet;
} }
} }
property.freeze(constraints); property.freeze(constraints);
return false; return BarrierKind::NoBarrier;
} }
bool BarrierKind
jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx, jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx,
types::CompilerConstraintList *constraints, types::CompilerConstraintList *constraints,
types::TypeObjectKey *object, PropertyName *name, types::TypeObjectKey *object, PropertyName *name,
@ -3177,45 +3200,55 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx,
return PropertyReadNeedsTypeBarrier(constraints, object, name, observed); return PropertyReadNeedsTypeBarrier(constraints, object, name, observed);
} }
bool BarrierKind
jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx, jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx,
types::CompilerConstraintList *constraints, types::CompilerConstraintList *constraints,
MDefinition *obj, PropertyName *name, MDefinition *obj, PropertyName *name,
types::TemporaryTypeSet *observed) types::TemporaryTypeSet *observed)
{ {
if (observed->unknown()) if (observed->unknown())
return false; return BarrierKind::NoBarrier;
types::TypeSet *types = obj->resultTypeSet(); types::TypeSet *types = obj->resultTypeSet();
if (!types || types->unknownObject()) if (!types || types->unknownObject())
return true; return BarrierKind::TypeSet;
BarrierKind res = BarrierKind::NoBarrier;
bool updateObserved = types->getObjectCount() == 1; bool updateObserved = types->getObjectCount() == 1;
for (size_t i = 0; i < types->getObjectCount(); i++) { for (size_t i = 0; i < types->getObjectCount(); i++) {
types::TypeObjectKey *object = types->getObject(i); types::TypeObjectKey *object = types->getObject(i);
if (object) { if (object) {
if (PropertyReadNeedsTypeBarrier(propertycx, constraints, object, name, BarrierKind kind = PropertyReadNeedsTypeBarrier(propertycx, constraints, object, name,
observed, updateObserved)) observed, updateObserved);
{ if (kind == BarrierKind::TypeSet)
return true; return BarrierKind::TypeSet;
if (kind == BarrierKind::TypeTagOnly) {
MOZ_ASSERT(res == BarrierKind::NoBarrier || res == BarrierKind::TypeTagOnly);
res = BarrierKind::TypeTagOnly;
} else {
MOZ_ASSERT(kind == BarrierKind::NoBarrier);
} }
} }
} }
return false; return res;
} }
bool BarrierKind
jit::PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *constraints, jit::PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *constraints,
MDefinition *obj, PropertyName *name, MDefinition *obj, PropertyName *name,
types::TemporaryTypeSet *observed) types::TemporaryTypeSet *observed)
{ {
if (observed->unknown()) if (observed->unknown())
return false; return BarrierKind::NoBarrier;
types::TypeSet *types = obj->resultTypeSet(); types::TypeSet *types = obj->resultTypeSet();
if (!types || types->unknownObject()) if (!types || types->unknownObject())
return true; return BarrierKind::TypeSet;
BarrierKind res = BarrierKind::NoBarrier;
for (size_t i = 0; i < types->getObjectCount(); i++) { for (size_t i = 0; i < types->getObjectCount(); i++) {
types::TypeObjectKey *object = types->getObject(i); types::TypeObjectKey *object = types->getObject(i);
@ -3223,16 +3256,24 @@ jit::PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *cons
continue; continue;
while (true) { while (true) {
if (!object->hasTenuredProto()) if (!object->hasTenuredProto())
return true; return BarrierKind::TypeSet;
if (!object->proto().isObject()) if (!object->proto().isObject())
break; break;
object = types::TypeObjectKey::get(object->proto().toObject()); object = types::TypeObjectKey::get(object->proto().toObject());
if (PropertyReadNeedsTypeBarrier(constraints, object, name, observed)) BarrierKind kind = PropertyReadNeedsTypeBarrier(constraints, object, name, observed);
return true; if (kind == BarrierKind::TypeSet)
return BarrierKind::TypeSet;
if (kind == BarrierKind::TypeTagOnly) {
MOZ_ASSERT(res == BarrierKind::NoBarrier || res == BarrierKind::TypeTagOnly);
res = BarrierKind::TypeTagOnly;
} else {
MOZ_ASSERT(kind == BarrierKind::NoBarrier);
}
} }
} }
return false; return res;
} }
bool bool
@ -3382,7 +3423,13 @@ TryAddTypeBarrierForWrite(TempAllocator &alloc, types::CompilerConstraintList *c
if (!types) if (!types)
return false; return false;
MInstruction *ins = MMonitorTypes::New(alloc, *pvalue, types); // If all possible objects can be stored without a barrier, we don't have to
// guard on the specific object types.
BarrierKind kind = BarrierKind::TypeSet;
if ((*pvalue)->resultTypeSet() && (*pvalue)->resultTypeSet()->objectsAreSubset(types))
kind = BarrierKind::TypeTagOnly;
MInstruction *ins = MMonitorTypes::New(alloc, *pvalue, types, kind);
current->add(ins); current->add(ins);
return true; return true;
} }

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

@ -89,7 +89,14 @@ MIRType MIRTypeFromValue(const js::Value &vp)
* Truncate Doubles. So every time removeUse is called, UseRemoved needs * Truncate Doubles. So every time removeUse is called, UseRemoved needs
* to get set. * to get set.
*/ \ */ \
_(UseRemoved) _(UseRemoved) \
\
/* Marks if the current instruction should go to the bailout paths instead
* of producing code as part of the control flow. This flag can only be set
* on instructions which are only used by ResumePoint or by other flagged
* instructions.
*/ \
_(RecoveredOnBailout)
class MDefinition; class MDefinition;
class MInstruction; class MInstruction;
@ -208,6 +215,8 @@ class MNode : public TempObject
inline MDefinition *toDefinition(); inline MDefinition *toDefinition();
inline MResumePoint *toResumePoint(); inline MResumePoint *toResumePoint();
virtual bool writeRecoverData(CompactBufferWriter &writer) const;
protected: protected:
// Sets an unset operand, updating use information. // Sets an unset operand, updating use information.
virtual void setOperand(size_t index, MDefinition *operand) = 0; virtual void setOperand(size_t index, MDefinition *operand) = 0;
@ -531,6 +540,10 @@ class MDefinition : public MNode
// (only counting MDefinitions, ignoring MResumePoints) // (only counting MDefinitions, ignoring MResumePoints)
bool hasDefUses() const; bool hasDefUses() const;
// Test whether this MDefinition has at least one non-recovered use.
// (only counting MDefinitions, ignoring MResumePoints)
bool hasLiveDefUses() const;
bool hasUses() const { bool hasUses() const {
return !uses_.empty(); return !uses_.empty();
} }
@ -606,6 +619,10 @@ class MDefinition : public MNode
JS_ASSERT(getAliasSet().flags() & store->getAliasSet().flags()); JS_ASSERT(getAliasSet().flags() & store->getAliasSet().flags());
return true; return true;
} }
virtual bool canRecoverOnBailout() const {
return false;
}
}; };
// An MUseDefIterator walks over uses in a definition, skipping any use that is // An MUseDefIterator walks over uses in a definition, skipping any use that is
@ -4000,6 +4017,11 @@ class MAdd : public MBinaryArithInstruction
void computeRange(TempAllocator &alloc); void computeRange(TempAllocator &alloc);
bool truncate(); bool truncate();
bool isOperandTruncated(size_t index) const; bool isOperandTruncated(size_t index) const;
bool writeRecoverData(CompactBufferWriter &writer) const;
bool canRecoverOnBailout() const {
return specialization_ < MIRType_Object;
}
}; };
class MSub : public MBinaryArithInstruction class MSub : public MBinaryArithInstruction
@ -9070,10 +9092,15 @@ class MTypeBarrier
: public MUnaryInstruction, : public MUnaryInstruction,
public TypeBarrierPolicy public TypeBarrierPolicy
{ {
MTypeBarrier(MDefinition *def, types::TemporaryTypeSet *types) BarrierKind barrierKind_;
: MUnaryInstruction(def)
MTypeBarrier(MDefinition *def, types::TemporaryTypeSet *types, BarrierKind kind)
: MUnaryInstruction(def),
barrierKind_(kind)
{ {
JS_ASSERT(!types->unknown()); MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
MOZ_ASSERT(!types->unknown());
setResultType(types->getKnownMIRType()); setResultType(types->getKnownMIRType());
setResultTypeSet(types); setResultTypeSet(types);
@ -9084,8 +9111,9 @@ class MTypeBarrier
public: public:
INSTRUCTION_HEADER(TypeBarrier) INSTRUCTION_HEADER(TypeBarrier)
static MTypeBarrier *New(TempAllocator &alloc, MDefinition *def, types::TemporaryTypeSet *types) { static MTypeBarrier *New(TempAllocator &alloc, MDefinition *def, types::TemporaryTypeSet *types,
return new(alloc) MTypeBarrier(def, types); BarrierKind kind = BarrierKind::TypeSet) {
return new(alloc) MTypeBarrier(def, types, kind);
} }
void printOpcode(FILE *fp) const; void printOpcode(FILE *fp) const;
@ -9103,6 +9131,9 @@ class MTypeBarrier
virtual bool neverHoist() const { virtual bool neverHoist() const {
return resultTypeSet()->empty(); return resultTypeSet()->empty();
} }
BarrierKind barrierKind() const {
return barrierKind_;
}
bool alwaysBails() const { bool alwaysBails() const {
// If mirtype of input doesn't agree with mirtype of barrier, // If mirtype of input doesn't agree with mirtype of barrier,
@ -9122,20 +9153,25 @@ class MTypeBarrier
class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy
{ {
const types::TemporaryTypeSet *typeSet_; const types::TemporaryTypeSet *typeSet_;
BarrierKind barrierKind_;
MMonitorTypes(MDefinition *def, const types::TemporaryTypeSet *types) MMonitorTypes(MDefinition *def, const types::TemporaryTypeSet *types, BarrierKind kind)
: MUnaryInstruction(def), : MUnaryInstruction(def),
typeSet_(types) typeSet_(types),
barrierKind_(kind)
{ {
MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || kind == BarrierKind::TypeSet);
setGuard(); setGuard();
JS_ASSERT(!types->unknown()); MOZ_ASSERT(!types->unknown());
} }
public: public:
INSTRUCTION_HEADER(MonitorTypes) INSTRUCTION_HEADER(MonitorTypes)
static MMonitorTypes *New(TempAllocator &alloc, MDefinition *def, const types::TemporaryTypeSet *types) { static MMonitorTypes *New(TempAllocator &alloc, MDefinition *def, const types::TemporaryTypeSet *types,
return new(alloc) MMonitorTypes(def, types); BarrierKind kind) {
return new(alloc) MMonitorTypes(def, types, kind);
} }
TypePolicy *typePolicy() { TypePolicy *typePolicy() {
@ -9145,6 +9181,10 @@ class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy
const types::TemporaryTypeSet *typeSet() const { const types::TemporaryTypeSet *typeSet() const {
return typeSet_; return typeSet_;
} }
BarrierKind barrierKind() const {
return barrierKind_;
}
AliasSet getAliasSet() const { AliasSet getAliasSet() const {
return AliasSet::None(); return AliasSet::None();
} }
@ -10094,15 +10134,15 @@ bool ElementAccessIsPacked(types::CompilerConstraintList *constraints, MDefiniti
bool ElementAccessHasExtraIndexedProperty(types::CompilerConstraintList *constraints, bool ElementAccessHasExtraIndexedProperty(types::CompilerConstraintList *constraints,
MDefinition *obj); MDefinition *obj);
MIRType DenseNativeElementType(types::CompilerConstraintList *constraints, MDefinition *obj); MIRType DenseNativeElementType(types::CompilerConstraintList *constraints, MDefinition *obj);
bool PropertyReadNeedsTypeBarrier(JSContext *propertycx, BarrierKind PropertyReadNeedsTypeBarrier(JSContext *propertycx,
types::CompilerConstraintList *constraints, types::CompilerConstraintList *constraints,
types::TypeObjectKey *object, PropertyName *name, types::TypeObjectKey *object, PropertyName *name,
types::TemporaryTypeSet *observed, bool updateObserved); types::TemporaryTypeSet *observed, bool updateObserved);
bool PropertyReadNeedsTypeBarrier(JSContext *propertycx, BarrierKind PropertyReadNeedsTypeBarrier(JSContext *propertycx,
types::CompilerConstraintList *constraints, types::CompilerConstraintList *constraints,
MDefinition *obj, PropertyName *name, MDefinition *obj, PropertyName *name,
types::TemporaryTypeSet *observed); types::TemporaryTypeSet *observed);
bool PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *constraints, BarrierKind PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *constraints,
MDefinition *obj, PropertyName *name, MDefinition *obj, PropertyName *name,
types::TemporaryTypeSet *observed); types::TemporaryTypeSet *observed);
bool PropertyReadIsIdempotent(types::CompilerConstraintList *constraints, bool PropertyReadIsIdempotent(types::CompilerConstraintList *constraints,

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

@ -6,21 +6,42 @@
#include "jit/Recover.h" #include "jit/Recover.h"
#include "jscntxt.h"
#include "jsmath.h"
#include "jit/IonSpewer.h" #include "jit/IonSpewer.h"
#include "jit/JitFrameIterator.h"
#include "jit/MIR.h" #include "jit/MIR.h"
#include "jit/MIRGraph.h" #include "jit/MIRGraph.h"
#include "vm/Interpreter.h"
using namespace js; using namespace js;
using namespace js::jit; using namespace js::jit;
bool
MNode::writeRecoverData(CompactBufferWriter &writer) const
{
MOZ_ASSUME_UNREACHABLE("This instruction is not serializable");
return false;
}
void void
RInstruction::readRecoverData(CompactBufferReader &reader, RInstructionStorage *raw) RInstruction::readRecoverData(CompactBufferReader &reader, RInstructionStorage *raw)
{ {
uint32_t op = reader.readUnsigned(); uint32_t op = reader.readUnsigned();
switch (Opcode(op)) { switch (Opcode(op)) {
case Recover_ResumePoint: # define MATCH_OPCODES_(op) \
new (raw->addr()) RResumePoint(reader); case Recover_##op: \
static_assert(sizeof(R##op) <= sizeof(RInstructionStorage), \
"Storage space is too small to decode R" #op " instructions."); \
new (raw->addr()) R##op(reader); \
break; break;
RECOVER_OPCODE_LIST(MATCH_OPCODES_)
# undef DEFINE_OPCODES_
case Recover_Invalid:
default: default:
MOZ_ASSUME_UNREACHABLE("Bad decoding of the previous instruction?"); MOZ_ASSUME_UNREACHABLE("Bad decoding of the previous instruction?");
break; break;
@ -101,10 +122,48 @@ MResumePoint::writeRecoverData(CompactBufferWriter &writer) const
RResumePoint::RResumePoint(CompactBufferReader &reader) RResumePoint::RResumePoint(CompactBufferReader &reader)
{ {
static_assert(sizeof(*this) <= sizeof(RInstructionStorage),
"Storage space is too small to decode this recover instruction.");
pcOffset_ = reader.readUnsigned(); pcOffset_ = reader.readUnsigned();
numOperands_ = reader.readUnsigned(); numOperands_ = reader.readUnsigned();
IonSpew(IonSpew_Snapshots, "Read RResumePoint (pc offset %u, nslots %u)", IonSpew(IonSpew_Snapshots, "Read RResumePoint (pc offset %u, nslots %u)",
pcOffset_, numOperands_); pcOffset_, numOperands_);
} }
bool
RResumePoint::recover(JSContext *cx, SnapshotIterator &iter) const
{
MOZ_ASSUME_UNREACHABLE("This instruction is not recoverable.");
}
bool
MAdd::writeRecoverData(CompactBufferWriter &writer) const
{
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_Add));
writer.writeByte(specialization_ == MIRType_Float32);
return true;
}
RAdd::RAdd(CompactBufferReader &reader)
{
isFloatOperation_ = reader.readByte();
}
bool
RAdd::recover(JSContext *cx, SnapshotIterator &iter) const
{
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
RootedValue result(cx);
MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
if (!js::AddValues(cx, &lhs, &rhs, &result))
return false;
// MIRType_Float32 is a specialization embedding the fact that the result is
// rounded to a Float32.
if (isFloatOperation_ && !RoundFloat32(cx, result, &result))
return false;
iter.storeInstructionResult(result);
return true;
}

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

@ -11,44 +11,71 @@
#include "jit/Snapshots.h" #include "jit/Snapshots.h"
class JSContext;
namespace js { namespace js {
namespace jit { namespace jit {
#define RECOVER_OPCODE_LIST(_) \
_(ResumePoint) \
_(Add)
class RResumePoint; class RResumePoint;
class SnapshotIterator;
class RInstruction class RInstruction
{ {
public: public:
enum Opcode enum Opcode
{ {
Recover_ResumePoint = 0 # define DEFINE_OPCODES_(op) Recover_##op,
RECOVER_OPCODE_LIST(DEFINE_OPCODES_)
# undef DEFINE_OPCODES_
Recover_Invalid
}; };
virtual Opcode opcode() const = 0; virtual Opcode opcode() const = 0;
// As opposed to the MIR, there is no need to add more methods as every
// other instruction is well abstracted under the "recover" method.
bool isResumePoint() const { bool isResumePoint() const {
return opcode() == Recover_ResumePoint; return opcode() == Recover_ResumePoint;
} }
inline const RResumePoint *toResumePoint() const; inline const RResumePoint *toResumePoint() const;
// Number of allocations which are encoded in the Snapshot for recovering
// the current instruction.
virtual uint32_t numOperands() const = 0; virtual uint32_t numOperands() const = 0;
// Function used to recover the value computed by this instruction. This
// function reads its arguments from the allocations listed on the snapshot
// iterator and stores its returned value on the snapshot iterator too.
virtual bool recover(JSContext *cx, SnapshotIterator &iter) const = 0;
// Decode an RInstruction on top of the reserved storage space, based on the
// tag written by the writeRecoverData function of the corresponding MIR
// instruction.
static void readRecoverData(CompactBufferReader &reader, RInstructionStorage *raw); static void readRecoverData(CompactBufferReader &reader, RInstructionStorage *raw);
}; };
#define RINSTRUCTION_HEADER_(op) \
private: \
friend class RInstruction; \
R##op(CompactBufferReader &reader); \
\
public: \
Opcode opcode() const { \
return RInstruction::Recover_##op; \
}
class RResumePoint MOZ_FINAL : public RInstruction class RResumePoint MOZ_FINAL : public RInstruction
{ {
private: private:
uint32_t pcOffset_; // Offset from script->code. uint32_t pcOffset_; // Offset from script->code.
uint32_t numOperands_; // Number of slots. uint32_t numOperands_; // Number of slots.
friend class RInstruction;
RResumePoint(CompactBufferReader &reader);
public: public:
virtual Opcode opcode() const { RINSTRUCTION_HEADER_(ResumePoint)
return Recover_ResumePoint;
}
uint32_t pcOffset() const { uint32_t pcOffset() const {
return pcOffset_; return pcOffset_;
@ -56,8 +83,26 @@ class RResumePoint MOZ_FINAL : public RInstruction
virtual uint32_t numOperands() const { virtual uint32_t numOperands() const {
return numOperands_; return numOperands_;
} }
bool recover(JSContext *cx, SnapshotIterator &iter) const;
}; };
class RAdd MOZ_FINAL : public RInstruction
{
private:
bool isFloatOperation_;
public:
RINSTRUCTION_HEADER_(Add)
virtual uint32_t numOperands() const {
return 2;
}
bool recover(JSContext *cx, SnapshotIterator &iter) const;
};
#undef RINSTRUCTION_HEADER_
const RResumePoint * const RResumePoint *
RInstruction::toResumePoint() const RInstruction::toResumePoint() const
{ {

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

@ -76,6 +76,9 @@ using namespace js::jit;
// first register/stack-offset correspond to the holder of the type, // first register/stack-offset correspond to the holder of the type,
// and the second correspond to the payload of the JS Value. // and the second correspond to the payload of the JS Value.
// //
// RECOVER_INSTRUCTION [INDEX]
// Index into the list of recovered instruction results.
//
// TYPED_REG [PACKED_TAG, GPR_REG]: // TYPED_REG [PACKED_TAG, GPR_REG]:
// Value with statically known type, which payload is stored in a // Value with statically known type, which payload is stored in a
// register. // register.
@ -219,6 +222,15 @@ RValueAllocation::layoutFromMode(Mode mode)
return layout; return layout;
} }
#endif #endif
case RECOVER_INSTRUCTION: {
static const RValueAllocation::Layout layout = {
PAYLOAD_INDEX,
PAYLOAD_NONE,
"instruction"
};
return layout;
}
default: { default: {
static const RValueAllocation::Layout regLayout = { static const RValueAllocation::Layout regLayout = {
PAYLOAD_PACKED_TAG, PAYLOAD_PACKED_TAG,
@ -662,20 +674,20 @@ SnapshotWriter::endSnapshot()
} }
RecoverOffset RecoverOffset
RecoverWriter::startRecover(uint32_t frameCount, bool resumeAfter) RecoverWriter::startRecover(uint32_t instructionCount, bool resumeAfter)
{ {
MOZ_ASSERT(frameCount); MOZ_ASSERT(instructionCount);
nframes_ = frameCount; instructionCount_ = instructionCount;
framesWritten_ = 0; instructionsWritten_ = 0;
IonSpew(IonSpew_Snapshots, "starting recover with frameCount %u", IonSpew(IonSpew_Snapshots, "starting recover with %u instruction(s)",
frameCount); instructionCount);
MOZ_ASSERT(!(uint32_t(resumeAfter) &~ RECOVER_RESUMEAFTER_MASK)); MOZ_ASSERT(!(uint32_t(resumeAfter) &~ RECOVER_RESUMEAFTER_MASK));
MOZ_ASSERT(frameCount < uint32_t(1 << RECOVER_RINSCOUNT_BITS)); MOZ_ASSERT(instructionCount < uint32_t(1 << RECOVER_RINSCOUNT_BITS));
uint32_t bits = uint32_t bits =
(uint32_t(resumeAfter) << RECOVER_RESUMEAFTER_SHIFT) | (uint32_t(resumeAfter) << RECOVER_RESUMEAFTER_SHIFT) |
(frameCount << RECOVER_RINSCOUNT_SHIFT); (instructionCount << RECOVER_RINSCOUNT_SHIFT);
RecoverOffset recoverOffset = writer_.length(); RecoverOffset recoverOffset = writer_.length();
writer_.writeUnsigned(bits); writer_.writeUnsigned(bits);
@ -683,16 +695,16 @@ RecoverWriter::startRecover(uint32_t frameCount, bool resumeAfter)
} }
bool bool
RecoverWriter::writeFrame(const MResumePoint *rp) RecoverWriter::writeInstruction(const MNode *rp)
{ {
if (!rp->writeRecoverData(writer_)) if (!rp->writeRecoverData(writer_))
return false; return false;
framesWritten_++; instructionsWritten_++;
return true; return true;
} }
void void
RecoverWriter::endRecover() RecoverWriter::endRecover()
{ {
JS_ASSERT(nframes_ == framesWritten_); MOZ_ASSERT(instructionCount_ == instructionsWritten_);
} }

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

@ -54,6 +54,8 @@ class RValueAllocation
UNTYPED_REG = 0x06, UNTYPED_REG = 0x06,
UNTYPED_STACK = 0x07, UNTYPED_STACK = 0x07,
#endif #endif
RECOVER_INSTRUCTION = 0x0a,
// The JSValueType is packed in the Mode. // The JSValueType is packed in the Mode.
TYPED_REG_MIN = 0x10, TYPED_REG_MIN = 0x10,
TYPED_REG_MAX = 0x17, TYPED_REG_MAX = 0x17,
@ -236,6 +238,11 @@ class RValueAllocation
return RValueAllocation(CONSTANT, payloadOfIndex(index)); return RValueAllocation(CONSTANT, payloadOfIndex(index));
} }
// Recover instruction's index
static RValueAllocation RecoverInstruction(uint32_t index) {
return RValueAllocation(RECOVER_INSTRUCTION, payloadOfIndex(index));
}
void writeHeader(CompactBufferWriter &writer, JSValueType type, uint32_t regCode) const; void writeHeader(CompactBufferWriter &writer, JSValueType type, uint32_t regCode) const;
public: public:
static RValueAllocation read(CompactBufferReader &reader); static RValueAllocation read(CompactBufferReader &reader);
@ -360,19 +367,19 @@ class SnapshotWriter
} }
}; };
class MResumePoint; class MNode;
class RecoverWriter class RecoverWriter
{ {
CompactBufferWriter writer_; CompactBufferWriter writer_;
uint32_t nframes_; uint32_t instructionCount_;
uint32_t framesWritten_; uint32_t instructionsWritten_;
public: public:
SnapshotOffset startRecover(uint32_t frameCount, bool resumeAfter); SnapshotOffset startRecover(uint32_t instructionCount, bool resumeAfter);
bool writeFrame(const MResumePoint *rp); bool writeInstruction(const MNode *rp);
void endRecover(); void endRecover();
@ -473,6 +480,13 @@ class RecoverReader
public: public:
RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size); RecoverReader(SnapshotReader &snapshot, const uint8_t *recovers, uint32_t size);
uint32_t numInstructions() const {
return numInstructions_;
}
uint32_t numInstructionsRead() const {
return numInstructionsRead_;
}
bool moreInstructions() const { bool moreInstructions() const {
return numInstructionsRead_ < numInstructions_; return numInstructionsRead_ < numInstructions_;
} }

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

@ -1402,6 +1402,10 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
ma_mov(Imm32(0), reg, NoSetCond, Signed); ma_mov(Imm32(0), reg, NoSetCond, Signed);
} }
void incrementInt32Value(const Address &addr) {
add32(Imm32(1), ToPayload(addr));
}
void cmp32(const Register &lhs, const Imm32 &rhs); void cmp32(const Register &lhs, const Imm32 &rhs);
void cmp32(const Register &lhs, const Register &rhs); void cmp32(const Register &lhs, const Register &rhs);
void cmp32(const Operand &lhs, const Imm32 &rhs); void cmp32(const Operand &lhs, const Imm32 &rhs);

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

@ -137,25 +137,37 @@ ToStackIndex(LAllocation *a)
} }
bool bool
CodeGeneratorShared::encodeAllocations(LSnapshot *snapshot, MResumePoint *resumePoint, CodeGeneratorShared::encodeAllocation(LSnapshot *snapshot, MDefinition *mir,
uint32_t *startIndex) uint32_t *allocIndex)
{ {
IonSpew(IonSpew_Codegen, "Encoding %u of resume point %p's operands starting from %u",
resumePoint->numOperands(), (void *) resumePoint, *startIndex);
for (uint32_t allocno = 0, e = resumePoint->numOperands(); allocno < e; allocno++) {
uint32_t i = allocno + *startIndex;
MDefinition *mir = resumePoint->getOperand(allocno);
if (mir->isBox()) if (mir->isBox())
mir = mir->toBox()->getOperand(0); mir = mir->toBox()->getOperand(0);
MIRType type = mir->isUnused() MIRType type =
? MIRType_MagicOptimizedOut mir->isRecoveredOnBailout() ? MIRType_None :
: mir->type(); mir->isUnused() ? MIRType_MagicOptimizedOut :
mir->type();
RValueAllocation alloc; RValueAllocation alloc;
switch (type) { switch (type) {
case MIRType_None:
{
MOZ_ASSERT(mir->isRecoveredOnBailout());
uint32_t index = 0;
LRecoverInfo *recoverInfo = snapshot->recoverInfo();
MNode **it = recoverInfo->begin(), **end = recoverInfo->end();
while (it != end && mir != *it) {
++it;
++index;
}
// This MDefinition is recovered, thus it should be listed in the
// LRecoverInfo.
MOZ_ASSERT(it != end && mir == *it);
alloc = RValueAllocation::RecoverInstruction(index);
break;
}
case MIRType_Undefined: case MIRType_Undefined:
alloc = RValueAllocation::Undefined(); alloc = RValueAllocation::Undefined();
break; break;
@ -169,7 +181,7 @@ CodeGeneratorShared::encodeAllocations(LSnapshot *snapshot, MResumePoint *resume
case MIRType_Double: case MIRType_Double:
case MIRType_Float32: case MIRType_Float32:
{ {
LAllocation *payload = snapshot->payloadOfSlot(i); LAllocation *payload = snapshot->payloadOfSlot(*allocIndex);
JSValueType valueType = ValueTypeFromMIRType(type); JSValueType valueType = ValueTypeFromMIRType(type);
if (payload->isMemory()) { if (payload->isMemory()) {
if (type == MIRType_Float32) if (type == MIRType_Float32)
@ -209,9 +221,9 @@ CodeGeneratorShared::encodeAllocations(LSnapshot *snapshot, MResumePoint *resume
default: default:
{ {
JS_ASSERT(mir->type() == MIRType_Value); JS_ASSERT(mir->type() == MIRType_Value);
LAllocation *payload = snapshot->payloadOfSlot(i); LAllocation *payload = snapshot->payloadOfSlot(*allocIndex);
#ifdef JS_NUNBOX32 #ifdef JS_NUNBOX32
LAllocation *type = snapshot->typeOfSlot(i); LAllocation *type = snapshot->typeOfSlot(*allocIndex);
if (type->isRegister()) { if (type->isRegister()) {
if (payload->isRegister()) if (payload->isRegister())
alloc = RValueAllocation::Untyped(ToRegister(type), ToRegister(payload)); alloc = RValueAllocation::Untyped(ToRegister(type), ToRegister(payload));
@ -234,9 +246,7 @@ CodeGeneratorShared::encodeAllocations(LSnapshot *snapshot, MResumePoint *resume
} }
snapshots_.add(alloc); snapshots_.add(alloc);
} *allocIndex += mir->isRecoveredOnBailout() ? 0 : 1;
*startIndex += resumePoint->numOperands();
return true; return true;
} }
@ -246,21 +256,18 @@ CodeGeneratorShared::encode(LRecoverInfo *recover)
if (recover->recoverOffset() != INVALID_RECOVER_OFFSET) if (recover->recoverOffset() != INVALID_RECOVER_OFFSET)
return true; return true;
uint32_t frameCount = recover->mir()->frameCount(); uint32_t numInstructions = recover->numInstructions();
IonSpew(IonSpew_Snapshots, "Encoding LRecoverInfo %p (frameCount %u)", IonSpew(IonSpew_Snapshots, "Encoding LRecoverInfo %p (frameCount %u, instructions %u)",
(void *)recover, frameCount); (void *)recover, recover->mir()->frameCount(), numInstructions);
MResumePoint::Mode mode = recover->mir()->mode(); MResumePoint::Mode mode = recover->mir()->mode();
JS_ASSERT(mode != MResumePoint::Outer); JS_ASSERT(mode != MResumePoint::Outer);
bool resumeAfter = (mode == MResumePoint::ResumeAfter); bool resumeAfter = (mode == MResumePoint::ResumeAfter);
RecoverOffset offset = recovers_.startRecover(frameCount, resumeAfter); RecoverOffset offset = recovers_.startRecover(numInstructions, resumeAfter);
for (MResumePoint **it = recover->begin(), **end = recover->end(); for (MNode **it = recover->begin(), **end = recover->end(); it != end; ++it) {
it != end; if (!recovers_.writeInstruction(*it))
++it)
{
if (!recovers_.writeFrame(*it))
return false; return false;
} }
@ -307,17 +314,17 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
snapshots_.trackSnapshot(pcOpcode, mirOpcode, mirId, lirOpcode, lirId); snapshots_.trackSnapshot(pcOpcode, mirOpcode, mirId, lirOpcode, lirId);
#endif #endif
uint32_t startIndex = 0; uint32_t allocIndex = 0;
for (MResumePoint **it = recoverInfo->begin(), **end = recoverInfo->end(); LRecoverInfo::OperandIter it(recoverInfo->begin());
it != end; LRecoverInfo::OperandIter end(recoverInfo->end());
++it) for (; it != end; ++it) {
{ DebugOnly<uint32_t> allocWritten = snapshots_.allocWritten();
MResumePoint *mir = *it; if (!encodeAllocation(snapshot, *it, &allocIndex))
if (!encodeAllocations(snapshot, mir, &startIndex))
return false; return false;
MOZ_ASSERT(allocWritten + 1 == snapshots_.allocWritten());
} }
MOZ_ASSERT(snapshots_.allocWritten() == snapshot->numSlots()); MOZ_ASSERT(allocIndex == snapshot->numSlots());
snapshots_.endSnapshot(); snapshots_.endSnapshot();
snapshot->setSnapshotOffset(offset); snapshot->setSnapshotOffset(offset);
return !snapshots_.oom(); return !snapshots_.oom();

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

@ -272,7 +272,7 @@ class CodeGeneratorShared : public LInstructionVisitor
// false on failure. // false on failure.
bool encode(LRecoverInfo *recover); bool encode(LRecoverInfo *recover);
bool encode(LSnapshot *snapshot); bool encode(LSnapshot *snapshot);
bool encodeAllocations(LSnapshot *snapshot, MResumePoint *resumePoint, uint32_t *startIndex); bool encodeAllocation(LSnapshot *snapshot, MDefinition *def, uint32_t *startIndex);
// Attempts to assign a BailoutId to a snapshot, if one isn't already set. // Attempts to assign a BailoutId to a snapshot, if one isn't already set.
// If the bailout table is full, this returns false, which is not a fatal // If the bailout table is full, this returns false, which is not a fatal

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

@ -74,22 +74,25 @@ LIRGeneratorShared::getRecoverInfo(MResumePoint *rp)
LSnapshot * LSnapshot *
LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind) LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind)
{ {
LRecoverInfo *recover = getRecoverInfo(rp); LRecoverInfo *recoverInfo = getRecoverInfo(rp);
if (!recover) if (!recoverInfo)
return nullptr; return nullptr;
LSnapshot *snapshot = LSnapshot::New(gen, recover, kind); LSnapshot *snapshot = LSnapshot::New(gen, recoverInfo, kind);
if (!snapshot) if (!snapshot)
return nullptr; return nullptr;
size_t i = 0; size_t index = 0;
for (MResumePoint **it = recover->begin(), **end = recover->end(); it != end; ++it) { LRecoverInfo::OperandIter it(recoverInfo->begin());
MResumePoint *mir = *it; LRecoverInfo::OperandIter end(recoverInfo->end());
for (size_t j = 0, e = mir->numOperands(); j < e; ++i, ++j) { for (; it != end; ++it) {
MDefinition *ins = mir->getOperand(j); MDefinition *ins = *it;
if (ins->isRecoveredOnBailout())
continue;
LAllocation *type = snapshot->typeOfSlot(i); LAllocation *type = snapshot->typeOfSlot(index);
LAllocation *payload = snapshot->payloadOfSlot(i); LAllocation *payload = snapshot->payloadOfSlot(index);
++index;
if (ins->isBox()) if (ins->isBox())
ins = ins->toBox()->getOperand(0); ins = ins->toBox()->getOperand(0);
@ -118,7 +121,6 @@ LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKi
*payload = usePayload(ins, LUse::KEEPALIVE); *payload = usePayload(ins, LUse::KEEPALIVE);
} }
} }
}
return snapshot; return snapshot;
} }
@ -128,19 +130,22 @@ LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKi
LSnapshot * LSnapshot *
LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind) LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKind kind)
{ {
LRecoverInfo *recover = getRecoverInfo(rp); LRecoverInfo *recoverInfo = getRecoverInfo(rp);
if (!recover) if (!recoverInfo)
return nullptr; return nullptr;
LSnapshot *snapshot = LSnapshot::New(gen, recover, kind); LSnapshot *snapshot = LSnapshot::New(gen, recoverInfo, kind);
if (!snapshot) if (!snapshot)
return nullptr; return nullptr;
size_t i = 0; size_t index = 0;
for (MResumePoint **it = recover->begin(), **end = recover->end(); it != end; ++it) { LRecoverInfo::OperandIter it(recoverInfo->begin());
MResumePoint *mir = *it; LRecoverInfo::OperandIter end(recoverInfo->end());
for (size_t j = 0, e = mir->numOperands(); j < e; ++i, ++j) { for (; it != end; ++it) {
MDefinition *def = mir->getOperand(j); MDefinition *def = *it;
if (def->isRecoveredOnBailout())
continue;
if (def->isBox()) if (def->isBox())
def = def->toBox()->getOperand(0); def = def->toBox()->getOperand(0);
@ -153,7 +158,7 @@ LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKi
// code between an instruction and the LOsiPoint that follows it. // code between an instruction and the LOsiPoint that follows it.
JS_ASSERT_IF(!def->isConstant(), !def->isEmittedAtUses()); JS_ASSERT_IF(!def->isConstant(), !def->isEmittedAtUses());
LAllocation *a = snapshot->getEntry(i); LAllocation *a = snapshot->getEntry(index++);
if (def->isUnused()) { if (def->isUnused()) {
*a = LConstantIndex::Bogus(); *a = LConstantIndex::Bogus();
@ -162,7 +167,6 @@ LIRGeneratorShared::buildSnapshot(LInstruction *ins, MResumePoint *rp, BailoutKi
*a = useKeepaliveOrConstant(def); *a = useKeepaliveOrConstant(def);
} }
}
return snapshot; return snapshot;
} }

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

@ -1237,6 +1237,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
} }
} }
void incrementInt32Value(const Address &addr) {
addPtr(Imm32(1), addr);
}
// If source is a double, load it into dest. If source is int32, // If source is a double, load it into dest. If source is int32,
// convert it to double. Else, branch to failure. // convert it to double. Else, branch to failure.
void ensureDouble(const ValueOperand &source, FloatRegister dest, Label *failure) { void ensureDouble(const ValueOperand &source, FloatRegister dest, Label *failure) {

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

@ -1035,6 +1035,9 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
bind(&noOverflow); bind(&noOverflow);
} }
void incrementInt32Value(const Address &addr) {
addl(Imm32(1), payloadOf(addr));
}
// If source is a double, load it into dest. If source is int32, // If source is a double, load it into dest. If source is int32,
// convert it to double. Else, branch to failure. // convert it to double. Else, branch to failure.

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

@ -235,13 +235,10 @@ class AutoVectorRooter : protected AutoGCRooter
return vector.reserve(newLength); return vector.reserve(newLength);
} }
T &operator[](size_t i) { return vector[i]; } JS::MutableHandle<T> operator[](size_t i) {
const T &operator[](size_t i) const { return vector[i]; }
JS::MutableHandle<T> handleAt(size_t i) {
return JS::MutableHandle<T>::fromMarkedLocation(&vector[i]); return JS::MutableHandle<T>::fromMarkedLocation(&vector[i]);
} }
JS::Handle<T> handleAt(size_t i) const { JS::Handle<T> operator[](size_t i) const {
return JS::Handle<T>::fromMarkedLocation(&vector[i]); return JS::Handle<T>::fromMarkedLocation(&vector[i]);
} }

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

@ -1744,14 +1744,14 @@ MergeSortByKey(K keys, size_t len, K scratch, C comparator, AutoValueVector *vec
do { do {
size_t k = keys[j].elementIndex; size_t k = keys[j].elementIndex;
keys[j].elementIndex = j; keys[j].elementIndex = j;
(*vec)[j] = (*vec)[k]; (*vec)[j].set((*vec)[k]);
j = k; j = k;
} while (j != i); } while (j != i);
// We could assert the loop invariant that |i == keys[i].elementIndex| // We could assert the loop invariant that |i == keys[i].elementIndex|
// here if we synced |keys[i].elementIndex|. But doing so would render // here if we synced |keys[i].elementIndex|. But doing so would render
// the assertion vacuous, so don't bother, even in debug builds. // the assertion vacuous, so don't bother, even in debug builds.
(*vec)[i] = tv; (*vec)[i].set(tv);
} }
return true; return true;
@ -1820,7 +1820,7 @@ SortNumerically(JSContext *cx, AutoValueVector *vec, size_t len, ComparatorMatch
return false; return false;
double dv; double dv;
if (!ToNumber(cx, vec->handleAt(i), &dv)) if (!ToNumber(cx, (*vec)[i], &dv))
return false; return false;
NumericElement el = { dv, i }; NumericElement el = { dv, i };

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

@ -2771,8 +2771,10 @@ BeginMarkPhase(JSRuntime *rt)
} }
if (!rt->gcShouldCleanUpEverything) { if (!rt->gcShouldCleanUpEverything) {
#ifdef JS_ION
if (JSCompartment *comp = jit::TopmostJitActivationCompartment(rt)) if (JSCompartment *comp = jit::TopmostJitActivationCompartment(rt))
comp->zone()->setPreservingCode(true); comp->zone()->setPreservingCode(true);
#endif
} }
/* /*

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

@ -351,6 +351,26 @@ TypeSet::mightBeMIRType(jit::MIRType type)
} }
} }
bool
TypeSet::objectsAreSubset(TypeSet *other)
{
if (other->unknownObject())
return true;
if (unknownObject())
return false;
for (unsigned i = 0; i < getObjectCount(); i++) {
TypeObjectKey *obj = getObject(i);
if (!obj)
continue;
if (!other->hasType(Type::ObjectType(obj)))
return false;
}
return true;
}
bool bool
TypeSet::isSubset(TypeSet *other) TypeSet::isSubset(TypeSet *other)
{ {

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

@ -584,6 +584,12 @@ class TypeSet
*/ */
bool isSubset(TypeSet *other); bool isSubset(TypeSet *other);
/*
* Get whether the objects in this TypeSet are a subset of the objects
* in other.
*/
bool objectsAreSubset(TypeSet *other);
/* Forward all types in this set to the specified constraint. */ /* Forward all types in this set to the specified constraint. */
bool addTypesToConstraint(JSContext *cx, TypeConstraint *constraint); bool addTypesToConstraint(JSContext *cx, TypeConstraint *constraint);

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

@ -463,7 +463,7 @@ js::math_imul(JSContext *cx, unsigned argc, Value *vp)
// Implements Math.fround (20.2.2.16) up to step 3 // Implements Math.fround (20.2.2.16) up to step 3
bool bool
js::RoundFloat32(JSContext *cx, Handle<Value> v, float *out) js::RoundFloat32(JSContext *cx, HandleValue v, float *out)
{ {
double d; double d;
bool success = ToNumber(cx, v, &d); bool success = ToNumber(cx, v, &d);
@ -471,6 +471,17 @@ js::RoundFloat32(JSContext *cx, Handle<Value> v, float *out)
return success; return success;
} }
bool
js::RoundFloat32(JSContext *cx, HandleValue arg, MutableHandleValue res)
{
float f;
if (!RoundFloat32(cx, arg, &f))
return false;
res.setDouble(static_cast<double>(f));
return true;
}
bool bool
js::math_fround(JSContext *cx, unsigned argc, Value *vp) js::math_fround(JSContext *cx, unsigned argc, Value *vp)
{ {

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

@ -110,7 +110,10 @@ extern bool
math_imul(JSContext *cx, unsigned argc, js::Value *vp); math_imul(JSContext *cx, unsigned argc, js::Value *vp);
extern bool extern bool
RoundFloat32(JSContext *cx, Handle<Value> v, float *out); RoundFloat32(JSContext *cx, HandleValue v, float *out);
extern bool
RoundFloat32(JSContext *cx, HandleValue arg, MutableHandleValue res);
extern bool extern bool
math_fround(JSContext *cx, unsigned argc, js::Value *vp); math_fround(JSContext *cx, unsigned argc, js::Value *vp);

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

@ -1003,7 +1003,7 @@ js::DefineProperties(JSContext *cx, HandleObject obj, HandleObject props)
bool dummy; bool dummy;
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>()); Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
for (size_t i = 0, len = ids.length(); i < len; i++) { for (size_t i = 0, len = ids.length(); i < len; i++) {
if (!DefinePropertyOnArray(cx, arr, ids.handleAt(i), descs[i], true, &dummy)) if (!DefinePropertyOnArray(cx, arr, ids[i], descs[i], true, &dummy))
return false; return false;
} }
return true; return true;
@ -1017,7 +1017,7 @@ js::DefineProperties(JSContext *cx, HandleObject obj, HandleObject props)
if (obj->is<ProxyObject>()) { if (obj->is<ProxyObject>()) {
for (size_t i = 0, len = ids.length(); i < len; i++) { for (size_t i = 0, len = ids.length(); i < len; i++) {
RootedValue pd(cx, descs[i].pd()); RootedValue pd(cx, descs[i].pd());
if (!Proxy::defineProperty(cx, obj, ids.handleAt(i), pd)) if (!Proxy::defineProperty(cx, obj, ids[i], pd))
return false; return false;
} }
return true; return true;
@ -1028,7 +1028,7 @@ js::DefineProperties(JSContext *cx, HandleObject obj, HandleObject props)
bool dummy; bool dummy;
for (size_t i = 0, len = ids.length(); i < len; i++) { for (size_t i = 0, len = ids.length(); i < len; i++) {
if (!DefinePropertyOnObject(cx, obj, ids.handleAt(i), descs[i], true, &dummy)) if (!DefinePropertyOnObject(cx, obj, ids[i], descs[i], true, &dummy))
return false; return false;
} }
@ -1743,7 +1743,7 @@ JS_CopyPropertiesFrom(JSContext *cx, HandleObject target, HandleObject obj)
return false; return false;
for (size_t i = 0; i < props.length(); ++i) { for (size_t i = 0; i < props.length(); ++i) {
if (!JS_CopyPropertyFrom(cx, props.handleAt(i), target, obj)) if (!JS_CopyPropertyFrom(cx, props[i], target, obj))
return false; return false;
} }
@ -2013,7 +2013,7 @@ js::XDRObjectLiteral(XDRState<mode> *xdr, MutableHandleObject obj)
} }
JS_ASSERT(it.front().hasDefaultGetter()); JS_ASSERT(it.front().hasDefaultGetter());
ids[it.front().slot()] = it.front().propid(); ids[it.front().slot()].set(it.front().propid());
} }
} }

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

@ -243,7 +243,7 @@ BaseProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
if (!getOwnPropertyDescriptor(cx, proxy, id, &desc)) if (!getOwnPropertyDescriptor(cx, proxy, id, &desc))
return false; return false;
if (desc.object() && desc.isEnumerable()) if (desc.object() && desc.isEnumerable())
props[i++] = id; props[i++].set(id);
} }
JS_ASSERT(i <= props.length()); JS_ASSERT(i <= props.length());
@ -1582,7 +1582,7 @@ ArrayToIdVector(JSContext *cx, HandleObject proxy, HandleObject target, HandleVa
// step iii // step iii
for (uint32_t j = 0; j < i; ++j) { for (uint32_t j = 0; j < i; ++j) {
if (props[j] == id) { if (props[j].get() == id) {
ReportInvalidTrapResult(cx, proxy, trapName); ReportInvalidTrapResult(cx, proxy, trapName);
return false; return false;
} }
@ -1618,7 +1618,7 @@ ArrayToIdVector(JSContext *cx, HandleObject proxy, HandleObject target, HandleVa
bool found = false; bool found = false;
for (size_t j = 0; j < props.length(); ++j) { for (size_t j = 0; j < props.length(); ++j) {
if (props[j] == id) { if (props[j].get() == id) {
found = true; found = true;
break; break;
} }
@ -2453,7 +2453,7 @@ js::AppendUnique(JSContext *cx, AutoIdVector &base, AutoIdVector &others)
for (size_t i = 0; i < others.length(); ++i) { for (size_t i = 0; i < others.length(); ++i) {
bool unique = true; bool unique = true;
for (size_t j = 0; j < base.length(); ++j) { for (size_t j = 0; j < base.length(); ++j) {
if (others[i] == base[j]) { if (others[i].get() == base[j]) {
unique = false; unique = false;
break; break;
} }

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