зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
e19d488d7d
|
@ -52,13 +52,15 @@ B2GAboutRedirector.prototype = {
|
|||
return flags | Ci.nsIAboutModule.ALLOW_SCRIPT;
|
||||
},
|
||||
|
||||
newChannel: function(aURI) {
|
||||
newChannel: function(aURI, aLoadInfo) {
|
||||
let moduleInfo = this._getModuleInfo(aURI);
|
||||
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
|
||||
var channel = ios.newChannel(moduleInfo.uri, null, null);
|
||||
var newURI = ios.newURI(moduleInfo.uri, null, null);
|
||||
|
||||
var channel = ios.newChannelFromURIWithLoadInfo(newURI, aLoadInfo);
|
||||
|
||||
if (!moduleInfo.privileged) {
|
||||
// Setting the owner to null means that we'll go through the normal
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
struct MOZ_NONHEAP_CLASS NonHeap {
|
||||
int i;
|
||||
void *operator new(size_t x) { return 0; }
|
||||
void *operator new(size_t x) throw() { return 0; }
|
||||
void *operator new(size_t blah, char *buffer) { return buffer; }
|
||||
};
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
struct MOZ_STACK_CLASS Stack {
|
||||
int i;
|
||||
void *operator new(size_t x) { return 0; }
|
||||
void *operator new(size_t x) throw() { return 0; }
|
||||
void *operator new(size_t blah, char *buffer) { return buffer; }
|
||||
};
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "nsCycleCollector.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
@ -3079,6 +3080,28 @@ WrappedJSToDictionary(JSContext* aCx, nsISupports* aObject, T& aDictionary)
|
|||
return aDictionary.Init(aCx, v);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline bool
|
||||
WrappedJSToDictionary(nsISupports* aObject, T& aDictionary)
|
||||
{
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(aObject);
|
||||
NS_ENSURE_TRUE(wrappedObj, false);
|
||||
JS::Rooted<JSObject*> obj(CycleCollectedJSRuntime::Get()->Runtime(),
|
||||
wrappedObj->GetJSObject());
|
||||
NS_ENSURE_TRUE(obj, false);
|
||||
|
||||
nsIGlobalObject* global = xpc::NativeGlobal(obj);
|
||||
NS_ENSURE_TRUE(global, false);
|
||||
|
||||
// we need this AutoEntryScript here because the spec requires us to execute
|
||||
// getters when parsing a dictionary
|
||||
AutoEntryScript aes(global);
|
||||
aes.TakeOwnershipOfErrorReporting();
|
||||
|
||||
JS::Rooted<JS::Value> v(aes.cx(), JS::ObjectValue(*obj));
|
||||
return aDictionary.Init(aes.cx(), v);
|
||||
}
|
||||
|
||||
|
||||
template<class T, class S>
|
||||
inline nsRefPtr<T>
|
||||
|
|
|
@ -2027,7 +2027,8 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
|
|||
mAudioChannelFaded(false),
|
||||
mPlayingThroughTheAudioChannel(false),
|
||||
mDisableVideo(false),
|
||||
mWaitingFor(MediaWaitingFor::None)
|
||||
mWaitingFor(MediaWaitingFor::None),
|
||||
mElementInTreeState(ELEMENT_NOT_INTREE)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (!gMediaElementLog) {
|
||||
|
@ -2479,8 +2480,14 @@ nsresult HTMLMediaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParen
|
|||
UpdatePreloadAction();
|
||||
}
|
||||
if (mDecoder) {
|
||||
mDecoder->SetDormantIfNecessary(false);
|
||||
// When the MediaElement is binding to tree, the dormant status is
|
||||
// aligned to document's hidden status.
|
||||
nsIDocument* ownerDoc = OwnerDoc();
|
||||
if (ownerDoc) {
|
||||
mDecoder->SetDormantIfNecessary(ownerDoc->Hidden());
|
||||
}
|
||||
}
|
||||
mElementInTreeState = ELEMENT_INTREE;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -2494,6 +2501,7 @@ void HTMLMediaElement::UnbindFromTree(bool aDeep,
|
|||
if (mDecoder) {
|
||||
mDecoder->SetDormantIfNecessary(true);
|
||||
}
|
||||
mElementInTreeState = ELEMENT_NOT_INTREE_HAD_INTREE;
|
||||
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
}
|
||||
|
@ -3561,7 +3569,15 @@ void HTMLMediaElement::NotifyOwnerDocumentActivityChanged()
|
|||
|
||||
if (mDecoder) {
|
||||
mDecoder->SetElementVisibility(!ownerDoc->Hidden());
|
||||
mDecoder->SetDormantIfNecessary(ownerDoc->Hidden());
|
||||
|
||||
if (mElementInTreeState == ELEMENT_NOT_INTREE_HAD_INTREE) {
|
||||
mDecoder->SetDormantIfNecessary(true);
|
||||
} else if (mElementInTreeState == ELEMENT_NOT_INTREE ||
|
||||
mElementInTreeState == ELEMENT_INTREE) {
|
||||
// The MediaElement had never been binded to tree, or in the tree now,
|
||||
// align to document.
|
||||
mDecoder->SetDormantIfNecessary(ownerDoc->Hidden());
|
||||
}
|
||||
}
|
||||
|
||||
// SetVisibilityState will update mMuted with MUTED_BY_AUDIO_CHANNEL via the
|
||||
|
|
|
@ -1297,6 +1297,19 @@ protected:
|
|||
nsRefPtr<VideoTrackList> mVideoTrackList;
|
||||
|
||||
MediaWaitingFor mWaitingFor;
|
||||
|
||||
enum ElementInTreeState {
|
||||
// The MediaElement is not in the DOM tree now.
|
||||
ELEMENT_NOT_INTREE,
|
||||
// The MediaElement is in the DOM tree now.
|
||||
ELEMENT_INTREE,
|
||||
// The MediaElement is not in the DOM tree now but had been binded to the
|
||||
// tree before.
|
||||
ELEMENT_NOT_INTREE_HAD_INTREE
|
||||
};
|
||||
|
||||
ElementInTreeState mElementInTreeState;
|
||||
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -165,6 +165,8 @@ public:
|
|||
std::max(mEnd, aByteRange.mEnd));
|
||||
}
|
||||
|
||||
int64_t Length() { return mEnd - mStart; }
|
||||
|
||||
int64_t mStart, mEnd;
|
||||
};
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MP4Reader.h"
|
||||
#include "MP4Stream.h"
|
||||
#include "MediaResource.h"
|
||||
#include "nsSize.h"
|
||||
#include "VideoUtils.h"
|
||||
|
@ -62,63 +63,6 @@ TrackTypeToStr(TrackType aTrack)
|
|||
}
|
||||
#endif
|
||||
|
||||
class MP4Stream : public Stream {
|
||||
public:
|
||||
|
||||
explicit MP4Stream(MediaResource* aResource)
|
||||
: mResource(aResource)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MP4Stream);
|
||||
MOZ_ASSERT(aResource);
|
||||
}
|
||||
virtual ~MP4Stream() {
|
||||
MOZ_COUNT_DTOR(MP4Stream);
|
||||
}
|
||||
|
||||
virtual bool ReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
|
||||
size_t* aBytesRead) MOZ_OVERRIDE
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
uint32_t bytesRead = 0;
|
||||
do {
|
||||
uint64_t offset = aOffset + sum;
|
||||
char* buffer = reinterpret_cast<char*>(aBuffer) + sum;
|
||||
uint32_t toRead = aCount - sum;
|
||||
nsresult rv = mResource->ReadAt(offset, buffer, toRead, &bytesRead);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
sum += bytesRead;
|
||||
} while (sum < aCount && bytesRead > 0);
|
||||
*aBytesRead = sum;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool CachedReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
|
||||
size_t* aBytesRead) MOZ_OVERRIDE
|
||||
{
|
||||
nsresult rv = mResource->ReadFromCache(reinterpret_cast<char*>(aBuffer),
|
||||
aOffset, aCount);
|
||||
if (NS_FAILED(rv)) {
|
||||
*aBytesRead = 0;
|
||||
return false;
|
||||
}
|
||||
*aBytesRead = aCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool Length(int64_t* aSize) MOZ_OVERRIDE
|
||||
{
|
||||
if (mResource->GetLength() < 0)
|
||||
return false;
|
||||
*aSize = mResource->GetLength();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<MediaResource> mResource;
|
||||
};
|
||||
|
||||
MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
|
||||
: MediaDecoderReader(aDecoder)
|
||||
, mAudio(MediaData::AUDIO_DATA, Preferences::GetUint("media.mp4-audio-decode-ahead", 2))
|
||||
|
@ -688,7 +632,9 @@ MP4Reader::ResetDecode()
|
|||
{
|
||||
MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
|
||||
Flush(kVideo);
|
||||
mDemuxer->SeekVideo(0);
|
||||
Flush(kAudio);
|
||||
mDemuxer->SeekAudio(0);
|
||||
return MediaDecoderReader::ResetDecode();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MP4Stream.h"
|
||||
#include "MediaResource.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MP4Stream::MP4Stream(MediaResource* aResource) : mResource(aResource)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MP4Stream);
|
||||
MOZ_ASSERT(aResource);
|
||||
}
|
||||
|
||||
MP4Stream::~MP4Stream()
|
||||
{
|
||||
MOZ_COUNT_DTOR(MP4Stream);
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Stream::ReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
|
||||
size_t* aBytesRead)
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
uint32_t bytesRead = 0;
|
||||
do {
|
||||
uint64_t offset = aOffset + sum;
|
||||
char* buffer = reinterpret_cast<char*>(aBuffer) + sum;
|
||||
uint32_t toRead = aCount - sum;
|
||||
nsresult rv = mResource->ReadAt(offset, buffer, toRead, &bytesRead);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
sum += bytesRead;
|
||||
} while (sum < aCount && bytesRead > 0);
|
||||
*aBytesRead = sum;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Stream::CachedReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
|
||||
size_t* aBytesRead)
|
||||
{
|
||||
nsresult rv = mResource->ReadFromCache(reinterpret_cast<char*>(aBuffer),
|
||||
aOffset, aCount);
|
||||
if (NS_FAILED(rv)) {
|
||||
*aBytesRead = 0;
|
||||
return false;
|
||||
}
|
||||
*aBytesRead = aCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4Stream::Length(int64_t* aSize)
|
||||
{
|
||||
if (mResource->GetLength() < 0)
|
||||
return false;
|
||||
*aSize = mResource->GetLength();
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MP4_STREAM_H_
|
||||
#define MP4_STREAM_H_
|
||||
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MediaResource;
|
||||
|
||||
class MP4Stream : public mp4_demuxer::Stream {
|
||||
public:
|
||||
explicit MP4Stream(MediaResource* aResource);
|
||||
virtual ~MP4Stream();
|
||||
virtual bool ReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
|
||||
size_t* aBytesRead) MOZ_OVERRIDE;
|
||||
virtual bool CachedReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
|
||||
size_t* aBytesRead) MOZ_OVERRIDE;
|
||||
virtual bool Length(int64_t* aSize) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
nsRefPtr<MediaResource> mResource;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -7,6 +7,7 @@
|
|||
EXPORTS += [
|
||||
'MP4Decoder.h',
|
||||
'MP4Reader.h',
|
||||
'MP4Stream.h',
|
||||
'PlatformDecoderModule.h',
|
||||
'SharedDecoderManager.h',
|
||||
]
|
||||
|
@ -14,6 +15,7 @@ EXPORTS += [
|
|||
UNIFIED_SOURCES += [
|
||||
'BlankDecoderModule.cpp',
|
||||
'MP4Decoder.cpp',
|
||||
'MP4Stream.cpp',
|
||||
'PlatformDecoderModule.cpp',
|
||||
'SharedDecoderManager.cpp',
|
||||
]
|
||||
|
|
|
@ -16,8 +16,11 @@ GMPDecryptorParent::GMPDecryptorParent(GMPParent* aPlugin)
|
|||
, mShuttingDown(false)
|
||||
, mPlugin(aPlugin)
|
||||
, mCallback(nullptr)
|
||||
#ifdef DEBUG
|
||||
, mGMPThread(aPlugin->GMPThread())
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(mPlugin);
|
||||
MOZ_ASSERT(mPlugin && mGMPThread);
|
||||
}
|
||||
|
||||
GMPDecryptorParent::~GMPDecryptorParent()
|
||||
|
@ -312,7 +315,7 @@ GMPDecryptorParent::RecvDecrypted(const uint32_t& aId,
|
|||
void
|
||||
GMPDecryptorParent::Close()
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
MOZ_ASSERT(mGMPThread == NS_GetCurrentThread());
|
||||
// Consumer is done with us; we can shut down. No more callbacks should
|
||||
// be made to mCallback. Note: do this before Shutdown()!
|
||||
mCallback = nullptr;
|
||||
|
@ -320,14 +323,14 @@ GMPDecryptorParent::Close()
|
|||
|
||||
// In case this is the last reference
|
||||
nsRefPtr<GMPDecryptorParent> kungfudeathgrip(this);
|
||||
NS_RELEASE(kungfudeathgrip);
|
||||
this->Release();
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void
|
||||
GMPDecryptorParent::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
|
||||
MOZ_ASSERT(mGMPThread == NS_GetCurrentThread());
|
||||
|
||||
if (mShuttingDown) {
|
||||
return;
|
||||
|
|
|
@ -109,6 +109,9 @@ private:
|
|||
bool mShuttingDown;
|
||||
nsRefPtr<GMPParent> mPlugin;
|
||||
GMPDecryptorProxyCallback* mCallback;
|
||||
#ifdef DEBUG
|
||||
nsIThread* const mGMPThread;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
|
|
|
@ -0,0 +1,328 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
#include "MP4Stream.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "MockMediaResource.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mp4_demuxer;
|
||||
|
||||
class MP4DemuxerBinding
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MP4DemuxerBinding);
|
||||
|
||||
nsRefPtr<MockMediaResource> resource;
|
||||
nsAutoPtr<MP4Demuxer> demuxer;
|
||||
|
||||
explicit MP4DemuxerBinding(const char* aFileName = "dash_dashinit.mp4")
|
||||
: resource(new MockMediaResource(aFileName))
|
||||
, demuxer(new MP4Demuxer(new MP4Stream(resource)))
|
||||
{
|
||||
EXPECT_EQ(NS_OK, resource->Open(nullptr));
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~MP4DemuxerBinding()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
TEST(MP4Demuxer, Seek)
|
||||
{
|
||||
nsRefPtr<MP4DemuxerBinding> b = new MP4DemuxerBinding();
|
||||
MP4Demuxer* d = b->demuxer;
|
||||
|
||||
EXPECT_TRUE(d->Init());
|
||||
|
||||
nsTArray<nsAutoPtr<MP4Sample>> samples;
|
||||
MP4Sample* sample;
|
||||
while (!!(sample = d->DemuxVideoSample())) {
|
||||
samples.AppendElement(sample);
|
||||
if (samples.Length() >= 2) {
|
||||
EXPECT_LT(samples[samples.Length() - 2]->decode_timestamp,
|
||||
samples[samples.Length() - 1]->decode_timestamp);
|
||||
}
|
||||
}
|
||||
Microseconds keyFrame = 0;
|
||||
for (size_t i = 0; i < samples.Length(); i++) {
|
||||
if (samples[i]->is_sync_point) {
|
||||
keyFrame = samples[i]->decode_timestamp;
|
||||
}
|
||||
d->SeekVideo(samples[i]->composition_timestamp);
|
||||
sample = d->DemuxVideoSample();
|
||||
EXPECT_EQ(keyFrame, sample->decode_timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
static nsCString
|
||||
ToCryptoString(CryptoSample& aCrypto)
|
||||
{
|
||||
nsCString res;
|
||||
if (aCrypto.valid) {
|
||||
res.AppendPrintf("%d %d ", aCrypto.mode, aCrypto.iv_size);
|
||||
for (size_t i = 0; i < aCrypto.key.Length(); i++) {
|
||||
res.AppendPrintf("%02x", aCrypto.key[i]);
|
||||
}
|
||||
res.Append(" ");
|
||||
for (size_t i = 0; i < aCrypto.iv.Length(); i++) {
|
||||
res.AppendPrintf("%02x", aCrypto.iv[i]);
|
||||
}
|
||||
EXPECT_EQ(aCrypto.plain_sizes.Length(), aCrypto.encrypted_sizes.Length());
|
||||
for (size_t i = 0; i < aCrypto.plain_sizes.Length(); i++) {
|
||||
res.AppendPrintf(" %d,%d", aCrypto.plain_sizes[i],
|
||||
aCrypto.encrypted_sizes[i]);
|
||||
}
|
||||
} else {
|
||||
res.Append("no crypto");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
TEST(MP4Demuxer, CENC)
|
||||
{
|
||||
nsRefPtr<MP4DemuxerBinding> b = new MP4DemuxerBinding("short-cenc.mp4");
|
||||
MP4Demuxer* d = b->demuxer;
|
||||
|
||||
EXPECT_TRUE(d->Init());
|
||||
|
||||
const char* video[] = {
|
||||
"1 16 7e571d017e571d017e571d017e571d01 00000000000000000000000000000000 5,686 5,388",
|
||||
"1 16 7e571d017e571d017e571d017e571d01 00000000000000000000000000000044 5,717",
|
||||
"1 16 7e571d017e571d017e571d017e571d01 00000000000000000000000000000071 5,613",
|
||||
"1 16 7e571d017e571d017e571d017e571d01 00000000000000000000000000000098 5,196",
|
||||
"1 16 7e571d017e571d017e571d017e571d01 000000000000000000000000000000a5 5,213",
|
||||
"1 16 7e571d017e571d017e571d017e571d01 000000000000000000000000000000b3 5,213",
|
||||
"1 16 7e571d017e571d017e571d017e571d01 000000000000000000000000000000c1 5,384",
|
||||
"1 16 7e571d017e571d017e571d017e571d01 000000000000000000000000000000d9 5,256",
|
||||
"1 16 7e571d017e571d017e571d017e571d01 000000000000000000000000000000e9 5,245",
|
||||
"1 16 7e571d017e571d017e571d017e571d01 000000000000000000000000000000f9 5,251",
|
||||
};
|
||||
|
||||
MP4Sample* sample;
|
||||
size_t i = 0;
|
||||
while (!!(sample = d->DemuxVideoSample())) {
|
||||
nsCString text = ToCryptoString(sample->crypto);
|
||||
EXPECT_STREQ(video[i++], text.get());
|
||||
}
|
||||
EXPECT_EQ(ArrayLength(video), i);
|
||||
|
||||
const char* audio[] = {
|
||||
"1 16 7e571d027e571d027e571d027e571d02 00000000000000000000000000000000 0,371",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 00000000000000000000000000000018 0,372",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 00000000000000000000000000000030 0,371",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 00000000000000000000000000000048 0,372",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 00000000000000000000000000000060 0,371",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 00000000000000000000000000000078 0,372",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 00000000000000000000000000000090 0,371",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 000000000000000000000000000000a8 0,372",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 000000000000000000000000000000c0 0,371",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 000000000000000000000000000000d8 0,372",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 000000000000000000000000000000f0 0,371",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 00000000000000000000000000000108 0,372",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 00000000000000000000000000000120 0,371",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 00000000000000000000000000000138 0,372",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 00000000000000000000000000000150 0,371",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 00000000000000000000000000000168 0,372",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 00000000000000000000000000000180 0,371",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 00000000000000000000000000000198 0,372",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 000000000000000000000000000001b0 0,371",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 000000000000000000000000000001c8 0,372",
|
||||
"1 16 7e571d027e571d027e571d027e571d02 000000000000000000000000000001e0 0,371",
|
||||
};
|
||||
|
||||
i = 0;
|
||||
while (!!(sample = d->DemuxAudioSample())) {
|
||||
nsCString text = ToCryptoString(sample->crypto);
|
||||
EXPECT_STREQ(audio[i++], text.get());
|
||||
}
|
||||
EXPECT_EQ(ArrayLength(audio), i);
|
||||
}
|
||||
|
||||
TEST(MP4Demuxer, CENCFrag)
|
||||
{
|
||||
nsRefPtr<MP4DemuxerBinding> b = new MP4DemuxerBinding("gizmo-frag.mp4");
|
||||
MP4Demuxer* d = b->demuxer;
|
||||
|
||||
EXPECT_TRUE(d->Init());
|
||||
|
||||
const char* video[] = {
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000000 5,684 5,16980",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000450 5,1826",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000004c3 5,1215",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 0000000000000000000000000000050f 5,1302",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000561 5,939",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 0000000000000000000000000000059c 5,763",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000005cc 5,672",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000005f6 5,748",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000625 5,1025",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000666 5,730",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000694 5,897",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000006cd 5,643",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000006f6 5,556",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000719 5,527",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 0000000000000000000000000000073a 5,606",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000760 5,701",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 0000000000000000000000000000078c 5,531",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000007ae 5,562",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000007d2 5,576",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000007f6 5,514",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000817 5,404",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000831 5,635",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000859 5,433",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000875 5,478",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000893 5,474",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000008b1 5,462",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000008ce 5,473",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000008ec 5,437",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000908 5,418",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000923 5,475",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000941 5,23133",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000ee7 5,475",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000f05 5,402",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000f1f 5,415",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000f39 5,408",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000f53 5,442",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000f6f 5,385",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000f88 5,368",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000f9f 5,354",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000fb6 5,400",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000fcf 5,399",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000fe8 5,1098",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 0000000000000000000000000000102d 5,1508",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 0000000000000000000000000000108c 5,1345",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000010e1 5,1945",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 0000000000000000000000000000115b 5,1824",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000011cd 5,2133",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000001253 5,2486",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000012ef 5,1739",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 0000000000000000000000000000135c 5,1836",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000013cf 5,2367",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000001463 5,2571",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000001504 5,3008",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000015c0 5,3255",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 0000000000000000000000000000168c 5,3225",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000001756 5,3118",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000001819 5,2407",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000018b0 5,2400",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000001946 5,2158",
|
||||
"1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000019cd 5,2392",
|
||||
};
|
||||
|
||||
MP4Sample* sample;
|
||||
size_t i = 0;
|
||||
while (!!(sample = d->DemuxVideoSample())) {
|
||||
nsCString text = ToCryptoString(sample->crypto);
|
||||
EXPECT_STREQ(video[i++], text.get());
|
||||
}
|
||||
EXPECT_EQ(ArrayLength(video), i);
|
||||
|
||||
const char* audio[] = {
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000000 0,281",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000012 0,257",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000023 0,246",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000033 0,257",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000044 0,260",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000055 0,260",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000066 0,272",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000077 0,280",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000089 0,284",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000009b 0,290",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000000ae 0,278",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000000c0 0,268",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000000d1 0,307",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000000e5 0,290",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000000f8 0,304",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000010b 0,316",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000011f 0,308",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000133 0,301",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000146 0,318",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000015a 0,311",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000016e 0,303",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000181 0,325",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000196 0,334",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000001ab 0,344",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000001c1 0,344",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000001d7 0,387",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000001f0 0,396",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000209 0,368",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000220 0,373",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000238 0,425",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000253 0,428",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000026e 0,426",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000289 0,427",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000002a4 0,424",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000002bf 0,447",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000002db 0,446",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000002f7 0,442",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000313 0,444",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000032f 0,374",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000347 0,405",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000361 0,372",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000379 0,395",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000392 0,435",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000003ae 0,426",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000003c9 0,430",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000003e4 0,390",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000003fd 0,335",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000412 0,339",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000428 0,352",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000043e 0,364",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000455 0,398",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000046e 0,451",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000048b 0,448",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000004a7 0,436",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000004c3 0,424",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000004de 0,428",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000004f9 0,413",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000513 0,430",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000052e 0,450",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000054b 0,386",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000564 0,320",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000578 0,347",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000058e 0,382",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000005a6 0,437",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000005c2 0,387",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000005db 0,340",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000005f1 0,337",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000607 0,389",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000620 0,428",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000063b 0,426",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000656 0,446",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000672 0,456",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000068f 0,468",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000006ad 0,468",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000006cb 0,463",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000006e8 0,467",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000706 0,460",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000723 0,446",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000073f 0,453",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000075c 0,448",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000778 0,446",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000794 0,439",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000007b0 0,436",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000007cc 0,441",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000007e8 0,465",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000806 0,448",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000822 0,448",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000083e 0,469",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000085c 0,431",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000877 0,437",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000893 0,474",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000008b1 0,436",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000008cd 0,433",
|
||||
"1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000008e9 0,481",
|
||||
};
|
||||
|
||||
i = 0;
|
||||
while (!!(sample = d->DemuxAudioSample())) {
|
||||
nsCString text = ToCryptoString(sample->crypto);
|
||||
EXPECT_STREQ(audio[i++], text.get());
|
||||
}
|
||||
EXPECT_EQ(ArrayLength(audio), i);
|
||||
}
|
Двоичный файл не отображается.
|
@ -4,10 +4,11 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
SOURCES += [
|
||||
'MockMediaResource.cpp',
|
||||
'TestAudioCompactor.cpp',
|
||||
'TestGMPCrossOrigin.cpp',
|
||||
'TestMP4Demuxer.cpp',
|
||||
'TestMP4Reader.cpp',
|
||||
'TestTrackEncoder.cpp',
|
||||
'TestVideoSegment.cpp',
|
||||
|
@ -15,14 +16,17 @@ UNIFIED_SOURCES += [
|
|||
]
|
||||
|
||||
if CONFIG['MOZ_WEBM_ENCODER']:
|
||||
UNIFIED_SOURCES += [
|
||||
SOURCES += [
|
||||
'TestVideoTrackEncoder.cpp',
|
||||
'TestVorbisTrackEncoder.cpp',
|
||||
'TestWebMWriter.cpp',
|
||||
]
|
||||
|
||||
TEST_HARNESS_FILES.gtest += [
|
||||
'../test/gizmo-frag.mp4',
|
||||
'../test/gizmo.mp4',
|
||||
'../test/short-cenc.mp4',
|
||||
'dash_dashinit.mp4',
|
||||
'mediasource_test.mp4',
|
||||
'test.webm',
|
||||
]
|
||||
|
|
Двоичный файл не отображается.
|
@ -1404,14 +1404,6 @@ PluginModuleParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs
|
|||
}
|
||||
TimeStamp callNpInitEnd = TimeStamp::Now();
|
||||
mTimeBlocked += (callNpInitEnd - callNpInitStart);
|
||||
/** mTimeBlocked measures the time that the main thread has been blocked
|
||||
* on plugin module initialization. As implemented, this is the sum of
|
||||
* plugin-container launch + NP_Initialize
|
||||
*/
|
||||
Telemetry::Accumulate(Telemetry::BLOCKED_ON_PLUGIN_MODULE_INIT_MS,
|
||||
GetHistogramKey(),
|
||||
static_cast<uint32_t>(mTimeBlocked.ToMilliseconds()));
|
||||
mTimeBlocked = TimeDuration();
|
||||
}
|
||||
|
||||
SetPluginFuncs(pFuncs);
|
||||
|
@ -1472,17 +1464,6 @@ PluginModuleChromeParent::NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error)
|
|||
InitializeInjector();
|
||||
#endif
|
||||
|
||||
/** This Accumulate must be placed below the call to InitializeInjector()
|
||||
* because mTimeBlocked is modified in that function.
|
||||
* mTimeBlocked measures the time that the main thread has been blocked
|
||||
* on plugin module initialization. As implemented, this is the sum of
|
||||
* plugin-container launch + toolhelp32 snapshot + NP_Initialize
|
||||
*/
|
||||
Telemetry::Accumulate(Telemetry::BLOCKED_ON_PLUGIN_MODULE_INIT_MS,
|
||||
GetHistogramKey(),
|
||||
static_cast<uint32_t>(mTimeBlocked.ToMilliseconds()));
|
||||
mTimeBlocked = TimeDuration();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
@ -1574,6 +1555,16 @@ PluginModuleParent::NPP_New(NPMIMEType pluginType, NPP instance,
|
|||
|
||||
if (mPluginName.IsEmpty()) {
|
||||
GetPluginDetails(mPluginName, mPluginVersion);
|
||||
/** mTimeBlocked measures the time that the main thread has been blocked
|
||||
* on plugin module initialization. As implemented, this is the sum of
|
||||
* plugin-container launch + toolhelp32 snapshot + NP_Initialize.
|
||||
* We don't accumulate its value until here because the plugin info
|
||||
* is not available until *after* NP_Initialize.
|
||||
*/
|
||||
Telemetry::Accumulate(Telemetry::BLOCKED_ON_PLUGIN_MODULE_INIT_MS,
|
||||
GetHistogramKey(),
|
||||
static_cast<uint32_t>(mTimeBlocked.ToMilliseconds()));
|
||||
mTimeBlocked = TimeDuration();
|
||||
}
|
||||
|
||||
// create the instance on the other side
|
||||
|
|
|
@ -175,6 +175,16 @@ class CompositableTextureRef {
|
|||
public:
|
||||
CompositableTextureRef() {}
|
||||
|
||||
explicit CompositableTextureRef(const CompositableTextureRef& aOther)
|
||||
{
|
||||
*this = aOther;
|
||||
}
|
||||
|
||||
explicit CompositableTextureRef(T* aOther)
|
||||
{
|
||||
*this = aOther;
|
||||
}
|
||||
|
||||
~CompositableTextureRef()
|
||||
{
|
||||
if (mRef) {
|
||||
|
@ -182,6 +192,18 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
CompositableTextureRef& operator=(const CompositableTextureRef& aOther)
|
||||
{
|
||||
if (aOther.get()) {
|
||||
aOther->AddCompositableRef();
|
||||
}
|
||||
if (mRef) {
|
||||
mRef->ReleaseCompositableRef();
|
||||
}
|
||||
mRef = aOther.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
CompositableTextureRef& operator=(const TemporaryRef<T>& aOther)
|
||||
{
|
||||
RefPtr<T> temp = aOther;
|
||||
|
|
|
@ -41,7 +41,8 @@ TiledLayerBufferComposite::RecycleCallback(TextureHost* textureHost, void* aClos
|
|||
|
||||
TiledLayerBufferComposite::TiledLayerBufferComposite(ISurfaceAllocator* aAllocator,
|
||||
const SurfaceDescriptorTiles& aDescriptor,
|
||||
const nsIntRegion& aOldPaintedRegion)
|
||||
const nsIntRegion& aOldPaintedRegion,
|
||||
Compositor* aCompositor)
|
||||
{
|
||||
mIsValid = true;
|
||||
mHasDoubleBufferedTiles = false;
|
||||
|
@ -61,8 +62,8 @@ TiledLayerBufferComposite::TiledLayerBufferComposite(ISurfaceAllocator* aAllocat
|
|||
|
||||
const InfallibleTArray<TileDescriptor>& tiles = aDescriptor.tiles();
|
||||
for(size_t i = 0; i < tiles.Length(); i++) {
|
||||
RefPtr<TextureHost> texture;
|
||||
RefPtr<TextureHost> textureOnWhite;
|
||||
CompositableTextureHostRef texture;
|
||||
CompositableTextureHostRef textureOnWhite;
|
||||
const TileDescriptor& tileDesc = tiles[i];
|
||||
switch (tileDesc.type()) {
|
||||
case TileDescriptor::TTexturedTileDescriptor : {
|
||||
|
@ -94,7 +95,21 @@ TiledLayerBufferComposite::TiledLayerBufferComposite(ISurfaceAllocator* aAllocat
|
|||
}
|
||||
}
|
||||
|
||||
mRetainedTiles.AppendElement(TileHost(sharedLock, texture, textureOnWhite));
|
||||
CompositableTextureSourceRef textureSource;
|
||||
CompositableTextureSourceRef textureSourceOnWhite;
|
||||
if (texture) {
|
||||
texture->SetCompositor(aCompositor);
|
||||
texture->PrepareTextureSource(textureSource);
|
||||
}
|
||||
if (textureOnWhite) {
|
||||
textureOnWhite->SetCompositor(aCompositor);
|
||||
textureOnWhite->PrepareTextureSource(textureSourceOnWhite);
|
||||
}
|
||||
mRetainedTiles.AppendElement(TileHost(sharedLock,
|
||||
texture.get(),
|
||||
textureOnWhite.get(),
|
||||
textureSource.get(),
|
||||
textureSourceOnWhite.get()));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -130,6 +145,8 @@ TiledLayerBufferComposite::ReleaseTextureHosts()
|
|||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
mRetainedTiles[i].mTextureHost = nullptr;
|
||||
mRetainedTiles[i].mTextureHostOnWhite = nullptr;
|
||||
mRetainedTiles[i].mTextureSource = nullptr;
|
||||
mRetainedTiles[i].mTextureSourceOnWhite = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -321,8 +338,10 @@ TiledContentHost::UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
|
|||
}
|
||||
}
|
||||
mLowPrecisionTiledBuffer =
|
||||
TiledLayerBufferComposite(aAllocator, aTiledDescriptor,
|
||||
mLowPrecisionTiledBuffer.GetPaintedRegion());
|
||||
TiledLayerBufferComposite(aAllocator,
|
||||
aTiledDescriptor,
|
||||
mLowPrecisionTiledBuffer.GetPaintedRegion(),
|
||||
mCompositor);
|
||||
if (!mLowPrecisionTiledBuffer.IsValid()) {
|
||||
// Something bad happened. Stop here, return false (kills the child process),
|
||||
// and do as little work as possible on the received data as it appears
|
||||
|
@ -341,8 +360,10 @@ TiledContentHost::UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
|
|||
mOldTiledBuffer.ReleaseTextureHosts();
|
||||
}
|
||||
}
|
||||
mTiledBuffer = TiledLayerBufferComposite(aAllocator, aTiledDescriptor,
|
||||
mTiledBuffer.GetPaintedRegion());
|
||||
mTiledBuffer = TiledLayerBufferComposite(aAllocator,
|
||||
aTiledDescriptor,
|
||||
mTiledBuffer.GetPaintedRegion(),
|
||||
mCompositor);
|
||||
if (!mTiledBuffer.IsValid()) {
|
||||
// Something bad happened. Stop here, return false (kills the child process),
|
||||
// and do as little work as possible on the received data as it appears
|
||||
|
@ -477,14 +498,16 @@ TiledContentHost::RenderTile(const TileHost& aTile,
|
|||
NS_WARNING("Failed to lock tile");
|
||||
return;
|
||||
}
|
||||
RefPtr<TextureSource> source = aTile.mTextureHost->GetTextureSources();
|
||||
RefPtr<TextureSource> sourceOnWhite =
|
||||
aTile.mTextureHostOnWhite ? aTile.mTextureHostOnWhite->GetTextureSources() : nullptr;
|
||||
if (!source || (aTile.mTextureHostOnWhite && !sourceOnWhite)) {
|
||||
|
||||
if (!aTile.mTextureHost->BindTextureSource(aTile.mTextureSource)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<TexturedEffect> effect = CreateTexturedEffect(source, sourceOnWhite, aFilter, true);
|
||||
if (aTile.mTextureHostOnWhite && !aTile.mTextureHostOnWhite->BindTextureSource(aTile.mTextureSourceOnWhite)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<TexturedEffect> effect = CreateTexturedEffect(aTile.mTextureSource, aTile.mTextureSourceOnWhite, aFilter, true);
|
||||
if (!effect) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -62,15 +62,21 @@ public:
|
|||
// Constructs a TileHost from a gfxSharedReadLock and TextureHost.
|
||||
TileHost(gfxSharedReadLock* aSharedLock,
|
||||
TextureHost* aTextureHost,
|
||||
TextureHost* aTextureHostOnWhite)
|
||||
TextureHost* aTextureHostOnWhite,
|
||||
TextureSource* aSource,
|
||||
TextureSource* aSourceOnWhite)
|
||||
: mSharedLock(aSharedLock)
|
||||
, mTextureHost(aTextureHost)
|
||||
, mTextureHostOnWhite(aTextureHostOnWhite)
|
||||
, mTextureSource(aSource)
|
||||
, mTextureSourceOnWhite(aSourceOnWhite)
|
||||
{}
|
||||
|
||||
TileHost(const TileHost& o) {
|
||||
mTextureHost = o.mTextureHost;
|
||||
mTextureHostOnWhite = o.mTextureHostOnWhite;
|
||||
mTextureSource = o.mTextureSource;
|
||||
mTextureSourceOnWhite = o.mTextureSourceOnWhite;
|
||||
mSharedLock = o.mSharedLock;
|
||||
}
|
||||
TileHost& operator=(const TileHost& o) {
|
||||
|
@ -79,6 +85,8 @@ public:
|
|||
}
|
||||
mTextureHost = o.mTextureHost;
|
||||
mTextureHostOnWhite = o.mTextureHostOnWhite;
|
||||
mTextureSource = o.mTextureSource;
|
||||
mTextureSourceOnWhite = o.mTextureSourceOnWhite;
|
||||
mSharedLock = o.mSharedLock;
|
||||
return *this;
|
||||
}
|
||||
|
@ -99,8 +107,10 @@ public:
|
|||
}
|
||||
|
||||
RefPtr<gfxSharedReadLock> mSharedLock;
|
||||
RefPtr<TextureHost> mTextureHost;
|
||||
RefPtr<TextureHost> mTextureHostOnWhite;
|
||||
CompositableTextureHostRef mTextureHost;
|
||||
CompositableTextureHostRef mTextureHostOnWhite;
|
||||
mutable CompositableTextureSourceRef mTextureSource;
|
||||
mutable CompositableTextureSourceRef mTextureSourceOnWhite;
|
||||
};
|
||||
|
||||
class TiledLayerBufferComposite
|
||||
|
@ -114,7 +124,8 @@ public:
|
|||
TiledLayerBufferComposite();
|
||||
TiledLayerBufferComposite(ISurfaceAllocator* aAllocator,
|
||||
const SurfaceDescriptorTiles& aDescriptor,
|
||||
const nsIntRegion& aOldPaintedRegion);
|
||||
const nsIntRegion& aOldPaintedRegion,
|
||||
Compositor* aCompositor);
|
||||
|
||||
TileHost GetPlaceholderTile() const { return TileHost(); }
|
||||
|
||||
|
|
|
@ -250,9 +250,9 @@ public:
|
|||
, mImageFlags(aImageFlags)
|
||||
{}
|
||||
virtual bool operator()(gfxContext* aContext,
|
||||
const gfxRect& aFillRect,
|
||||
const GraphicsFilter& aFilter,
|
||||
const gfxMatrix& aTransform);
|
||||
const gfxRect& aFillRect,
|
||||
const GraphicsFilter& aFilter,
|
||||
const gfxMatrix& aTransform);
|
||||
private:
|
||||
nsRefPtr<SVGDocumentWrapper> mSVGDocumentWrapper;
|
||||
const nsIntRect mViewport;
|
||||
|
@ -756,13 +756,11 @@ struct SVGDrawingParameters
|
|||
|
||||
//******************************************************************************
|
||||
/* [noscript] void draw(in gfxContext aContext,
|
||||
* in gfxGraphicsFilter aFilter,
|
||||
* [const] in gfxMatrix aUserSpaceToImageSpace,
|
||||
* [const] in gfxRect aFill,
|
||||
* [const] in nsIntRect aSubimage,
|
||||
* [const] in nsIntSize aViewportSize,
|
||||
* [const] in SVGImageContext aSVGContext,
|
||||
* [const] in nsIntSize aSize,
|
||||
* [const] in ImageRegion aRegion,
|
||||
* in uint32_t aWhichFrame,
|
||||
* in gfxGraphicsFilter aFilter,
|
||||
* [const] in MaybeSVGImageContext aSVGContext,
|
||||
* in uint32_t aFlags); */
|
||||
NS_IMETHODIMP
|
||||
VectorImage::Draw(gfxContext* aContext,
|
||||
|
|
|
@ -3246,3 +3246,4 @@ dtoa
|
|||
*rve = s;
|
||||
return s0;
|
||||
}
|
||||
#undef CONST
|
||||
|
|
|
@ -1650,7 +1650,7 @@ Parser<ParseHandler>::functionArguments(FunctionSyntaxKind kind, Node *listp, No
|
|||
data.pn = ParseHandler::null();
|
||||
data.op = JSOP_DEFVAR;
|
||||
data.binder = bindDestructuringArg;
|
||||
Node lhs = destructuringExpr(&data, tt);
|
||||
Node lhs = destructuringExprWithoutYield(&data, tt, JSMSG_YIELD_IN_DEFAULT);
|
||||
if (!lhs)
|
||||
return false;
|
||||
|
||||
|
@ -3503,6 +3503,21 @@ Parser<ParseHandler>::destructuringExpr(BindData<ParseHandler> *data, TokenKind
|
|||
return pn;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::destructuringExprWithoutYield(BindData<ParseHandler> *data, TokenKind tt,
|
||||
unsigned msg)
|
||||
{
|
||||
uint32_t startYieldOffset = pc->lastYieldOffset;
|
||||
Node res = destructuringExpr(data, tt);
|
||||
if (res && pc->lastYieldOffset != startYieldOffset) {
|
||||
reportWithOffset(ParseError, false, pc->lastYieldOffset,
|
||||
msg, js_yield_str);
|
||||
return null();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::pushLexicalScope(HandleStaticBlockObject blockObj, StmtInfoPC *stmt)
|
||||
|
|
|
@ -613,6 +613,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
|
|||
bool argumentList(Node listNode, bool *isSpread);
|
||||
Node letBlock(LetContext letContext);
|
||||
Node destructuringExpr(BindData<ParseHandler> *data, TokenKind tt);
|
||||
Node destructuringExprWithoutYield(BindData<ParseHandler> *data, TokenKind tt, unsigned msg);
|
||||
|
||||
Node identifierName();
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// |jit-test| error: TypeError
|
||||
//
|
||||
// Make sure we can recover missing arguments even when it gets assigned to
|
||||
// another slot.
|
||||
|
||||
load(libdir + "evalInFrame.js");
|
||||
|
||||
function h() {
|
||||
evalInFrame(1, "a.push(0)");
|
||||
}
|
||||
|
||||
function f() {
|
||||
var a = arguments;
|
||||
h();
|
||||
}
|
||||
|
||||
f();
|
|
@ -0,0 +1,10 @@
|
|||
// |jit-test| error: ReferenceError
|
||||
|
||||
var g = newGlobal();
|
||||
g.parent = this;
|
||||
g.eval("new Debugger(parent).onExceptionUnwind = function () { hits++; };");
|
||||
evaluate('\
|
||||
var fe="v";\
|
||||
for (i=0; String.fromCharCode(0x004E); i++)\
|
||||
fe += fe;\
|
||||
', { compileAndGo : true });
|
|
@ -0,0 +1,7 @@
|
|||
try {
|
||||
gcslice(0)(""());
|
||||
} catch (e) {}
|
||||
g = newGlobal()
|
||||
g.parent = this
|
||||
g.eval("Debugger(parent).onExceptionUnwind=(function(){})");
|
||||
gcparam("maxBytes", gcparam("gcBytes"));
|
|
@ -0,0 +1,17 @@
|
|||
var evalInFrame = (function (global) {
|
||||
var dbgGlobal = newGlobal();
|
||||
var dbg = new dbgGlobal.Debugger();
|
||||
return function evalInFrame(upCount, code) {
|
||||
dbg.addDebuggee(global);
|
||||
var frame = dbg.getNewestFrame().older;
|
||||
var completion = frame.eval(code);
|
||||
};
|
||||
})(this);
|
||||
function g1(x, args) {}
|
||||
function f1(x, y, o) {
|
||||
for (var i=0; i<50; i++) {
|
||||
o.apply(evalInFrame(0, "x"), x);
|
||||
}
|
||||
}
|
||||
var o1 = {apply: g1};
|
||||
assertEq(f1(3, 5, o1), undefined);
|
|
@ -0,0 +1,17 @@
|
|||
g = newGlobal()
|
||||
g.parent = this
|
||||
g.eval("Debugger(parent).onExceptionUnwind=(function(){})")
|
||||
try {
|
||||
function f(code) {
|
||||
n = parseInt('', 0);
|
||||
return g("try{}catch(e){}", n)
|
||||
}
|
||||
function g(s, n) {
|
||||
s2 = s + s
|
||||
d = (n - (function () {
|
||||
return "" + this.id + eval.id;
|
||||
} )().abstract) / 2
|
||||
m = g(s2, d)
|
||||
}
|
||||
f("switch(''){default:break;}")
|
||||
} catch(exc1) {}
|
|
@ -0,0 +1,2 @@
|
|||
// |jit-test| error: SyntaxError
|
||||
function d([{ [yield]: {} } ]) f
|
|
@ -1028,28 +1028,29 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
|||
// of exception propagation for debug mode. See note below.
|
||||
PCMappingSlotInfo slotInfo;
|
||||
uint8_t *nativeCodeForPC = baselineScript->maybeNativeCodeForPC(script, pc, &slotInfo);
|
||||
unsigned numUnsynced;
|
||||
unsigned numUnsynced = slotInfo.numUnsynced();
|
||||
|
||||
if (excInfo && excInfo->propagatingIonExceptionForDebugMode()) {
|
||||
if (excInfo && excInfo->propagatingIonExceptionForDebugMode() && resumeAfter) {
|
||||
// When propagating an exception for debug mode, set the
|
||||
// return address as the return-from-IC for the throw, so that
|
||||
// Debugger hooks report the correct pc offset of the throwing
|
||||
// op instead of its successor.
|
||||
// return address as the return-from-IC for the throwing op,
|
||||
// so that Debugger hooks report the correct pc offset of the
|
||||
// throwing op instead of its successor.
|
||||
//
|
||||
// This should not be done if we are at a resume-at point, as
|
||||
// might be the case when propagating an exception thrown from
|
||||
// an interrupt handler. That interrupt could have happened to
|
||||
// interrupt at a loop head, which would have no ICEntry at
|
||||
// that point.
|
||||
//
|
||||
// Note that we never resume into this address, it is set for
|
||||
// the sake of frame iterators giving the correct answer.
|
||||
ICEntry &icEntry = baselineScript->anyKindICEntryFromPCOffset(iter.pcOffset());
|
||||
nativeCodeForPC = baselineScript->returnAddressForIC(icEntry);
|
||||
|
||||
// The pc after the throwing PC could be unreachable, in which
|
||||
// case we have no native code for it and no slot info. But in
|
||||
// that case, there are definitely no unsynced slots.
|
||||
numUnsynced = nativeCodeForPC ? slotInfo.numUnsynced() : 0;
|
||||
} else {
|
||||
MOZ_ASSERT(nativeCodeForPC);
|
||||
numUnsynced = slotInfo.numUnsynced();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(nativeCodeForPC);
|
||||
MOZ_ASSERT(numUnsynced <= 2);
|
||||
PCMappingSlotInfo::SlotLocation loc1, loc2;
|
||||
if (numUnsynced > 0) {
|
||||
|
|
|
@ -754,6 +754,8 @@ BaselineCompiler::emitDebugTrap()
|
|||
|
||||
// Emit patchable call to debug trap handler.
|
||||
JitCode *handler = cx->runtime()->jitRuntime()->debugTrapHandler(cx);
|
||||
if (!handler)
|
||||
return false;
|
||||
mozilla::DebugOnly<CodeOffsetLabel> offset = masm.toggledCall(handler, enabled);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -217,7 +217,7 @@ CollectJitStackScripts(JSContext *cx, const Debugger::ExecutionObservableSet &ob
|
|||
// *after* the bytecode that threw the exception, which
|
||||
// may have no ICEntry.
|
||||
MOZ_ASSERT(iter.baselineFrame()->isDebuggerHandlingException());
|
||||
jsbytecode *pc = script->baselineScript()->pcForReturnAddress(script, retAddr);
|
||||
jsbytecode *pc = script->baselineScript()->pcForNativeAddress(script, retAddr);
|
||||
if (!entries.append(DebugModeOSREntry(script, script->pcToOffset(pc))))
|
||||
return false;
|
||||
}
|
||||
|
@ -685,6 +685,7 @@ RecompileBaselineScriptForDebugMode(JSContext *cx, JSScript *script,
|
|||
_(GetProp_CallDOMProxyNative) \
|
||||
_(GetProp_CallDOMProxyWithGenerationNative) \
|
||||
_(GetProp_DOMProxyShadowed) \
|
||||
_(GetProp_Generic) \
|
||||
_(SetProp_CallScripted) \
|
||||
_(SetProp_CallNative)
|
||||
|
||||
|
|
|
@ -7848,6 +7848,13 @@ ICGetProp_ArgumentsCallee::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* static */ ICGetProp_Generic *
|
||||
ICGetProp_Generic::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
|
||||
ICGetProp_Generic &other)
|
||||
{
|
||||
return New(space, other.jitCode(), firstMonitorStub);
|
||||
}
|
||||
|
||||
static bool
|
||||
DoGetPropGeneric(JSContext *cx, BaselineFrame *frame, ICGetProp_Generic *stub, MutableHandleValue val, MutableHandleValue res)
|
||||
{
|
||||
|
|
|
@ -4196,6 +4196,9 @@ class ICGetProp_Generic : public ICMonitoredStub
|
|||
return space->allocate<ICGetProp_Generic>(code, firstMonitorStub);
|
||||
}
|
||||
|
||||
static ICGetProp_Generic *Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
|
||||
ICGetProp_Generic &other);
|
||||
|
||||
class Compiler : public ICStubCompiler {
|
||||
protected:
|
||||
bool generateStubCode(MacroAssembler &masm);
|
||||
|
|
|
@ -9766,11 +9766,9 @@ CodeGenerator::visitInterruptCheck(LInterruptCheck *lir)
|
|||
void
|
||||
CodeGenerator::visitAsmJSInterruptCheck(LAsmJSInterruptCheck *lir)
|
||||
{
|
||||
Register scratch = ToRegister(lir->scratch());
|
||||
masm.movePtr(AsmJSImmPtr(AsmJSImm_RuntimeInterruptUint32), scratch);
|
||||
masm.load32(Address(scratch, 0), scratch);
|
||||
Label rejoin;
|
||||
masm.branch32(Assembler::Equal, scratch, Imm32(0), &rejoin);
|
||||
masm.branch32(Assembler::Equal, AsmJSAbsoluteAddress(AsmJSImm_RuntimeInterruptUint32),
|
||||
Imm32(0), &rejoin);
|
||||
{
|
||||
uint32_t stackFixup = ComputeByteAlignment(masm.framePushed() + sizeof(AsmJSFrame),
|
||||
ABIStackAlignment);
|
||||
|
|
|
@ -587,7 +587,7 @@ class InlineFrameIterator
|
|||
|
||||
private:
|
||||
void findNextFrame();
|
||||
JSObject *computeScopeChain(Value scopeChainValue) const;
|
||||
JSObject *computeScopeChain(Value scopeChainValue, bool *hasCallObj = nullptr) const;
|
||||
|
||||
public:
|
||||
InlineFrameIterator(ThreadSafeContext *cx, const JitFrameIterator *iter);
|
||||
|
@ -619,7 +619,7 @@ class InlineFrameIterator
|
|||
|
||||
template <class ArgOp, class LocalOp>
|
||||
void readFrameArgsAndLocals(ThreadSafeContext *cx, ArgOp &argOp, LocalOp &localOp,
|
||||
JSObject **scopeChain, Value *rval,
|
||||
JSObject **scopeChain, bool *hasCallObj, Value *rval,
|
||||
ArgumentsObject **argsObj, Value *thisv,
|
||||
ReadFrameArgsBehavior behavior,
|
||||
MaybeReadFallback &fallback) const
|
||||
|
@ -631,7 +631,7 @@ class InlineFrameIterator
|
|||
s.readCommonFrameSlots(&scopeChainValue, rval);
|
||||
|
||||
if (scopeChain)
|
||||
*scopeChain = computeScopeChain(scopeChainValue);
|
||||
*scopeChain = computeScopeChain(scopeChainValue, hasCallObj);
|
||||
|
||||
// Read arguments, which only function frames have.
|
||||
if (isFunctionFrame()) {
|
||||
|
@ -700,7 +700,8 @@ class InlineFrameIterator
|
|||
MaybeReadFallback &fallback) const
|
||||
{
|
||||
Nop nop;
|
||||
readFrameArgsAndLocals(cx, op, nop, nullptr, nullptr, nullptr, nullptr, behavior, fallback);
|
||||
readFrameArgsAndLocals(cx, op, nop, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, behavior, fallback);
|
||||
}
|
||||
|
||||
JSScript *script() const {
|
||||
|
|
|
@ -417,10 +417,10 @@ HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromEx
|
|||
RootedScript script(cx, frame.script());
|
||||
jsbytecode *pc = frame.pc();
|
||||
|
||||
if (cx->compartment()->isDebuggee()) {
|
||||
// We need to bail when we are the debuggee of a Debugger with a live
|
||||
// onExceptionUnwind hook, or if a Debugger has observed this frame
|
||||
// (e.g., for onPop).
|
||||
if (cx->compartment()->isDebuggee() && cx->isExceptionPending()) {
|
||||
// We need to bail when there is a catchable exception, and we are the
|
||||
// debuggee of a Debugger with a live onExceptionUnwind hook, or if a
|
||||
// Debugger has observed this frame (e.g., for onPop).
|
||||
bool shouldBail = Debugger::hasLiveHook(cx->global(), Debugger::OnExceptionUnwind);
|
||||
if (!shouldBail) {
|
||||
JitActivation *act = cx->mainThread().activation()->asJit();
|
||||
|
@ -2345,10 +2345,13 @@ InlineFrameIterator::findNextFrame()
|
|||
}
|
||||
|
||||
JSObject *
|
||||
InlineFrameIterator::computeScopeChain(Value scopeChainValue) const
|
||||
InlineFrameIterator::computeScopeChain(Value scopeChainValue, bool *hasCallObj) const
|
||||
{
|
||||
if (scopeChainValue.isObject())
|
||||
if (scopeChainValue.isObject()) {
|
||||
if (hasCallObj)
|
||||
*hasCallObj = isFunctionFrame() && callee()->isHeavyweight();
|
||||
return &scopeChainValue.toObject();
|
||||
}
|
||||
|
||||
// Note we can hit this case even for heavyweight functions, in case we
|
||||
// are walking the frame during the function prologue, before the scope
|
||||
|
|
|
@ -447,6 +447,9 @@ class LSimdBinaryBitwiseX4 : public LInstructionHelper<1, 2, 0>
|
|||
MSimdBinaryBitwise::Operation operation() const {
|
||||
return mir_->toSimdBinaryBitwise()->operation();
|
||||
}
|
||||
MIRType type() const {
|
||||
return mir_->type();
|
||||
}
|
||||
};
|
||||
|
||||
class LSimdShift : public LInstructionHelper<1, 2, 0>
|
||||
|
@ -1163,7 +1166,7 @@ class LCheckOverRecursedPar : public LInstructionHelper<0, 1, 1>
|
|||
}
|
||||
};
|
||||
|
||||
class LAsmJSInterruptCheck : public LInstructionHelper<0, 0, 1>
|
||||
class LAsmJSInterruptCheck : public LInstructionHelper<0, 0, 0>
|
||||
{
|
||||
Label *interruptExit_;
|
||||
const CallSiteDesc &funcDesc_;
|
||||
|
@ -1171,15 +1174,9 @@ class LAsmJSInterruptCheck : public LInstructionHelper<0, 0, 1>
|
|||
public:
|
||||
LIR_HEADER(AsmJSInterruptCheck);
|
||||
|
||||
LAsmJSInterruptCheck(const LDefinition &scratch, Label *interruptExit,
|
||||
const CallSiteDesc &funcDesc)
|
||||
LAsmJSInterruptCheck(Label *interruptExit, const CallSiteDesc &funcDesc)
|
||||
: interruptExit_(interruptExit), funcDesc_(funcDesc)
|
||||
{
|
||||
setTemp(0, scratch);
|
||||
}
|
||||
|
||||
const LDefinition *scratch() {
|
||||
return getTemp(0);
|
||||
}
|
||||
|
||||
bool isCall() const {
|
||||
|
|
|
@ -2294,8 +2294,7 @@ LIRGenerator::visitAsmJSInterruptCheck(MAsmJSInterruptCheck *ins)
|
|||
{
|
||||
gen->setPerformsCall();
|
||||
|
||||
LAsmJSInterruptCheck *lir = new(alloc()) LAsmJSInterruptCheck(temp(),
|
||||
ins->interruptExit(),
|
||||
LAsmJSInterruptCheck *lir = new(alloc()) LAsmJSInterruptCheck(ins->interruptExit(),
|
||||
ins->funcDesc());
|
||||
add(lir, ins);
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ RematerializedFrame::RematerializedFrame(JSContext *cx, uint8_t *top, unsigned n
|
|||
{
|
||||
CopyValueToRematerializedFrame op(slots_);
|
||||
MaybeReadFallback fallback(MagicValue(JS_OPTIMIZED_OUT));
|
||||
iter.readFrameArgsAndLocals(cx, op, op, &scopeChain_, &returnValue_,
|
||||
iter.readFrameArgsAndLocals(cx, op, op, &scopeChain_, &hasCallObj_, &returnValue_,
|
||||
&argsObj_, &thisValue_, ReadFrame_Actuals,
|
||||
fallback);
|
||||
}
|
||||
|
@ -49,16 +49,16 @@ RematerializedFrame::RematerializedFrame(JSContext *cx, uint8_t *top, unsigned n
|
|||
RematerializedFrame::New(JSContext *cx, uint8_t *top, InlineFrameIterator &iter)
|
||||
{
|
||||
unsigned numFormals = iter.isFunctionFrame() ? iter.callee()->nargs() : 0;
|
||||
unsigned numActualArgs = Max(numFormals, iter.numActualArgs());
|
||||
unsigned argSlots = Max(numFormals, iter.numActualArgs());
|
||||
size_t numBytes = sizeof(RematerializedFrame) +
|
||||
(numActualArgs + iter.script()->nfixed()) * sizeof(Value) -
|
||||
(argSlots + iter.script()->nfixed()) * sizeof(Value) -
|
||||
sizeof(Value); // 1 Value included in sizeof(RematerializedFrame)
|
||||
|
||||
void *buf = cx->pod_calloc<uint8_t>(numBytes);
|
||||
if (!buf)
|
||||
return nullptr;
|
||||
|
||||
return new (buf) RematerializedFrame(cx, top, numActualArgs, iter);
|
||||
return new (buf) RematerializedFrame(cx, top, iter.numActualArgs(), iter);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
@ -139,6 +139,7 @@ RematerializedFrame::initFunctionScopeObjects(JSContext *cx)
|
|||
if (!callobj)
|
||||
return false;
|
||||
pushOnScopeChain(*callobj);
|
||||
hasCallObj_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,9 @@ class RematerializedFrame
|
|||
// Propagated to the Baseline frame once this is popped.
|
||||
bool isDebuggee_;
|
||||
|
||||
// Has a call object been pushed?
|
||||
bool hasCallObj_;
|
||||
|
||||
// The fp of the top frame associated with this possibly inlined frame.
|
||||
uint8_t *top_;
|
||||
|
||||
|
@ -107,9 +110,8 @@ class RematerializedFrame
|
|||
bool initFunctionScopeObjects(JSContext *cx);
|
||||
|
||||
bool hasCallObj() const {
|
||||
return maybeFun() &&
|
||||
fun()->isHeavyweight() &&
|
||||
scopeChain()->is<CallObject>();
|
||||
MOZ_ASSERT(fun()->isHeavyweight());
|
||||
return hasCallObj_;
|
||||
}
|
||||
CallObject &callObj() const;
|
||||
|
||||
|
|
|
@ -1098,6 +1098,11 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
|||
ma_cmp(secondScratchReg_, rhs);
|
||||
ma_b(label, cond);
|
||||
}
|
||||
void branch32(Condition cond, AsmJSAbsoluteAddress addr, Imm32 imm, Label *label) {
|
||||
loadPtr(addr, ScratchRegister);
|
||||
ma_cmp(ScratchRegister, imm);
|
||||
ma_b(label, cond);
|
||||
}
|
||||
|
||||
void loadUnboxedValue(Address address, MIRType type, AnyRegister dest) {
|
||||
if (dest.isFloat())
|
||||
|
|
|
@ -841,6 +841,11 @@ public:
|
|||
loadPtr(lhs, ScratchRegister);
|
||||
ma_b(ScratchRegister, rhs, label, cond);
|
||||
}
|
||||
void branch32(Condition cond, AsmJSAbsoluteAddress addr, Imm32 imm,
|
||||
Label *label) {
|
||||
loadPtr(addr, ScratchRegister);
|
||||
ma_b(ScratchRegister, imm, label, cond);
|
||||
}
|
||||
|
||||
void loadUnboxedValue(Address address, MIRType type, AnyRegister dest) {
|
||||
if (dest.isFloat())
|
||||
|
|
|
@ -90,6 +90,8 @@ class LIRGeneratorNone : public LIRGeneratorShared
|
|||
void visitSimdSplatX4(MSimdSplatX4 *ins) { MOZ_CRASH(); }
|
||||
void visitSimdValueX4(MSimdValueX4 *lir) { MOZ_CRASH(); }
|
||||
void visitSubstr(MSubstr *) { MOZ_CRASH(); }
|
||||
void visitSimdBinaryArith(js::jit::MSimdBinaryArith*) { MOZ_CRASH(); }
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
#ifdef _MSC_VER
|
||||
# include <intrin.h> // for __cpuid
|
||||
# if defined(_M_X64) && (_MSC_FULL_VER >= 160040219)
|
||||
# include <immintrin.h> // for _xgetbv
|
||||
# endif
|
||||
#endif
|
||||
|
||||
using namespace js;
|
||||
|
@ -141,6 +144,30 @@ CPUInfo::SSEVersion CPUInfo::maxEnabledSSEVersion = UnknownSSE;
|
|||
bool CPUInfo::avxPresent = false;
|
||||
bool CPUInfo::avxEnabled = true;
|
||||
|
||||
static uintptr_t
|
||||
ReadXGETBV()
|
||||
{
|
||||
// We use a variety of low-level mechanisms to get at the xgetbv
|
||||
// instruction, including spelling out the xgetbv instruction as bytes,
|
||||
// because older compilers and assemblers may not recognize the instruction
|
||||
// by name.
|
||||
size_t xcr0EAX = 0;
|
||||
#if defined(_XCR_XFEATURE_ENABLED_MASK)
|
||||
xcr0EAX = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
|
||||
#elif defined(__GNUC__)
|
||||
// xgetbv returns its results in %eax and %edx, and for our purposes here,
|
||||
// we're only interested in the %eax value.
|
||||
asm(".byte 0x0f, 0x01, 0xd0" : "=a"(xcr0EAX) : "c"(0) : "%edx");
|
||||
#elif defined(_MSC_VER) && defined(_M_IX86)
|
||||
__asm {
|
||||
xor ecx, ecx
|
||||
_asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0
|
||||
mov xcr0EAX, eax
|
||||
}
|
||||
#endif
|
||||
return xcr0EAX;
|
||||
}
|
||||
|
||||
void
|
||||
CPUInfo::SetSSEVersion()
|
||||
{
|
||||
|
@ -202,4 +229,12 @@ CPUInfo::SetSSEVersion()
|
|||
static const int AVXBit = 1 << 28;
|
||||
static const int XSAVEBit = 1 << 27;
|
||||
avxPresent = (flagsECX & AVXBit) && (flagsECX & XSAVEBit) && avxEnabled;
|
||||
|
||||
// If the hardware supports AVX, check whether the OS supports it too.
|
||||
if (avxPresent) {
|
||||
size_t xcr0EAX = ReadXGETBV();
|
||||
static const int xcr0SSEBit = 1 << 1;
|
||||
static const int xcr0AVXBit = 1 << 2;
|
||||
avxPresent = (xcr0EAX & xcr0SSEBit) && (xcr0EAX & xcr0AVXBit);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -248,7 +248,7 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
NoParity = X86Assembler::ConditionNP
|
||||
};
|
||||
|
||||
// If this bit is set, the ucomisd operands have to be inverted.
|
||||
// If this bit is set, the vucomisd operands have to be inverted.
|
||||
static const int DoubleConditionBitInvert = 0x10;
|
||||
|
||||
// Bit set when a DoubleCondition does not map to a single x86 condition.
|
||||
|
@ -632,13 +632,13 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
MOZ_ASSERT(HasSSE2());
|
||||
masm.movdqa_rr(src.code(), dest.code());
|
||||
}
|
||||
void cvtss2sd(FloatRegister src, FloatRegister dest) {
|
||||
void vcvtss2sd(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.cvtss2sd_rr(src.code(), dest.code());
|
||||
masm.vcvtss2sd_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void cvtsd2ss(FloatRegister src, FloatRegister dest) {
|
||||
void vcvtsd2ss(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.cvtsd2ss_rr(src.code(), dest.code());
|
||||
masm.vcvtsd2ss_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void movzbl(const Operand &src, Register dest) {
|
||||
switch (src.kind()) {
|
||||
|
@ -980,13 +980,10 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
static bool SupportsSimd() { return CPUInfo::IsSSE2Present(); }
|
||||
static bool HasAVX() { return CPUInfo::IsAVXPresent(); }
|
||||
|
||||
// The below cmpl methods switch the lhs and rhs when it invokes the
|
||||
// macroassembler to conform with intel standard. When calling this
|
||||
// function put the left operand on the left as you would expect.
|
||||
void cmpl(Register lhs, Register rhs) {
|
||||
void cmpl(Register rhs, Register lhs) {
|
||||
masm.cmpl_rr(rhs.code(), lhs.code());
|
||||
}
|
||||
void cmpl(Register lhs, const Operand &rhs) {
|
||||
void cmpl(const Operand &rhs, Register lhs) {
|
||||
switch (rhs.kind()) {
|
||||
case Operand::REG:
|
||||
masm.cmpl_rr(rhs.reg(), lhs.code());
|
||||
|
@ -994,32 +991,14 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
case Operand::MEM_REG_DISP:
|
||||
masm.cmpl_mr(rhs.disp(), rhs.base(), lhs.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void cmpl(Register src, Imm32 imm) {
|
||||
masm.cmpl_ir(imm.value, src.code());
|
||||
}
|
||||
void cmpl(const Operand &op, Imm32 imm) {
|
||||
switch (op.kind()) {
|
||||
case Operand::REG:
|
||||
masm.cmpl_ir(imm.value, op.reg());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.cmpl_im(imm.value, op.disp(), op.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.cmpl_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.cmpl_im(imm.value, op.address());
|
||||
masm.cmpl_mr(rhs.address(), lhs.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void cmpl(const Operand &lhs, Register rhs) {
|
||||
void cmpl(Register rhs, const Operand &lhs) {
|
||||
switch (lhs.kind()) {
|
||||
case Operand::REG:
|
||||
masm.cmpl_rr(rhs.code(), lhs.reg());
|
||||
|
@ -1034,52 +1013,55 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void cmpl(const Operand &op, ImmWord imm) {
|
||||
switch (op.kind()) {
|
||||
void cmpl(Imm32 rhs, Register lhs) {
|
||||
masm.cmpl_ir(rhs.value, lhs.code());
|
||||
}
|
||||
void cmpl(Imm32 rhs, const Operand &lhs) {
|
||||
switch (lhs.kind()) {
|
||||
case Operand::REG:
|
||||
masm.cmpl_ir(imm.value, op.reg());
|
||||
masm.cmpl_ir(rhs.value, lhs.reg());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.cmpl_im(imm.value, op.disp(), op.base());
|
||||
masm.cmpl_im(rhs.value, lhs.disp(), lhs.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.cmpl_im(rhs.value, lhs.disp(), lhs.base(), lhs.index(), lhs.scale());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.cmpl_im(imm.value, op.address());
|
||||
masm.cmpl_im(rhs.value, lhs.address());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void cmpl(const Operand &op, ImmPtr imm) {
|
||||
cmpl(op, ImmWord(uintptr_t(imm.value)));
|
||||
}
|
||||
CodeOffsetLabel cmplWithPatch(Register lhs, Imm32 rhs) {
|
||||
masm.cmpl_ir_force32(rhs.value, lhs.code());
|
||||
CodeOffsetLabel cmplWithPatch(Imm32 rhs, Register lhs) {
|
||||
masm.cmpl_i32r(rhs.value, lhs.code());
|
||||
return CodeOffsetLabel(masm.currentOffset());
|
||||
}
|
||||
void cmpw(Register lhs, Register rhs) {
|
||||
masm.cmpw_rr(lhs.code(), rhs.code());
|
||||
void cmpw(Register rhs, Register lhs) {
|
||||
masm.cmpw_rr(rhs.code(), lhs.code());
|
||||
}
|
||||
void setCC(Condition cond, Register r) {
|
||||
masm.setCC_r(static_cast<X86Assembler::Condition>(cond), r.code());
|
||||
}
|
||||
void testb(Register lhs, Register rhs) {
|
||||
MOZ_ASSERT(GeneralRegisterSet(Registers::SingleByteRegs).has(lhs));
|
||||
void testb(Register rhs, Register lhs) {
|
||||
MOZ_ASSERT(GeneralRegisterSet(Registers::SingleByteRegs).has(rhs));
|
||||
MOZ_ASSERT(GeneralRegisterSet(Registers::SingleByteRegs).has(lhs));
|
||||
masm.testb_rr(rhs.code(), lhs.code());
|
||||
}
|
||||
void testw(Register lhs, Register rhs) {
|
||||
masm.testw_rr(rhs.code(), lhs.code());
|
||||
void testw(Register rhs, Register lhs) {
|
||||
masm.testw_rr(lhs.code(), rhs.code());
|
||||
}
|
||||
void testl(Register lhs, Register rhs) {
|
||||
masm.testl_rr(rhs.code(), lhs.code());
|
||||
void testl(Register rhs, Register lhs) {
|
||||
masm.testl_rr(lhs.code(), rhs.code());
|
||||
}
|
||||
void testl(Register lhs, Imm32 rhs) {
|
||||
masm.testl_i32r(rhs.value, lhs.code());
|
||||
void testl(Imm32 rhs, Register lhs) {
|
||||
masm.testl_ir(rhs.value, lhs.code());
|
||||
}
|
||||
void testl(const Operand &lhs, Imm32 rhs) {
|
||||
void testl(Imm32 rhs, const Operand &lhs) {
|
||||
switch (lhs.kind()) {
|
||||
case Operand::REG:
|
||||
masm.testl_i32r(rhs.value, lhs.reg());
|
||||
masm.testl_ir(rhs.value, lhs.reg());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.testl_i32m(rhs.value, lhs.disp(), lhs.base());
|
||||
|
@ -1096,8 +1078,9 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
void addl(Imm32 imm, Register dest) {
|
||||
masm.addl_ir(imm.value, dest.code());
|
||||
}
|
||||
void addl_wide(Imm32 imm, Register dest) {
|
||||
masm.addl_ir_wide(imm.value, dest.code());
|
||||
CodeOffsetLabel addlWithPatch(Imm32 imm, Register dest) {
|
||||
masm.addl_i32r(imm.value, dest.code());
|
||||
return CodeOffsetLabel(masm.currentOffset());
|
||||
}
|
||||
void addl(Imm32 imm, const Operand &op) {
|
||||
switch (op.kind()) {
|
||||
|
@ -1274,13 +1257,13 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
masm.imull_r(multiplier.code());
|
||||
}
|
||||
void imull(Imm32 imm, Register dest) {
|
||||
masm.imull_i32r(dest.code(), imm.value, dest.code());
|
||||
masm.imull_ir(imm.value, dest.code(), dest.code());
|
||||
}
|
||||
void imull(Register src, Register dest) {
|
||||
masm.imull_rr(src.code(), dest.code());
|
||||
}
|
||||
void imull(Imm32 imm, Register src, Register dest) {
|
||||
masm.imull_i32r(src.code(), imm.value, dest.code());
|
||||
masm.imull_ir(imm.value, src.code(), dest.code());
|
||||
}
|
||||
void imull(const Operand &src, Register dest) {
|
||||
switch (src.kind()) {
|
||||
|
@ -1441,7 +1424,7 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
}
|
||||
|
||||
void push(const Imm32 imm) {
|
||||
masm.push_i32(imm.value);
|
||||
masm.push_i(imm.value);
|
||||
}
|
||||
|
||||
void push(const Operand &src) {
|
||||
|
@ -1584,113 +1567,113 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
masm.psrld_ir(count.value, dest.code());
|
||||
}
|
||||
|
||||
void cvtsi2sd(const Operand &src, FloatRegister dest) {
|
||||
void vcvtsi2sd(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src.kind()) {
|
||||
switch (src1.kind()) {
|
||||
case Operand::REG:
|
||||
masm.cvtsi2sd_rr(src.reg(), dest.code());
|
||||
masm.vcvtsi2sd_rr(src1.reg(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.cvtsi2sd_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vcvtsi2sd_mr(src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.cvtsi2sd_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code());
|
||||
masm.vcvtsi2sd_mr(src1.disp(), src1.base(), src1.index(), src1.scale(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void cvttsd2si(FloatRegister src, Register dest) {
|
||||
void vcvttsd2si(FloatRegister src, Register dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.cvttsd2si_rr(src.code(), dest.code());
|
||||
masm.vcvttsd2si_rr(src.code(), dest.code());
|
||||
}
|
||||
void cvttss2si(FloatRegister src, Register dest) {
|
||||
void vcvttss2si(FloatRegister src, Register dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.cvttss2si_rr(src.code(), dest.code());
|
||||
masm.vcvttss2si_rr(src.code(), dest.code());
|
||||
}
|
||||
void cvtsi2ss(const Operand &src, FloatRegister dest) {
|
||||
void vcvtsi2ss(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src.kind()) {
|
||||
switch (src1.kind()) {
|
||||
case Operand::REG:
|
||||
masm.cvtsi2ss_rr(src.reg(), dest.code());
|
||||
masm.vcvtsi2ss_rr(src1.reg(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.cvtsi2ss_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vcvtsi2ss_mr(src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.cvtsi2ss_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code());
|
||||
masm.vcvtsi2ss_mr(src1.disp(), src1.base(), src1.index(), src1.scale(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void cvtsi2ss(Register src, FloatRegister dest) {
|
||||
void vcvtsi2ss(Register src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.cvtsi2ss_rr(src.code(), dest.code());
|
||||
masm.vcvtsi2ss_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void cvtsi2sd(Register src, FloatRegister dest) {
|
||||
void vcvtsi2sd(Register src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.cvtsi2sd_rr(src.code(), dest.code());
|
||||
masm.vcvtsi2sd_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void cvttps2dq(FloatRegister src, FloatRegister dest) {
|
||||
void vcvttps2dq(FloatRegister src, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.cvttps2dq_rr(src.code(), dest.code());
|
||||
masm.vcvttps2dq_rr(src.code(), dest.code());
|
||||
}
|
||||
void cvtdq2ps(FloatRegister src, FloatRegister dest) {
|
||||
void vcvtdq2ps(FloatRegister src, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.cvtdq2ps_rr(src.code(), dest.code());
|
||||
masm.vcvtdq2ps_rr(src.code(), dest.code());
|
||||
}
|
||||
void movmskpd(FloatRegister src, Register dest) {
|
||||
void vmovmskpd(FloatRegister src, Register dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.movmskpd_rr(src.code(), dest.code());
|
||||
masm.vmovmskpd_rr(src.code(), dest.code());
|
||||
}
|
||||
void movmskps(FloatRegister src, Register dest) {
|
||||
void vmovmskps(FloatRegister src, Register dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.movmskps_rr(src.code(), dest.code());
|
||||
masm.vmovmskps_rr(src.code(), dest.code());
|
||||
}
|
||||
void ptest(FloatRegister lhs, FloatRegister rhs) {
|
||||
void vptest(FloatRegister rhs, FloatRegister lhs) {
|
||||
MOZ_ASSERT(HasSSE41());
|
||||
masm.ptest_rr(rhs.code(), lhs.code());
|
||||
masm.vptest_rr(rhs.code(), lhs.code());
|
||||
}
|
||||
void ucomisd(FloatRegister lhs, FloatRegister rhs) {
|
||||
void vucomisd(FloatRegister rhs, FloatRegister lhs) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.ucomisd_rr(rhs.code(), lhs.code());
|
||||
masm.vucomisd_rr(rhs.code(), lhs.code());
|
||||
}
|
||||
void ucomiss(FloatRegister lhs, FloatRegister rhs) {
|
||||
void vucomiss(FloatRegister rhs, FloatRegister lhs) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.ucomiss_rr(rhs.code(), lhs.code());
|
||||
masm.vucomiss_rr(rhs.code(), lhs.code());
|
||||
}
|
||||
void pcmpeqw(FloatRegister lhs, FloatRegister rhs) {
|
||||
void vpcmpeqw(FloatRegister rhs, FloatRegister lhs, FloatRegister dst) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.pcmpeqw_rr(rhs.code(), lhs.code());
|
||||
masm.vpcmpeqw_rr(rhs.code(), lhs.code(), dst.code());
|
||||
}
|
||||
void pcmpeqd(const Operand &src, FloatRegister dest) {
|
||||
void vpcmpeqd(const Operand &rhs, FloatRegister lhs, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src.kind()) {
|
||||
switch (rhs.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.pcmpeqd_rr(src.fpu(), dest.code());
|
||||
masm.vpcmpeqd_rr(rhs.fpu(), lhs.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.pcmpeqd_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vpcmpeqd_mr(rhs.disp(), rhs.base(), lhs.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.pcmpeqd_mr(src.address(), dest.code());
|
||||
masm.vpcmpeqd_mr(rhs.address(), lhs.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void pcmpgtd(const Operand &src, FloatRegister dest) {
|
||||
void vpcmpgtd(const Operand &rhs, FloatRegister lhs, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src.kind()) {
|
||||
switch (rhs.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.pcmpgtd_rr(src.fpu(), dest.code());
|
||||
masm.vpcmpgtd_rr(rhs.fpu(), lhs.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.pcmpgtd_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vpcmpgtd_mr(rhs.disp(), rhs.base(), lhs.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.pcmpgtd_mr(src.address(), dest.code());
|
||||
masm.vpcmpgtd_mr(rhs.address(), lhs.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
|
@ -1727,89 +1710,89 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
void vcmpneqps(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
vcmpps(X86Assembler::ConditionCmp_NEQ, src1, src0, dest);
|
||||
}
|
||||
void rcpps(const Operand &src, FloatRegister dest) {
|
||||
void vrcpps(const Operand &src, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.rcpps_rr(src.fpu(), dest.code());
|
||||
masm.vrcpps_rr(src.fpu(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.rcpps_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vrcpps_mr(src.disp(), src.base(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.rcpps_mr(src.address(), dest.code());
|
||||
masm.vrcpps_mr(src.address(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void sqrtps(const Operand &src, FloatRegister dest) {
|
||||
void vsqrtps(const Operand &src, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.sqrtps_rr(src.fpu(), dest.code());
|
||||
masm.vsqrtps_rr(src.fpu(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.sqrtps_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vsqrtps_mr(src.disp(), src.base(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.sqrtps_mr(src.address(), dest.code());
|
||||
masm.vsqrtps_mr(src.address(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void rsqrtps(const Operand &src, FloatRegister dest) {
|
||||
void vrsqrtps(const Operand &src, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.rsqrtps_rr(src.fpu(), dest.code());
|
||||
masm.vrsqrtps_rr(src.fpu(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.rsqrtps_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vrsqrtps_mr(src.disp(), src.base(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.rsqrtps_mr(src.address(), dest.code());
|
||||
masm.vrsqrtps_mr(src.address(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void movd(Register src, FloatRegister dest) {
|
||||
void vmovd(Register src, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.movd_rr(src.code(), dest.code());
|
||||
masm.vmovd_rr(src.code(), dest.code());
|
||||
}
|
||||
void movd(FloatRegister src, Register dest) {
|
||||
void vmovd(FloatRegister src, Register dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.movd_rr(src.code(), dest.code());
|
||||
masm.vmovd_rr(src.code(), dest.code());
|
||||
}
|
||||
void paddd(const Operand &src, FloatRegister dest) {
|
||||
void vpaddd(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src.kind()) {
|
||||
switch (src1.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.paddd_rr(src.fpu(), dest.code());
|
||||
masm.vpaddd_rr(src1.fpu(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.paddd_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vpaddd_mr(src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.paddd_mr(src.address(), dest.code());
|
||||
masm.vpaddd_mr(src1.address(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void psubd(const Operand &src, FloatRegister dest) {
|
||||
void vpsubd(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src.kind()) {
|
||||
switch (src1.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.psubd_rr(src.fpu(), dest.code());
|
||||
masm.vpsubd_rr(src1.fpu(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.psubd_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vpsubd_mr(src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.psubd_mr(src.address(), dest.code());
|
||||
masm.vpsubd_mr(src1.address(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
|
@ -1931,75 +1914,152 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void andps(const Operand &src, FloatRegister dest) {
|
||||
void vandps(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src.kind()) {
|
||||
switch (src1.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.andps_rr(src.fpu(), dest.code());
|
||||
masm.vandps_rr(src1.fpu(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.andps_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vandps_mr(src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.andps_mr(src.address(), dest.code());
|
||||
masm.vandps_mr(src1.address(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void andnps(const Operand &src, FloatRegister dest) {
|
||||
void vandnps(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
// Negates bits of dest and then applies AND
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src.kind()) {
|
||||
switch (src1.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.andnps_rr(src.fpu(), dest.code());
|
||||
masm.vandnps_rr(src1.fpu(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.andnps_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vandnps_mr(src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.andnps_mr(src.address(), dest.code());
|
||||
masm.vandnps_mr(src1.address(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void orps(const Operand &src, FloatRegister dest) {
|
||||
void vorps(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src.kind()) {
|
||||
switch (src1.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.orps_rr(src.fpu(), dest.code());
|
||||
masm.vorps_rr(src1.fpu(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.orps_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vorps_mr(src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.orps_mr(src.address(), dest.code());
|
||||
masm.vorps_mr(src1.address(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void xorps(const Operand &src, FloatRegister dest) {
|
||||
void vxorps(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src.kind()) {
|
||||
switch (src1.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.xorps_rr(src.fpu(), dest.code());
|
||||
masm.vxorps_rr(src1.fpu(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.xorps_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vxorps_mr(src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.xorps_mr(src.address(), dest.code());
|
||||
masm.vxorps_mr(src1.address(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void pxor(FloatRegister src, FloatRegister dest) {
|
||||
void vpand(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.pxor_rr(src.code(), dest.code());
|
||||
masm.vpand_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void vpand(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src1.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.vpand_rr(src1.fpu(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.vpand_mr(src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.vpand_mr(src1.address(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void vpor(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.vpor_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void vpor(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src1.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.vpor_rr(src1.fpu(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.vpor_mr(src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.vpor_mr(src1.address(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void vpxor(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.vpxor_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void vpxor(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src1.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.vpxor_rr(src1.fpu(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.vpxor_mr(src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.vpxor_mr(src1.address(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void vpandn(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.vpandn_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void vpandn(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src1.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.vpandn_rr(src1.fpu(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.vpandn_mr(src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.vpandn_mr(src1.address(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
|
||||
void pshufd(uint32_t mask, FloatRegister src, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.pshufd_irr(mask, src.code(), dest.code());
|
||||
|
@ -2020,21 +2080,21 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void movhlps(FloatRegister src, FloatRegister dest) {
|
||||
void vmovhlps(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.movhlps_rr(src.code(), dest.code());
|
||||
masm.vmovhlps_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void movlhps(FloatRegister src, FloatRegister dest) {
|
||||
void vmovlhps(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.movlhps_rr(src.code(), dest.code());
|
||||
masm.vmovlhps_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void unpcklps(FloatRegister src, FloatRegister dest) {
|
||||
void vunpcklps(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.unpcklps_rr(src.code(), dest.code());
|
||||
masm.vunpcklps_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void unpckhps(FloatRegister src, FloatRegister dest) {
|
||||
void vunpckhps(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.unpckhps_rr(src.code(), dest.code());
|
||||
masm.vunpckhps_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void shufps(uint32_t mask, FloatRegister src, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
|
@ -2198,37 +2258,37 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void xorpd(FloatRegister src, FloatRegister dest) {
|
||||
void vxorpd(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.xorpd_rr(src.code(), dest.code());
|
||||
masm.vxorpd_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void xorps(FloatRegister src, FloatRegister dest) {
|
||||
void vxorps(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.xorps_rr(src.code(), dest.code());
|
||||
masm.vxorps_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void orpd(FloatRegister src, FloatRegister dest) {
|
||||
void vorpd(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.orpd_rr(src.code(), dest.code());
|
||||
masm.vorpd_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void orps(FloatRegister src, FloatRegister dest) {
|
||||
void vorps(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.orps_rr(src.code(), dest.code());
|
||||
masm.vorps_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void andpd(FloatRegister src, FloatRegister dest) {
|
||||
void vandpd(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.andpd_rr(src.code(), dest.code());
|
||||
masm.vandpd_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void andps(FloatRegister src, FloatRegister dest) {
|
||||
void vandps(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.andps_rr(src.code(), dest.code());
|
||||
masm.vandps_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void sqrtsd(FloatRegister src, FloatRegister dest) {
|
||||
void vsqrtsd(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.sqrtsd_rr(src.code(), dest.code());
|
||||
masm.vsqrtsd_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void sqrtss(FloatRegister src, FloatRegister dest) {
|
||||
void vsqrtss(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.sqrtss_rr(src.code(), dest.code());
|
||||
masm.vsqrtss_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void roundsd(X86Assembler::RoundingMode mode, FloatRegister src, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE41());
|
||||
|
@ -2290,81 +2350,81 @@ class AssemblerX86Shared : public AssemblerShared
|
|||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void movsldup(FloatRegister src, FloatRegister dest) {
|
||||
void vmovsldup(FloatRegister src, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE3());
|
||||
masm.movsldup_rr(src.code(), dest.code());
|
||||
masm.vmovsldup_rr(src.code(), dest.code());
|
||||
}
|
||||
void movsldup(const Operand &src, FloatRegister dest) {
|
||||
void vmovsldup(const Operand &src, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE3());
|
||||
switch (src.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.movsldup_rr(src.fpu(), dest.code());
|
||||
masm.vmovsldup_rr(src.fpu(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.movsldup_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vmovsldup_mr(src.disp(), src.base(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void movshdup(FloatRegister src, FloatRegister dest) {
|
||||
void vmovshdup(FloatRegister src, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE3());
|
||||
masm.movshdup_rr(src.code(), dest.code());
|
||||
masm.vmovshdup_rr(src.code(), dest.code());
|
||||
}
|
||||
void movshdup(const Operand &src, FloatRegister dest) {
|
||||
void vmovshdup(const Operand &src, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE3());
|
||||
switch (src.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.movshdup_rr(src.fpu(), dest.code());
|
||||
masm.vmovshdup_rr(src.fpu(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.movshdup_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vmovshdup_mr(src.disp(), src.base(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void minsd(FloatRegister src, FloatRegister dest) {
|
||||
void vminsd(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.minsd_rr(src.code(), dest.code());
|
||||
masm.vminsd_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void minsd(const Operand &src, FloatRegister dest) {
|
||||
void vminsd(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src.kind()) {
|
||||
switch (src1.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.minsd_rr(src.fpu(), dest.code());
|
||||
masm.vminsd_rr(src1.fpu(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.minsd_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vminsd_mr(src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void minss(FloatRegister src, FloatRegister dest) {
|
||||
void vminss(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.minss_rr(src.code(), dest.code());
|
||||
masm.vminss_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void maxsd(FloatRegister src, FloatRegister dest) {
|
||||
void vmaxsd(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.maxsd_rr(src.code(), dest.code());
|
||||
masm.vmaxsd_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void maxsd(const Operand &src, FloatRegister dest) {
|
||||
void vmaxsd(const Operand &src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
switch (src.kind()) {
|
||||
switch (src1.kind()) {
|
||||
case Operand::FPREG:
|
||||
masm.maxsd_rr(src.fpu(), dest.code());
|
||||
masm.vmaxsd_rr(src1.fpu(), src0.code(), dest.code());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.maxsd_mr(src.disp(), src.base(), dest.code());
|
||||
masm.vmaxsd_mr(src1.disp(), src1.base(), src0.code(), dest.code());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void maxss(FloatRegister src, FloatRegister dest) {
|
||||
void vmaxss(FloatRegister src1, FloatRegister src0, FloatRegister dest) {
|
||||
MOZ_ASSERT(HasSSE2());
|
||||
masm.maxss_rr(src.code(), dest.code());
|
||||
masm.vmaxss_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void fisttp(const Operand &dest) {
|
||||
MOZ_ASSERT(HasSSE3());
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -116,7 +116,7 @@ CodeGeneratorX86Shared::visitTestIAndBranch(LTestIAndBranch *test)
|
|||
const LAllocation *opd = test->input();
|
||||
|
||||
// Test the operand
|
||||
masm.testl(ToRegister(opd), ToRegister(opd));
|
||||
masm.test32(ToRegister(opd), ToRegister(opd));
|
||||
emitBranch(Assembler::NonZero, test->ifTrue(), test->ifFalse());
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ CodeGeneratorX86Shared::visitTestDAndBranch(LTestDAndBranch *test)
|
|||
{
|
||||
const LAllocation *opd = test->input();
|
||||
|
||||
// ucomisd flags:
|
||||
// vucomisd flags:
|
||||
// Z P C
|
||||
// ---------
|
||||
// NaN 1 1 1
|
||||
|
@ -136,7 +136,7 @@ CodeGeneratorX86Shared::visitTestDAndBranch(LTestDAndBranch *test)
|
|||
// NaN is falsey, so comparing against 0 and then using the Z flag is
|
||||
// enough to determine which branch to take.
|
||||
masm.zeroDouble(ScratchDoubleReg);
|
||||
masm.ucomisd(ToFloatRegister(opd), ScratchDoubleReg);
|
||||
masm.vucomisd(ScratchDoubleReg, ToFloatRegister(opd));
|
||||
emitBranch(Assembler::NotEqual, test->ifTrue(), test->ifFalse());
|
||||
}
|
||||
|
||||
|
@ -144,9 +144,9 @@ void
|
|||
CodeGeneratorX86Shared::visitTestFAndBranch(LTestFAndBranch *test)
|
||||
{
|
||||
const LAllocation *opd = test->input();
|
||||
// ucomiss flags are the same as doubles; see comment above
|
||||
// vucomiss flags are the same as doubles; see comment above
|
||||
masm.zeroFloat32(ScratchFloat32Reg);
|
||||
masm.ucomiss(ToFloatRegister(opd), ScratchFloat32Reg);
|
||||
masm.vucomiss(ScratchFloat32Reg, ToFloatRegister(opd));
|
||||
emitBranch(Assembler::NotEqual, test->ifTrue(), test->ifFalse());
|
||||
}
|
||||
|
||||
|
@ -154,9 +154,9 @@ void
|
|||
CodeGeneratorX86Shared::visitBitAndAndBranch(LBitAndAndBranch *baab)
|
||||
{
|
||||
if (baab->right()->isConstant())
|
||||
masm.testl(ToRegister(baab->left()), Imm32(ToInt32(baab->right())));
|
||||
masm.test32(ToRegister(baab->left()), Imm32(ToInt32(baab->right())));
|
||||
else
|
||||
masm.testl(ToRegister(baab->left()), ToRegister(baab->right()));
|
||||
masm.test32(ToRegister(baab->left()), ToRegister(baab->right()));
|
||||
emitBranch(Assembler::NonZero, baab->ifTrue(), baab->ifFalse());
|
||||
}
|
||||
|
||||
|
@ -165,15 +165,15 @@ CodeGeneratorX86Shared::emitCompare(MCompare::CompareType type, const LAllocatio
|
|||
{
|
||||
#ifdef JS_CODEGEN_X64
|
||||
if (type == MCompare::Compare_Object) {
|
||||
masm.cmpq(ToRegister(left), ToOperand(right));
|
||||
masm.cmpPtr(ToRegister(left), ToOperand(right));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (right->isConstant())
|
||||
masm.cmpl(ToRegister(left), Imm32(ToInt32(right)));
|
||||
masm.cmp32(ToRegister(left), Imm32(ToInt32(right)));
|
||||
else
|
||||
masm.cmpl(ToRegister(left), ToOperand(right));
|
||||
masm.cmp32(ToRegister(left), ToOperand(right));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -228,7 +228,7 @@ CodeGeneratorX86Shared::visitCompareF(LCompareF *comp)
|
|||
void
|
||||
CodeGeneratorX86Shared::visitNotI(LNotI *ins)
|
||||
{
|
||||
masm.cmpl(ToRegister(ins->input()), Imm32(0));
|
||||
masm.cmp32(ToRegister(ins->input()), Imm32(0));
|
||||
masm.emitSet(Assembler::Equal, ToRegister(ins->output()));
|
||||
}
|
||||
|
||||
|
@ -492,12 +492,12 @@ CodeGeneratorX86Shared::visitMinMaxD(LMinMaxD *ins)
|
|||
|
||||
Label done, nan, minMaxInst;
|
||||
|
||||
// Do a ucomisd to catch equality and NaNs, which both require special
|
||||
// Do a vucomisd to catch equality and NaNs, which both require special
|
||||
// handling. If the operands are ordered and inequal, we branch straight to
|
||||
// the min/max instruction. If we wanted, we could also branch for less-than
|
||||
// or greater-than here instead of using min/max, however these conditions
|
||||
// will sometimes be hard on the branch predictor.
|
||||
masm.ucomisd(first, second);
|
||||
masm.vucomisd(second, first);
|
||||
masm.j(Assembler::NotEqual, &minMaxInst);
|
||||
if (!ins->mir()->range() || ins->mir()->range()->canBeNaN())
|
||||
masm.j(Assembler::Parity, &nan);
|
||||
|
@ -506,9 +506,9 @@ CodeGeneratorX86Shared::visitMinMaxD(LMinMaxD *ins)
|
|||
// and negative zero. These instructions merge the sign bits in that
|
||||
// case, and are no-ops otherwise.
|
||||
if (ins->mir()->isMax())
|
||||
masm.andpd(second, first);
|
||||
masm.vandpd(second, first, first);
|
||||
else
|
||||
masm.orpd(second, first);
|
||||
masm.vorpd(second, first, first);
|
||||
masm.jump(&done);
|
||||
|
||||
// x86's min/max are not symmetric; if either operand is a NaN, they return
|
||||
|
@ -516,7 +516,7 @@ CodeGeneratorX86Shared::visitMinMaxD(LMinMaxD *ins)
|
|||
// NaN, so we explicitly check for a NaN in the read-write operand.
|
||||
if (!ins->mir()->range() || ins->mir()->range()->canBeNaN()) {
|
||||
masm.bind(&nan);
|
||||
masm.ucomisd(first, first);
|
||||
masm.vucomisd(first, first);
|
||||
masm.j(Assembler::Parity, &done);
|
||||
}
|
||||
|
||||
|
@ -524,9 +524,9 @@ CodeGeneratorX86Shared::visitMinMaxD(LMinMaxD *ins)
|
|||
// return the value we need.
|
||||
masm.bind(&minMaxInst);
|
||||
if (ins->mir()->isMax())
|
||||
masm.maxsd(second, first);
|
||||
masm.vmaxsd(second, first, first);
|
||||
else
|
||||
masm.minsd(second, first);
|
||||
masm.vminsd(second, first, first);
|
||||
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
@ -543,12 +543,12 @@ CodeGeneratorX86Shared::visitMinMaxF(LMinMaxF *ins)
|
|||
|
||||
Label done, nan, minMaxInst;
|
||||
|
||||
// Do a ucomiss to catch equality and NaNs, which both require special
|
||||
// Do a vucomiss to catch equality and NaNs, which both require special
|
||||
// handling. If the operands are ordered and inequal, we branch straight to
|
||||
// the min/max instruction. If we wanted, we could also branch for less-than
|
||||
// or greater-than here instead of using min/max, however these conditions
|
||||
// will sometimes be hard on the branch predictor.
|
||||
masm.ucomiss(first, second);
|
||||
masm.vucomiss(second, first);
|
||||
masm.j(Assembler::NotEqual, &minMaxInst);
|
||||
if (!ins->mir()->range() || ins->mir()->range()->canBeNaN())
|
||||
masm.j(Assembler::Parity, &nan);
|
||||
|
@ -557,9 +557,9 @@ CodeGeneratorX86Shared::visitMinMaxF(LMinMaxF *ins)
|
|||
// and negative zero. These instructions merge the sign bits in that
|
||||
// case, and are no-ops otherwise.
|
||||
if (ins->mir()->isMax())
|
||||
masm.andps(second, first);
|
||||
masm.vandps(second, first, first);
|
||||
else
|
||||
masm.orps(second, first);
|
||||
masm.vorps(second, first, first);
|
||||
masm.jump(&done);
|
||||
|
||||
// x86's min/max are not symmetric; if either operand is a NaN, they return
|
||||
|
@ -567,7 +567,7 @@ CodeGeneratorX86Shared::visitMinMaxF(LMinMaxF *ins)
|
|||
// NaN, so we explicitly check for a NaN in the read-write operand.
|
||||
if (!ins->mir()->range() || ins->mir()->range()->canBeNaN()) {
|
||||
masm.bind(&nan);
|
||||
masm.ucomiss(first, first);
|
||||
masm.vucomiss(first, first);
|
||||
masm.j(Assembler::Parity, &done);
|
||||
}
|
||||
|
||||
|
@ -575,9 +575,9 @@ CodeGeneratorX86Shared::visitMinMaxF(LMinMaxF *ins)
|
|||
// return the value we need.
|
||||
masm.bind(&minMaxInst);
|
||||
if (ins->mir()->isMax())
|
||||
masm.maxss(second, first);
|
||||
masm.vmaxss(second, first, first);
|
||||
else
|
||||
masm.minss(second, first);
|
||||
masm.vminss(second, first, first);
|
||||
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
@ -590,7 +590,7 @@ CodeGeneratorX86Shared::visitAbsD(LAbsD *ins)
|
|||
// Load a value which is all ones except for the sign bit.
|
||||
masm.loadConstantDouble(SpecificNaN<double>(0, FloatingPoint<double>::kSignificandBits),
|
||||
ScratchDoubleReg);
|
||||
masm.andpd(ScratchDoubleReg, input);
|
||||
masm.vandpd(ScratchDoubleReg, input, input);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -601,7 +601,7 @@ CodeGeneratorX86Shared::visitAbsF(LAbsF *ins)
|
|||
// Same trick as visitAbsD above.
|
||||
masm.loadConstantFloat32(SpecificNaN<float>(0, FloatingPoint<float>::kSignificandBits),
|
||||
ScratchFloat32Reg);
|
||||
masm.andps(ScratchFloat32Reg, input);
|
||||
masm.vandps(ScratchFloat32Reg, input, input);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -613,7 +613,7 @@ CodeGeneratorX86Shared::visitClzI(LClzI *ins)
|
|||
// bsr is undefined on 0
|
||||
Label done, nonzero;
|
||||
if (!ins->mir()->operandIsNeverZero()) {
|
||||
masm.testl(input, input);
|
||||
masm.test32(input, input);
|
||||
masm.j(Assembler::NonZero, &nonzero);
|
||||
masm.move32(Imm32(32), output);
|
||||
masm.jump(&done);
|
||||
|
@ -630,7 +630,7 @@ CodeGeneratorX86Shared::visitSqrtD(LSqrtD *ins)
|
|||
{
|
||||
FloatRegister input = ToFloatRegister(ins->input());
|
||||
FloatRegister output = ToFloatRegister(ins->output());
|
||||
masm.sqrtsd(input, output);
|
||||
masm.vsqrtsd(input, output, output);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -638,14 +638,14 @@ CodeGeneratorX86Shared::visitSqrtF(LSqrtF *ins)
|
|||
{
|
||||
FloatRegister input = ToFloatRegister(ins->input());
|
||||
FloatRegister output = ToFloatRegister(ins->output());
|
||||
masm.sqrtss(input, output);
|
||||
masm.vsqrtss(input, output, output);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorX86Shared::visitPowHalfD(LPowHalfD *ins)
|
||||
{
|
||||
FloatRegister input = ToFloatRegister(ins->input());
|
||||
MOZ_ASSERT(input == ToFloatRegister(ins->output()));
|
||||
FloatRegister output = ToFloatRegister(ins->output());
|
||||
|
||||
Label done, sqrt;
|
||||
|
||||
|
@ -672,7 +672,7 @@ CodeGeneratorX86Shared::visitPowHalfD(LPowHalfD *ins)
|
|||
masm.addDouble(ScratchDoubleReg, input);
|
||||
}
|
||||
|
||||
masm.sqrtsd(input, input);
|
||||
masm.vsqrtsd(input, output, output);
|
||||
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
@ -796,7 +796,7 @@ CodeGeneratorX86Shared::visitMulI(LMulI *ins)
|
|||
int32_t constant = ToInt32(rhs);
|
||||
if (mul->canBeNegativeZero() && constant <= 0) {
|
||||
Assembler::Condition bailoutCond = (constant == 0) ? Assembler::Signed : Assembler::Equal;
|
||||
masm.testl(ToRegister(lhs), ToRegister(lhs));
|
||||
masm.test32(ToRegister(lhs), ToRegister(lhs));
|
||||
bailoutIf(bailoutCond, ins->snapshot());
|
||||
}
|
||||
|
||||
|
@ -840,7 +840,7 @@ CodeGeneratorX86Shared::visitMulI(LMulI *ins)
|
|||
MulNegativeZeroCheck *ool = new(alloc()) MulNegativeZeroCheck(ins);
|
||||
addOutOfLineCode(ool, mul);
|
||||
|
||||
masm.testl(ToRegister(lhs), ToRegister(lhs));
|
||||
masm.test32(ToRegister(lhs), ToRegister(lhs));
|
||||
masm.j(Assembler::Zero, ool->entry());
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
@ -890,7 +890,7 @@ CodeGeneratorX86Shared::visitUDivOrMod(LUDivOrMod *ins)
|
|||
|
||||
// Prevent divide by zero.
|
||||
if (ins->canBeDivideByZero()) {
|
||||
masm.testl(rhs, rhs);
|
||||
masm.test32(rhs, rhs);
|
||||
if (ins->mir()->isTruncated()) {
|
||||
if (!ool)
|
||||
ool = new(alloc()) ReturnZero(output);
|
||||
|
@ -907,14 +907,14 @@ CodeGeneratorX86Shared::visitUDivOrMod(LUDivOrMod *ins)
|
|||
// If the remainder is > 0, bailout since this must be a double.
|
||||
if (ins->mir()->isDiv() && !ins->mir()->toDiv()->canTruncateRemainder()) {
|
||||
Register remainder = ToRegister(ins->remainder());
|
||||
masm.testl(remainder, remainder);
|
||||
masm.test32(remainder, remainder);
|
||||
bailoutIf(Assembler::NonZero, ins->snapshot());
|
||||
}
|
||||
|
||||
// Unsigned div or mod can return a value that's not a signed int32.
|
||||
// If our users aren't expecting that, bail.
|
||||
if (!ins->mir()->isTruncated()) {
|
||||
masm.testl(output, output);
|
||||
masm.test32(output, output);
|
||||
bailoutIf(Assembler::Signed, ins->snapshot());
|
||||
}
|
||||
|
||||
|
@ -958,14 +958,14 @@ CodeGeneratorX86Shared::visitDivPowTwoI(LDivPowTwoI *ins)
|
|||
|
||||
if (!mir->isTruncated() && negativeDivisor) {
|
||||
// 0 divided by a negative number must return a double.
|
||||
masm.testl(lhs, lhs);
|
||||
masm.test32(lhs, lhs);
|
||||
bailoutIf(Assembler::Zero, ins->snapshot());
|
||||
}
|
||||
|
||||
if (shift != 0) {
|
||||
if (!mir->isTruncated()) {
|
||||
// If the remainder is != 0, bailout since this must be a double.
|
||||
masm.testl(lhs, Imm32(UINT32_MAX >> (32 - shift)));
|
||||
masm.test32(lhs, Imm32(UINT32_MAX >> (32 - shift)));
|
||||
bailoutIf(Assembler::NonZero, ins->snapshot());
|
||||
}
|
||||
|
||||
|
@ -1044,13 +1044,13 @@ CodeGeneratorX86Shared::visitDivOrModConstantI(LDivOrModConstantI *ins) {
|
|||
// This is a division op. Multiply the obtained value by d to check if
|
||||
// the correct answer is an integer. This cannot overflow, since |d| > 1.
|
||||
masm.imull(Imm32(d), edx, eax);
|
||||
masm.cmpl(lhs, eax);
|
||||
masm.cmp32(lhs, eax);
|
||||
bailoutIf(Assembler::NotEqual, ins->snapshot());
|
||||
|
||||
// If lhs is zero and the divisor is negative, the answer should have
|
||||
// been -0.
|
||||
if (d < 0) {
|
||||
masm.testl(lhs, lhs);
|
||||
masm.test32(lhs, lhs);
|
||||
bailoutIf(Assembler::Zero, ins->snapshot());
|
||||
}
|
||||
} else if (ins->canBeNegativeDividend()) {
|
||||
|
@ -1058,10 +1058,10 @@ CodeGeneratorX86Shared::visitDivOrModConstantI(LDivOrModConstantI *ins) {
|
|||
// is negative, the answer should have been -0.
|
||||
Label done;
|
||||
|
||||
masm.cmpl(lhs, Imm32(0));
|
||||
masm.cmp32(lhs, Imm32(0));
|
||||
masm.j(Assembler::GreaterThanOrEqual, &done);
|
||||
|
||||
masm.testl(eax, eax);
|
||||
masm.test32(eax, eax);
|
||||
bailoutIf(Assembler::Zero, ins->snapshot());
|
||||
|
||||
masm.bind(&done);
|
||||
|
@ -1094,7 +1094,7 @@ CodeGeneratorX86Shared::visitDivI(LDivI *ins)
|
|||
|
||||
// Handle divide by zero.
|
||||
if (mir->canBeDivideByZero()) {
|
||||
masm.testl(rhs, rhs);
|
||||
masm.test32(rhs, rhs);
|
||||
if (mir->canTruncateInfinities()) {
|
||||
// Truncated division by zero is zero (Infinity|0 == 0)
|
||||
if (!ool)
|
||||
|
@ -1109,9 +1109,9 @@ CodeGeneratorX86Shared::visitDivI(LDivI *ins)
|
|||
// Handle an integer overflow exception from -2147483648 / -1.
|
||||
if (mir->canBeNegativeOverflow()) {
|
||||
Label notmin;
|
||||
masm.cmpl(lhs, Imm32(INT32_MIN));
|
||||
masm.cmp32(lhs, Imm32(INT32_MIN));
|
||||
masm.j(Assembler::NotEqual, ¬min);
|
||||
masm.cmpl(rhs, Imm32(-1));
|
||||
masm.cmp32(rhs, Imm32(-1));
|
||||
if (mir->canTruncateOverflow()) {
|
||||
// (-INT32_MIN)|0 == INT32_MIN and INT32_MIN is already in the
|
||||
// output register (lhs == eax).
|
||||
|
@ -1126,9 +1126,9 @@ CodeGeneratorX86Shared::visitDivI(LDivI *ins)
|
|||
// Handle negative 0.
|
||||
if (!mir->canTruncateNegativeZero() && mir->canBeNegativeZero()) {
|
||||
Label nonzero;
|
||||
masm.testl(lhs, lhs);
|
||||
masm.test32(lhs, lhs);
|
||||
masm.j(Assembler::NonZero, &nonzero);
|
||||
masm.cmpl(rhs, Imm32(0));
|
||||
masm.cmp32(rhs, Imm32(0));
|
||||
bailoutIf(Assembler::LessThan, ins->snapshot());
|
||||
masm.bind(&nonzero);
|
||||
}
|
||||
|
@ -1141,7 +1141,7 @@ CodeGeneratorX86Shared::visitDivI(LDivI *ins)
|
|||
|
||||
if (!mir->canTruncateRemainder()) {
|
||||
// If the remainder is > 0, bailout since this must be a double.
|
||||
masm.testl(remainder, remainder);
|
||||
masm.test32(remainder, remainder);
|
||||
bailoutIf(Assembler::NonZero, ins->snapshot());
|
||||
}
|
||||
|
||||
|
@ -1222,7 +1222,7 @@ class ModOverflowCheck : public OutOfLineCodeBase<CodeGeneratorX86Shared>
|
|||
void
|
||||
CodeGeneratorX86Shared::visitModOverflowCheck(ModOverflowCheck *ool)
|
||||
{
|
||||
masm.cmpl(ool->rhs(), Imm32(-1));
|
||||
masm.cmp32(ool->rhs(), Imm32(-1));
|
||||
if (ool->ins()->mir()->isTruncated()) {
|
||||
masm.j(Assembler::NotEqual, ool->rejoin());
|
||||
masm.mov(ImmWord(0), edx);
|
||||
|
@ -1256,7 +1256,7 @@ CodeGeneratorX86Shared::visitModI(LModI *ins)
|
|||
|
||||
// Prevent divide by zero.
|
||||
if (ins->mir()->canBeDivideByZero()) {
|
||||
masm.testl(rhs, rhs);
|
||||
masm.test32(rhs, rhs);
|
||||
if (ins->mir()->isTruncated()) {
|
||||
if (!ool)
|
||||
ool = new(alloc()) ReturnZero(edx);
|
||||
|
@ -1308,7 +1308,7 @@ CodeGeneratorX86Shared::visitModI(LModI *ins)
|
|||
|
||||
// Prevent an integer overflow exception from -2147483648 % -1
|
||||
Label notmin;
|
||||
masm.cmpl(lhs, Imm32(INT32_MIN));
|
||||
masm.cmp32(lhs, Imm32(INT32_MIN));
|
||||
overflow = new(alloc()) ModOverflowCheck(ins, rhs);
|
||||
masm.j(Assembler::Equal, overflow->entry());
|
||||
masm.bind(overflow->rejoin());
|
||||
|
@ -1317,7 +1317,7 @@ CodeGeneratorX86Shared::visitModI(LModI *ins)
|
|||
|
||||
if (!ins->mir()->isTruncated()) {
|
||||
// A remainder of 0 means that the rval must be -0, which is a double.
|
||||
masm.testl(remainder, remainder);
|
||||
masm.test32(remainder, remainder);
|
||||
bailoutIf(Assembler::Zero, ins->snapshot());
|
||||
}
|
||||
}
|
||||
|
@ -1396,7 +1396,7 @@ CodeGeneratorX86Shared::visitShiftI(LShiftI *ins)
|
|||
masm.shrl(Imm32(shift), lhs);
|
||||
} else if (ins->mir()->toUrsh()->fallible()) {
|
||||
// x >>> 0 can overflow.
|
||||
masm.testl(lhs, lhs);
|
||||
masm.test32(lhs, lhs);
|
||||
bailoutIf(Assembler::Signed, ins->snapshot());
|
||||
}
|
||||
break;
|
||||
|
@ -1416,7 +1416,7 @@ CodeGeneratorX86Shared::visitShiftI(LShiftI *ins)
|
|||
masm.shrl_cl(lhs);
|
||||
if (ins->mir()->toUrsh()->fallible()) {
|
||||
// x >>> 0 can overflow.
|
||||
masm.testl(lhs, lhs);
|
||||
masm.test32(lhs, lhs);
|
||||
bailoutIf(Assembler::Signed, ins->snapshot());
|
||||
}
|
||||
break;
|
||||
|
@ -1514,7 +1514,7 @@ CodeGeneratorX86Shared::emitTableSwitchDispatch(MTableSwitch *mir, Register inde
|
|||
|
||||
// Jump to default case if input is out of range
|
||||
int32_t cases = mir->numCases();
|
||||
masm.cmpl(index, Imm32(cases));
|
||||
masm.cmp32(index, Imm32(cases));
|
||||
masm.j(AssemblerX86Shared::AboveOrEqual, defaultcase);
|
||||
|
||||
// To fill in the CodeLabels for the case entries, we need to first
|
||||
|
@ -1710,7 +1710,7 @@ CodeGeneratorX86Shared::visitCeil(LCeil *lir)
|
|||
scratch, &lessThanMinusOne);
|
||||
|
||||
// Test for remaining values with the sign bit set, i.e. ]-1; -0]
|
||||
masm.movmskpd(input, output);
|
||||
masm.vmovmskpd(input, output);
|
||||
masm.branchTest32(Assembler::NonZero, output, Imm32(1), &bailout);
|
||||
bailoutFrom(&bailout, lir->snapshot());
|
||||
|
||||
|
@ -1762,7 +1762,7 @@ CodeGeneratorX86Shared::visitCeilF(LCeilF *lir)
|
|||
scratch, &lessThanMinusOne);
|
||||
|
||||
// Test for remaining values with the sign bit set, i.e. ]-1; -0]
|
||||
masm.movmskps(input, output);
|
||||
masm.vmovmskps(input, output);
|
||||
masm.branchTest32(Assembler::NonZero, output, Imm32(1), &bailout);
|
||||
bailoutFrom(&bailout, lir->snapshot());
|
||||
|
||||
|
@ -1852,7 +1852,7 @@ CodeGeneratorX86Shared::visitRound(LRound *lir)
|
|||
|
||||
// If the result is positive zero, then the actual result is -0. Bail.
|
||||
// Otherwise, the truncation will have produced the correct negative integer.
|
||||
masm.testl(output, output);
|
||||
masm.test32(output, output);
|
||||
bailoutIf(Assembler::Zero, lir->snapshot());
|
||||
} else {
|
||||
masm.addDouble(input, temp);
|
||||
|
@ -1935,7 +1935,7 @@ CodeGeneratorX86Shared::visitRoundF(LRoundF *lir)
|
|||
|
||||
// If the result is positive zero, then the actual result is -0. Bail.
|
||||
// Otherwise, the truncation will have produced the correct negative integer.
|
||||
masm.testl(output, output);
|
||||
masm.test32(output, output);
|
||||
bailoutIf(Assembler::Zero, lir->snapshot());
|
||||
} else {
|
||||
masm.addFloat32(input, temp);
|
||||
|
@ -2090,7 +2090,7 @@ CodeGeneratorX86Shared::visitSimdValueInt32x4(LSimdValueInt32x4 *ins)
|
|||
|
||||
FloatRegister output = ToFloatRegister(ins->output());
|
||||
if (AssemblerX86Shared::HasSSE41()) {
|
||||
masm.movd(ToRegister(ins->getOperand(0)), output);
|
||||
masm.vmovd(ToRegister(ins->getOperand(0)), output);
|
||||
for (size_t i = 1; i < 4; ++i) {
|
||||
Register r = ToRegister(ins->getOperand(i));
|
||||
masm.pinsrd(i, r, output);
|
||||
|
@ -2119,9 +2119,9 @@ CodeGeneratorX86Shared::visitSimdValueFloat32x4(LSimdValueFloat32x4 *ins)
|
|||
FloatRegister r2 = ToFloatRegister(ins->getOperand(2));
|
||||
FloatRegister r3 = ToFloatRegister(ins->getOperand(3));
|
||||
|
||||
masm.unpcklps(r3, r1);
|
||||
masm.unpcklps(r2, r0);
|
||||
masm.unpcklps(r1, r0);
|
||||
masm.vunpcklps(r3, r1, r1);
|
||||
masm.vunpcklps(r2, r0, r0);
|
||||
masm.vunpcklps(r1, r0, r0);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2136,7 +2136,7 @@ CodeGeneratorX86Shared::visitSimdSplatX4(LSimdSplatX4 *ins)
|
|||
switch (mir->type()) {
|
||||
case MIRType_Int32x4: {
|
||||
Register r = ToRegister(ins->getOperand(0));
|
||||
masm.movd(r, output);
|
||||
masm.vmovd(r, output);
|
||||
masm.pshufd(0, output, output);
|
||||
break;
|
||||
}
|
||||
|
@ -2200,8 +2200,8 @@ CodeGeneratorX86Shared::visitSimdInsertElementI(LSimdInsertElementI *ins)
|
|||
|
||||
unsigned component = unsigned(ins->lane());
|
||||
|
||||
// Note that, contrarily to float32x4, we cannot use movd if the inserted
|
||||
// value goes into the first component, as movd clears out the higher lanes
|
||||
// Note that, contrarily to float32x4, we cannot use vmovd if the inserted
|
||||
// value goes into the first component, as vmovd clears out the higher lanes
|
||||
// of the output.
|
||||
if (AssemblerX86Shared::HasSSE41()) {
|
||||
masm.pinsrd(component, value, output);
|
||||
|
@ -2252,7 +2252,7 @@ CodeGeneratorX86Shared::visitSimdSignMaskX4(LSimdSignMaskX4 *ins)
|
|||
Register output = ToRegister(ins->output());
|
||||
|
||||
// For Float32x4 and Int32x4.
|
||||
masm.movmskps(input, output);
|
||||
masm.vmovmskps(input, output);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2283,11 +2283,11 @@ CodeGeneratorX86Shared::visitSimdSwizzleF(LSimdSwizzleF *ins)
|
|||
|
||||
if (AssemblerX86Shared::HasSSE3()) {
|
||||
if (ins->lanesMatch(0, 0, 2, 2)) {
|
||||
masm.movsldup(input, output);
|
||||
masm.vmovsldup(input, output);
|
||||
return;
|
||||
}
|
||||
if (ins->lanesMatch(1, 1, 3, 3)) {
|
||||
masm.movshdup(input, output);
|
||||
masm.vmovshdup(input, output);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -2295,26 +2295,26 @@ CodeGeneratorX86Shared::visitSimdSwizzleF(LSimdSwizzleF *ins)
|
|||
// TODO Here and below, arch specific lowering could identify this pattern
|
||||
// and use defineReuseInput to avoid this move (bug 1084404)
|
||||
if (ins->lanesMatch(2, 3, 2, 3)) {
|
||||
masm.movaps(input, output);
|
||||
masm.movhlps(input, output);
|
||||
FloatRegister inputCopy = masm.reusedInputFloat32x4(input, output);
|
||||
masm.vmovhlps(input, inputCopy, output);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ins->lanesMatch(0, 1, 0, 1)) {
|
||||
masm.movaps(input, output);
|
||||
masm.movlhps(input, output);
|
||||
FloatRegister inputCopy = masm.reusedInputFloat32x4(input, output);
|
||||
masm.vmovlhps(input, inputCopy, output);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ins->lanesMatch(0, 0, 1, 1)) {
|
||||
masm.movaps(input, output);
|
||||
masm.unpcklps(input, output);
|
||||
FloatRegister inputCopy = masm.reusedInputFloat32x4(input, output);
|
||||
masm.vunpcklps(input, inputCopy, output);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ins->lanesMatch(2, 2, 3, 3)) {
|
||||
masm.movaps(input, output);
|
||||
masm.unpckhps(input, output);
|
||||
FloatRegister inputCopy = masm.reusedInputFloat32x4(input, output);
|
||||
masm.vunpckhps(input, inputCopy, output);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2447,40 +2447,52 @@ CodeGeneratorX86Shared::visitSimdShuffle(LSimdShuffle *ins)
|
|||
// TODO Here and below, symmetric case would be more handy to avoid a move,
|
||||
// but can't be reached because operands would get swapped (bug 1084404).
|
||||
if (ins->lanesMatch(2, 3, 6, 7)) {
|
||||
masm.movaps(rhs, ScratchSimdReg);
|
||||
masm.movhlps(lhs, ScratchSimdReg);
|
||||
masm.movaps(ScratchSimdReg, out);
|
||||
if (AssemblerX86Shared::HasAVX()) {
|
||||
masm.vmovhlps(lhs, rhs, out);
|
||||
} else {
|
||||
masm.movaps(rhs, ScratchSimdReg);
|
||||
masm.vmovhlps(lhs, ScratchSimdReg, ScratchSimdReg);
|
||||
masm.movaps(ScratchSimdReg, out);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ins->lanesMatch(0, 1, 4, 5)) {
|
||||
masm.movlhps(rhs, lhs);
|
||||
masm.vmovlhps(rhs, lhs, out);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ins->lanesMatch(0, 4, 1, 5)) {
|
||||
masm.unpcklps(rhs, lhs);
|
||||
masm.vunpcklps(rhs, lhs, out);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO swapped case would be better (bug 1084404)
|
||||
if (ins->lanesMatch(4, 0, 5, 1)) {
|
||||
masm.movaps(rhs, ScratchSimdReg);
|
||||
masm.unpcklps(lhs, ScratchSimdReg);
|
||||
masm.movaps(ScratchSimdReg, out);
|
||||
if (AssemblerX86Shared::HasAVX()) {
|
||||
masm.vunpcklps(lhs, rhs, out);
|
||||
} else {
|
||||
masm.movaps(rhs, ScratchSimdReg);
|
||||
masm.vunpcklps(lhs, ScratchSimdReg, ScratchSimdReg);
|
||||
masm.movaps(ScratchSimdReg, out);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ins->lanesMatch(2, 6, 3, 7)) {
|
||||
masm.unpckhps(rhs, lhs);
|
||||
masm.vunpckhps(rhs, lhs, lhs);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO swapped case would be better (bug 1084404)
|
||||
if (ins->lanesMatch(6, 2, 7, 3)) {
|
||||
masm.movaps(rhs, ScratchSimdReg);
|
||||
masm.unpckhps(lhs, ScratchSimdReg);
|
||||
masm.movaps(ScratchSimdReg, out);
|
||||
if (AssemblerX86Shared::HasAVX()) {
|
||||
masm.vunpckhps(lhs, rhs, out);
|
||||
} else {
|
||||
masm.movaps(rhs, ScratchSimdReg);
|
||||
masm.vunpckhps(lhs, ScratchSimdReg, ScratchSimdReg);
|
||||
masm.movaps(ScratchSimdReg, out);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2616,15 +2628,15 @@ CodeGeneratorX86Shared::visitSimdBinaryArithIx4(LSimdBinaryArithIx4 *ins)
|
|||
{
|
||||
FloatRegister lhs = ToFloatRegister(ins->lhs());
|
||||
Operand rhs = ToOperand(ins->rhs());
|
||||
MOZ_ASSERT(ToFloatRegister(ins->output()) == lhs);
|
||||
FloatRegister output = ToFloatRegister(ins->output());
|
||||
|
||||
MSimdBinaryArith::Operation op = ins->operation();
|
||||
switch (op) {
|
||||
case MSimdBinaryArith::Add:
|
||||
masm.packedAddInt32(rhs, lhs);
|
||||
masm.vpaddd(rhs, lhs, output);
|
||||
return;
|
||||
case MSimdBinaryArith::Sub:
|
||||
masm.packedSubInt32(rhs, lhs);
|
||||
masm.vpsubd(rhs, lhs, output);
|
||||
return;
|
||||
case MSimdBinaryArith::Mul: {
|
||||
if (AssemblerX86Shared::HasSSE41()) {
|
||||
|
@ -2695,29 +2707,29 @@ CodeGeneratorX86Shared::visitSimdBinaryArithFx4(LSimdBinaryArithFx4 *ins)
|
|||
masm.vmaxps(Operand(lhs), rhsCopy, tmp);
|
||||
masm.vmaxps(rhs, lhs, output);
|
||||
|
||||
masm.andps(tmp, output);
|
||||
masm.orps(ScratchSimdReg, output); // or in the all-ones NaNs
|
||||
masm.vandps(tmp, output, output);
|
||||
masm.vorps(ScratchSimdReg, output, output); // or in the all-ones NaNs
|
||||
return;
|
||||
}
|
||||
case MSimdBinaryArith::Min: {
|
||||
FloatRegister rhsCopy = masm.reusedInputAlignedFloat32x4(rhs, ScratchSimdReg);
|
||||
masm.vminps(Operand(lhs), rhsCopy, ScratchSimdReg);
|
||||
masm.vminps(rhs, lhs, output);
|
||||
masm.orps(ScratchSimdReg, output); // NaN or'd with arbitrary bits is NaN
|
||||
masm.vorps(ScratchSimdReg, output, output); // NaN or'd with arbitrary bits is NaN
|
||||
return;
|
||||
}
|
||||
case MSimdBinaryArith::MinNum: {
|
||||
FloatRegister tmp = ToFloatRegister(ins->temp());
|
||||
masm.loadConstantInt32x4(SimdConstant::SplatX4(int32_t(0x80000000)), ScratchSimdReg);
|
||||
masm.movdqa(ScratchSimdReg, tmp);
|
||||
masm.loadConstantInt32x4(SimdConstant::SplatX4(int32_t(0x80000000)), tmp);
|
||||
|
||||
FloatRegister mask = ScratchSimdReg;
|
||||
masm.pcmpeqd(Operand(lhs), mask);
|
||||
masm.andps(tmp, mask);
|
||||
FloatRegister tmpCopy = masm.reusedInputFloat32x4(tmp, ScratchSimdReg);
|
||||
masm.vpcmpeqd(Operand(lhs), tmpCopy, mask);
|
||||
masm.vandps(tmp, mask, mask);
|
||||
|
||||
FloatRegister lhsCopy = masm.reusedInputFloat32x4(lhs, tmp);
|
||||
masm.vminps(rhs, lhsCopy, tmp);
|
||||
masm.orps(mask, tmp);
|
||||
masm.vorps(mask, tmp, tmp);
|
||||
|
||||
FloatRegister rhsCopy = masm.reusedInputAlignedFloat32x4(rhs, mask);
|
||||
masm.vcmpneqps(rhs, rhsCopy, mask);
|
||||
|
@ -2730,24 +2742,24 @@ CodeGeneratorX86Shared::visitSimdBinaryArithFx4(LSimdBinaryArithFx4 *ins)
|
|||
// it requires the mask to be in xmm0.
|
||||
if (lhs != output)
|
||||
masm.movaps(lhs, output);
|
||||
masm.andps(Operand(mask), output);
|
||||
masm.andnps(Operand(tmp), mask);
|
||||
masm.orps(Operand(mask), output);
|
||||
masm.vandps(Operand(mask), output, output);
|
||||
masm.vandnps(Operand(tmp), mask, mask);
|
||||
masm.vorps(Operand(mask), output, output);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case MSimdBinaryArith::MaxNum: {
|
||||
FloatRegister mask = ScratchSimdReg;
|
||||
masm.loadConstantInt32x4(SimdConstant::SplatX4(0), mask);
|
||||
masm.pcmpeqd(Operand(lhs), mask);
|
||||
masm.vpcmpeqd(Operand(lhs), mask, mask);
|
||||
|
||||
FloatRegister tmp = ToFloatRegister(ins->temp());
|
||||
masm.loadConstantInt32x4(SimdConstant::SplatX4(int32_t(0x80000000)), tmp);
|
||||
masm.andps(tmp, mask);
|
||||
masm.vandps(tmp, mask, mask);
|
||||
|
||||
FloatRegister lhsCopy = masm.reusedInputFloat32x4(lhs, tmp);
|
||||
masm.vmaxps(rhs, lhsCopy, tmp);
|
||||
masm.andnps(Operand(tmp), mask);
|
||||
masm.vandnps(Operand(tmp), mask, mask);
|
||||
|
||||
// Ensure tmp always contains the temporary result
|
||||
mask = tmp;
|
||||
|
@ -2764,9 +2776,9 @@ CodeGeneratorX86Shared::visitSimdBinaryArithFx4(LSimdBinaryArithFx4 *ins)
|
|||
// it requires the mask to be in xmm0.
|
||||
if (lhs != output)
|
||||
masm.movaps(lhs, output);
|
||||
masm.andps(Operand(mask), output);
|
||||
masm.andnps(Operand(tmp), mask);
|
||||
masm.orps(Operand(mask), output);
|
||||
masm.vandps(Operand(mask), output, output);
|
||||
masm.vandnps(Operand(tmp), mask, mask);
|
||||
masm.vorps(Operand(mask), output, output);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -2784,7 +2796,7 @@ CodeGeneratorX86Shared::visitSimdUnaryArithIx4(LSimdUnaryArithIx4 *ins)
|
|||
|
||||
switch (ins->operation()) {
|
||||
case MSimdUnaryArith::neg:
|
||||
masm.pxor(out, out);
|
||||
masm.zeroInt32x4(out);
|
||||
masm.packedSubInt32(in, out);
|
||||
return;
|
||||
case MSimdUnaryArith::not_:
|
||||
|
@ -2848,18 +2860,27 @@ CodeGeneratorX86Shared::visitSimdBinaryBitwiseX4(LSimdBinaryBitwiseX4 *ins)
|
|||
{
|
||||
FloatRegister lhs = ToFloatRegister(ins->lhs());
|
||||
Operand rhs = ToOperand(ins->rhs());
|
||||
MOZ_ASSERT(ToFloatRegister(ins->output()) == lhs);
|
||||
FloatRegister output = ToFloatRegister(ins->output());
|
||||
|
||||
MSimdBinaryBitwise::Operation op = ins->operation();
|
||||
switch (op) {
|
||||
case MSimdBinaryBitwise::and_:
|
||||
masm.bitwiseAndX4(rhs, lhs);
|
||||
if (ins->type() == MIRType_Float32x4)
|
||||
masm.vandps(rhs, lhs, output);
|
||||
else
|
||||
masm.vpand(rhs, lhs, output);
|
||||
return;
|
||||
case MSimdBinaryBitwise::or_:
|
||||
masm.bitwiseOrX4(rhs, lhs);
|
||||
if (ins->type() == MIRType_Float32x4)
|
||||
masm.vorps(rhs, lhs, output);
|
||||
else
|
||||
masm.vpor(rhs, lhs, output);
|
||||
return;
|
||||
case MSimdBinaryBitwise::xor_:
|
||||
masm.bitwiseXorX4(rhs, lhs);
|
||||
if (ins->type() == MIRType_Float32x4)
|
||||
masm.vxorps(rhs, lhs, output);
|
||||
else
|
||||
masm.vpxor(rhs, lhs, output);
|
||||
return;
|
||||
}
|
||||
MOZ_CRASH("unexpected SIMD bitwise op");
|
||||
|
@ -2896,7 +2917,7 @@ CodeGeneratorX86Shared::visitSimdShift(LSimdShift *ins)
|
|||
|
||||
MOZ_ASSERT(val->isRegister());
|
||||
FloatRegister tmp = ScratchFloat32Reg;
|
||||
masm.movd(ToRegister(val), tmp);
|
||||
masm.vmovd(ToRegister(val), tmp);
|
||||
|
||||
switch (ins->operation()) {
|
||||
case MSimdShift::lsh:
|
||||
|
|
|
@ -100,17 +100,17 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
|
|||
bailoutIf(Assembler::Zero, snapshot);
|
||||
}
|
||||
void bailoutCvttsd2si(FloatRegister src, Register dest, LSnapshot *snapshot) {
|
||||
// cvttsd2si returns 0x80000000 on failure. Test for it by
|
||||
// vcvttsd2si returns 0x80000000 on failure. Test for it by
|
||||
// subtracting 1 and testing overflow. The other possibility is to test
|
||||
// equality for INT_MIN after a comparison, but 1 costs fewer bytes to
|
||||
// materialize.
|
||||
masm.cvttsd2si(src, dest);
|
||||
masm.vcvttsd2si(src, dest);
|
||||
masm.cmp32(dest, Imm32(1));
|
||||
bailoutIf(Assembler::Overflow, snapshot);
|
||||
}
|
||||
void bailoutCvttss2si(FloatRegister src, Register dest, LSnapshot *snapshot) {
|
||||
// Same trick as explained in the above comment.
|
||||
masm.cvttss2si(src, dest);
|
||||
masm.vcvttss2si(src, dest);
|
||||
masm.cmp32(dest, Imm32(1));
|
||||
bailoutIf(Assembler::Overflow, snapshot);
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ LIRGeneratorX86Shared::visitPowHalf(MPowHalf *ins)
|
|||
MDefinition *input = ins->input();
|
||||
MOZ_ASSERT(input->type() == MIRType_Double);
|
||||
LPowHalfD *lir = new(alloc()) LPowHalfD(useRegisterAtStart(input));
|
||||
defineReuseInput(lir, ins, 0);
|
||||
define(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -96,29 +96,13 @@ LIRGeneratorX86Shared::lowerForALU(LInstructionHelper<1, 2, 0> *ins, MDefinition
|
|||
defineReuseInput(ins, mir, 0);
|
||||
}
|
||||
|
||||
static bool
|
||||
UseAVXEncoding(MIRType type)
|
||||
{
|
||||
if (!Assembler::HasAVX())
|
||||
return false;
|
||||
|
||||
// TODO: For now, we just do this for floating-point types, until the rest
|
||||
// of the assembler support is done.
|
||||
if (IsFloatingPointType(type))
|
||||
return true;
|
||||
if (IsSimdType(type) && IsFloatingPointType(SimdTypeToScalarType(type)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<size_t Temps>
|
||||
void
|
||||
LIRGeneratorX86Shared::lowerForFPU(LInstructionHelper<1, 2, Temps> *ins, MDefinition *mir, MDefinition *lhs, MDefinition *rhs)
|
||||
{
|
||||
// Without AVX, we'll need to use the x86 encodings where one of the
|
||||
// inputs must be the same location as the output.
|
||||
if (!UseAVXEncoding(mir->type())) {
|
||||
if (!Assembler::HasAVX()) {
|
||||
ins->setOperand(0, useRegisterAtStart(lhs));
|
||||
ins->setOperand(1, lhs != rhs ? use(rhs) : useAtStart(rhs));
|
||||
defineReuseInput(ins, mir, 0);
|
||||
|
|
|
@ -122,7 +122,7 @@ MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output)
|
|||
// Truncate to int32 and ensure the result <= 255. This relies on the
|
||||
// processor setting output to a value > 255 for doubles outside the int32
|
||||
// range (for instance 0x80000000).
|
||||
cvttsd2si(input, output);
|
||||
vcvttsd2si(input, output);
|
||||
branch32(Assembler::Above, output, Imm32(255), &outOfRange);
|
||||
{
|
||||
// Check if we had a tie.
|
||||
|
@ -217,13 +217,13 @@ MacroAssemblerX86Shared::branchNegativeZero(FloatRegister reg,
|
|||
// if not already compared to zero
|
||||
if (maybeNonZero) {
|
||||
// Compare to zero. Lets through {0, -0}.
|
||||
xorpd(ScratchDoubleReg, ScratchDoubleReg);
|
||||
zeroDouble(ScratchDoubleReg);
|
||||
|
||||
// If reg is non-zero, jump to nonZero.
|
||||
branchDouble(DoubleNotEqual, reg, ScratchDoubleReg, &nonZero);
|
||||
}
|
||||
// Input register is either zero or negative zero. Retrieve sign of input.
|
||||
movmskpd(reg, scratch);
|
||||
vmovmskpd(reg, scratch);
|
||||
|
||||
// If reg is 1 or 3, input is negative zero.
|
||||
// If reg is 0 or 2, input is a normal zero.
|
||||
|
@ -232,7 +232,7 @@ MacroAssemblerX86Shared::branchNegativeZero(FloatRegister reg,
|
|||
bind(&nonZero);
|
||||
#elif defined(JS_CODEGEN_X64)
|
||||
movq(reg, scratch);
|
||||
cmpq(scratch, Imm32(1));
|
||||
cmpq(Imm32(1), scratch);
|
||||
j(Overflow, label);
|
||||
#endif
|
||||
}
|
||||
|
@ -242,7 +242,7 @@ MacroAssemblerX86Shared::branchNegativeZeroFloat32(FloatRegister reg,
|
|||
Register scratch,
|
||||
Label *label)
|
||||
{
|
||||
movd(reg, scratch);
|
||||
cmpl(scratch, Imm32(1));
|
||||
vmovd(reg, scratch);
|
||||
cmp32(scratch, Imm32(1));
|
||||
j(Overflow, label);
|
||||
}
|
||||
|
|
|
@ -38,9 +38,9 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
|
||||
void compareDouble(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs) {
|
||||
if (cond & DoubleConditionBitInvert)
|
||||
ucomisd(rhs, lhs);
|
||||
vucomisd(lhs, rhs);
|
||||
else
|
||||
ucomisd(lhs, rhs);
|
||||
vucomisd(rhs, lhs);
|
||||
}
|
||||
void branchDouble(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs, Label *label)
|
||||
{
|
||||
|
@ -65,9 +65,9 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
|
||||
void compareFloat(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs) {
|
||||
if (cond & DoubleConditionBitInvert)
|
||||
ucomiss(rhs, lhs);
|
||||
vucomiss(lhs, rhs);
|
||||
else
|
||||
ucomiss(lhs, rhs);
|
||||
vucomiss(rhs, lhs);
|
||||
}
|
||||
void branchFloat(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs, Label *label)
|
||||
{
|
||||
|
@ -133,25 +133,34 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
negl(reg);
|
||||
}
|
||||
void test32(Register lhs, Register rhs) {
|
||||
testl(lhs, rhs);
|
||||
testl(rhs, lhs);
|
||||
}
|
||||
void test32(const Address &addr, Imm32 imm) {
|
||||
testl(Operand(addr), imm);
|
||||
testl(imm, Operand(addr));
|
||||
}
|
||||
void test32(const Operand lhs, Imm32 imm) {
|
||||
testl(imm, lhs);
|
||||
}
|
||||
void test32(Register lhs, Imm32 rhs) {
|
||||
testl(lhs, rhs);
|
||||
testl(rhs, lhs);
|
||||
}
|
||||
void cmp32(Register lhs, Imm32 rhs) {
|
||||
cmpl(lhs, rhs);
|
||||
cmpl(rhs, lhs);
|
||||
}
|
||||
void cmp32(Register a, Register b) {
|
||||
cmpl(a, b);
|
||||
void cmp32(Register lhs, Register rhs) {
|
||||
cmpl(rhs, lhs);
|
||||
}
|
||||
void cmp32(const Operand &lhs, Imm32 rhs) {
|
||||
cmpl(lhs, rhs);
|
||||
cmpl(rhs, lhs);
|
||||
}
|
||||
void cmp32(const Operand &lhs, Register rhs) {
|
||||
cmpl(lhs, rhs);
|
||||
cmpl(rhs, lhs);
|
||||
}
|
||||
void cmp32(Register lhs, const Operand &rhs) {
|
||||
cmpl(rhs, lhs);
|
||||
}
|
||||
CodeOffsetLabel cmp32WithPatch(Register lhs, Imm32 rhs) {
|
||||
return cmplWithPatch(rhs, lhs);
|
||||
}
|
||||
void add32(Register src, Register dest) {
|
||||
addl(src, dest);
|
||||
|
@ -159,15 +168,24 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
void add32(Imm32 imm, Register dest) {
|
||||
addl(imm, dest);
|
||||
}
|
||||
void add32(Imm32 imm, const Operand &dest) {
|
||||
addl(imm, dest);
|
||||
}
|
||||
void add32(Imm32 imm, const Address &dest) {
|
||||
addl(imm, Operand(dest));
|
||||
}
|
||||
void sub32(Imm32 imm, Register dest) {
|
||||
subl(imm, dest);
|
||||
}
|
||||
void sub32(const Operand &src, Register dest) {
|
||||
subl(src, dest);
|
||||
}
|
||||
void sub32(Register src, Register dest) {
|
||||
subl(src, dest);
|
||||
}
|
||||
void sub32(Register src, const Operand &dest) {
|
||||
subl(src, dest);
|
||||
}
|
||||
template <typename T>
|
||||
void branchAdd32(Condition cond, T src, Register dest, Label *label) {
|
||||
add32(src, dest);
|
||||
|
@ -483,58 +501,58 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
}
|
||||
|
||||
void branch16(Condition cond, Register lhs, Register rhs, Label *label) {
|
||||
cmpw(lhs, rhs);
|
||||
cmpw(rhs, lhs);
|
||||
j(cond, label);
|
||||
}
|
||||
void branch32(Condition cond, const Operand &lhs, Register rhs, Label *label) {
|
||||
cmpl(lhs, rhs);
|
||||
cmp32(lhs, rhs);
|
||||
j(cond, label);
|
||||
}
|
||||
void branch32(Condition cond, const Operand &lhs, Imm32 rhs, Label *label) {
|
||||
cmpl(lhs, rhs);
|
||||
cmp32(lhs, rhs);
|
||||
j(cond, label);
|
||||
}
|
||||
void branch32(Condition cond, const Address &lhs, Register rhs, Label *label) {
|
||||
cmpl(Operand(lhs), rhs);
|
||||
cmp32(Operand(lhs), rhs);
|
||||
j(cond, label);
|
||||
}
|
||||
void branch32(Condition cond, const Address &lhs, Imm32 imm, Label *label) {
|
||||
cmpl(Operand(lhs), imm);
|
||||
cmp32(Operand(lhs), imm);
|
||||
j(cond, label);
|
||||
}
|
||||
void branch32(Condition cond, const BaseIndex &lhs, Register rhs, Label *label) {
|
||||
cmpl(Operand(lhs), rhs);
|
||||
cmp32(Operand(lhs), rhs);
|
||||
j(cond, label);
|
||||
}
|
||||
void branch32(Condition cond, const BaseIndex &lhs, Imm32 imm, Label *label) {
|
||||
cmpl(Operand(lhs), imm);
|
||||
cmp32(Operand(lhs), imm);
|
||||
j(cond, label);
|
||||
}
|
||||
void branch32(Condition cond, Register lhs, Imm32 imm, Label *label) {
|
||||
cmpl(lhs, imm);
|
||||
cmp32(lhs, imm);
|
||||
j(cond, label);
|
||||
}
|
||||
void branch32(Condition cond, Register lhs, Register rhs, Label *label) {
|
||||
cmpl(lhs, rhs);
|
||||
cmp32(lhs, rhs);
|
||||
j(cond, label);
|
||||
}
|
||||
void branchTest16(Condition cond, Register lhs, Register rhs, Label *label) {
|
||||
testw(lhs, rhs);
|
||||
testw(rhs, lhs);
|
||||
j(cond, label);
|
||||
}
|
||||
void branchTest32(Condition cond, Register lhs, Register rhs, Label *label) {
|
||||
MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
|
||||
testl(lhs, rhs);
|
||||
test32(lhs, rhs);
|
||||
j(cond, label);
|
||||
}
|
||||
void branchTest32(Condition cond, Register lhs, Imm32 imm, Label *label) {
|
||||
MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
|
||||
testl(lhs, imm);
|
||||
test32(lhs, imm);
|
||||
j(cond, label);
|
||||
}
|
||||
void branchTest32(Condition cond, const Address &address, Imm32 imm, Label *label) {
|
||||
MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
|
||||
testl(Operand(address), imm);
|
||||
test32(Operand(address), imm);
|
||||
j(cond, label);
|
||||
}
|
||||
|
||||
|
@ -593,14 +611,14 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
}
|
||||
|
||||
void convertInt32ToDouble(Register src, FloatRegister dest) {
|
||||
// cvtsi2sd and friends write only part of their output register, which
|
||||
// vcvtsi2sd and friends write only part of their output register, which
|
||||
// causes slowdowns on out-of-order processors. Explicitly break
|
||||
// dependencies with xorpd (and xorps elsewhere), which are handled
|
||||
// dependencies with vxorpd (and vxorps elsewhere), which are handled
|
||||
// specially in modern CPUs, for this purpose. See sections 8.14, 9.8,
|
||||
// 10.8, 12.9, 13.16, 14.14, and 15.8 of Agner's Microarchitecture
|
||||
// document.
|
||||
zeroDouble(dest);
|
||||
cvtsi2sd(src, dest);
|
||||
vcvtsi2sd(src, dest, dest);
|
||||
}
|
||||
void convertInt32ToDouble(const Address &src, FloatRegister dest) {
|
||||
convertInt32ToDouble(Operand(src), dest);
|
||||
|
@ -608,12 +626,12 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
void convertInt32ToDouble(const Operand &src, FloatRegister dest) {
|
||||
// Clear the output register first to break dependencies; see above;
|
||||
zeroDouble(dest);
|
||||
cvtsi2sd(Operand(src), dest);
|
||||
vcvtsi2sd(Operand(src), dest, dest);
|
||||
}
|
||||
void convertInt32ToFloat32(Register src, FloatRegister dest) {
|
||||
// Clear the output register first to break dependencies; see above;
|
||||
zeroFloat32(dest);
|
||||
cvtsi2ss(src, dest);
|
||||
vcvtsi2ss(src, dest, dest);
|
||||
}
|
||||
void convertInt32ToFloat32(const Address &src, FloatRegister dest) {
|
||||
convertInt32ToFloat32(Operand(src), dest);
|
||||
|
@ -621,11 +639,11 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
void convertInt32ToFloat32(const Operand &src, FloatRegister dest) {
|
||||
// Clear the output register first to break dependencies; see above;
|
||||
zeroFloat32(dest);
|
||||
cvtsi2ss(src, dest);
|
||||
vcvtsi2ss(src, dest, dest);
|
||||
}
|
||||
Condition testDoubleTruthy(bool truthy, FloatRegister reg) {
|
||||
zeroDouble(ScratchDoubleReg);
|
||||
ucomisd(ScratchDoubleReg, reg);
|
||||
vucomisd(reg, ScratchDoubleReg);
|
||||
return truthy ? NonZero : Zero;
|
||||
}
|
||||
void branchTestDoubleTruthy(bool truthy, FloatRegister reg, Label *label) {
|
||||
|
@ -763,25 +781,25 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
movapd(src, dest);
|
||||
}
|
||||
void zeroDouble(FloatRegister reg) {
|
||||
xorpd(reg, reg);
|
||||
vxorpd(reg, reg, reg);
|
||||
}
|
||||
void zeroFloat32(FloatRegister reg) {
|
||||
xorps(reg, reg);
|
||||
vxorps(reg, reg, reg);
|
||||
}
|
||||
void negateDouble(FloatRegister reg) {
|
||||
// From MacroAssemblerX86Shared::maybeInlineDouble
|
||||
pcmpeqw(ScratchDoubleReg, ScratchDoubleReg);
|
||||
vpcmpeqw(ScratchDoubleReg, ScratchDoubleReg, ScratchDoubleReg);
|
||||
psllq(Imm32(63), ScratchDoubleReg);
|
||||
|
||||
// XOR the float in a float register with -0.0.
|
||||
xorpd(ScratchDoubleReg, reg); // s ^ 0x80000000000000
|
||||
vxorpd(ScratchDoubleReg, reg, reg); // s ^ 0x80000000000000
|
||||
}
|
||||
void negateFloat(FloatRegister reg) {
|
||||
pcmpeqw(ScratchFloat32Reg, ScratchFloat32Reg);
|
||||
vpcmpeqw(ScratchFloat32Reg, ScratchFloat32Reg, ScratchFloat32Reg);
|
||||
psllq(Imm32(31), ScratchFloat32Reg);
|
||||
|
||||
// XOR the float in a float register with -0.0.
|
||||
xorps(ScratchFloat32Reg, reg); // s ^ 0x80000000
|
||||
vxorps(ScratchFloat32Reg, reg, reg); // s ^ 0x80000000
|
||||
}
|
||||
void addDouble(FloatRegister src, FloatRegister dest) {
|
||||
vaddsd(src, dest, dest);
|
||||
|
@ -799,10 +817,10 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
vaddss(src, dest, dest);
|
||||
}
|
||||
void convertFloat32ToDouble(FloatRegister src, FloatRegister dest) {
|
||||
cvtss2sd(src, dest);
|
||||
vcvtss2sd(src, dest, dest);
|
||||
}
|
||||
void convertDoubleToFloat32(FloatRegister src, FloatRegister dest) {
|
||||
cvtsd2ss(src, dest);
|
||||
vcvtsd2ss(src, dest, dest);
|
||||
}
|
||||
|
||||
void convertFloat32x4ToInt32x4(FloatRegister src, FloatRegister dest) {
|
||||
|
@ -811,25 +829,31 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
// least signed int32, or NaN), this will return the undefined integer
|
||||
// value (0x8000000). Spec should define what to do in such cases. See
|
||||
// also bug 1068020.
|
||||
cvttps2dq(src, dest);
|
||||
vcvttps2dq(src, dest);
|
||||
}
|
||||
void convertInt32x4ToFloat32x4(FloatRegister src, FloatRegister dest) {
|
||||
cvtdq2ps(src, dest);
|
||||
vcvtdq2ps(src, dest);
|
||||
}
|
||||
|
||||
void bitwiseAndX4(const Operand &src, FloatRegister dest) {
|
||||
// TODO Using the "ps" variant for all types incurs a domain crossing
|
||||
// penalty for integer types and double.
|
||||
andps(src, dest);
|
||||
vandps(src, dest, dest);
|
||||
}
|
||||
void bitwiseAndNotX4(const Operand &src, FloatRegister dest) {
|
||||
andnps(src, dest);
|
||||
vandnps(src, dest, dest);
|
||||
}
|
||||
void bitwiseOrX4(const Operand &src, FloatRegister dest) {
|
||||
orps(src, dest);
|
||||
vorps(src, dest, dest);
|
||||
}
|
||||
void bitwiseXorX4(const Operand &src, FloatRegister dest) {
|
||||
xorps(src, dest);
|
||||
vxorps(src, dest, dest);
|
||||
}
|
||||
void zeroFloat32x4(FloatRegister dest) {
|
||||
vxorps(dest, dest, dest);
|
||||
}
|
||||
void zeroInt32x4(FloatRegister dest) {
|
||||
vpxor(dest, dest, dest);
|
||||
}
|
||||
|
||||
void loadAlignedInt32x4(const Address &src, FloatRegister dest) {
|
||||
|
@ -869,29 +893,29 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
movdqu(src, dest);
|
||||
}
|
||||
void packedEqualInt32x4(const Operand &src, FloatRegister dest) {
|
||||
pcmpeqd(src, dest);
|
||||
vpcmpeqd(src, dest, dest);
|
||||
}
|
||||
void packedGreaterThanInt32x4(const Operand &src, FloatRegister dest) {
|
||||
pcmpgtd(src, dest);
|
||||
vpcmpgtd(src, dest, dest);
|
||||
}
|
||||
void packedAddInt32(const Operand &src, FloatRegister dest) {
|
||||
paddd(src, dest);
|
||||
vpaddd(src, dest, dest);
|
||||
}
|
||||
void packedSubInt32(const Operand &src, FloatRegister dest) {
|
||||
psubd(src, dest);
|
||||
vpsubd(src, dest, dest);
|
||||
}
|
||||
void packedReciprocalFloat32x4(const Operand &src, FloatRegister dest) {
|
||||
// This function is an approximation of the result, this might need
|
||||
// fix up if the spec requires a given precision for this operation.
|
||||
// TODO See also bug 1068028.
|
||||
rcpps(src, dest);
|
||||
vrcpps(src, dest);
|
||||
}
|
||||
void packedReciprocalSqrtFloat32x4(const Operand &src, FloatRegister dest) {
|
||||
// TODO See comment above. See also bug 1068028.
|
||||
rsqrtps(src, dest);
|
||||
vrsqrtps(src, dest);
|
||||
}
|
||||
void packedSqrtFloat32x4(const Operand &src, FloatRegister dest) {
|
||||
sqrtps(src, dest);
|
||||
vsqrtps(src, dest);
|
||||
}
|
||||
|
||||
void packedLeftShiftByScalar(FloatRegister src, FloatRegister dest) {
|
||||
|
@ -975,11 +999,11 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
pshufd(mask, src, dest);
|
||||
}
|
||||
void moveLowInt32(FloatRegister src, Register dest) {
|
||||
movd(src, dest);
|
||||
vmovd(src, dest);
|
||||
}
|
||||
|
||||
void moveHighPairToLowPairFloat32(FloatRegister src, FloatRegister dest) {
|
||||
movhlps(src, dest);
|
||||
vmovhlps(src, dest, dest);
|
||||
}
|
||||
void shuffleFloat32(uint32_t mask, FloatRegister src, FloatRegister dest) {
|
||||
// The shuffle instruction on x86 is such that it moves 2 words from
|
||||
|
@ -998,20 +1022,20 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
}
|
||||
|
||||
void moveFloatAsDouble(Register src, FloatRegister dest) {
|
||||
movd(src, dest);
|
||||
cvtss2sd(dest, dest);
|
||||
vmovd(src, dest);
|
||||
vcvtss2sd(dest, dest, dest);
|
||||
}
|
||||
void loadFloatAsDouble(const Address &src, FloatRegister dest) {
|
||||
movss(src, dest);
|
||||
cvtss2sd(dest, dest);
|
||||
vcvtss2sd(dest, dest, dest);
|
||||
}
|
||||
void loadFloatAsDouble(const BaseIndex &src, FloatRegister dest) {
|
||||
movss(src, dest);
|
||||
cvtss2sd(dest, dest);
|
||||
vcvtss2sd(dest, dest, dest);
|
||||
}
|
||||
void loadFloatAsDouble(const Operand &src, FloatRegister dest) {
|
||||
loadFloat32(src, dest);
|
||||
cvtss2sd(dest, dest);
|
||||
vcvtss2sd(dest, dest, dest);
|
||||
}
|
||||
void loadFloat32(const Address &src, FloatRegister dest) {
|
||||
movss(src, dest);
|
||||
|
@ -1064,9 +1088,9 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
if (negativeZeroCheck)
|
||||
branchNegativeZero(src, dest, fail);
|
||||
|
||||
cvttsd2si(src, dest);
|
||||
cvtsi2sd(dest, ScratchDoubleReg);
|
||||
ucomisd(src, ScratchDoubleReg);
|
||||
vcvttsd2si(src, dest);
|
||||
convertInt32ToDouble(dest, ScratchDoubleReg);
|
||||
vucomisd(ScratchDoubleReg, src);
|
||||
j(Assembler::Parity, fail);
|
||||
j(Assembler::NotEqual, fail);
|
||||
|
||||
|
@ -1082,9 +1106,9 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
if (negativeZeroCheck)
|
||||
branchNegativeZeroFloat32(src, dest, fail);
|
||||
|
||||
cvttss2si(src, dest);
|
||||
vcvttss2si(src, dest);
|
||||
convertInt32ToFloat32(dest, ScratchFloat32Reg);
|
||||
ucomiss(src, ScratchFloat32Reg);
|
||||
vucomiss(ScratchFloat32Reg, src);
|
||||
j(Assembler::Parity, fail);
|
||||
j(Assembler::NotEqual, fail);
|
||||
}
|
||||
|
@ -1105,11 +1129,11 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
|
||||
// Loading zero with xor is specially optimized in hardware.
|
||||
if (u == 0) {
|
||||
xorpd(dest, dest);
|
||||
zeroDouble(dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
// It is also possible to load several common constants using pcmpeqw
|
||||
// It is also possible to load several common constants using vpcmpeqw
|
||||
// to get all ones and then psllq and psrlq to get zeros at the ends,
|
||||
// as described in "13.4 Generating constants" of
|
||||
// "2. Optimizing subroutines in assembly language" by Agner Fog, and as
|
||||
|
@ -1125,7 +1149,7 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
|
||||
// See comment above
|
||||
if (u == 0) {
|
||||
xorps(dest, dest);
|
||||
zeroFloat32(dest);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -1135,11 +1159,11 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
static const SimdConstant zero = SimdConstant::CreateX4(0, 0, 0, 0);
|
||||
static const SimdConstant minusOne = SimdConstant::CreateX4(-1, -1, -1, -1);
|
||||
if (v == zero) {
|
||||
pxor(dest, dest);
|
||||
zeroInt32x4(dest);
|
||||
return true;
|
||||
}
|
||||
if (v == minusOne) {
|
||||
pcmpeqw(dest, dest);
|
||||
vpcmpeqw(dest, dest, dest);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -1149,7 +1173,7 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
if (v == zero) {
|
||||
// This won't get inlined if the SimdConstant v contains -0 in any
|
||||
// lane, as operator== here does a memcmp.
|
||||
xorps(dest, dest);
|
||||
zeroFloat32x4(dest);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -85,9 +85,9 @@ MoveEmitterX86::maybeEmitOptimizedCycle(const MoveResolver &moves, size_t i,
|
|||
// it's cheap to do an XOR swap.
|
||||
FloatRegister a = moves.getMove(i).to().floatReg();
|
||||
FloatRegister b = moves.getMove(i + 1).to().floatReg();
|
||||
masm.xorpd(a, b);
|
||||
masm.xorpd(b, a);
|
||||
masm.xorpd(a, b);
|
||||
masm.vxorpd(a, b, b);
|
||||
masm.vxorpd(b, a, a);
|
||||
masm.vxorpd(a, b, b);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -639,10 +639,10 @@ class Assembler : public AssemblerX86Shared
|
|||
append(AsmJSGlobalAccess(label, AsmJSHeapGlobalDataOffset));
|
||||
}
|
||||
|
||||
// The below cmpq methods switch the lhs and rhs when it invokes the
|
||||
// macroassembler to conform with intel standard. When calling this
|
||||
// function put the left operand on the left as you would expect.
|
||||
void cmpq(const Operand &lhs, Register rhs) {
|
||||
void cmpq(Register rhs, Register lhs) {
|
||||
masm.cmpq_rr(rhs.code(), lhs.code());
|
||||
}
|
||||
void cmpq(Register rhs, const Operand &lhs) {
|
||||
switch (lhs.kind()) {
|
||||
case Operand::REG:
|
||||
masm.cmpq_rr(rhs.code(), lhs.reg());
|
||||
|
@ -657,7 +657,10 @@ class Assembler : public AssemblerX86Shared
|
|||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void cmpq(const Operand &lhs, Imm32 rhs) {
|
||||
void cmpq(Imm32 rhs, Register lhs) {
|
||||
masm.cmpq_ir(rhs.value, lhs.code());
|
||||
}
|
||||
void cmpq(Imm32 rhs, const Operand &lhs) {
|
||||
switch (lhs.kind()) {
|
||||
case Operand::REG:
|
||||
masm.cmpq_ir(rhs.value, lhs.reg());
|
||||
|
@ -672,7 +675,7 @@ class Assembler : public AssemblerX86Shared
|
|||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void cmpq(Register lhs, const Operand &rhs) {
|
||||
void cmpq(const Operand &rhs, Register lhs) {
|
||||
switch (rhs.kind()) {
|
||||
case Operand::REG:
|
||||
masm.cmpq_rr(rhs.reg(), lhs.code());
|
||||
|
@ -684,23 +687,17 @@ class Assembler : public AssemblerX86Shared
|
|||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void cmpq(Register lhs, Register rhs) {
|
||||
masm.cmpq_rr(rhs.code(), lhs.code());
|
||||
}
|
||||
void cmpq(Register lhs, Imm32 rhs) {
|
||||
masm.cmpq_ir(rhs.value, lhs.code());
|
||||
}
|
||||
|
||||
void testq(Register lhs, Imm32 rhs) {
|
||||
masm.testq_i32r(rhs.value, lhs.code());
|
||||
void testq(Imm32 rhs, Register lhs) {
|
||||
masm.testq_ir(rhs.value, lhs.code());
|
||||
}
|
||||
void testq(Register lhs, Register rhs) {
|
||||
void testq(Register rhs, Register lhs) {
|
||||
masm.testq_rr(rhs.code(), lhs.code());
|
||||
}
|
||||
void testq(const Operand &lhs, Imm32 rhs) {
|
||||
void testq(Imm32 rhs, const Operand &lhs) {
|
||||
switch (lhs.kind()) {
|
||||
case Operand::REG:
|
||||
masm.testq_i32r(rhs.value, lhs.reg());
|
||||
masm.testq_ir(rhs.value, lhs.reg());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.testq_i32m(rhs.value, lhs.disp(), lhs.base());
|
||||
|
@ -750,17 +747,17 @@ class Assembler : public AssemblerX86Shared
|
|||
// Do not mask shared implementations.
|
||||
using AssemblerX86Shared::call;
|
||||
|
||||
void cvttsd2sq(FloatRegister src, Register dest) {
|
||||
masm.cvttsd2sq_rr(src.code(), dest.code());
|
||||
void vcvttsd2sq(FloatRegister src, Register dest) {
|
||||
masm.vcvttsd2sq_rr(src.code(), dest.code());
|
||||
}
|
||||
void cvttss2sq(FloatRegister src, Register dest) {
|
||||
masm.cvttss2sq_rr(src.code(), dest.code());
|
||||
void vcvttss2sq(FloatRegister src, Register dest) {
|
||||
masm.vcvttss2sq_rr(src.code(), dest.code());
|
||||
}
|
||||
void cvtsq2sd(Register src, FloatRegister dest) {
|
||||
masm.cvtsq2sd_rr(src.code(), dest.code());
|
||||
void vcvtsq2sd(Register src1, FloatRegister src0, FloatRegister dest) {
|
||||
masm.vcvtsq2sd_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
void cvtsq2ss(Register src, FloatRegister dest) {
|
||||
masm.cvtsq2ss_rr(src.code(), dest.code());
|
||||
void vcvtsq2ss(Register src1, FloatRegister src0, FloatRegister dest) {
|
||||
masm.vcvtsq2ss_rr(src1.code(), src0.code(), dest.code());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ ICCompare_Int32::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
// Directly compare the int32 payload of R0 and R1.
|
||||
Assembler::Condition cond = JSOpToCondition(op, /* signed = */true);
|
||||
masm.mov(ImmWord(0), ScratchReg);
|
||||
masm.cmpl(R0.valueReg(), R1.valueReg());
|
||||
masm.cmp32(R0.valueReg(), R1.valueReg());
|
||||
masm.setCC(cond, ScratchReg);
|
||||
|
||||
// Box the result and return
|
||||
|
@ -166,7 +166,7 @@ ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
masm.unboxInt32(R1, ecx); // This clobbers R0
|
||||
|
||||
masm.shrl_cl(ExtractTemp0);
|
||||
masm.testl(ExtractTemp0, ExtractTemp0);
|
||||
masm.test32(ExtractTemp0, ExtractTemp0);
|
||||
if (allowDouble_) {
|
||||
Label toUint;
|
||||
masm.j(Assembler::Signed, &toUint);
|
||||
|
|
|
@ -153,7 +153,7 @@ CodeGeneratorX64::visitCompareB(LCompareB *lir)
|
|||
masm.boxValue(JSVAL_TYPE_BOOLEAN, ToRegister(rhs), ScratchReg);
|
||||
|
||||
// Perform the comparison.
|
||||
masm.cmpq(lhs.valueReg(), ScratchReg);
|
||||
masm.cmpPtr(lhs.valueReg(), ScratchReg);
|
||||
masm.emitSet(JSOpToCondition(mir->compareType(), mir->jsop()), output);
|
||||
}
|
||||
|
||||
|
@ -174,7 +174,7 @@ CodeGeneratorX64::visitCompareBAndBranch(LCompareBAndBranch *lir)
|
|||
masm.boxValue(JSVAL_TYPE_BOOLEAN, ToRegister(rhs), ScratchReg);
|
||||
|
||||
// Perform the comparison.
|
||||
masm.cmpq(lhs.valueReg(), ScratchReg);
|
||||
masm.cmpPtr(lhs.valueReg(), ScratchReg);
|
||||
emitBranch(JSOpToCondition(mir->compareType(), mir->jsop()), lir->ifTrue(), lir->ifFalse());
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@ CodeGeneratorX64::visitCompareV(LCompareV *lir)
|
|||
|
||||
MOZ_ASSERT(IsEqualityOp(mir->jsop()));
|
||||
|
||||
masm.cmpq(lhs.valueReg(), rhs.valueReg());
|
||||
masm.cmpPtr(lhs.valueReg(), rhs.valueReg());
|
||||
masm.emitSet(JSOpToCondition(mir->compareType(), mir->jsop()), output);
|
||||
}
|
||||
|
||||
|
@ -203,7 +203,7 @@ CodeGeneratorX64::visitCompareVAndBranch(LCompareVAndBranch *lir)
|
|||
MOZ_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ ||
|
||||
mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE);
|
||||
|
||||
masm.cmpq(lhs.valueReg(), rhs.valueReg());
|
||||
masm.cmpPtr(lhs.valueReg(), rhs.valueReg());
|
||||
emitBranch(JSOpToCondition(mir->compareType(), mir->jsop()), lir->ifTrue(), lir->ifFalse());
|
||||
}
|
||||
|
||||
|
@ -278,7 +278,7 @@ CodeGeneratorX64::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins)
|
|||
ool = new(alloc()) OutOfLineLoadTypedArrayOutOfBounds(ToAnyRegister(out), vt);
|
||||
addOutOfLineCode(ool, ins->mir());
|
||||
|
||||
CodeOffsetLabel cmp = masm.cmplWithPatch(ToRegister(ptr), Imm32(0));
|
||||
CodeOffsetLabel cmp = masm.cmp32WithPatch(ToRegister(ptr), Imm32(0));
|
||||
masm.j(Assembler::AboveOrEqual, ool->entry());
|
||||
maybeCmpOffset = cmp.offset();
|
||||
}
|
||||
|
@ -326,7 +326,7 @@ CodeGeneratorX64::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
|
|||
Label rejoin;
|
||||
uint32_t maybeCmpOffset = AsmJSHeapAccess::NoLengthCheck;
|
||||
if (mir->needsBoundsCheck()) {
|
||||
CodeOffsetLabel cmp = masm.cmplWithPatch(ToRegister(ptr), Imm32(0));
|
||||
CodeOffsetLabel cmp = masm.cmp32WithPatch(ToRegister(ptr), Imm32(0));
|
||||
masm.j(Assembler::AboveOrEqual, &rejoin);
|
||||
maybeCmpOffset = cmp.offset();
|
||||
}
|
||||
|
@ -388,7 +388,7 @@ CodeGeneratorX64::visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap *ins)
|
|||
Label rejoin;
|
||||
uint32_t maybeCmpOffset = AsmJSHeapAccess::NoLengthCheck;
|
||||
if (mir->needsBoundsCheck()) {
|
||||
maybeCmpOffset = masm.cmplWithPatch(ToRegister(ptr), Imm32(0)).offset();
|
||||
maybeCmpOffset = masm.cmp32WithPatch(ToRegister(ptr), Imm32(0)).offset();
|
||||
Label goahead;
|
||||
masm.j(Assembler::Below, &goahead);
|
||||
memoryBarrier(MembarFull);
|
||||
|
@ -425,7 +425,7 @@ CodeGeneratorX64::visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap *ins)
|
|||
Label rejoin;
|
||||
uint32_t maybeCmpOffset = AsmJSHeapAccess::NoLengthCheck;
|
||||
if (mir->needsBoundsCheck()) {
|
||||
maybeCmpOffset = masm.cmplWithPatch(ToRegister(ptr), Imm32(0)).offset();
|
||||
maybeCmpOffset = masm.cmp32WithPatch(ToRegister(ptr), Imm32(0)).offset();
|
||||
Label goahead;
|
||||
masm.j(Assembler::Below, &goahead);
|
||||
memoryBarrier(MembarFull);
|
||||
|
@ -559,7 +559,7 @@ CodeGeneratorX64::visitTruncateDToInt32(LTruncateDToInt32 *ins)
|
|||
FloatRegister input = ToFloatRegister(ins->input());
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
// On x64, branchTruncateDouble uses cvttsd2sq. Unlike the x86
|
||||
// On x64, branchTruncateDouble uses vcvttsd2sq. Unlike the x86
|
||||
// implementation, this should handle most doubles and we can just
|
||||
// call a stub if it fails.
|
||||
emitTruncateDouble(input, output, ins->mir());
|
||||
|
@ -571,7 +571,7 @@ CodeGeneratorX64::visitTruncateFToInt32(LTruncateFToInt32 *ins)
|
|||
FloatRegister input = ToFloatRegister(ins->input());
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
// On x64, branchTruncateFloat32 uses cvttss2sq. Unlike the x86
|
||||
// On x64, branchTruncateFloat32 uses vcvttss2sq. Unlike the x86
|
||||
// implementation, this should handle most floats and we can just
|
||||
// call a stub if it fails.
|
||||
emitTruncateFloat32(input, output, ins->mir());
|
||||
|
|
|
@ -293,7 +293,7 @@ MacroAssemblerX64::callWithABIPre(uint32_t *stackAdjust)
|
|||
#ifdef DEBUG
|
||||
{
|
||||
Label good;
|
||||
testq(rsp, Imm32(ABIStackAlignment - 1));
|
||||
testPtr(rsp, Imm32(ABIStackAlignment - 1));
|
||||
j(Equal, &good);
|
||||
breakpoint();
|
||||
bind(&good);
|
||||
|
|
|
@ -271,58 +271,58 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
|
||||
Condition testUndefined(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_UNDEFINED));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_UNDEFINED));
|
||||
return cond;
|
||||
}
|
||||
Condition testInt32(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_INT32));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_INT32));
|
||||
return cond;
|
||||
}
|
||||
Condition testBoolean(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_BOOLEAN));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_BOOLEAN));
|
||||
return cond;
|
||||
}
|
||||
Condition testNull(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_NULL));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_NULL));
|
||||
return cond;
|
||||
}
|
||||
Condition testString(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_STRING));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_STRING));
|
||||
return cond;
|
||||
}
|
||||
Condition testSymbol(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_SYMBOL));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_SYMBOL));
|
||||
return cond;
|
||||
}
|
||||
Condition testObject(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_OBJECT));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_OBJECT));
|
||||
return cond;
|
||||
}
|
||||
Condition testDouble(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, Imm32(JSVAL_TAG_MAX_DOUBLE));
|
||||
cmp32(tag, Imm32(JSVAL_TAG_MAX_DOUBLE));
|
||||
return cond == Equal ? BelowOrEqual : Above;
|
||||
}
|
||||
Condition testNumber(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, Imm32(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET));
|
||||
cmp32(tag, Imm32(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET));
|
||||
return cond == Equal ? BelowOrEqual : Above;
|
||||
}
|
||||
Condition testGCThing(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, Imm32(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
|
||||
cmp32(tag, Imm32(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
|
||||
return cond == Equal ? AboveOrEqual : Below;
|
||||
}
|
||||
|
||||
Condition testMagic(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_MAGIC));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_MAGIC));
|
||||
return cond;
|
||||
}
|
||||
Condition testError(Condition cond, Register tag) {
|
||||
|
@ -330,7 +330,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
}
|
||||
Condition testPrimitive(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET));
|
||||
cmp32(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET));
|
||||
return cond == Equal ? Below : AboveOrEqual;
|
||||
}
|
||||
|
||||
|
@ -480,10 +480,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
void cmpPtr(Register lhs, const ImmWord rhs) {
|
||||
MOZ_ASSERT(lhs != ScratchReg);
|
||||
if (intptr_t(rhs.value) <= INT32_MAX && intptr_t(rhs.value) >= INT32_MIN) {
|
||||
cmpq(lhs, Imm32(int32_t(rhs.value)));
|
||||
cmpPtr(lhs, Imm32(int32_t(rhs.value)));
|
||||
} else {
|
||||
movq(rhs, ScratchReg);
|
||||
cmpq(lhs, ScratchReg);
|
||||
movePtr(rhs, ScratchReg);
|
||||
cmpPtr(lhs, ScratchReg);
|
||||
}
|
||||
}
|
||||
void cmpPtr(Register lhs, const ImmPtr rhs) {
|
||||
|
@ -491,26 +491,26 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
}
|
||||
void cmpPtr(Register lhs, const ImmGCPtr rhs) {
|
||||
MOZ_ASSERT(lhs != ScratchReg);
|
||||
movq(rhs, ScratchReg);
|
||||
cmpq(lhs, ScratchReg);
|
||||
movePtr(rhs, ScratchReg);
|
||||
cmpPtr(lhs, ScratchReg);
|
||||
}
|
||||
void cmpPtr(Register lhs, const Imm32 rhs) {
|
||||
cmpq(lhs, rhs);
|
||||
cmpq(rhs, lhs);
|
||||
}
|
||||
void cmpPtr(const Operand &lhs, const ImmGCPtr rhs) {
|
||||
MOZ_ASSERT(!lhs.containsReg(ScratchReg));
|
||||
movq(rhs, ScratchReg);
|
||||
cmpq(lhs, ScratchReg);
|
||||
movePtr(rhs, ScratchReg);
|
||||
cmpPtr(lhs, ScratchReg);
|
||||
}
|
||||
void cmpPtr(const Operand &lhs, const ImmMaybeNurseryPtr rhs) {
|
||||
cmpPtr(lhs, noteMaybeNurseryPtr(rhs));
|
||||
}
|
||||
void cmpPtr(const Operand &lhs, const ImmWord rhs) {
|
||||
if ((intptr_t)rhs.value <= INT32_MAX && (intptr_t)rhs.value >= INT32_MIN) {
|
||||
cmpq(lhs, Imm32((int32_t)rhs.value));
|
||||
cmpPtr(lhs, Imm32((int32_t)rhs.value));
|
||||
} else {
|
||||
mov(rhs, ScratchReg);
|
||||
cmpq(lhs, ScratchReg);
|
||||
movePtr(rhs, ScratchReg);
|
||||
cmpPtr(lhs, ScratchReg);
|
||||
}
|
||||
}
|
||||
void cmpPtr(const Operand &lhs, const ImmPtr rhs) {
|
||||
|
@ -526,19 +526,28 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
|
||||
}
|
||||
void cmpPtr(const Operand &lhs, Register rhs) {
|
||||
cmpq(lhs, rhs);
|
||||
cmpq(rhs, lhs);
|
||||
}
|
||||
void cmpPtr(Register lhs, const Operand &rhs) {
|
||||
cmpq(rhs, lhs);
|
||||
}
|
||||
void cmpPtr(const Operand &lhs, const Imm32 rhs) {
|
||||
cmpq(lhs, rhs);
|
||||
cmpq(rhs, lhs);
|
||||
}
|
||||
void cmpPtr(const Address &lhs, Register rhs) {
|
||||
cmpPtr(Operand(lhs), rhs);
|
||||
}
|
||||
void cmpPtr(Register lhs, Register rhs) {
|
||||
return cmpq(lhs, rhs);
|
||||
cmpq(rhs, lhs);
|
||||
}
|
||||
void testPtr(Register lhs, Register rhs) {
|
||||
testq(lhs, rhs);
|
||||
testq(rhs, lhs);
|
||||
}
|
||||
void testPtr(Register lhs, Imm32 rhs) {
|
||||
testq(rhs, lhs);
|
||||
}
|
||||
void testPtr(const Operand &lhs, Imm32 rhs) {
|
||||
testq(rhs, lhs);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
|
@ -629,6 +638,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
branch32(cond, Address(ScratchReg, 0), rhs, label);
|
||||
}
|
||||
}
|
||||
void branch32(Condition cond, AsmJSAbsoluteAddress lhs, Imm32 rhs, Label *label) {
|
||||
mov(AsmJSImmPtr(lhs.kind()), ScratchReg);
|
||||
branch32(cond, Address(ScratchReg, 0), rhs, label);
|
||||
}
|
||||
void branch32(Condition cond, AbsoluteAddress lhs, Register rhs, Label *label) {
|
||||
if (X86Assembler::isAddressImmediate(lhs.addr)) {
|
||||
branch32(cond, Operand(lhs), rhs, label);
|
||||
|
@ -639,10 +652,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
}
|
||||
void branchTest32(Condition cond, AbsoluteAddress address, Imm32 imm, Label *label) {
|
||||
if (X86Assembler::isAddressImmediate(address.addr)) {
|
||||
testl(Operand(address), imm);
|
||||
test32(Operand(address), imm);
|
||||
} else {
|
||||
mov(ImmPtr(address.addr), ScratchReg);
|
||||
testl(Operand(ScratchReg, 0), imm);
|
||||
test32(Operand(ScratchReg, 0), imm);
|
||||
}
|
||||
j(cond, label);
|
||||
}
|
||||
|
@ -712,15 +725,15 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
j(cond, label);
|
||||
}
|
||||
void branchTestPtr(Condition cond, Register lhs, Register rhs, Label *label) {
|
||||
testq(lhs, rhs);
|
||||
testPtr(lhs, rhs);
|
||||
j(cond, label);
|
||||
}
|
||||
void branchTestPtr(Condition cond, Register lhs, Imm32 imm, Label *label) {
|
||||
testq(lhs, imm);
|
||||
testPtr(lhs, imm);
|
||||
j(cond, label);
|
||||
}
|
||||
void branchTestPtr(Condition cond, const Address &lhs, Imm32 imm, Label *label) {
|
||||
testq(Operand(lhs), imm);
|
||||
testPtr(Operand(lhs), imm);
|
||||
j(cond, label);
|
||||
}
|
||||
void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label *label) {
|
||||
|
@ -875,7 +888,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
}
|
||||
void cmpTag(const ValueOperand &operand, ImmTag tag) {
|
||||
Register reg = splitTagForTest(operand);
|
||||
cmpl(reg, tag);
|
||||
cmp32(reg, tag);
|
||||
}
|
||||
|
||||
void branchTestUndefined(Condition cond, Register tag, Label *label) {
|
||||
|
@ -920,7 +933,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
// accesses half as much memory, and removes a right-shift.
|
||||
void branchTestUndefined(Condition cond, const Operand &operand, Label *label) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_UNDEFINED))));
|
||||
cmp32(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_UNDEFINED))));
|
||||
j(cond, label);
|
||||
}
|
||||
void branchTestUndefined(Condition cond, const Address &address, Label *label) {
|
||||
|
@ -929,7 +942,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
}
|
||||
void branchTestInt32(Condition cond, const Operand &operand, Label *label) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_INT32))));
|
||||
cmp32(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_INT32))));
|
||||
j(cond, label);
|
||||
}
|
||||
void branchTestInt32(Condition cond, const Address &address, Label *label) {
|
||||
|
@ -947,12 +960,12 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
}
|
||||
void branchTestBoolean(Condition cond, const Operand &operand, Label *label) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_BOOLEAN))));
|
||||
cmp32(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_BOOLEAN))));
|
||||
j(cond, label);
|
||||
}
|
||||
void branchTestNull(Condition cond, const Operand &operand, Label *label) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_NULL))));
|
||||
cmp32(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_NULL))));
|
||||
j(cond, label);
|
||||
}
|
||||
void branchTestNull(Condition cond, const Address &address, Label *label) {
|
||||
|
@ -1065,7 +1078,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
void branchTestValue(Condition cond, const ValueOperand &value, const Value &v, Label *label) {
|
||||
MOZ_ASSERT(value.valueReg() != ScratchReg);
|
||||
moveValue(v, ScratchReg);
|
||||
cmpq(value.valueReg(), ScratchReg);
|
||||
cmpPtr(value.valueReg(), ScratchReg);
|
||||
j(cond, label);
|
||||
}
|
||||
void branchTestValue(Condition cond, const Address &valaddr, const ValueOperand &value,
|
||||
|
@ -1265,28 +1278,28 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
void loadConstantFloat32x4(const SimdConstant &v, FloatRegister dest);
|
||||
|
||||
void branchTruncateDouble(FloatRegister src, Register dest, Label *fail) {
|
||||
cvttsd2sq(src, dest);
|
||||
vcvttsd2sq(src, dest);
|
||||
|
||||
// cvttsd2sq returns 0x8000000000000000 on failure. Test for it by
|
||||
// vcvttsd2sq returns 0x8000000000000000 on failure. Test for it by
|
||||
// subtracting 1 and testing overflow (this avoids the need to
|
||||
// materialize that value in a register).
|
||||
cmpq(dest, Imm32(1));
|
||||
cmpPtr(dest, Imm32(1));
|
||||
j(Assembler::Overflow, fail);
|
||||
|
||||
movl(dest, dest); // Zero upper 32-bits.
|
||||
}
|
||||
void branchTruncateFloat32(FloatRegister src, Register dest, Label *fail) {
|
||||
cvttss2sq(src, dest);
|
||||
vcvttss2sq(src, dest);
|
||||
|
||||
// Same trick as for Doubles
|
||||
cmpq(dest, Imm32(1));
|
||||
cmpPtr(dest, Imm32(1));
|
||||
j(Assembler::Overflow, fail);
|
||||
|
||||
movl(dest, dest); // Zero upper 32-bits.
|
||||
}
|
||||
|
||||
Condition testInt32Truthy(bool truthy, const ValueOperand &operand) {
|
||||
testl(operand.valueReg(), operand.valueReg());
|
||||
test32(operand.valueReg(), operand.valueReg());
|
||||
return truthy ? NonZero : Zero;
|
||||
}
|
||||
void branchTestInt32Truthy(bool truthy, const ValueOperand &operand, Label *label) {
|
||||
|
@ -1294,12 +1307,12 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
j(cond, label);
|
||||
}
|
||||
void branchTestBooleanTruthy(bool truthy, const ValueOperand &operand, Label *label) {
|
||||
testl(operand.valueReg(), operand.valueReg());
|
||||
test32(operand.valueReg(), operand.valueReg());
|
||||
j(truthy ? NonZero : Zero, label);
|
||||
}
|
||||
Condition testStringTruthy(bool truthy, const ValueOperand &value) {
|
||||
unboxString(value, ScratchReg);
|
||||
cmpl(Operand(ScratchReg, JSString::offsetOfLength()), Imm32(0));
|
||||
cmp32(Operand(ScratchReg, JSString::offsetOfLength()), Imm32(0));
|
||||
return truthy ? Assembler::NotEqual : Assembler::Equal;
|
||||
}
|
||||
void branchTestStringTruthy(bool truthy, const ValueOperand &value, Label *label) {
|
||||
|
@ -1335,11 +1348,11 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
}
|
||||
|
||||
void convertUInt32ToDouble(Register src, FloatRegister dest) {
|
||||
cvtsq2sd(src, dest);
|
||||
vcvtsq2sd(src, dest, dest);
|
||||
}
|
||||
|
||||
void convertUInt32ToFloat32(Register src, FloatRegister dest) {
|
||||
cvtsq2ss(src, dest);
|
||||
vcvtsq2ss(src, dest, dest);
|
||||
}
|
||||
|
||||
void inc64(AbsoluteAddress dest) {
|
||||
|
|
|
@ -117,7 +117,7 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
|
|||
Label header, footer;
|
||||
masm.bind(&header);
|
||||
|
||||
masm.cmpq(r13, reg_argv);
|
||||
masm.cmpPtr(r13, reg_argv);
|
||||
masm.j(AssemblerX86Shared::BelowOrEqual, &footer);
|
||||
|
||||
masm.subq(Imm32(8), r13);
|
||||
|
|
|
@ -204,7 +204,7 @@ class Assembler : public AssemblerX86Shared
|
|||
// Actual assembly emitting functions.
|
||||
|
||||
void push(ImmGCPtr ptr) {
|
||||
push(Imm32(uintptr_t(ptr.value)));
|
||||
masm.push_i32(int32_t(ptr.value));
|
||||
writeDataRelocation(ptr);
|
||||
}
|
||||
void push(ImmMaybeNurseryPtr ptr) {
|
||||
|
@ -222,7 +222,7 @@ class Assembler : public AssemblerX86Shared
|
|||
}
|
||||
|
||||
CodeOffsetLabel pushWithPatch(ImmWord word) {
|
||||
push(Imm32(word.value));
|
||||
masm.push_i32(int32_t(word.value));
|
||||
return CodeOffsetLabel(masm.currentOffset());
|
||||
}
|
||||
|
||||
|
@ -329,44 +329,48 @@ class Assembler : public AssemblerX86Shared
|
|||
}
|
||||
}
|
||||
|
||||
void cmpl(const Register src, ImmWord ptr) {
|
||||
masm.cmpl_ir(ptr.value, src.code());
|
||||
void cmpl(ImmWord rhs, Register lhs) {
|
||||
masm.cmpl_ir(rhs.value, lhs.code());
|
||||
}
|
||||
void cmpl(const Register src, ImmPtr imm) {
|
||||
cmpl(src, ImmWord(uintptr_t(imm.value)));
|
||||
void cmpl(ImmPtr rhs, Register lhs) {
|
||||
cmpl(ImmWord(uintptr_t(rhs.value)), lhs);
|
||||
}
|
||||
void cmpl(const Register src, ImmGCPtr ptr) {
|
||||
masm.cmpl_ir(uintptr_t(ptr.value), src.code());
|
||||
writeDataRelocation(ptr);
|
||||
void cmpl(ImmGCPtr rhs, Register lhs) {
|
||||
masm.cmpl_i32r(uintptr_t(rhs.value), lhs.code());
|
||||
writeDataRelocation(rhs);
|
||||
}
|
||||
void cmpl(Register lhs, Register rhs) {
|
||||
void cmpl(Register rhs, Register lhs) {
|
||||
masm.cmpl_rr(rhs.code(), lhs.code());
|
||||
}
|
||||
void cmpl(const Operand &op, ImmGCPtr imm) {
|
||||
switch (op.kind()) {
|
||||
void cmpl(ImmGCPtr rhs, const Operand &lhs) {
|
||||
switch (lhs.kind()) {
|
||||
case Operand::REG:
|
||||
masm.cmpl_ir_force32(uintptr_t(imm.value), op.reg());
|
||||
writeDataRelocation(imm);
|
||||
masm.cmpl_i32r(uintptr_t(rhs.value), lhs.reg());
|
||||
writeDataRelocation(rhs);
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.cmpl_im_force32(uintptr_t(imm.value), op.disp(), op.base());
|
||||
writeDataRelocation(imm);
|
||||
masm.cmpl_i32m(uintptr_t(rhs.value), lhs.disp(), lhs.base());
|
||||
writeDataRelocation(rhs);
|
||||
break;
|
||||
case Operand::MEM_ADDRESS32:
|
||||
masm.cmpl_im(uintptr_t(imm.value), op.address());
|
||||
writeDataRelocation(imm);
|
||||
masm.cmpl_i32m(uintptr_t(rhs.value), lhs.address());
|
||||
writeDataRelocation(rhs);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void cmpl(const Operand &op, ImmMaybeNurseryPtr imm) {
|
||||
cmpl(op, noteMaybeNurseryPtr(imm));
|
||||
void cmpl(ImmMaybeNurseryPtr rhs, const Operand &lhs) {
|
||||
cmpl(noteMaybeNurseryPtr(rhs), lhs);
|
||||
}
|
||||
void cmpl(AsmJSAbsoluteAddress lhs, Register rhs) {
|
||||
masm.cmpl_rm_force32(rhs.code(), (void*)-1);
|
||||
void cmpl(Register rhs, AsmJSAbsoluteAddress lhs) {
|
||||
masm.cmpl_rm_disp32(rhs.code(), (void*)-1);
|
||||
append(AsmJSAbsoluteLink(CodeOffsetLabel(masm.currentOffset()), lhs.kind()));
|
||||
}
|
||||
void cmpl(Imm32 rhs, AsmJSAbsoluteAddress lhs) {
|
||||
JmpSrc src = masm.cmpl_im_disp32(rhs.value, (void*)-1);
|
||||
append(AsmJSAbsoluteLink(CodeOffsetLabel(src.offset()), lhs.kind()));
|
||||
}
|
||||
|
||||
void jmp(ImmPtr target, Relocation::Kind reloc = Relocation::HARDCODED) {
|
||||
JmpSrc src = masm.jmp();
|
||||
|
|
|
@ -28,7 +28,7 @@ ICCompare_Int32::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
|
||||
// Compare payload regs of R0 and R1.
|
||||
Assembler::Condition cond = JSOpToCondition(op, /* signed = */true);
|
||||
masm.cmpl(R0.payloadReg(), R1.payloadReg());
|
||||
masm.cmp32(R0.payloadReg(), R1.payloadReg());
|
||||
masm.setCC(cond, R0.payloadReg());
|
||||
masm.movzbl(R0.payloadReg(), R0.payloadReg());
|
||||
|
||||
|
@ -81,7 +81,7 @@ ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
masm.imull(R1.payloadReg(), scratchReg);
|
||||
masm.j(Assembler::Overflow, &failure);
|
||||
|
||||
masm.testl(scratchReg, scratchReg);
|
||||
masm.test32(scratchReg, scratchReg);
|
||||
masm.j(Assembler::Zero, &maybeNegZero);
|
||||
|
||||
masm.movl(scratchReg, R0.payloadReg());
|
||||
|
@ -173,7 +173,7 @@ ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm)
|
|||
|
||||
masm.movl(R1.payloadReg(), ecx);
|
||||
masm.shrl_cl(R0.payloadReg());
|
||||
masm.testl(R0.payloadReg(), R0.payloadReg());
|
||||
masm.test32(R0.payloadReg(), R0.payloadReg());
|
||||
if (allowDouble_) {
|
||||
Label toUint;
|
||||
masm.j(Assembler::Signed, &toUint);
|
||||
|
|
|
@ -127,7 +127,7 @@ CodeGeneratorX86::visitUnbox(LUnbox *unbox)
|
|||
MUnbox *mir = unbox->mir();
|
||||
|
||||
if (mir->fallible()) {
|
||||
masm.cmpl(ToOperand(unbox->type()), Imm32(MIRTypeToTag(mir->type())));
|
||||
masm.cmp32(ToOperand(unbox->type()), Imm32(MIRTypeToTag(mir->type())));
|
||||
bailoutIf(Assembler::NotEqual, unbox->snapshot());
|
||||
}
|
||||
}
|
||||
|
@ -303,7 +303,7 @@ CodeGeneratorX86::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic
|
|||
addOutOfLineCode(ool, ins->mir());
|
||||
}
|
||||
|
||||
masm.cmpl(ptr, Imm32(mir->length()));
|
||||
masm.cmpPtr(ptr, ImmWord(mir->length()));
|
||||
if (ool)
|
||||
masm.j(Assembler::AboveOrEqual, ool->entry());
|
||||
else
|
||||
|
@ -385,7 +385,7 @@ CodeGeneratorX86::visitAsmJSLoadHeap(LAsmJSLoadHeap *ins)
|
|||
OutOfLineLoadTypedArrayOutOfBounds *ool = new(alloc()) OutOfLineLoadTypedArrayOutOfBounds(ToAnyRegister(out), vt);
|
||||
addOutOfLineCode(ool, mir);
|
||||
|
||||
CodeOffsetLabel cmp = masm.cmplWithPatch(ptrReg, Imm32(0));
|
||||
CodeOffsetLabel cmp = masm.cmp32WithPatch(ptrReg, Imm32(0));
|
||||
masm.j(Assembler::AboveOrEqual, ool->entry());
|
||||
|
||||
uint32_t before = masm.size();
|
||||
|
@ -443,7 +443,7 @@ CodeGeneratorX86::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStati
|
|||
}
|
||||
|
||||
MOZ_ASSERT(offset == 0);
|
||||
masm.cmpl(ptr, Imm32(mir->length()));
|
||||
masm.cmpPtr(ptr, ImmWord(mir->length()));
|
||||
Label rejoin;
|
||||
masm.j(Assembler::AboveOrEqual, &rejoin);
|
||||
|
||||
|
@ -482,7 +482,7 @@ CodeGeneratorX86::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
|
|||
return;
|
||||
}
|
||||
|
||||
CodeOffsetLabel cmp = masm.cmplWithPatch(ptrReg, Imm32(0));
|
||||
CodeOffsetLabel cmp = masm.cmp32WithPatch(ptrReg, Imm32(0));
|
||||
Label rejoin;
|
||||
masm.j(Assembler::AboveOrEqual, &rejoin);
|
||||
|
||||
|
@ -511,7 +511,7 @@ CodeGeneratorX86::visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap *ins)
|
|||
uint32_t maybeCmpOffset = AsmJSHeapAccess::NoLengthCheck;
|
||||
|
||||
if (mir->needsBoundsCheck()) {
|
||||
maybeCmpOffset = masm.cmplWithPatch(ptrReg, Imm32(0)).offset();
|
||||
maybeCmpOffset = masm.cmp32WithPatch(ptrReg, Imm32(0)).offset();
|
||||
Label goahead;
|
||||
masm.j(Assembler::Below, &goahead);
|
||||
memoryBarrier(MembarFull);
|
||||
|
@ -524,7 +524,7 @@ CodeGeneratorX86::visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap *ins)
|
|||
// Add in the actual heap pointer explicitly, to avoid opening up
|
||||
// the abstraction that is compareExchangeToTypedIntArray at this time.
|
||||
uint32_t before = masm.size();
|
||||
masm.addl_wide(Imm32(0), ptrReg);
|
||||
masm.addlWithPatch(Imm32(0), ptrReg);
|
||||
uint32_t after = masm.size();
|
||||
masm.append(AsmJSHeapAccess(before, after, mir->viewType(), maybeCmpOffset));
|
||||
|
||||
|
@ -557,7 +557,7 @@ CodeGeneratorX86::visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap *ins)
|
|||
uint32_t maybeCmpOffset = AsmJSHeapAccess::NoLengthCheck;
|
||||
|
||||
if (mir->needsBoundsCheck()) {
|
||||
maybeCmpOffset = masm.cmplWithPatch(ptrReg, Imm32(0)).offset();
|
||||
maybeCmpOffset = masm.cmp32WithPatch(ptrReg, Imm32(0)).offset();
|
||||
Label goahead;
|
||||
masm.j(Assembler::Below, &goahead);
|
||||
memoryBarrier(MembarFull);
|
||||
|
@ -570,7 +570,7 @@ CodeGeneratorX86::visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap *ins)
|
|||
// Add in the actual heap pointer explicitly, to avoid opening up
|
||||
// the abstraction that is atomicBinopToTypedIntArray at this time.
|
||||
uint32_t before = masm.size();
|
||||
masm.addl_wide(Imm32(0), ptrReg);
|
||||
masm.addlWithPatch(Imm32(0), ptrReg);
|
||||
uint32_t after = masm.size();
|
||||
masm.append(AsmJSHeapAccess(before, after, mir->viewType(), maybeCmpOffset));
|
||||
|
||||
|
@ -846,7 +846,7 @@ CodeGeneratorX86::visitOutOfLineTruncate(OutOfLineTruncate *ool)
|
|||
// This has to be an exact conversion, as otherwise the truncation works
|
||||
// incorrectly on the modified value.
|
||||
masm.zeroDouble(ScratchDoubleReg);
|
||||
masm.ucomisd(input, ScratchDoubleReg);
|
||||
masm.vucomisd(ScratchDoubleReg, input);
|
||||
masm.j(Assembler::Parity, &fail);
|
||||
|
||||
{
|
||||
|
@ -863,10 +863,10 @@ CodeGeneratorX86::visitOutOfLineTruncate(OutOfLineTruncate *ool)
|
|||
}
|
||||
|
||||
masm.addDouble(input, temp);
|
||||
masm.cvttsd2si(temp, output);
|
||||
masm.cvtsi2sd(output, ScratchDoubleReg);
|
||||
masm.vcvttsd2si(temp, output);
|
||||
masm.vcvtsi2sd(output, ScratchDoubleReg, ScratchDoubleReg);
|
||||
|
||||
masm.ucomisd(temp, ScratchDoubleReg);
|
||||
masm.vucomisd(ScratchDoubleReg, temp);
|
||||
masm.j(Assembler::Parity, &fail);
|
||||
masm.j(Assembler::Equal, ool->rejoin());
|
||||
}
|
||||
|
@ -920,7 +920,7 @@ CodeGeneratorX86::visitOutOfLineTruncateFloat32(OutOfLineTruncateFloat32 *ool)
|
|||
masm.fisttp(Operand(esp, 0));
|
||||
|
||||
// Load low word, pop 64bits and jump back.
|
||||
masm.movl(Operand(esp, 0), output);
|
||||
masm.load32(Address(esp, 0), output);
|
||||
masm.addl(Imm32(sizeof(uint64_t)), esp);
|
||||
masm.jump(ool->rejoin());
|
||||
|
||||
|
@ -935,7 +935,7 @@ CodeGeneratorX86::visitOutOfLineTruncateFloat32(OutOfLineTruncateFloat32 *ool)
|
|||
// This has to be an exact conversion, as otherwise the truncation works
|
||||
// incorrectly on the modified value.
|
||||
masm.zeroFloat32(ScratchFloat32Reg);
|
||||
masm.ucomiss(input, ScratchFloat32Reg);
|
||||
masm.vucomiss(ScratchFloat32Reg, input);
|
||||
masm.j(Assembler::Parity, &fail);
|
||||
|
||||
{
|
||||
|
@ -952,10 +952,10 @@ CodeGeneratorX86::visitOutOfLineTruncateFloat32(OutOfLineTruncateFloat32 *ool)
|
|||
}
|
||||
|
||||
masm.addFloat32(input, temp);
|
||||
masm.cvttss2si(temp, output);
|
||||
masm.cvtsi2ss(output, ScratchFloat32Reg);
|
||||
masm.vcvttss2si(temp, output);
|
||||
masm.vcvtsi2ss(output, ScratchFloat32Reg, ScratchFloat32Reg);
|
||||
|
||||
masm.ucomiss(temp, ScratchFloat32Reg);
|
||||
masm.vucomiss(ScratchFloat32Reg, temp);
|
||||
masm.j(Assembler::Parity, &fail);
|
||||
masm.j(Assembler::Equal, ool->rejoin());
|
||||
}
|
||||
|
@ -966,7 +966,7 @@ CodeGeneratorX86::visitOutOfLineTruncateFloat32(OutOfLineTruncateFloat32 *ool)
|
|||
|
||||
masm.push(input);
|
||||
masm.setupUnalignedABICall(1, output);
|
||||
masm.cvtss2sd(input, input);
|
||||
masm.vcvtss2sd(input, input, input);
|
||||
masm.passABIArg(input, MoveOp::DOUBLE);
|
||||
|
||||
if (gen->compilingAsmJS())
|
||||
|
|
|
@ -291,7 +291,7 @@ MacroAssemblerX86::callWithABIPre(uint32_t *stackAdjust)
|
|||
{
|
||||
// Check call alignment.
|
||||
Label good;
|
||||
testl(esp, Imm32(ABIStackAlignment - 1));
|
||||
test32(esp, Imm32(ABIStackAlignment - 1));
|
||||
j(Equal, &good);
|
||||
breakpoint();
|
||||
bind(&good);
|
||||
|
@ -443,15 +443,15 @@ MacroAssemblerX86::branchTestValue(Condition cond, const ValueOperand &value, co
|
|||
{
|
||||
jsval_layout jv = JSVAL_TO_IMPL(v);
|
||||
if (v.isMarkable())
|
||||
cmpl(value.payloadReg(), ImmGCPtr(reinterpret_cast<gc::Cell *>(v.toGCThing())));
|
||||
cmpPtr(value.payloadReg(), ImmGCPtr(reinterpret_cast<gc::Cell *>(v.toGCThing())));
|
||||
else
|
||||
cmpl(value.payloadReg(), Imm32(jv.s.payload.i32));
|
||||
cmpPtr(value.payloadReg(), ImmWord(jv.s.payload.i32));
|
||||
|
||||
if (cond == Equal) {
|
||||
Label done;
|
||||
j(NotEqual, &done);
|
||||
{
|
||||
cmpl(value.typeReg(), Imm32(jv.s.tag));
|
||||
cmp32(value.typeReg(), Imm32(jv.s.tag));
|
||||
j(Equal, label);
|
||||
}
|
||||
bind(&done);
|
||||
|
@ -459,7 +459,7 @@ MacroAssemblerX86::branchTestValue(Condition cond, const ValueOperand &value, co
|
|||
MOZ_ASSERT(cond == NotEqual);
|
||||
j(NotEqual, label);
|
||||
|
||||
cmpl(value.typeReg(), Imm32(jv.s.tag));
|
||||
cmp32(value.typeReg(), Imm32(jv.s.tag));
|
||||
j(NotEqual, label);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -271,78 +271,78 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
|
||||
Condition testUndefined(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_UNDEFINED));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_UNDEFINED));
|
||||
return cond;
|
||||
}
|
||||
Condition testBoolean(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_BOOLEAN));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_BOOLEAN));
|
||||
return cond;
|
||||
}
|
||||
Condition testInt32(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_INT32));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_INT32));
|
||||
return cond;
|
||||
}
|
||||
Condition testDouble(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
|
||||
Condition actual = (cond == Equal) ? Below : AboveOrEqual;
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_CLEAR));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_CLEAR));
|
||||
return actual;
|
||||
}
|
||||
Condition testNull(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_NULL));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_NULL));
|
||||
return cond;
|
||||
}
|
||||
Condition testString(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_STRING));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_STRING));
|
||||
return cond;
|
||||
}
|
||||
Condition testSymbol(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_SYMBOL));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_SYMBOL));
|
||||
return cond;
|
||||
}
|
||||
Condition testObject(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_OBJECT));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_OBJECT));
|
||||
return cond;
|
||||
}
|
||||
Condition testNumber(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET));
|
||||
cmp32(tag, ImmTag(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET));
|
||||
return cond == Equal ? BelowOrEqual : Above;
|
||||
}
|
||||
Condition testGCThing(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
|
||||
cmp32(tag, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
|
||||
return cond == Equal ? AboveOrEqual : Below;
|
||||
}
|
||||
Condition testGCThing(Condition cond, const Address &address) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
|
||||
cmp32(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
|
||||
return cond == Equal ? AboveOrEqual : Below;
|
||||
}
|
||||
Condition testMagic(Condition cond, const Address &address) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_MAGIC));
|
||||
cmp32(tagOf(address), ImmTag(JSVAL_TAG_MAGIC));
|
||||
return cond;
|
||||
}
|
||||
Condition testMagic(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_TAG_MAGIC));
|
||||
cmp32(tag, ImmTag(JSVAL_TAG_MAGIC));
|
||||
return cond;
|
||||
}
|
||||
Condition testMagic(Condition cond, const Operand &operand) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(ToType(operand), ImmTag(JSVAL_TAG_MAGIC));
|
||||
cmp32(ToType(operand), ImmTag(JSVAL_TAG_MAGIC));
|
||||
return cond;
|
||||
}
|
||||
Condition testPrimitive(Condition cond, Register tag) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET));
|
||||
cmp32(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET));
|
||||
return cond == Equal ? Below : AboveOrEqual;
|
||||
}
|
||||
Condition testError(Condition cond, Register tag) {
|
||||
|
@ -350,7 +350,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
}
|
||||
Condition testInt32(Condition cond, const Operand &operand) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(ToType(operand), ImmTag(JSVAL_TAG_INT32));
|
||||
cmp32(ToType(operand), ImmTag(JSVAL_TAG_INT32));
|
||||
return cond;
|
||||
}
|
||||
Condition testInt32(Condition cond, const Address &address) {
|
||||
|
@ -360,7 +360,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
Condition testDouble(Condition cond, const Operand &operand) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
Condition actual = (cond == Equal) ? Below : AboveOrEqual;
|
||||
cmpl(ToType(operand), ImmTag(JSVAL_TAG_CLEAR));
|
||||
cmp32(ToType(operand), ImmTag(JSVAL_TAG_CLEAR));
|
||||
return actual;
|
||||
}
|
||||
Condition testDouble(Condition cond, const Address &address) {
|
||||
|
@ -371,7 +371,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
|
||||
Condition testUndefined(Condition cond, const Operand &operand) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(ToType(operand), ImmTag(JSVAL_TAG_UNDEFINED));
|
||||
cmp32(ToType(operand), ImmTag(JSVAL_TAG_UNDEFINED));
|
||||
return cond;
|
||||
}
|
||||
Condition testUndefined(Condition cond, const Address &addr) {
|
||||
|
@ -379,7 +379,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
}
|
||||
Condition testNull(Condition cond, const Operand &operand) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(ToType(operand), ImmTag(JSVAL_TAG_NULL));
|
||||
cmp32(ToType(operand), ImmTag(JSVAL_TAG_NULL));
|
||||
return cond;
|
||||
}
|
||||
Condition testNull(Condition cond, const Address &addr) {
|
||||
|
@ -429,53 +429,53 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
|
||||
Condition testUndefined(Condition cond, const BaseIndex &address) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_UNDEFINED));
|
||||
cmp32(tagOf(address), ImmTag(JSVAL_TAG_UNDEFINED));
|
||||
return cond;
|
||||
}
|
||||
Condition testNull(Condition cond, const BaseIndex &address) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_NULL));
|
||||
cmp32(tagOf(address), ImmTag(JSVAL_TAG_NULL));
|
||||
return cond;
|
||||
}
|
||||
Condition testBoolean(Condition cond, const BaseIndex &address) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_BOOLEAN));
|
||||
cmp32(tagOf(address), ImmTag(JSVAL_TAG_BOOLEAN));
|
||||
return cond;
|
||||
}
|
||||
Condition testString(Condition cond, const BaseIndex &address) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_STRING));
|
||||
cmp32(tagOf(address), ImmTag(JSVAL_TAG_STRING));
|
||||
return cond;
|
||||
}
|
||||
Condition testSymbol(Condition cond, const BaseIndex &address) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_SYMBOL));
|
||||
cmp32(tagOf(address), ImmTag(JSVAL_TAG_SYMBOL));
|
||||
return cond;
|
||||
}
|
||||
Condition testInt32(Condition cond, const BaseIndex &address) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_INT32));
|
||||
cmp32(tagOf(address), ImmTag(JSVAL_TAG_INT32));
|
||||
return cond;
|
||||
}
|
||||
Condition testObject(Condition cond, const BaseIndex &address) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_OBJECT));
|
||||
cmp32(tagOf(address), ImmTag(JSVAL_TAG_OBJECT));
|
||||
return cond;
|
||||
}
|
||||
Condition testDouble(Condition cond, const BaseIndex &address) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
Condition actual = (cond == Equal) ? Below : AboveOrEqual;
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_CLEAR));
|
||||
cmp32(tagOf(address), ImmTag(JSVAL_TAG_CLEAR));
|
||||
return actual;
|
||||
}
|
||||
Condition testMagic(Condition cond, const BaseIndex &address) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_TAG_MAGIC));
|
||||
cmp32(tagOf(address), ImmTag(JSVAL_TAG_MAGIC));
|
||||
return cond;
|
||||
}
|
||||
Condition testGCThing(Condition cond, const BaseIndex &address) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmpl(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
|
||||
cmp32(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
|
||||
return cond == Equal ? AboveOrEqual : Below;
|
||||
}
|
||||
|
||||
|
@ -515,43 +515,58 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
}
|
||||
|
||||
void cmpPtr(Register lhs, const ImmWord rhs) {
|
||||
cmpl(lhs, Imm32(rhs.value));
|
||||
cmpl(Imm32(rhs.value), lhs);
|
||||
}
|
||||
void cmpPtr(Register lhs, const ImmPtr imm) {
|
||||
cmpPtr(lhs, ImmWord(uintptr_t(imm.value)));
|
||||
}
|
||||
void cmpPtr(Register lhs, const ImmGCPtr rhs) {
|
||||
cmpl(lhs, rhs);
|
||||
cmpl(rhs, lhs);
|
||||
}
|
||||
void cmpPtr(Register lhs, const Imm32 rhs) {
|
||||
cmpl(lhs, rhs);
|
||||
void cmpPtr(const Operand &lhs, Imm32 rhs) {
|
||||
cmp32(lhs, rhs);
|
||||
}
|
||||
void cmpPtr(const Operand &lhs, const ImmWord rhs) {
|
||||
cmpl(lhs, rhs);
|
||||
cmp32(lhs, Imm32(rhs.value));
|
||||
}
|
||||
void cmpPtr(const Operand &lhs, const ImmPtr imm) {
|
||||
cmpPtr(lhs, ImmWord(uintptr_t(imm.value)));
|
||||
}
|
||||
void cmpPtr(const Operand &lhs, const ImmGCPtr rhs) {
|
||||
cmpl(lhs, rhs);
|
||||
}
|
||||
void cmpPtr(const Operand &lhs, const Imm32 rhs) {
|
||||
cmpl(lhs, rhs);
|
||||
cmpl(rhs, lhs);
|
||||
}
|
||||
void cmpPtr(const Address &lhs, Register rhs) {
|
||||
cmpl(Operand(lhs), rhs);
|
||||
cmpPtr(Operand(lhs), rhs);
|
||||
}
|
||||
void cmpPtr(const Operand &lhs, Register rhs) {
|
||||
cmp32(lhs, rhs);
|
||||
}
|
||||
void cmpPtr(const Address &lhs, const ImmWord rhs) {
|
||||
cmpl(Operand(lhs), rhs);
|
||||
cmpPtr(Operand(lhs), rhs);
|
||||
}
|
||||
void cmpPtr(const Address &lhs, const ImmPtr rhs) {
|
||||
cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
|
||||
}
|
||||
void cmpPtr(Register lhs, Register rhs) {
|
||||
cmpl(lhs, rhs);
|
||||
cmp32(lhs, rhs);
|
||||
}
|
||||
void cmpPtr(const Operand &lhs, ImmMaybeNurseryPtr rhs) {
|
||||
cmpl(rhs, lhs);
|
||||
}
|
||||
void testPtr(Register lhs, Register rhs) {
|
||||
testl(lhs, rhs);
|
||||
test32(lhs, rhs);
|
||||
}
|
||||
void testPtr(Register lhs, Imm32 rhs) {
|
||||
test32(lhs, rhs);
|
||||
}
|
||||
void testPtr(Register lhs, ImmWord rhs) {
|
||||
test32(lhs, Imm32(rhs.value));
|
||||
}
|
||||
void testPtr(const Operand &lhs, Imm32 rhs) {
|
||||
test32(lhs, rhs);
|
||||
}
|
||||
void testPtr(const Operand &lhs, ImmWord rhs) {
|
||||
test32(lhs, Imm32(rhs.value));
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
|
@ -592,64 +607,68 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
}
|
||||
|
||||
void addPtr(Register src, Register dest) {
|
||||
addl(src, dest);
|
||||
add32(src, dest);
|
||||
}
|
||||
void addPtr(Imm32 imm, Register dest) {
|
||||
addl(imm, dest);
|
||||
add32(imm, dest);
|
||||
}
|
||||
void addPtr(ImmWord imm, Register dest) {
|
||||
addl(Imm32(imm.value), dest);
|
||||
add32(Imm32(imm.value), dest);
|
||||
}
|
||||
void addPtr(ImmPtr imm, Register dest) {
|
||||
addPtr(ImmWord(uintptr_t(imm.value)), dest);
|
||||
}
|
||||
void addPtr(Imm32 imm, const Address &dest) {
|
||||
addl(imm, Operand(dest));
|
||||
add32(imm, Operand(dest));
|
||||
}
|
||||
void addPtr(Imm32 imm, const Operand &dest) {
|
||||
addl(imm, dest);
|
||||
add32(imm, dest);
|
||||
}
|
||||
void addPtr(const Address &src, Register dest) {
|
||||
addl(Operand(src), dest);
|
||||
}
|
||||
void subPtr(Imm32 imm, Register dest) {
|
||||
subl(imm, dest);
|
||||
sub32(imm, dest);
|
||||
}
|
||||
void subPtr(Register src, Register dest) {
|
||||
subl(src, dest);
|
||||
sub32(src, dest);
|
||||
}
|
||||
void subPtr(const Address &addr, Register dest) {
|
||||
subl(Operand(addr), dest);
|
||||
sub32(Operand(addr), dest);
|
||||
}
|
||||
void subPtr(Register src, const Address &dest) {
|
||||
subl(src, Operand(dest));
|
||||
sub32(src, Operand(dest));
|
||||
}
|
||||
void mulBy3(const Register &src, const Register &dest) {
|
||||
lea(Operand(src, src, TimesTwo), dest);
|
||||
}
|
||||
|
||||
void branch32(Condition cond, AbsoluteAddress lhs, Imm32 rhs, Label *label) {
|
||||
cmpl(Operand(lhs), rhs);
|
||||
cmp32(Operand(lhs), rhs);
|
||||
j(cond, label);
|
||||
}
|
||||
void branch32(Condition cond, AsmJSAbsoluteAddress lhs, Imm32 rhs, Label *label) {
|
||||
cmpl(rhs, lhs);
|
||||
j(cond, label);
|
||||
}
|
||||
void branch32(Condition cond, AbsoluteAddress lhs, Register rhs, Label *label) {
|
||||
cmpl(Operand(lhs), rhs);
|
||||
cmp32(Operand(lhs), rhs);
|
||||
j(cond, label);
|
||||
}
|
||||
void branchTest32(Condition cond, AbsoluteAddress address, Imm32 imm, Label *label) {
|
||||
testl(Operand(address), imm);
|
||||
test32(Operand(address), imm);
|
||||
j(cond, label);
|
||||
}
|
||||
|
||||
// Specialization for AsmJSAbsoluteAddress.
|
||||
void branchPtr(Condition cond, AsmJSAbsoluteAddress lhs, Register ptr, Label *label) {
|
||||
cmpl(lhs, ptr);
|
||||
cmpl(ptr, lhs);
|
||||
j(cond, label);
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
void branchPtr(Condition cond, T lhs, S ptr, Label *label) {
|
||||
cmpl(Operand(lhs), ptr);
|
||||
cmpPtr(Operand(lhs), ptr);
|
||||
j(cond, label);
|
||||
}
|
||||
|
||||
|
@ -663,7 +682,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
|
||||
template <typename T, typename S>
|
||||
void branchPtr(Condition cond, T lhs, S ptr, RepatchLabel *label) {
|
||||
cmpl(Operand(lhs), ptr);
|
||||
cmpPtr(Operand(lhs), ptr);
|
||||
j(cond, label);
|
||||
}
|
||||
|
||||
|
@ -687,23 +706,23 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
return CodeOffsetJump(size());
|
||||
}
|
||||
void branchPtr(Condition cond, Register lhs, Register rhs, RepatchLabel *label) {
|
||||
cmpl(lhs, rhs);
|
||||
cmpPtr(lhs, rhs);
|
||||
j(cond, label);
|
||||
}
|
||||
void branchPtr(Condition cond, Register lhs, Register rhs, Label *label) {
|
||||
cmpl(lhs, rhs);
|
||||
cmpPtr(lhs, rhs);
|
||||
j(cond, label);
|
||||
}
|
||||
void branchTestPtr(Condition cond, Register lhs, Register rhs, Label *label) {
|
||||
testl(lhs, rhs);
|
||||
testPtr(lhs, rhs);
|
||||
j(cond, label);
|
||||
}
|
||||
void branchTestPtr(Condition cond, Register lhs, Imm32 imm, Label *label) {
|
||||
testl(lhs, imm);
|
||||
testPtr(lhs, imm);
|
||||
j(cond, label);
|
||||
}
|
||||
void branchTestPtr(Condition cond, const Address &lhs, Imm32 imm, Label *label) {
|
||||
testl(Operand(lhs), imm);
|
||||
testPtr(Operand(lhs), imm);
|
||||
j(cond, label);
|
||||
}
|
||||
void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label *label) {
|
||||
|
@ -848,12 +867,12 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
// Note: this function clobbers the source register.
|
||||
void boxDouble(FloatRegister src, const ValueOperand &dest) {
|
||||
if (Assembler::HasSSE41()) {
|
||||
movd(src, dest.payloadReg());
|
||||
vmovd(src, dest.payloadReg());
|
||||
pextrd(1, src, dest.typeReg());
|
||||
} else {
|
||||
movd(src, dest.payloadReg());
|
||||
vmovd(src, dest.payloadReg());
|
||||
psrldq(Imm32(4), src);
|
||||
movd(src, dest.typeReg());
|
||||
vmovd(src, dest.typeReg());
|
||||
}
|
||||
}
|
||||
void boxNonDouble(JSValueType type, Register src, const ValueOperand &dest) {
|
||||
|
@ -885,12 +904,12 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
void unboxDouble(const ValueOperand &src, FloatRegister dest) {
|
||||
MOZ_ASSERT(dest != ScratchDoubleReg);
|
||||
if (Assembler::HasSSE41()) {
|
||||
movd(src.payloadReg(), dest);
|
||||
vmovd(src.payloadReg(), dest);
|
||||
pinsrd(1, src.typeReg(), dest);
|
||||
} else {
|
||||
movd(src.payloadReg(), dest);
|
||||
movd(src.typeReg(), ScratchDoubleReg);
|
||||
unpcklps(ScratchDoubleReg, dest);
|
||||
vmovd(src.payloadReg(), dest);
|
||||
vmovd(src.typeReg(), ScratchDoubleReg);
|
||||
vunpcklps(ScratchDoubleReg, dest, dest);
|
||||
}
|
||||
}
|
||||
void unboxDouble(const Operand &payload, const Operand &type,
|
||||
|
@ -898,15 +917,15 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
MOZ_ASSERT(dest != ScratchDoubleReg);
|
||||
if (Assembler::HasSSE41()) {
|
||||
movl(payload, scratch);
|
||||
movd(scratch, dest);
|
||||
vmovd(scratch, dest);
|
||||
movl(type, scratch);
|
||||
pinsrd(1, scratch, dest);
|
||||
} else {
|
||||
movl(payload, scratch);
|
||||
movd(scratch, dest);
|
||||
vmovd(scratch, dest);
|
||||
movl(type, scratch);
|
||||
movd(scratch, ScratchDoubleReg);
|
||||
unpcklps(ScratchDoubleReg, dest);
|
||||
vmovd(scratch, ScratchDoubleReg);
|
||||
vunpcklps(ScratchDoubleReg, dest, dest);
|
||||
}
|
||||
}
|
||||
void unboxValue(const ValueOperand &src, AnyRegister dest) {
|
||||
|
@ -977,26 +996,26 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
void loadConstantFloat32x4(const SimdConstant &v, FloatRegister dest);
|
||||
|
||||
void branchTruncateDouble(FloatRegister src, Register dest, Label *fail) {
|
||||
cvttsd2si(src, dest);
|
||||
vcvttsd2si(src, dest);
|
||||
|
||||
// cvttsd2si returns 0x80000000 on failure. Test for it by
|
||||
// vcvttsd2si returns 0x80000000 on failure. Test for it by
|
||||
// subtracting 1 and testing overflow (this permits the use of a
|
||||
// smaller immediate field).
|
||||
cmpl(dest, Imm32(1));
|
||||
cmp32(dest, Imm32(1));
|
||||
j(Assembler::Overflow, fail);
|
||||
}
|
||||
void branchTruncateFloat32(FloatRegister src, Register dest, Label *fail) {
|
||||
cvttss2si(src, dest);
|
||||
vcvttss2si(src, dest);
|
||||
|
||||
// cvttss2si returns 0x80000000 on failure. Test for it by
|
||||
// vcvttss2si returns 0x80000000 on failure. Test for it by
|
||||
// subtracting 1 and testing overflow (this permits the use of a
|
||||
// smaller immediate field).
|
||||
cmpl(dest, Imm32(1));
|
||||
cmp32(dest, Imm32(1));
|
||||
j(Assembler::Overflow, fail);
|
||||
}
|
||||
|
||||
Condition testInt32Truthy(bool truthy, const ValueOperand &operand) {
|
||||
testl(operand.payloadReg(), operand.payloadReg());
|
||||
test32(operand.payloadReg(), operand.payloadReg());
|
||||
return truthy ? NonZero : Zero;
|
||||
}
|
||||
void branchTestInt32Truthy(bool truthy, const ValueOperand &operand, Label *label) {
|
||||
|
@ -1004,12 +1023,12 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
j(cond, label);
|
||||
}
|
||||
void branchTestBooleanTruthy(bool truthy, const ValueOperand &operand, Label *label) {
|
||||
testl(operand.payloadReg(), operand.payloadReg());
|
||||
test32(operand.payloadReg(), operand.payloadReg());
|
||||
j(truthy ? NonZero : Zero, label);
|
||||
}
|
||||
Condition testStringTruthy(bool truthy, const ValueOperand &value) {
|
||||
Register string = value.payloadReg();
|
||||
cmpl(Operand(string, JSString::offsetOfLength()), Imm32(0));
|
||||
cmp32(Operand(string, JSString::offsetOfLength()), Imm32(0));
|
||||
return truthy ? Assembler::NotEqual : Assembler::Equal;
|
||||
}
|
||||
void branchTestStringTruthy(bool truthy, const ValueOperand &value, Label *label) {
|
||||
|
@ -1162,7 +1181,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
}
|
||||
|
||||
void callWithExitFrame(JitCode *target, Register dynStack) {
|
||||
addPtr(Imm32(framePushed()), dynStack);
|
||||
addPtr(ImmWord(framePushed()), dynStack);
|
||||
makeFrameDescriptor(dynStack, JitFrame_IonJS);
|
||||
Push(dynStack);
|
||||
call(target);
|
||||
|
|
|
@ -105,7 +105,7 @@ JitRuntime::generateEnterJIT(JSContext *cx, EnterJitType type)
|
|||
Label header, footer;
|
||||
masm.bind(&header);
|
||||
|
||||
masm.cmpl(eax, ebx);
|
||||
masm.cmp32(eax, ebx);
|
||||
masm.j(Assembler::BelowOrEqual, &footer);
|
||||
|
||||
// eax -= 8 --move to previous argument
|
||||
|
|
|
@ -443,8 +443,8 @@ Debugger::getScriptFrameWithIter(JSContext *cx, AbstractFramePtr frame,
|
|||
if (!p) {
|
||||
/* Create and populate the Debugger.Frame object. */
|
||||
JSObject *proto = &object->getReservedSlot(JSSLOT_DEBUG_FRAME_PROTO).toObject();
|
||||
NativeObject *frameobj =
|
||||
NewNativeObjectWithGivenProto(cx, &DebuggerFrame_class, proto, nullptr);
|
||||
RootedNativeObject frameobj(cx, NewNativeObjectWithGivenProto(cx, &DebuggerFrame_class,
|
||||
proto, nullptr));
|
||||
if (!frameobj)
|
||||
return false;
|
||||
|
||||
|
@ -461,13 +461,13 @@ Debugger::getScriptFrameWithIter(JSContext *cx, AbstractFramePtr frame,
|
|||
|
||||
frameobj->setReservedSlot(JSSLOT_DEBUGFRAME_OWNER, ObjectValue(*object));
|
||||
|
||||
if (!ensureExecutionObservabilityOfFrame(cx, frame))
|
||||
return false;
|
||||
|
||||
if (!frames.add(p, frame, frameobj)) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ensureExecutionObservabilityOfFrame(cx, frame))
|
||||
return false;
|
||||
}
|
||||
vp.setObject(*p->value());
|
||||
return true;
|
||||
|
@ -4540,8 +4540,10 @@ Debugger::replaceFrameGuts(JSContext *cx, AbstractFramePtr from, AbstractFramePt
|
|||
}
|
||||
}
|
||||
|
||||
// Rekey missingScopes to maintain Debugger.Environment identity.
|
||||
DebugScopes::rekeyMissingScopes(cx, from, to);
|
||||
// Rekey missingScopes to maintain Debugger.Environment identity and
|
||||
// forward liveScopes to point to the new frame, as the old frame will be
|
||||
// gone.
|
||||
DebugScopes::forwardLiveFrame(cx, from, to);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1487,14 +1487,34 @@ class DebugScopeProxy : public BaseProxyHandler
|
|||
!scope.as<CallObject>().callee().nonLazyScript()->needsArgsObj();
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the value is the magic value JS_OPTIMIZED_ARGUMENTS. The
|
||||
* arguments analysis may have optimized out the 'arguments', and this
|
||||
* magic value could have propagated to other local slots. e.g.,
|
||||
*
|
||||
* function f() { var a = arguments; h(); }
|
||||
* function h() { evalInFrame(1, "a.push(0)"); }
|
||||
*
|
||||
* where evalInFrame(N, str) means to evaluate str N frames up.
|
||||
*
|
||||
* In this case we don't know we need to recover a missing arguments
|
||||
* object until after we've performed the property get.
|
||||
*/
|
||||
static bool isMagicMissingArgumentsValue(JSContext *cx, ScopeObject &scope, HandleValue v)
|
||||
{
|
||||
bool isMagic = v.isMagic() && v.whyMagic() == JS_OPTIMIZED_ARGUMENTS;
|
||||
MOZ_ASSERT_IF(isMagic, isFunctionScope(scope) &&
|
||||
!scope.as<CallObject>().callee().nonLazyScript()->needsArgsObj());
|
||||
return isMagic;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a missing arguments object. If the function returns true but
|
||||
* argsObj is null, it means the scope is dead.
|
||||
*/
|
||||
static bool createMissingArguments(JSContext *cx, jsid id, ScopeObject &scope,
|
||||
static bool createMissingArguments(JSContext *cx, ScopeObject &scope,
|
||||
MutableHandleArgumentsObject argsObj)
|
||||
{
|
||||
MOZ_ASSERT(isMissingArguments(cx, id, scope));
|
||||
argsObj.set(nullptr);
|
||||
|
||||
ScopeIterVal *maybeScope = DebugScopes::hasLiveScope(scope);
|
||||
|
@ -1532,30 +1552,37 @@ class DebugScopeProxy : public BaseProxyHandler
|
|||
return getOwnPropertyDescriptor(cx, proxy, id, desc);
|
||||
}
|
||||
|
||||
bool getMissingArgumentsPropertyDescriptor(JSContext *cx,
|
||||
Handle<DebugScopeObject *> debugScope,
|
||||
ScopeObject &scope,
|
||||
MutableHandle<PropertyDescriptor> desc) const
|
||||
{
|
||||
RootedArgumentsObject argsObj(cx);
|
||||
if (!createMissingArguments(cx, scope, &argsObj))
|
||||
return false;
|
||||
|
||||
if (!argsObj) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_LIVE,
|
||||
"Debugger scope");
|
||||
return false;
|
||||
}
|
||||
|
||||
desc.object().set(debugScope);
|
||||
desc.setAttributes(JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT);
|
||||
desc.value().setObject(*argsObj);
|
||||
desc.setGetter(nullptr);
|
||||
desc.setSetter(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
MutableHandle<PropertyDescriptor> desc) const MOZ_OVERRIDE
|
||||
MutableHandle<PropertyDescriptor> desc) const
|
||||
{
|
||||
Rooted<DebugScopeObject*> debugScope(cx, &proxy->as<DebugScopeObject>());
|
||||
Rooted<ScopeObject*> scope(cx, &debugScope->scope());
|
||||
|
||||
if (isMissingArguments(cx, id, *scope)) {
|
||||
RootedArgumentsObject argsObj(cx);
|
||||
if (!createMissingArguments(cx, id, *scope, &argsObj))
|
||||
return false;
|
||||
|
||||
if (!argsObj) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_LIVE,
|
||||
"Debugger scope");
|
||||
return false;
|
||||
}
|
||||
|
||||
desc.object().set(debugScope);
|
||||
desc.setAttributes(JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT);
|
||||
desc.value().setObject(*argsObj);
|
||||
desc.setGetter(nullptr);
|
||||
desc.setSetter(nullptr);
|
||||
return true;
|
||||
}
|
||||
if (isMissingArguments(cx, id, *scope))
|
||||
return getMissingArgumentsPropertyDescriptor(cx, debugScope, *scope, desc);
|
||||
|
||||
RootedValue v(cx);
|
||||
AccessResult access;
|
||||
|
@ -1564,6 +1591,8 @@ class DebugScopeProxy : public BaseProxyHandler
|
|||
|
||||
switch (access) {
|
||||
case ACCESS_UNALIASED:
|
||||
if (isMagicMissingArgumentsValue(cx, *scope, v))
|
||||
return getMissingArgumentsPropertyDescriptor(cx, debugScope, *scope, desc);
|
||||
desc.object().set(debugScope);
|
||||
desc.setAttributes(JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT);
|
||||
desc.value().set(v);
|
||||
|
@ -1580,26 +1609,30 @@ class DebugScopeProxy : public BaseProxyHandler
|
|||
}
|
||||
}
|
||||
|
||||
bool getMissingArguments(JSContext *cx, ScopeObject &scope, MutableHandleValue vp) const
|
||||
{
|
||||
RootedArgumentsObject argsObj(cx);
|
||||
if (!createMissingArguments(cx, scope, &argsObj))
|
||||
return false;
|
||||
|
||||
if (!argsObj) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_LIVE,
|
||||
"Debugger scope");
|
||||
return false;
|
||||
}
|
||||
|
||||
vp.setObject(*argsObj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
|
||||
MutableHandleValue vp) const MOZ_OVERRIDE
|
||||
{
|
||||
Rooted<DebugScopeObject*> debugScope(cx, &proxy->as<DebugScopeObject>());
|
||||
Rooted<ScopeObject*> scope(cx, &proxy->as<DebugScopeObject>().scope());
|
||||
|
||||
if (isMissingArguments(cx, id, *scope)) {
|
||||
RootedArgumentsObject argsObj(cx);
|
||||
if (!createMissingArguments(cx, id, *scope, &argsObj))
|
||||
return false;
|
||||
|
||||
if (!argsObj) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_LIVE,
|
||||
"Debugger scope");
|
||||
return false;
|
||||
}
|
||||
|
||||
vp.setObject(*argsObj);
|
||||
return true;
|
||||
}
|
||||
if (isMissingArguments(cx, id, *scope))
|
||||
return getMissingArguments(cx, *scope, vp);
|
||||
|
||||
AccessResult access;
|
||||
if (!handleUnaliasedAccess(cx, debugScope, scope, id, GET, vp, &access))
|
||||
|
@ -1607,6 +1640,8 @@ class DebugScopeProxy : public BaseProxyHandler
|
|||
|
||||
switch (access) {
|
||||
case ACCESS_UNALIASED:
|
||||
if (isMagicMissingArgumentsValue(cx, *scope, vp))
|
||||
return getMissingArguments(cx, *scope, vp);
|
||||
return true;
|
||||
case ACCESS_GENERIC:
|
||||
return JSObject::getGeneric(cx, scope, scope, id, vp);
|
||||
|
@ -1618,6 +1653,16 @@ class DebugScopeProxy : public BaseProxyHandler
|
|||
}
|
||||
}
|
||||
|
||||
bool getMissingArgumentsMaybeSentinelValue(JSContext *cx, ScopeObject &scope,
|
||||
MutableHandleValue vp) const
|
||||
{
|
||||
RootedArgumentsObject argsObj(cx);
|
||||
if (!createMissingArguments(cx, scope, &argsObj))
|
||||
return false;
|
||||
vp.set(argsObj ? ObjectValue(*argsObj) : MagicValue(JS_OPTIMIZED_ARGUMENTS));
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like 'get', but returns sentinel values instead of throwing on
|
||||
* exceptional cases.
|
||||
|
@ -1627,13 +1672,8 @@ class DebugScopeProxy : public BaseProxyHandler
|
|||
{
|
||||
Rooted<ScopeObject*> scope(cx, &debugScope->scope());
|
||||
|
||||
if (isMissingArguments(cx, id, *scope)) {
|
||||
RootedArgumentsObject argsObj(cx);
|
||||
if (!createMissingArguments(cx, id, *scope, &argsObj))
|
||||
return false;
|
||||
vp.set(argsObj ? ObjectValue(*argsObj) : MagicValue(JS_OPTIMIZED_ARGUMENTS));
|
||||
return true;
|
||||
}
|
||||
if (isMissingArguments(cx, id, *scope))
|
||||
return getMissingArgumentsMaybeSentinelValue(cx, *scope, vp);
|
||||
|
||||
AccessResult access;
|
||||
if (!handleUnaliasedAccess(cx, debugScope, scope, id, GET, vp, &access))
|
||||
|
@ -1641,6 +1681,8 @@ class DebugScopeProxy : public BaseProxyHandler
|
|||
|
||||
switch (access) {
|
||||
case ACCESS_UNALIASED:
|
||||
if (isMagicMissingArgumentsValue(cx, *scope, vp))
|
||||
return getMissingArgumentsMaybeSentinelValue(cx, *scope, vp);
|
||||
return true;
|
||||
case ACCESS_GENERIC:
|
||||
return JSObject::getGeneric(cx, scope, scope, id, vp);
|
||||
|
@ -2351,7 +2393,7 @@ DebugScopes::hasLiveScope(ScopeObject &scope)
|
|||
}
|
||||
|
||||
/* static */ void
|
||||
DebugScopes::rekeyMissingScopes(JSContext *cx, AbstractFramePtr from, AbstractFramePtr to)
|
||||
DebugScopes::forwardLiveFrame(JSContext *cx, AbstractFramePtr from, AbstractFramePtr to)
|
||||
{
|
||||
DebugScopes *scopes = cx->compartment()->debugScopes;
|
||||
if (!scopes)
|
||||
|
@ -2364,6 +2406,12 @@ DebugScopes::rekeyMissingScopes(JSContext *cx, AbstractFramePtr from, AbstractFr
|
|||
e.rekeyFront(key);
|
||||
}
|
||||
}
|
||||
|
||||
for (LiveScopeMap::Enum e(scopes->liveScopes); !e.empty(); e.popFront()) {
|
||||
ScopeIterVal &val = e.front().value();
|
||||
if (val.frame() == from)
|
||||
val.updateFrame(to);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
@ -812,6 +812,7 @@ class ScopeIterVal
|
|||
hasScopeObject_(si.hasScopeObject_) {}
|
||||
|
||||
AbstractFramePtr frame() const { return frame_; }
|
||||
void updateFrame(AbstractFramePtr frame) { frame_ = frame; }
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -942,7 +943,10 @@ class DebugScopes
|
|||
static bool updateLiveScopes(JSContext *cx);
|
||||
static ScopeIterVal *hasLiveScope(ScopeObject &scope);
|
||||
|
||||
static void rekeyMissingScopes(JSContext *cx, AbstractFramePtr from, AbstractFramePtr to);
|
||||
// When a frame bails out from Ion to Baseline, there might be missing
|
||||
// scopes keyed on, and live scopes containing, the old
|
||||
// RematerializedFrame. Forward those values to the new BaselineFrame.
|
||||
static void forwardLiveFrame(JSContext *cx, AbstractFramePtr from, AbstractFramePtr to);
|
||||
|
||||
// In debug-mode, these must be called whenever exiting a scope that might
|
||||
// have stack-allocated locals.
|
||||
|
|
|
@ -34,7 +34,7 @@ class SharedTypedArrayObject : public NativeObject
|
|||
static const size_t DATA_SLOT = TypedArrayLayout::DATA_SLOT;
|
||||
|
||||
public:
|
||||
typedef SharedTypedArrayObject AnyTypedArray;
|
||||
typedef SharedTypedArrayObject SomeTypedArray;
|
||||
typedef SharedArrayBufferObject BufferType;
|
||||
|
||||
template<typename T> struct OfType;
|
||||
|
|
|
@ -130,7 +130,7 @@ template<class SpecificArray>
|
|||
class ElementSpecific
|
||||
{
|
||||
typedef typename SpecificArray::ElementType T;
|
||||
typedef typename SpecificArray::AnyTypedArray AnyTypedArray;
|
||||
typedef typename SpecificArray::SomeTypedArray SomeTypedArray;
|
||||
|
||||
public:
|
||||
/*
|
||||
|
@ -139,24 +139,27 @@ class ElementSpecific
|
|||
* case the two memory ranges overlap.
|
||||
*/
|
||||
static bool
|
||||
setFromTypedArray(JSContext *cx,
|
||||
Handle<AnyTypedArray*> target, Handle<AnyTypedArray*> source,
|
||||
uint32_t offset)
|
||||
setFromAnyTypedArray(JSContext *cx,
|
||||
Handle<SomeTypedArray*> target, HandleObject source,
|
||||
uint32_t offset)
|
||||
{
|
||||
MOZ_ASSERT(SpecificArray::ArrayTypeID() == target->type(),
|
||||
"calling wrong setFromTypedArray specialization");
|
||||
"calling wrong setFromAnyTypedArray specialization");
|
||||
|
||||
MOZ_ASSERT(offset <= target->length());
|
||||
MOZ_ASSERT(source->length() <= target->length() - offset);
|
||||
MOZ_ASSERT(AnyTypedArrayLength(source) <= target->length() - offset);
|
||||
|
||||
if (AnyTypedArray::sameBuffer(target, source))
|
||||
return setFromOverlappingTypedArray(cx, target, source, offset);
|
||||
if (source->is<SomeTypedArray>()) {
|
||||
Rooted<SomeTypedArray*> src(cx, source.as<SomeTypedArray>());
|
||||
if (SomeTypedArray::sameBuffer(target, src))
|
||||
return setFromOverlappingTypedArray(cx, target, src, offset);
|
||||
}
|
||||
|
||||
T *dest = static_cast<T*>(target->viewData()) + offset;
|
||||
uint32_t count = source->length();
|
||||
uint32_t count = AnyTypedArrayLength(source);
|
||||
|
||||
if (source->type() == target->type()) {
|
||||
mozilla::PodCopy(dest, static_cast<T*>(source->viewData()), count);
|
||||
if (AnyTypedArrayType(source) == target->type()) {
|
||||
mozilla::PodCopy(dest, static_cast<T*>(AnyTypedArrayViewData(source)), count);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -166,8 +169,8 @@ class ElementSpecific
|
|||
# define JS_VOLATILE_ARM /* nothing */
|
||||
#endif
|
||||
|
||||
void *data = source->viewData();
|
||||
switch (source->type()) {
|
||||
void *data = AnyTypedArrayViewData(source);
|
||||
switch (AnyTypedArrayType(source)) {
|
||||
case Scalar::Int8: {
|
||||
JS_VOLATILE_ARM
|
||||
int8_t *src = static_cast<int8_t*>(data);
|
||||
|
@ -227,7 +230,7 @@ class ElementSpecific
|
|||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("setFromTypedArray with a typed array with bogus type");
|
||||
MOZ_CRASH("setFromAnyTypedArray with a typed array with bogus type");
|
||||
}
|
||||
|
||||
#undef JS_VOLATILE_ARM
|
||||
|
@ -241,13 +244,13 @@ class ElementSpecific
|
|||
* typed array.
|
||||
*/
|
||||
static bool
|
||||
setFromNonTypedArray(JSContext *cx, Handle<AnyTypedArray*> target, HandleObject source,
|
||||
setFromNonTypedArray(JSContext *cx, Handle<SomeTypedArray*> target, HandleObject source,
|
||||
uint32_t len, uint32_t offset = 0)
|
||||
{
|
||||
MOZ_ASSERT(target->type() == SpecificArray::ArrayTypeID(),
|
||||
"target type and NativeType must match");
|
||||
MOZ_ASSERT(!source->is<AnyTypedArray>(),
|
||||
"use setFromTypedArray instead of this method");
|
||||
MOZ_ASSERT(!IsAnyTypedArray(source),
|
||||
"use setFromAnyTypedArray instead of this method");
|
||||
|
||||
uint32_t i = 0;
|
||||
if (source->isNative()) {
|
||||
|
@ -295,13 +298,13 @@ class ElementSpecific
|
|||
private:
|
||||
static bool
|
||||
setFromOverlappingTypedArray(JSContext *cx,
|
||||
Handle<AnyTypedArray*> target,
|
||||
Handle<AnyTypedArray*> source,
|
||||
Handle<SomeTypedArray*> target,
|
||||
Handle<SomeTypedArray*> source,
|
||||
uint32_t offset)
|
||||
{
|
||||
MOZ_ASSERT(SpecificArray::ArrayTypeID() == target->type(),
|
||||
"calling wrong setFromTypedArray specialization");
|
||||
MOZ_ASSERT(AnyTypedArray::sameBuffer(target, source),
|
||||
MOZ_ASSERT(SomeTypedArray::sameBuffer(target, source),
|
||||
"provided arrays don't actually overlap, so it's "
|
||||
"undesirable to use this method");
|
||||
|
||||
|
@ -446,34 +449,34 @@ class ElementSpecific
|
|||
}
|
||||
};
|
||||
|
||||
template<typename AnyTypedArray>
|
||||
template<typename SomeTypedArray>
|
||||
class TypedArrayMethods
|
||||
{
|
||||
static_assert(mozilla::IsSame<AnyTypedArray, TypedArrayObject>::value ||
|
||||
mozilla::IsSame<AnyTypedArray, SharedTypedArrayObject>::value,
|
||||
static_assert(mozilla::IsSame<SomeTypedArray, TypedArrayObject>::value ||
|
||||
mozilla::IsSame<SomeTypedArray, SharedTypedArrayObject>::value,
|
||||
"methods must be shared/unshared-specific, not "
|
||||
"element-type-specific");
|
||||
|
||||
typedef typename AnyTypedArray::BufferType BufferType;
|
||||
typedef typename SomeTypedArray::BufferType BufferType;
|
||||
|
||||
typedef typename AnyTypedArray::template OfType<int8_t>::Type Int8ArrayType;
|
||||
typedef typename AnyTypedArray::template OfType<uint8_t>::Type Uint8ArrayType;
|
||||
typedef typename AnyTypedArray::template OfType<int16_t>::Type Int16ArrayType;
|
||||
typedef typename AnyTypedArray::template OfType<uint16_t>::Type Uint16ArrayType;
|
||||
typedef typename AnyTypedArray::template OfType<int32_t>::Type Int32ArrayType;
|
||||
typedef typename AnyTypedArray::template OfType<uint32_t>::Type Uint32ArrayType;
|
||||
typedef typename AnyTypedArray::template OfType<float>::Type Float32ArrayType;
|
||||
typedef typename AnyTypedArray::template OfType<double>::Type Float64ArrayType;
|
||||
typedef typename AnyTypedArray::template OfType<uint8_clamped>::Type Uint8ClampedArrayType;
|
||||
typedef typename SomeTypedArray::template OfType<int8_t>::Type Int8ArrayType;
|
||||
typedef typename SomeTypedArray::template OfType<uint8_t>::Type Uint8ArrayType;
|
||||
typedef typename SomeTypedArray::template OfType<int16_t>::Type Int16ArrayType;
|
||||
typedef typename SomeTypedArray::template OfType<uint16_t>::Type Uint16ArrayType;
|
||||
typedef typename SomeTypedArray::template OfType<int32_t>::Type Int32ArrayType;
|
||||
typedef typename SomeTypedArray::template OfType<uint32_t>::Type Uint32ArrayType;
|
||||
typedef typename SomeTypedArray::template OfType<float>::Type Float32ArrayType;
|
||||
typedef typename SomeTypedArray::template OfType<double>::Type Float64ArrayType;
|
||||
typedef typename SomeTypedArray::template OfType<uint8_clamped>::Type Uint8ClampedArrayType;
|
||||
|
||||
public:
|
||||
/* subarray(start[, end]) */
|
||||
static bool
|
||||
subarray(JSContext *cx, CallArgs args)
|
||||
{
|
||||
MOZ_ASSERT(AnyTypedArray::is(args.thisv()));
|
||||
MOZ_ASSERT(SomeTypedArray::is(args.thisv()));
|
||||
|
||||
Rooted<AnyTypedArray*> tarray(cx, &args.thisv().toObject().as<AnyTypedArray>());
|
||||
Rooted<SomeTypedArray*> tarray(cx, &args.thisv().toObject().as<SomeTypedArray>());
|
||||
|
||||
// These are the default values.
|
||||
uint32_t initialLength = tarray->length();
|
||||
|
@ -497,7 +500,7 @@ class TypedArrayMethods
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!AnyTypedArray::ensureHasBuffer(cx, tarray))
|
||||
if (!SomeTypedArray::ensureHasBuffer(cx, tarray))
|
||||
return false;
|
||||
|
||||
Rooted<BufferType*> bufobj(cx, tarray->buffer());
|
||||
|
@ -558,10 +561,10 @@ class TypedArrayMethods
|
|||
static bool
|
||||
copyWithin(JSContext *cx, CallArgs args)
|
||||
{
|
||||
MOZ_ASSERT(AnyTypedArray::is(args.thisv()));
|
||||
MOZ_ASSERT(SomeTypedArray::is(args.thisv()));
|
||||
|
||||
// Steps 1-2.
|
||||
Rooted<AnyTypedArray*> obj(cx, &args.thisv().toObject().as<AnyTypedArray>());
|
||||
Rooted<SomeTypedArray*> obj(cx, &args.thisv().toObject().as<SomeTypedArray>());
|
||||
|
||||
// Steps 3-4.
|
||||
uint32_t len = obj->length();
|
||||
|
@ -645,9 +648,9 @@ class TypedArrayMethods
|
|||
static bool
|
||||
set(JSContext *cx, CallArgs args)
|
||||
{
|
||||
MOZ_ASSERT(AnyTypedArray::is(args.thisv()));
|
||||
MOZ_ASSERT(SomeTypedArray::is(args.thisv()));
|
||||
|
||||
Rooted<AnyTypedArray*> target(cx, &args.thisv().toObject().as<AnyTypedArray>());
|
||||
Rooted<SomeTypedArray*> target(cx, &args.thisv().toObject().as<SomeTypedArray>());
|
||||
|
||||
// The first argument must be either a typed array or arraylike.
|
||||
if (args.length() == 0 || !args[0].isObject()) {
|
||||
|
@ -669,14 +672,13 @@ class TypedArrayMethods
|
|||
}
|
||||
|
||||
RootedObject arg0(cx, &args[0].toObject());
|
||||
if (arg0->is<AnyTypedArray>()) {
|
||||
Rooted<AnyTypedArray*> source(cx, &arg0->as<AnyTypedArray>());
|
||||
if (source->length() > target->length() - offset) {
|
||||
if (IsAnyTypedArray(arg0)) {
|
||||
if (AnyTypedArrayLength(arg0) > target->length() - offset) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!setFromTypedArray(cx, target, source, offset))
|
||||
if (!setFromAnyTypedArray(cx, target, arg0, offset))
|
||||
return false;
|
||||
} else {
|
||||
uint32_t len;
|
||||
|
@ -697,44 +699,44 @@ class TypedArrayMethods
|
|||
}
|
||||
|
||||
static bool
|
||||
setFromArrayLike(JSContext *cx, Handle<AnyTypedArray*> target, HandleObject source, uint32_t len,
|
||||
setFromArrayLike(JSContext *cx, Handle<SomeTypedArray*> target, HandleObject source, uint32_t len,
|
||||
uint32_t offset = 0)
|
||||
{
|
||||
MOZ_ASSERT(offset <= target->length());
|
||||
MOZ_ASSERT(len <= target->length() - offset);
|
||||
|
||||
if (source->is<AnyTypedArray>()) {
|
||||
Rooted<AnyTypedArray*> src(cx, &source->as<AnyTypedArray>());
|
||||
return setFromTypedArray(cx, target, src, offset);
|
||||
}
|
||||
if (IsAnyTypedArray(source))
|
||||
return setFromAnyTypedArray(cx, target, source, offset);
|
||||
|
||||
return setFromNonTypedArray(cx, target, source, len, offset);
|
||||
}
|
||||
|
||||
private:
|
||||
static bool
|
||||
setFromTypedArray(JSContext *cx, Handle<AnyTypedArray*> target, Handle<AnyTypedArray*> source,
|
||||
uint32_t offset)
|
||||
setFromAnyTypedArray(JSContext *cx, Handle<SomeTypedArray*> target, HandleObject source,
|
||||
uint32_t offset)
|
||||
{
|
||||
MOZ_ASSERT(IsAnyTypedArray(source), "use setFromNonTypedArray");
|
||||
|
||||
switch (target->type()) {
|
||||
case Scalar::Int8:
|
||||
return ElementSpecific<Int8ArrayType>::setFromTypedArray(cx, target, source, offset);
|
||||
return ElementSpecific<Int8ArrayType>::setFromAnyTypedArray(cx, target, source, offset);
|
||||
case Scalar::Uint8:
|
||||
return ElementSpecific<Uint8ArrayType>::setFromTypedArray(cx, target, source, offset);
|
||||
return ElementSpecific<Uint8ArrayType>::setFromAnyTypedArray(cx, target, source, offset);
|
||||
case Scalar::Int16:
|
||||
return ElementSpecific<Int16ArrayType>::setFromTypedArray(cx, target, source, offset);
|
||||
return ElementSpecific<Int16ArrayType>::setFromAnyTypedArray(cx, target, source, offset);
|
||||
case Scalar::Uint16:
|
||||
return ElementSpecific<Uint16ArrayType>::setFromTypedArray(cx, target, source, offset);
|
||||
return ElementSpecific<Uint16ArrayType>::setFromAnyTypedArray(cx, target, source, offset);
|
||||
case Scalar::Int32:
|
||||
return ElementSpecific<Int32ArrayType>::setFromTypedArray(cx, target, source, offset);
|
||||
return ElementSpecific<Int32ArrayType>::setFromAnyTypedArray(cx, target, source, offset);
|
||||
case Scalar::Uint32:
|
||||
return ElementSpecific<Uint32ArrayType>::setFromTypedArray(cx, target, source, offset);
|
||||
return ElementSpecific<Uint32ArrayType>::setFromAnyTypedArray(cx, target, source, offset);
|
||||
case Scalar::Float32:
|
||||
return ElementSpecific<Float32ArrayType>::setFromTypedArray(cx, target, source, offset);
|
||||
return ElementSpecific<Float32ArrayType>::setFromAnyTypedArray(cx, target, source, offset);
|
||||
case Scalar::Float64:
|
||||
return ElementSpecific<Float64ArrayType>::setFromTypedArray(cx, target, source, offset);
|
||||
return ElementSpecific<Float64ArrayType>::setFromAnyTypedArray(cx, target, source, offset);
|
||||
case Scalar::Uint8Clamped:
|
||||
return ElementSpecific<Uint8ClampedArrayType>::setFromTypedArray(cx, target, source, offset);
|
||||
return ElementSpecific<Uint8ClampedArrayType>::setFromAnyTypedArray(cx, target, source, offset);
|
||||
case Scalar::Float32x4:
|
||||
case Scalar::Int32x4:
|
||||
case Scalar::MaxTypedArrayViewType:
|
||||
|
@ -745,10 +747,10 @@ class TypedArrayMethods
|
|||
}
|
||||
|
||||
static bool
|
||||
setFromNonTypedArray(JSContext *cx, Handle<AnyTypedArray*> target, HandleObject source,
|
||||
setFromNonTypedArray(JSContext *cx, Handle<SomeTypedArray*> target, HandleObject source,
|
||||
uint32_t len, uint32_t offset)
|
||||
{
|
||||
MOZ_ASSERT(!source->is<AnyTypedArray>(), "use setFromTypedArray");
|
||||
MOZ_ASSERT(!IsAnyTypedArray(source), "use setFromAnyTypedArray");
|
||||
|
||||
switch (target->type()) {
|
||||
case Scalar::Int8:
|
||||
|
|
|
@ -78,7 +78,7 @@ class TypedArrayLayout
|
|||
class TypedArrayObject : public NativeObject
|
||||
{
|
||||
public:
|
||||
typedef TypedArrayObject AnyTypedArray;
|
||||
typedef TypedArrayObject SomeTypedArray;
|
||||
typedef ArrayBufferObject BufferType;
|
||||
|
||||
template<typename T> struct OfType;
|
||||
|
|
|
@ -2904,6 +2904,13 @@ ElementRestyler::ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
|
|||
return eRestyleResult_Continue;
|
||||
}
|
||||
|
||||
if (oldContext->IsDirectlyInsideRuby() !=
|
||||
aNewContext->IsDirectlyInsideRuby()) {
|
||||
LOG_RESTYLE_CONTINUE("NS_STYLE_IS_DIRECTLY_INSIDE_RUBY differes between old"
|
||||
" and new style contexts");
|
||||
return eRestyleResult_Continue;
|
||||
}
|
||||
|
||||
return eRestyleResult_Stop;
|
||||
}
|
||||
|
||||
|
|
|
@ -5538,6 +5538,11 @@ struct SnappedImageDrawingParameters {
|
|||
// The region in tiled image space which will be drawn, with an associated
|
||||
// region to which sampling should be restricted.
|
||||
ImageRegion region;
|
||||
// The default viewport size for SVG images, which we use unless a different
|
||||
// one has been explicitly specified. This is the same as |size| except that
|
||||
// it does not take into account any transformation on the gfxContext we're
|
||||
// drawing to - for example, CSS transforms are not taken into account.
|
||||
nsIntSize svgViewportSize;
|
||||
// Whether there's anything to draw at all.
|
||||
bool shouldDraw;
|
||||
|
||||
|
@ -5548,10 +5553,12 @@ struct SnappedImageDrawingParameters {
|
|||
|
||||
SnappedImageDrawingParameters(const gfxMatrix& aImageSpaceToDeviceSpace,
|
||||
const nsIntSize& aSize,
|
||||
const ImageRegion& aRegion)
|
||||
const ImageRegion& aRegion,
|
||||
const nsIntSize& aSVGViewportSize)
|
||||
: imageSpaceToDeviceSpace(aImageSpaceToDeviceSpace)
|
||||
, size(aSize)
|
||||
, region(aRegion)
|
||||
, svgViewportSize(aSVGViewportSize)
|
||||
, shouldDraw(true)
|
||||
{}
|
||||
};
|
||||
|
@ -5666,6 +5673,11 @@ ComputeSnappedImageDrawingParameters(gfxContext* aCtx,
|
|||
aGraphicsFilter, aImageFlags);
|
||||
gfxSize imageSize(intImageSize.width, intImageSize.height);
|
||||
|
||||
nsIntSize svgViewportSize = currentMatrix.IsIdentity()
|
||||
? intImageSize
|
||||
: nsIntSize(NSAppUnitsToIntPixels(dest.width, aAppUnitsPerDevPixel),
|
||||
NSAppUnitsToIntPixels(dest.height, aAppUnitsPerDevPixel));
|
||||
|
||||
// Compute the set of pixels that would be sampled by an ideal rendering
|
||||
gfxPoint subimageTopLeft =
|
||||
MapToFloatImagePixels(imageSize, devPixelDest, devPixelFill.TopLeft());
|
||||
|
@ -5743,7 +5755,9 @@ ComputeSnappedImageDrawingParameters(gfxContext* aCtx,
|
|||
|
||||
ImageRegion region =
|
||||
ImageRegion::CreateWithSamplingRestriction(imageSpaceFill, subimage);
|
||||
return SnappedImageDrawingParameters(transform, intImageSize, region);
|
||||
|
||||
return SnappedImageDrawingParameters(transform, intImageSize,
|
||||
region, svgViewportSize);
|
||||
}
|
||||
|
||||
|
||||
|
@ -5781,8 +5795,14 @@ DrawImageInternal(gfxContext& aContext,
|
|||
gfxContextMatrixAutoSaveRestore contextMatrixRestorer(&aContext);
|
||||
aContext.SetMatrix(params.imageSpaceToDeviceSpace);
|
||||
|
||||
Maybe<SVGImageContext> svgContext = ToMaybe(aSVGContext);
|
||||
if (!svgContext) {
|
||||
// Use the default viewport.
|
||||
svgContext = Some(SVGImageContext(params.svgViewportSize, Nothing()));
|
||||
}
|
||||
|
||||
aImage->Draw(&aContext, params.size, params.region, imgIContainer::FRAME_CURRENT,
|
||||
aGraphicsFilter, ToMaybe(aSVGContext), aImageFlags);
|
||||
aGraphicsFilter, svgContext, aImageFlags);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1087872 - Test for dynamic insertion of ruby frames</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>One space should exist between 'a' and 'b':</p>
|
||||
|
||||
<p>a<rbc><rb></rb> <rb></rb></rbc>b</p>
|
||||
<p>a<ruby><rb></rb> <rb></rb></ruby>b</p>
|
||||
<p>a<ruby><rbc></rbc> <rbc></rbc></ruby>b</p>
|
||||
<p>a<rtc><rt></rt> <rt></rt></rtc>b</p>
|
||||
<p>a<ruby><rt></rt> <rt></rt></ruby>b</p>
|
||||
|
||||
<p>a<rbc><rb></rb> <rb></rb></rbc>b</p>
|
||||
<p>a<ruby><rb></rb> <rb></rb></ruby>b</p>
|
||||
<p>a<ruby><rbc></rbc> <rbc></rbc></ruby>b</p>
|
||||
<p>a<rtc><rt></rt> <rt></rt></rtc>b</p>
|
||||
<p>a<ruby><rt></rt> <rt></rt></ruby>b</p>
|
||||
|
||||
<p>a<rb></rb><span></span> <rt></rt>b</p>
|
||||
<p>a<rb></rb> <span></span><rt></rt>b</p>
|
||||
<p>a<rb></rb> <rb></rb><rt></rt>b</p>
|
||||
<p>a<rt></rt><rb></rb> <rb></rb>b</p>
|
||||
<p>a<rbc></rbc> <rbc></rbc><rt></rt>b</p>
|
||||
<p>a<rb></rb><rt></rt> <rt></rt>b</p>
|
||||
<p>a<rt></rt> <rt></rt><rb></rb>b</p>
|
||||
|
||||
<p>a<rb></rb> <rb></rb>b</p>
|
||||
<p>a<rbc></rbc> <rbc></rbc>b</p>
|
||||
<p>a<rt></rt> <rt></rt>b</p>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,55 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1087872 - Test for dynamic insertion of ruby frames</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<script src="dynamic-insertion.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>One space should exist between 'a' and 'b':</p>
|
||||
|
||||
<!-- leading white space -->
|
||||
<!-- => inter-base white space -->
|
||||
<p>a<rbc data-insert="start" data-tag="rb"> <rb></rb></rbc>b</p>
|
||||
<p>a<ruby data-insert="start" data-tag="rb"> <rb></rb></ruby>b</p>
|
||||
<!-- => inter-segment white space -->
|
||||
<p>a<ruby data-insert="start" data-tag="rbc"> <rbc></rbc></ruby>b</p>
|
||||
<!-- => inter-annotation white space -->
|
||||
<p>a<rtc data-insert="start" data-tag="rt"> <rt></rt></rtc>b</p>
|
||||
<p>a<ruby data-insert="start" data-tag="rt"> <rt></rt></ruby>b</p>
|
||||
|
||||
<!-- trailing white space -->
|
||||
<!-- => inter-base white space -->
|
||||
<p>a<rbc data-insert="end" data-tag="rb"><rb></rb> </rbc>b</p>
|
||||
<p>a<ruby data-insert="end" data-tag="rb"><rb></rb> </ruby>b</p>
|
||||
<!-- => inter-segment white space -->
|
||||
<p>a<ruby data-insert="end" data-tag="rbc"><rbc></rbc> </ruby>b</p>
|
||||
<!-- => inter-annotation white space -->
|
||||
<p>a<rtc data-insert="end" data-tag="rt"><rt></rt> </rtc>b</p>
|
||||
<p>a<ruby data-insert="end" data-tag="rt"><rt></rt> </ruby>b</p>
|
||||
|
||||
<!-- inter-level white space -->
|
||||
<!-- => normal white space -->
|
||||
<p>a<rb data-insert="after" data-tag="span"></rb> <rt></rt>b</p>
|
||||
<p>a<rb></rb> <rt data-insert="before" data-tag="span"></rt>b</p>
|
||||
<!-- => inter-base white space -->
|
||||
<p>a<rb></rb> <rt data-insert="before" data-tag="rb"></rt>b</p>
|
||||
<p>a<rt data-insert="after" data-tag="rb"></rt> <rb></rb>b</p>
|
||||
<!-- => inter-segment white space -->
|
||||
<p>a<rbc></rbc> <rt data-insert="before" data-tag="rbc"></rt>b</p>
|
||||
<!-- => inter-annotation white space -->
|
||||
<p>a<rb data-insert="after" data-tag="rt"></rb> <rt></rt>b</p>
|
||||
<p>a<rt></rt> <rb data-insert="before" data-tag="rt"></rb>b</p>
|
||||
|
||||
<!-- insert white space -->
|
||||
<!-- inter-base white space -->
|
||||
<p>a<rb data-insert="after" data-text=" "></rb><rb></rb>b</p>
|
||||
<!-- inter-segment white space -->
|
||||
<p>a<rbc data-insert="after" data-text=" "></rbc><rbc></rbc>b</p>
|
||||
<!-- inter-annotation white space -->
|
||||
<p>a<rt data-insert="after" data-text=" "></rt><rt></rt>b</p>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1087872 - Test for dynamic insertion of ruby frames</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>No space should exist between 'a' and 'b':</p>
|
||||
|
||||
<p><span>a</span><rb></rb> <rt></rt>b</p>
|
||||
<p>a<rb></rb> <rt></rt><span>b</span></p>
|
||||
<p>a<rb></rb> <rt></rt><rb></rb>b</p>
|
||||
<p>a<rbc></rbc> <rt></rt><rb></rb>b</p>
|
||||
<p>a<rt></rt><rb></rb> <rt></rt>b</p>
|
||||
|
||||
<p>a<ruby> <rb></rb></ruby>b</p>
|
||||
<p>a<rbc> <rb></rb></rbc>b</p>
|
||||
<p>a<rtc> <rt></rt></rtc>b</p>
|
||||
<p>a<ruby><rb></rb> </ruby>b</p>
|
||||
<p>a<rbc><rb></rb> </rbc>b</p>
|
||||
<p>a<rtc><rt></rt> </rtc>b</p>
|
||||
<p>a<rb></rb> <rt></rt>b</p>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1087872 - Test for dynamic insertion of ruby frames</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<script src="dynamic-insertion.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>No space should exist between 'a' and 'b':</p>
|
||||
|
||||
<!-- inter-level white space -->
|
||||
<!-- <= normal white space -->
|
||||
<p><span data-insert="after" data-tag="rb">a</span> <rt></rt>b</p>
|
||||
<p>a<rb></rb> <span data-insert="before" data-tag="rt">b</span></p>
|
||||
<!-- <= inter-base white space -->
|
||||
<p>a<rb></rb> <rb data-insert="before" data-tag="rt"></rb>b</p>
|
||||
<!-- <= inter-segment white space -->
|
||||
<p>a<rbc></rbc> <rb data-insert="before" data-tag="rt"></rb>b</p>
|
||||
<!-- <= inter-annotation white space -->
|
||||
<p>a<rt data-insert="after" data-tag="rb"></rt> <rt></rt>b</p>
|
||||
|
||||
<!-- insert white space -->
|
||||
<!-- leading white space -->
|
||||
<p>a<ruby data-insert="start" data-text=" "><rb></rb></ruby>b</p>
|
||||
<p>a<rbc data-insert="start" data-text=" "><rb></rb></rbc>b</p>
|
||||
<p>a<rtc data-insert="start" data-text=" "><rt></rt></rtc>b</p>
|
||||
<!-- trailing white space -->
|
||||
<p>a<ruby data-insert="end" data-text=" "><rb></rb></ruby>b</p>
|
||||
<p>a<rbc data-insert="end" data-text=" "><rb></rb></rbc>b</p>
|
||||
<p>a<rtc data-insert="end" data-text=" "><rt></rt></rtc>b</p>
|
||||
<!-- inter-level white space -->
|
||||
<p>a<rb data-insert="after" data-text=" "></rb><rt></rt>b</p>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1087872 - Test for dynamic insertion of ruby frames</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>'a' and 'b' should be paired with 'x' and 'y' respectively:</p>
|
||||
|
||||
<p><rb></rb><span></span><rb>a</rb><rb>b</rb><rt>x</rt><rt>y</rt></p>
|
||||
<p><rb></rb><rt></rt><rb>a</rb><rb>b</rb><rt>x</rt><rt>y</rt></p>
|
||||
<p><rb>a</rb><rt>x</rt><rb>b</rb><rt>y</rt></p>
|
||||
<p><rbc><span>a</span><rb></rb>b</rbc><rt>x</rt><rt></rt><rt>y</rt></p>
|
||||
<p><rb>a</rb><rb></rb><rb>b</rb><rtc><span>x</span><rt></rt>y</rtc></p>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1087872 - Test for dynamic insertion of ruby frames</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<script src="dynamic-insertion.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>'a' and 'b' should be paired with 'x' and 'y' respectively:</p>
|
||||
|
||||
<!-- split -->
|
||||
<!-- pseudo ruby -->
|
||||
<p><rb data-insert="after" data-tag="span"></rb><rb>a</rb><rb>b</rb><rt>x</rt><rt>y</rt></p>
|
||||
<!-- pseudo ruby base container -->
|
||||
<p><rb data-insert="after" data-tag="rt"></rb><rb>a</rb><rb>b</rb><rt>x</rt><rt>y</rt></p>
|
||||
<!-- pseudo ruby text container -->
|
||||
<p><rb>a</rb><rt data-insert="after" data-tag="rb" data-text="b">x</rt><rt>y</rt></p>
|
||||
<!-- pseudo ruby base -->
|
||||
<p><rbc><span data-insert="after" data-tag="rb">a</span>b</rbc><rt>x</rt><rt></rt><rt>y</rt></p>
|
||||
<!-- pseudo ruby text -->
|
||||
<p><rb>a</rb><rb></rb><rb>b</rb><rtc><span data-insert="after" data-tag="rt">x</span>y</rtc></p>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,42 @@
|
|||
window.onload = function() {
|
||||
// Force a reflow before any changes.
|
||||
document.body.clientWidth;
|
||||
|
||||
var elems = document.querySelectorAll('[data-insert]');
|
||||
Array.from(elems).forEach(function(e) {
|
||||
var parent, ref;
|
||||
switch (e.dataset.insert) {
|
||||
case 'start':
|
||||
parent = e;
|
||||
ref = e.firstChild;
|
||||
break;
|
||||
|
||||
case 'end':
|
||||
parent = e;
|
||||
ref = null;
|
||||
break;
|
||||
|
||||
case 'before':
|
||||
parent = e.parentNode;
|
||||
ref = e;
|
||||
break;
|
||||
|
||||
case 'after':
|
||||
parent = e.parentNode;
|
||||
ref = e.nextSibling;
|
||||
break;
|
||||
}
|
||||
|
||||
var elem, textnode;
|
||||
if ('text' in e.dataset) {
|
||||
textnode = document.createTextNode(e.dataset.text);
|
||||
}
|
||||
if ('tag' in e.dataset) {
|
||||
elem = document.createElement(e.dataset.tag);
|
||||
if (textnode) {
|
||||
elem.appendChild(textnode);
|
||||
}
|
||||
}
|
||||
parent.insertBefore(elem ? elem : textnode, ref);
|
||||
});
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1087872 - Test for dynamic removal of ruby frames</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>No space should exist between 'a' and 'b':</p>
|
||||
|
||||
<p>a<ruby> <rb></rb></ruby>b</p>
|
||||
<p>a<ruby><rb></rb> </ruby>b</p>
|
||||
<p>a<ruby><rb></rb> <rt></rt></ruby>b</p>
|
||||
|
||||
<p>a<ruby> <rbc></rbc></ruby>b</p>
|
||||
<p>a<ruby><rbc></rbc> </ruby>b</p>
|
||||
<p>a<rbc></rbc> <rtc></rtc>b</p>
|
||||
|
||||
<p><rb>a</rb><rb>b</rb><rtc> <rt>x</rt></rtc></p>
|
||||
<p><rb>a</rb><rb>b</rb><rtc><rt>x</rt> </rtc></p>
|
||||
<p><rb>a</rb><rb>b</rb> <rt>x</rt></p>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1087872 - Test for dynamic removal of ruby frames</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<script src="dynamic-removal.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>No space should exist between 'a' and 'b':</p>
|
||||
|
||||
<!-- inter-base white space -->
|
||||
<!-- => leading white space -->
|
||||
<p>a<ruby><rb class="remove"></rb> <rb></rb></ruby>b</p>
|
||||
<!-- => trailing white space -->
|
||||
<p>a<ruby><rb></rb> <rb class="remove"></rb></ruby>b</p>
|
||||
<!-- => inter-level white space -->
|
||||
<p>a<ruby><rb></rb> <rb class="remove"></rb><rt></rt></ruby>b</p>
|
||||
|
||||
<!-- inter-segment white space -->
|
||||
<!-- => leading white space -->
|
||||
<p>a<ruby><rbc class="remove"></rbc> <rbc></rbc></ruby>b</p>
|
||||
<!-- => trailing white space -->
|
||||
<p>a<ruby><rbc></rbc> <rbc class="remove"></rbc></ruby>b</p>
|
||||
<!-- => inter-level white space -->
|
||||
<p>a<rbc></rbc> <rbc class="remove"></rbc><rtc></rtc>b</p>
|
||||
|
||||
<!-- inter-annotation white space -->
|
||||
<!-- => leading white space -->
|
||||
<p><rb>a</rb><rb>b</rb><rtc><rt class="remove"></rt> <rt>x</rt></rtc></p>
|
||||
<!-- => trailing white space -->
|
||||
<p><rb>a</rb><rb>b</rb><rtc><rt>x</rt> <rt class="remove"></rt></rtc></p>
|
||||
<!-- => inter-level white space -->
|
||||
<p><rb>a</rb><rb>b</rb><rt class="remove"></rt> <rt>x</rt></p>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1087872 - Test for dynamic removal of ruby frames</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>One space should exist between 'a' and 'b':</p>
|
||||
|
||||
<p>a <rt></rt>b</p>
|
||||
<p>a<rb></rb> b</p>
|
||||
<p>a<rb></rb> <rb></rb>b</p>
|
||||
<p>a<rbc></rbc> <rbc></rbc>b</p>
|
||||
<p><rb>a</rb> <rb>b</rb><rt>x</rt> <rt>y</rt></p>
|
||||
|
||||
</body>
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1087872 - Test for dynamic removal of ruby frames</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<script src="dynamic-removal.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>One space should exist between 'a' and 'b':</p>
|
||||
|
||||
<!-- inter-level white space -->
|
||||
<!-- => normal white space -->
|
||||
<p>a<rb class="remove"></rb> <rt></rt>b</p>
|
||||
<p>a<rb></rb> <rt class="remove"></rt>b</p>
|
||||
<!-- => inter-base white space -->
|
||||
<p>a<rb></rb> <rt class="remove"></rt><rb></rb>b</p>
|
||||
<!-- => inter-segment white space -->
|
||||
<p>a<rbc></rbc> <rtc class="remove"></rtc><rbc></rbc>b</p>
|
||||
<!-- => inter-annotation white space -->
|
||||
<p><rb>a</rb> <rb>b</rb><rt>x</rt><rb class="remove"></rb> <rt>y</rt></p>
|
||||
|
||||
</body>
|
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1087872 - Test for dynamic removal of ruby frames</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>'a' and 'b' should be paired with 'x' and 'y' respectively:</p>
|
||||
|
||||
|
||||
<p><rb>a</rb><rb>b</rb><rt>x</rt><rt>y</rt></p>
|
||||
<p><rb>a</rb><rb>b</rb><rt>x</rt><rt>y</rt></p>
|
||||
<p><rb>a</rb><rb>b</rb><rt>x</rt><rt>y</rt></p>
|
||||
|
||||
<p><rb>a</rb><rb>b</rb><rt>x</rt><rt>y</rt></p>
|
||||
<p><rb>a</rb><rb>b</rb><rt>x</rt><rt>y</rt></p>
|
||||
|
||||
<p>'ab' should be paried with 'xy':</p>
|
||||
|
||||
<p><rbc>ab</rbc><rt>xy</rt></p>
|
||||
<p><rb>ab</rb><rtc>xy</rtc></p>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,36 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1087872 - Test for dynamic removal of ruby frames</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<script src="dynamic-removal.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>'a' and 'b' should be paired with 'x' and 'y' respectively:</p>
|
||||
|
||||
<!-- merge -->
|
||||
<!-- pseudo ruby -->
|
||||
<p><rb>a</rb><span class="remove"></span><rb>b</rb><rt>x</rt><rt>y</rt></p>
|
||||
<!-- pseudo ruby base container -->
|
||||
<p><rb>a</rb><rt class="remove"></rt><rb>b</rb><rt>x</rt><rt>y</rt></p>
|
||||
<!-- pseudo ruby text container -->
|
||||
<p><rb>a</rb><rb>b</rb><rt>x</rt><rb class="remove"></rb><rt>y</rt></p>
|
||||
|
||||
<!-- white space removal -->
|
||||
<!-- inter-base white space -->
|
||||
<p><rb class="remove-after">a</rb> <rb>b</rb><rt>x</rt><rt>y</rt></p>
|
||||
<!-- inter-annotation white space -->
|
||||
<p><rb>a</rb><rb>b</rb><rt class="remove-after">x</rt> <rt>y</rt></p>
|
||||
|
||||
<p>'ab' should be paried with 'xy':</p>
|
||||
|
||||
<!-- merge -->
|
||||
<!-- pseudo ruby base -->
|
||||
<p><rbc>a<rb class="remove"></rb>b</rbc><rt>xy</rt></p>
|
||||
<!-- pseudo ruby text -->
|
||||
<p><rb>ab</rb><rtc>x<rt class="remove"></rt>y</rtc></p>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,14 @@
|
|||
function getElements(className) {
|
||||
return Array.from(document.getElementsByClassName(className));
|
||||
}
|
||||
window.onload = function() {
|
||||
// Force a reflow before any changes.
|
||||
document.body.clientWidth;
|
||||
|
||||
getElements('remove').forEach(function(e) {
|
||||
e.parentNode.removeChild(e);
|
||||
});
|
||||
getElements('remove-after').forEach(function(e) {
|
||||
e.parentNode.removeChild(e.nextSibling);
|
||||
});
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1098257 - Inlinize block-level boxes inside ruby</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<style>
|
||||
.inline {
|
||||
display: inline-block;
|
||||
background-color: yellow;
|
||||
width: 30px; height: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div><ruby>a<div class="inline">b</div>c</ruby></div>
|
||||
<div><rb>a<div class="inline">b</div>c</rb></div>
|
||||
<div><rt>a<div class="inline">b</div>c</rt></div>
|
||||
<div><rbc>a<div class="inline">b</div>c</rbc></div>
|
||||
<div><rtc>a<div class="inline">b</div>c</rtc></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1098257 - Inlinize block-level boxes inside ruby</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<style>
|
||||
.inline {
|
||||
display: block;
|
||||
background-color: yellow;
|
||||
width: 30px; height: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div><ruby>a<div class="inline">b</div>c</ruby></div>
|
||||
<div><rb>a<div class="inline">b</div>c</rb></div>
|
||||
<div><rt>a<div class="inline">b</div>c</rt></div>
|
||||
<div><rbc>a<div class="inline">b</div>c</rbc></div>
|
||||
<div><rtc>a<div class="inline">b</div>c</rtc></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1098257 - Inlinize block-level boxes inside ruby</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<style>
|
||||
.block, table, .flex {
|
||||
background-color: yellow;
|
||||
width: 100px; height: 30px;
|
||||
border: 1px solid blue;
|
||||
}
|
||||
.block { display: inline-block; }
|
||||
table { display: inline-table; border-collapse: collapse; }
|
||||
td { border: 3px solid red; }
|
||||
.flex { display: inline-flex; }
|
||||
.flex-item { flex: auto; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div><rb>a<div class="block">b</div>c</rb><rt>x<div class="block">y</div>z</rt></div>
|
||||
<div>
|
||||
<rb>a<table><tr><td>b1</td><td>b2</td></tr></table>c</rb>
|
||||
<rt>x<table><tr><td>y1</td><td>y2</td></tr></table>z</rt>
|
||||
</div>
|
||||
<div>
|
||||
<rb>a<div class="flex">
|
||||
<div class="flex-item">b1</div>
|
||||
<div class="flex-item">b2</div>
|
||||
</div>c</rb>
|
||||
<rt>x<div class="flex">
|
||||
<div class="flex-item">y1</div>
|
||||
<div class="flex-item">y2</div>
|
||||
</div>z</rt>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1098257 - Inlinize block-level boxes inside ruby</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<style>
|
||||
.block, table, .flex {
|
||||
background-color: yellow;
|
||||
width: 100px; height: 30px;
|
||||
border: 1px solid blue;
|
||||
}
|
||||
.block { display: block; }
|
||||
table { border-collapse: collapse; }
|
||||
td { border: 3px solid red; }
|
||||
.flex { display: flex; }
|
||||
.flex-item { flex: auto; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div><rb>a<div class="block">b</div>c</rb><rt>x<div class="block">y</div>z</rt></div>
|
||||
<div>
|
||||
<rb>a<table><tr><td>b1</td><td>b2</td></tr></table>c</rb>
|
||||
<rt>x<table><tr><td>y1</td><td>y2</td></tr></table>z</rt>
|
||||
</div>
|
||||
<div>
|
||||
<rb>a<div class="flex">
|
||||
<div class="flex-item">b1</div>
|
||||
<div class="flex-item">b2</div>
|
||||
</div>c</rb>
|
||||
<rt>x<div class="flex">
|
||||
<div class="flex-item">y1</div>
|
||||
<div class="flex-item">y2</div>
|
||||
</div>z</rt>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1098257 - Inlinize block-level boxes inside ruby</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<style>
|
||||
div { border-collapse: collapse; }
|
||||
.table { display: inline-table; }
|
||||
.cell {
|
||||
display: table-cell;
|
||||
background-color: yellow;
|
||||
border: 3px solid blue;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div><ruby>a<div class="table"><div class="cell">b1</div><div class="cell">b2</div></div>c</ruby></div>
|
||||
<div><rb>a<div class="table"><div class="cell">b1</div><div class="cell">b2</div></div>c</rb></div>
|
||||
<div><rt>a<div class="table"><div class="cell">b1</div><div class="cell">b2</div></div>c</rt></div>
|
||||
<div><rbc>a<div class="table"><div class="cell">b1</div><div class="cell">b2</div></div>c</rbc></div>
|
||||
<div><rtc>a<div class="table"><div class="cell">b1</div><div class="cell">b2</div></div>c</rtc></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1098257 - Inlinize block-level boxes inside ruby</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<style>
|
||||
body { border-collapse: collapse; }
|
||||
.cell {
|
||||
display: table-cell;
|
||||
background-color: yellow;
|
||||
border: 3px solid blue;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div><ruby>a<div class="cell">b1</div><div class="cell">b2</div>c</ruby></div>
|
||||
<div><rb>a<div class="cell">b1</div><div class="cell">b2</div>c</rb></div>
|
||||
<div><rt>a<div class="cell">b1</div><div class="cell">b2</div>c</rt></div>
|
||||
<div><rbc>a<div class="cell">b1</div><div class="cell">b2</div>c</rbc></div>
|
||||
<div><rtc>a<div class="cell">b1</div><div class="cell">b2</div>c</rtc></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1098257 - Inlinize block-level boxes inside ruby</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<style>
|
||||
.inline {
|
||||
display: inline-block;
|
||||
background-color: yellow;
|
||||
width: 30px; height: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div><ruby>a<span><div class="inline">b</div></span>c</ruby></div>
|
||||
<div><rb>a<span><div class="inline">b</div></span>c</rb></div>
|
||||
<div><rt>a<span><div class="inline">b</div></span>c</rt></div>
|
||||
<div><rbc>a<span><div class="inline">b</div></span>c</rbc></div>
|
||||
<div><rtc>a<span><div class="inline">b</div></span>c</rtc></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1098257 - Inlinize block-level boxes inside ruby</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<style>
|
||||
.inline {
|
||||
display: block;
|
||||
background-color: yellow;
|
||||
width: 30px; height: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div><ruby>a<span><div class="inline">b</div></span>c</ruby></div>
|
||||
<div><rb>a<span><div class="inline">b</div></span>c</rb></div>
|
||||
<div><rt>a<span><div class="inline">b</div></span>c</rt></div>
|
||||
<div><rbc>a<span><div class="inline">b</div></span>c</rbc></div>
|
||||
<div><rtc>a<span><div class="inline">b</div></span>c</rtc></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1098257 - Inlinize block-level boxes inside ruby</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<style>
|
||||
ruby::before, rb::before, rt::before, rbc::before, rtc::before {
|
||||
content: "a";
|
||||
display: inline-block;
|
||||
background-color: yellow;
|
||||
width: 30px; height: 30px;
|
||||
}
|
||||
ruby::after, rb::after, rt::after, rbc::after, rtc::after {
|
||||
content: "c";
|
||||
display: inline-block;
|
||||
background-color: yellow;
|
||||
width: 30px; height: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div><ruby>b</ruby></div>
|
||||
<div><rb>b</rb></div>
|
||||
<div><rt>b</rt></div>
|
||||
<div><rbc>b</rbc></div>
|
||||
<div><rtc>b</rtc></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1098257 - Inlinize block-level boxes inside ruby</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<style>
|
||||
ruby::before, rb::before, rt::before, rbc::before, rtc::before {
|
||||
content: "a";
|
||||
display: block;
|
||||
background-color: yellow;
|
||||
width: 30px; height: 30px;
|
||||
}
|
||||
ruby::after, rb::after, rt::after, rbc::after, rtc::after {
|
||||
content: "c";
|
||||
display: block;
|
||||
background-color: yellow;
|
||||
width: 30px; height: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div><ruby>b</ruby></div>
|
||||
<div><rb>b</rb></div>
|
||||
<div><rt>b</rt></div>
|
||||
<div><rbc>b</rbc></div>
|
||||
<div><rtc>b</rtc></div>
|
||||
</body>
|
||||
</html>
|
|
@ -5,6 +5,17 @@ default-preferences pref(layout.css.ruby.enabled,true)
|
|||
== box-generation-3.html box-generation-3-ref.html
|
||||
== box-generation-4.html box-generation-4-ref.html
|
||||
== box-generation-5.html box-generation-5-ref.html
|
||||
== dynamic-insertion-1.html dynamic-insertion-1-ref.html
|
||||
== dynamic-insertion-2.html dynamic-insertion-2-ref.html
|
||||
== dynamic-insertion-3.html dynamic-insertion-3-ref.html
|
||||
== dynamic-removal-1.html dynamic-removal-1-ref.html
|
||||
== dynamic-removal-2.html dynamic-removal-2-ref.html
|
||||
fuzzy-if(winWidget,28,1) == dynamic-removal-3.html dynamic-removal-3-ref.html # bug 1111891
|
||||
== inlinize-blocks-1.html inlinize-blocks-1-ref.html
|
||||
== inlinize-blocks-2.html inlinize-blocks-2-ref.html
|
||||
== inlinize-blocks-3.html inlinize-blocks-3-ref.html
|
||||
== inlinize-blocks-4.html inlinize-blocks-4-ref.html
|
||||
== inlinize-blocks-5.html inlinize-blocks-5-ref.html
|
||||
== ruby-whitespace-1.html ruby-whitespace-1-ref.html
|
||||
== ruby-whitespace-2.html ruby-whitespace-2-ref.html
|
||||
!= ruby-reflow-1-opaqueruby.html ruby-reflow-1-noruby.html
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче