Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2015-02-02 13:27:44 +01:00
Родитель aacc3dba1c 2f3b89cbe9
Коммит d21b001eef
181 изменённых файлов: 2752 добавлений и 853 удалений

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

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 1109248 - This needed a CLOBBER on Windows and OSX.
Bug 1120369 - Needed a CLOBBER on at least Linux and OSX.

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

@ -149,7 +149,7 @@ nsCoreUtils::DispatchTouchEvent(uint32_t aEventType, int32_t aX, int32_t aY,
event.time = PR_IntervalNow();
// XXX: Touch has an identifier of -1 to hint that it is synthesized.
nsRefPtr<dom::Touch> t = new dom::Touch(-1, nsIntPoint(aX, aY),
nsRefPtr<dom::Touch> t = new dom::Touch(-1, LayoutDeviceIntPoint(aX, aY),
nsIntPoint(1, 1), 0.0f, 1.0f);
t->SetTarget(aContent);
event.touches.AppendElement(t);

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

@ -78,6 +78,11 @@ def GeckoBinary(linkage='dependent', msvcrt='dynamic', mozglue=None):
else:
error('`mozglue` must be "program" or "library"')
if not CONFIG['JS_STANDALONE']:
USE_LIBS += [
'fallible',
]
@template
def GeckoProgram(name, linkage='standalone', **kwargs):

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

@ -13680,7 +13680,7 @@ nsDocShell::GetAsyncPanZoomEnabled(bool* aOut)
*aOut = tabChild->IsAsyncPanZoomEnabled();
return NS_OK;
}
*aOut = false;
*aOut = Preferences::GetBool("layers.async-pan-zoom.enabled", false);
return NS_OK;
}

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

@ -109,7 +109,7 @@ DOMParser::ParseFromString(const nsAString& str,
nsAutoCString utf8str;
// Convert from UTF16 to UTF8 using fallible allocations
if (!AppendUTF16toUTF8(str, utf8str, mozilla::fallible_t())) {
if (!AppendUTF16toUTF8(str, utf8str, mozilla::fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}

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

@ -2202,7 +2202,7 @@ public:
bool ToString(nsAString& aOut)
{
if (!aOut.SetCapacity(mLength, fallible_t())) {
if (!aOut.SetCapacity(mLength, fallible)) {
return false;
}

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

@ -190,7 +190,7 @@ URLSearchParams::ConvertString(const nsACString& aInput, nsAString& aOutput)
return;
}
if (!aOutput.SetLength(outputLength, fallible_t())) {
if (!aOutput.SetLength(outputLength, fallible)) {
return;
}

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

@ -732,7 +732,7 @@ nsContentUtils::Atob(const nsAString& aAsciiBase64String,
const char16_t* start = aAsciiBase64String.BeginReading();
const char16_t* end = aAsciiBase64String.EndReading();
nsString trimmedString;
if (!trimmedString.SetCapacity(aAsciiBase64String.Length(), fallible_t())) {
if (!trimmedString.SetCapacity(aAsciiBase64String.Length(), fallible)) {
return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
}
while (start < end) {
@ -4425,20 +4425,20 @@ nsContentUtils::SetNodeTextContent(nsIContent* aContent,
static bool
AppendNodeTextContentsRecurse(nsINode* aNode, nsAString& aResult,
const mozilla::fallible_t&)
const fallible_t& aFallible)
{
for (nsIContent* child = aNode->GetFirstChild();
child;
child = child->GetNextSibling()) {
if (child->IsElement()) {
bool ok = AppendNodeTextContentsRecurse(child, aResult,
mozilla::fallible_t());
aFallible);
if (!ok) {
return false;
}
}
else if (child->IsNodeOfType(nsINode::eTEXT)) {
bool ok = child->AppendTextTo(aResult, mozilla::fallible_t());
bool ok = child->AppendTextTo(aResult, aFallible);
if (!ok) {
return false;
}
@ -4452,21 +4452,21 @@ AppendNodeTextContentsRecurse(nsINode* aNode, nsAString& aResult,
bool
nsContentUtils::AppendNodeTextContent(nsINode* aNode, bool aDeep,
nsAString& aResult,
const mozilla::fallible_t&)
const fallible_t& aFallible)
{
if (aNode->IsNodeOfType(nsINode::eTEXT)) {
return static_cast<nsIContent*>(aNode)->AppendTextTo(aResult,
mozilla::fallible_t());
aFallible);
}
else if (aDeep) {
return AppendNodeTextContentsRecurse(aNode, aResult, mozilla::fallible_t());
return AppendNodeTextContentsRecurse(aNode, aResult, aFallible);
}
else {
for (nsIContent* child = aNode->GetFirstChild();
child;
child = child->GetNextSibling()) {
if (child->IsNodeOfType(nsINode::eTEXT)) {
bool ok = child->AppendTextTo(aResult, mozilla::fallible_t());
bool ok = child->AppendTextTo(aResult, fallible);
if (!ok) {
return false;
}
@ -6242,7 +6242,7 @@ void nsContentUtils::RemoveNewlines(nsString &aString)
void
nsContentUtils::PlatformToDOMLineBreaks(nsString &aString)
{
if (!PlatformToDOMLineBreaks(aString, mozilla::fallible_t())) {
if (!PlatformToDOMLineBreaks(aString, fallible)) {
aString.AllocFailed(aString.Length());
}
}
@ -6962,7 +6962,7 @@ bool
nsContentUtils::GetNodeTextContent(nsINode* aNode, bool aDeep, nsAString& aResult)
{
aResult.Truncate();
return AppendNodeTextContent(aNode, aDeep, aResult, mozilla::fallible_t());
return AppendNodeTextContent(aNode, aDeep, aResult, fallible);
}
void

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

@ -348,7 +348,7 @@ nsDOMFileReader::DoReadData(nsIAsyncInputStream* aStream, uint64_t aCount)
if (uint64_t(oldLen) + aCount > UINT32_MAX)
return NS_ERROR_OUT_OF_MEMORY;
char16_t *buf = nullptr;
mResult.GetMutableData(&buf, oldLen + aCount, fallible_t());
mResult.GetMutableData(&buf, oldLen + aCount, fallible);
NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);
uint32_t bytesRead = 0;
@ -522,7 +522,7 @@ nsDOMFileReader::GetAsDataURL(nsIDOMBlob *aFile,
rv = Base64Encode(Substring(aFileData, aDataLen), encodedData);
NS_ENSURE_SUCCESS(rv, rv);
if (!AppendASCIItoUTF16(encodedData, aResult, fallible_t())) {
if (!AppendASCIItoUTF16(encodedData, aResult, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}

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

@ -1158,7 +1158,7 @@ nsDOMWindowUtils::SendTouchEventCommon(const nsAString& aType,
LayoutDeviceIntPoint pt =
ToWidgetPoint(CSSPoint(aXs[i], aYs[i]), offset, presContext);
nsRefPtr<Touch> t = new Touch(aIdentifiers[i],
LayoutDeviceIntPoint::ToUntyped(pt),
pt,
nsIntPoint(aRxs[i], aRys[i]),
aRotationAngles[i],
aForces[i]);
@ -3392,8 +3392,8 @@ nsDOMWindowUtils::SelectAtPoint(float aX, float aY, uint32_t aSelectBehavior,
// Get the target frame at the client coordinates passed to us
nsPoint offset;
nsCOMPtr<nsIWidget> widget = GetWidget(&offset);
nsIntPoint pt = LayoutDeviceIntPoint::ToUntyped(
ToWidgetPoint(CSSPoint(aX, aY), offset, GetPresContext()));
LayoutDeviceIntPoint pt =
ToWidgetPoint(CSSPoint(aX, aY), offset, GetPresContext());
nsPoint ptInRoot =
nsLayoutUtils::GetEventCoordinatesRelativeTo(widget, pt, rootFrame);
nsIFrame* targetFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, ptInRoot);

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

@ -572,7 +572,7 @@ ConvertAndWrite(const nsAString& aString,
}
nsAutoCString charXferString;
if (!charXferString.SetLength(charLength, fallible_t()))
if (!charXferString.SetLength(charLength, fallible))
return NS_ERROR_OUT_OF_MEMORY;
char* charXferBuf = charXferString.BeginWriting();

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

@ -1074,9 +1074,10 @@ nsGenericDOMDataNode::AppendTextTo(nsAString& aResult)
}
bool
nsGenericDOMDataNode::AppendTextTo(nsAString& aResult, const mozilla::fallible_t&)
nsGenericDOMDataNode::AppendTextTo(nsAString& aResult,
const mozilla::fallible_t& aFallible)
{
return mText.AppendTo(aResult, mozilla::fallible_t());
return mText.AppendTo(aResult, aFallible);
}
already_AddRefed<nsIAtom>

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

@ -2773,7 +2773,6 @@ nsJSArgArray::nsJSArgArray(JSContext *aContext, uint32_t argc, JS::Value *argv,
// copy the array - we don't know its lifetime, and ours is tied to xpcom
// refcounting.
if (argc) {
static const fallible_t fallible = fallible_t();
mArgv = new (fallible) JS::Heap<JS::Value>[argc];
if (!mArgv) {
*prv = NS_ERROR_OUT_OF_MEMORY;

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

@ -161,7 +161,7 @@ AssignJSString(JSContext *cx, T &dest, JSString *s)
size_t len = js::GetStringLength(s);
static_assert(js::MaxStringLength < (1 << 28),
"Shouldn't overflow here or in SetCapacity");
if (MOZ_UNLIKELY(!dest.SetLength(len, mozilla::fallible_t()))) {
if (MOZ_UNLIKELY(!dest.SetLength(len, mozilla::fallible))) {
JS_ReportOutOfMemory(cx);
return false;
}

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

@ -328,13 +328,13 @@ nsScriptNameSpaceManager::Init()
mIsInitialized = PL_DHashTableInit(&mGlobalNames, &hash_table_ops,
sizeof(GlobalNameMapEntry),
fallible_t(),
fallible,
GLOBALNAME_HASHTABLE_INITIAL_LENGTH);
NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_OUT_OF_MEMORY);
mIsInitialized = PL_DHashTableInit(&mNavigatorNames, &hash_table_ops,
sizeof(GlobalNameMapEntry),
fallible_t(),
fallible,
GLOBALNAME_HASHTABLE_INITIAL_LENGTH);
if (!mIsInitialized) {
PL_DHashTableFinish(&mGlobalNames);

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

@ -125,7 +125,7 @@ public:
* Append the contents of this string fragment to aString
*/
void AppendTo(nsAString& aString) const {
if (!AppendTo(aString, mozilla::fallible_t())) {
if (!AppendTo(aString, mozilla::fallible)) {
aString.AllocFailed(aString.Length() + GetLength());
}
}
@ -135,9 +135,9 @@ public:
* @return false if an out of memory condition is detected, true otherwise
*/
bool AppendTo(nsAString& aString,
const mozilla::fallible_t&) const NS_WARN_UNUSED_RESULT {
const mozilla::fallible_t& aFallible) const NS_WARN_UNUSED_RESULT {
if (mState.mIs2b) {
bool ok = aString.Append(m2b, mState.mLength, mozilla::fallible_t());
bool ok = aString.Append(m2b, mState.mLength, aFallible);
if (!ok) {
return false;
}
@ -145,7 +145,7 @@ public:
return true;
} else {
return AppendASCIItoUTF16(Substring(m1b, mState.mLength), aString,
mozilla::fallible_t());
aFallible);
}
}
@ -155,7 +155,7 @@ public:
* @param aLength the length of the substring
*/
void AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength) const {
if (!AppendTo(aString, aOffset, aLength, mozilla::fallible_t())) {
if (!AppendTo(aString, aOffset, aLength, mozilla::fallible)) {
aString.AllocFailed(aString.Length() + aLength);
}
}
@ -168,10 +168,10 @@ public:
* @return false if an out of memory condition is detected, true otherwise
*/
bool AppendTo(nsAString& aString, int32_t aOffset, int32_t aLength,
const mozilla::fallible_t&) const NS_WARN_UNUSED_RESULT
const mozilla::fallible_t& aFallible) const NS_WARN_UNUSED_RESULT
{
if (mState.mIs2b) {
bool ok = aString.Append(m2b + aOffset, aLength, mozilla::fallible_t());
bool ok = aString.Append(m2b + aOffset, aLength, aFallible);
if (!ok) {
return false;
}
@ -179,7 +179,7 @@ public:
return true;
} else {
return AppendASCIItoUTF16(Substring(m1b + aOffset, aLength), aString,
mozilla::fallible_t());
aFallible);
}
}

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

@ -670,7 +670,7 @@ nsXMLHttpRequest::AppendToResponseText(const char * aSrcBuffer,
&destBufferLen);
NS_ENSURE_SUCCESS(rv, rv);
if (!mResponseText.SetCapacity(mResponseText.Length() + destBufferLen, fallible_t())) {
if (!mResponseText.SetCapacity(mResponseText.Length() + destBufferLen, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}

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

@ -102,9 +102,7 @@ public:
DataType* AddEntry(const nsAString& aKey) NS_WARN_UNUSED_RESULT
{
// XXXbz can't just use fallible_t() because our superclass has a
// private typedef by that name.
EntryType* ent = this->PutEntry(aKey, mozilla::fallible_t());
EntryType* ent = this->PutEntry(aKey, fallible);
if (!ent) {
return nullptr;
}

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

@ -1060,7 +1060,6 @@ WebGLContext::GetImageBuffer(uint8_t** out_imageBuffer, int32_t* out_format)
if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map))
return;
static const fallible_t fallible = fallible_t();
uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4];
if (!imageBuffer) {
dataSurface->Unmap();

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

@ -581,7 +581,7 @@ WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
GetAndFlushUnderlyingGLErrors();
if (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray) {
UniquePtr<GLfloat[]> array(new ((fallible_t())) GLfloat[4 * vertexCount]);
UniquePtr<GLfloat[]> array(new (fallible) GLfloat[4 * vertexCount]);
if (!array) {
ErrorOutOfMemory("Fake attrib0 array.");
return false;

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

@ -48,7 +48,6 @@
#include "mozilla/dom/ImageData.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/Endian.h"
#include "mozilla/fallible.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -2086,7 +2085,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
uint32_t subrect_byteLength = (subrect_height-1)*subrect_alignedRowSize + subrect_plainRowSize;
// create subrect buffer, call glReadPixels, copy pixels into destination buffer, delete subrect buffer
UniquePtr<GLubyte> subrect_data(new ((fallible_t())) GLubyte[subrect_byteLength]);
UniquePtr<GLubyte> subrect_data(new (fallible) GLubyte[subrect_byteLength]);
if (!subrect_data)
return ErrorOutOfMemory("readPixels: subrect_data");
@ -3203,7 +3202,7 @@ WebGLContext::TexImage2D_base(TexImageTarget texImageTarget, GLint level,
else
{
size_t convertedDataSize = height * dstStride;
convertedData = new ((fallible_t())) uint8_t[convertedDataSize];
convertedData = new (fallible) uint8_t[convertedDataSize];
if (!convertedData) {
ErrorOutOfMemory("texImage2D: Ran out of memory when allocating"
" a buffer for doing format conversion.");
@ -3404,7 +3403,7 @@ WebGLContext::TexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
if (!noConversion) {
size_t convertedDataSize = height * dstStride;
convertedData = new ((fallible_t())) uint8_t[convertedDataSize];
convertedData = new (fallible) uint8_t[convertedDataSize];
if (!convertedData) {
ErrorOutOfMemory("texImage2D: Ran out of memory when allocating"
" a buffer for doing format conversion.");

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

@ -63,7 +63,6 @@ TextDecoder::Decode(const char* aInput, const int32_t aLength,
}
// Need a fallible allocator because the caller may be a content
// and the content can specify the length of the string.
static const fallible_t fallible = fallible_t();
nsAutoArrayPtr<char16_t> buf(new (fallible) char16_t[outLen + 1]);
if (!buf) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);

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

@ -53,7 +53,6 @@ TextEncoder::Encode(JSContext* aCx,
}
// Need a fallible allocator because the caller may be a content
// and the content can specify the length of the string.
static const fallible_t fallible = fallible_t();
nsAutoArrayPtr<char> buf(new (fallible) char[maxLen + 1]);
if (!buf) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);

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

@ -966,8 +966,7 @@ Event::GetClientCoords(nsPresContext* aPresContext,
return CSSIntPoint(0, 0);
}
nsPoint pt =
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
LayoutDeviceIntPoint::ToUntyped(aPoint), rootFrame);
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, aPoint, rootFrame);
return CSSIntPoint::FromAppUnitsRounded(pt);
}

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

@ -33,7 +33,7 @@ Touch::Touch(EventTarget* aTarget,
mPagePoint = CSSIntPoint(aPageX, aPageY);
mScreenPoint = nsIntPoint(aScreenX, aScreenY);
mClientPoint = CSSIntPoint(aClientX, aClientY);
mRefPoint = nsIntPoint(0, 0);
mRefPoint = LayoutDeviceIntPoint(0, 0);
mPointsInitialized = true;
mRadius.x = aRadiusX;
mRadius.y = aRadiusY;
@ -46,7 +46,7 @@ Touch::Touch(EventTarget* aTarget,
}
Touch::Touch(int32_t aIdentifier,
nsIntPoint aPoint,
LayoutDeviceIntPoint aPoint,
nsIntPoint aRadius,
float aRotationAngle,
float aForce)
@ -106,13 +106,10 @@ Touch::InitializePoints(nsPresContext* aPresContext, WidgetEvent* aEvent)
return;
}
mClientPoint = Event::GetClientCoords(
aPresContext, aEvent, LayoutDeviceIntPoint::FromUntyped(mRefPoint),
mClientPoint);
aPresContext, aEvent, mRefPoint, mClientPoint);
mPagePoint = Event::GetPageCoords(
aPresContext, aEvent, LayoutDeviceIntPoint::FromUntyped(mRefPoint),
mClientPoint);
mScreenPoint = Event::GetScreenCoords(aPresContext, aEvent,
LayoutDeviceIntPoint::FromUntyped(mRefPoint));
aPresContext, aEvent, mRefPoint, mClientPoint);
mScreenPoint = Event::GetScreenCoords(aPresContext, aEvent, mRefPoint);
mPointsInitialized = true;
}

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

@ -40,7 +40,7 @@ public:
float aRotationAngle,
float aForce);
Touch(int32_t aIdentifier,
nsIntPoint aPoint,
LayoutDeviceIntPoint aPoint,
nsIntPoint aRadius,
float aRotationAngle,
float aForce);
@ -73,7 +73,7 @@ public:
float Force() const { return mForce; }
nsCOMPtr<EventTarget> mTarget;
nsIntPoint mRefPoint;
LayoutDeviceIntPoint mRefPoint;
bool mChanged;
uint32_t mMessage;
int32_t mIdentifier;

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

@ -470,7 +470,7 @@ ExtractFromUSVString(const nsString& aStr,
}
nsCString encoded;
if (!encoded.SetCapacity(destBufferLen, fallible_t())) {
if (!encoded.SetCapacity(destBufferLen, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -583,7 +583,7 @@ public:
return rv;
}
if (!mDecoded.SetCapacity(mDecoded.Length() + destBufferLen, fallible_t())) {
if (!mDecoded.SetCapacity(mDecoded.Length() + destBufferLen, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}

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

@ -26,7 +26,7 @@ MemoryOutputStream::Create(uint64_t aSize)
nsRefPtr<MemoryOutputStream> stream = new MemoryOutputStream();
char* dummy;
uint32_t length = stream->mData.GetMutableData(&dummy, aSize, fallible_t());
uint32_t length = stream->mData.GetMutableData(&dummy, aSize, fallible);
NS_ENSURE_TRUE(length == aSize, nullptr);
return stream.forget();

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

@ -232,7 +232,6 @@ HTMLFrameSetElement::ParseRowCol(const nsAString & aValue,
commaX = spec.FindChar(sComma, commaX + 1);
}
static const fallible_t fallible = fallible_t();
nsFramesetSpec* specs = new (fallible) nsFramesetSpec[count];
if (!specs) {
*aSpecs = nullptr;

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

@ -1873,8 +1873,6 @@ bool
nsTextEditorState::SetValue(const nsAString& aValue, bool aUserInput,
bool aSetValueChanged)
{
mozilla::fallible_t fallible;
if (mEditor && mBoundFrame) {
// The InsertText call below might flush pending notifications, which
// could lead into a scheduled PrepareEditor to be called. That will

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

@ -146,8 +146,6 @@ const int32_t kStorageProgressGranularity = 1000;
const char kSavepointClause[] = "SAVEPOINT sp;";
const fallible_t fallible = fallible_t();
const uint32_t kFileCopyBufferSize = 32768;
const char kJournalDirectoryName[] = "journals";

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

@ -464,7 +464,7 @@ StructuredCloneReadString(JSStructuredCloneReader* aReader,
}
length = NativeEndian::swapFromLittleEndian(length);
if (!aString.SetLength(length, fallible_t())) {
if (!aString.SetLength(length, fallible)) {
NS_WARNING("Out of memory?");
return false;
}

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

@ -2302,9 +2302,8 @@ TabChild::RecvMouseWheelEvent(const WidgetWheelEvent& aEvent,
if (nsIPresShell* shell = document->GetShell()) {
if (nsIFrame* rootFrame = shell->GetRootFrame()) {
nsTArray<ScrollableLayerGuid> targets;
nsIntPoint refPoint(aEvent.refPoint.x, aEvent.refPoint.y);
bool waitForRefresh =
PrepareForSetTargetAPZCNotification(aGuid, aInputBlockId, rootFrame, refPoint, &targets);
PrepareForSetTargetAPZCNotification(aGuid, aInputBlockId, rootFrame, aEvent.refPoint, &targets);
SendSetTargetAPZCNotification(shell, aInputBlockId, targets, waitForRefresh);
}
@ -2541,7 +2540,7 @@ bool
TabChild::PrepareForSetTargetAPZCNotification(const ScrollableLayerGuid& aGuid,
const uint64_t& aInputBlockId,
nsIFrame* aRootFrame,
const nsIntPoint& aRefPoint,
const LayoutDeviceIntPoint& aRefPoint,
nsTArray<ScrollableLayerGuid>* aTargets)
{
ScrollableLayerGuid guid(aGuid.mLayersId, 0, FrameMetrics::NULL_SCROLL_ID);

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

@ -592,7 +592,7 @@ private:
bool PrepareForSetTargetAPZCNotification(const ScrollableLayerGuid& aGuid,
const uint64_t& aInputBlockId,
nsIFrame* aRootFrame,
const nsIntPoint& aRefPoint,
const LayoutDeviceIntPoint& aRefPoint,
nsTArray<ScrollableLayerGuid>* aTargets);
// Sends a SetTarget notification for APZC, given one or more previous

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

@ -1085,7 +1085,7 @@ TabParent::MapEventCoordinatesForChildProcess(
for (uint32_t i = 0; i < touches.Length(); ++i) {
Touch* touch = touches[i];
if (touch) {
touch->mRefPoint += LayoutDeviceIntPoint::ToUntyped(aOffset);
touch->mRefPoint += aOffset;
}
}
}
@ -1731,7 +1731,7 @@ TabParent::GetChildProcessOffset()
return offset;
}
nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(widget,
nsIntPoint(0, 0),
LayoutDeviceIntPoint(0, 0),
targetFrame);
return LayoutDeviceIntPoint::ToUntyped(LayoutDeviceIntPoint::FromAppUnitsToNearest(
@ -2485,7 +2485,7 @@ TabParent::InjectTouchEvent(const nsAString& aType,
presContext->AppUnitsPerDevPixel());
nsRefPtr<Touch> t = new Touch(aIdentifiers[i],
LayoutDeviceIntPoint::ToUntyped(pt),
pt,
nsIntPoint(aRxs[i], aRys[i]),
aRotationAngles[i],
aForces[i]);

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

@ -191,6 +191,12 @@ static int64_t DurationToUsecs(TimeDuration aDuration) {
return static_cast<int64_t>(aDuration.ToSeconds() * USECS_PER_S);
}
static const uint32_t MIN_VIDEO_QUEUE_SIZE = 3;
static const uint32_t MAX_VIDEO_QUEUE_SIZE = 10;
static uint32_t sVideoQueueDefaultSize = MAX_VIDEO_QUEUE_SIZE;
static uint32_t sVideoQueueHWAccelSize = MIN_VIDEO_QUEUE_SIZE;
MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
MediaDecoderReader* aReader,
bool aRealTime) :
@ -216,7 +222,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mVolume(1.0),
mPlaybackRate(1.0),
mPreservesPitch(true),
mAmpleVideoFrames(2),
mAmpleVideoFrames(MIN_VIDEO_QUEUE_SIZE),
mLowAudioThresholdUsecs(detail::LOW_AUDIO_USECS),
mAmpleAudioThresholdUsecs(detail::AMPLE_AUDIO_USECS),
mQuickBufferingLowDataThresholdUsecs(detail::QUICK_BUFFERING_LOW_DATA_USECS),
@ -247,8 +253,16 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
MOZ_COUNT_CTOR(MediaDecoderStateMachine);
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
mAmpleVideoFrames =
std::max<uint32_t>(Preferences::GetUint("media.video-queue.default-size", 10), 3);
static bool sPrefCacheInit = false;
if (!sPrefCacheInit) {
sPrefCacheInit = true;
Preferences::AddUintVarCache(&sVideoQueueDefaultSize,
"media.video-queue.default-size",
MAX_VIDEO_QUEUE_SIZE);
Preferences::AddUintVarCache(&sVideoQueueHWAccelSize,
"media.video-queue.hw-accel-size",
MIN_VIDEO_QUEUE_SIZE);
}
mBufferingWait = IsRealTime() ? 0 : 30;
mLowDataThresholdUsecs = IsRealTime() ? 0 : detail::LOW_DATA_THRESHOLD_USECS;
@ -2215,16 +2229,27 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
return NS_OK;
}
if (NS_FAILED(res) || (!info.HasValidMedia())) {
DECODER_WARN("ReadMetadata failed, res=%x HasValidMedia=%d", res, info.HasValidMedia());
return NS_ERROR_FAILURE;
}
if (NS_SUCCEEDED(res)) {
mDecoder->SetMediaSeekable(mReader->IsMediaSeekable());
}
mInfo = info;
if (NS_FAILED(res) || (!info.HasValidMedia())) {
DECODER_WARN("ReadMetadata failed, res=%x HasValidMedia=%d", res, info.HasValidMedia());
return NS_ERROR_FAILURE;
if (HasVideo()) {
mAmpleVideoFrames = (mReader->IsAsync() && mInfo.mVideo.mIsHardwareAccelerated)
? std::max<uint32_t>(sVideoQueueHWAccelSize, MIN_VIDEO_QUEUE_SIZE)
: std::max<uint32_t>(sVideoQueueDefaultSize, MIN_VIDEO_QUEUE_SIZE);
DECODER_LOG("Video decode isAsync=%d HWAccel=%d videoQueueSize=%d",
mReader->IsAsync(),
mInfo.mVideo.mIsHardwareAccelerated,
mAmpleVideoFrames);
}
mDecoder->StartProgressUpdates();
mGotDurationFromMetaData = (GetDuration() != -1) || mDurationSet;

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

@ -41,6 +41,7 @@ public:
: mDisplay(0,0)
, mStereoMode(StereoMode::MONO)
, mHasVideo(false)
, mIsHardwareAccelerated(false)
{
// TODO: TrackInfo should be initialized by its specific codec decoder.
// This following call should be removed once we have that implemented.
@ -59,6 +60,8 @@ public:
bool mHasVideo;
TrackInfo mTrackInfo;
bool mIsHardwareAccelerated;
};
class AudioInfo {

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

@ -465,6 +465,7 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
NS_ENSURE_TRUE(mVideo.mDecoder != nullptr, NS_ERROR_FAILURE);
nsresult rv = mVideo.mDecoder->Init();
NS_ENSURE_SUCCESS(rv, rv);
mInfo.mVideo.mIsHardwareAccelerated = mVideo.mDecoder->IsHardwareAccelerated();
}
// Get the duration, and report it to the decoder if we have it.

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

@ -11,7 +11,6 @@
#include "MediaResource.h"
#include "mozilla/fallible.h"
#include "mozilla/Maybe.h"
#include "mozilla/Monitor.h"
@ -77,7 +76,7 @@ private:
bool Init()
{
mBuffer = new ((fallible_t())) char[mCount];
mBuffer = new (fallible) char[mCount];
return !!mBuffer;
}

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

@ -245,6 +245,7 @@ public:
virtual void AllocateMediaResources() {}
virtual void ReleaseMediaResources() {}
virtual void ReleaseDecoder() {}
virtual bool IsHardwareAccelerated() const { return false; }
};
} // namespace mozilla

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

@ -237,4 +237,11 @@ SharedDecoderProxy::ReleaseDecoder()
mManager->mDecoder->ReleaseMediaResources();
}
}
bool
SharedDecoderProxy::IsHardwareAccelerated() const
{
return mManager->mDecoder->IsHardwareAccelerated();
}
}

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

@ -70,6 +70,7 @@ public:
virtual bool IsDormantNeeded() MOZ_OVERRIDE;
virtual void ReleaseMediaResources() MOZ_OVERRIDE;
virtual void ReleaseDecoder() MOZ_OVERRIDE;
virtual bool IsHardwareAccelerated() const MOZ_OVERRIDE;
friend class SharedDecoderManager;

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

@ -179,4 +179,9 @@ WMFMediaDataDecoder::ReleaseDecoder()
ReleaseMediaResources();
}
bool
WMFMediaDataDecoder::IsHardwareAccelerated() const {
return mMFTManager && mMFTManager->IsHardwareAccelerated();
}
} // namespace mozilla

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

@ -46,6 +46,9 @@ public:
// Destroys all resources.
virtual void Shutdown() = 0;
virtual bool IsHardwareAccelerated() const { return false; }
};
// Decodes audio and video using Windows Media Foundation. Samples are decoded
@ -75,6 +78,7 @@ public:
virtual void AllocateMediaResources() MOZ_OVERRIDE;
virtual void ReleaseMediaResources() MOZ_OVERRIDE;
virtual void ReleaseDecoder() MOZ_OVERRIDE;
virtual bool IsHardwareAccelerated() const MOZ_OVERRIDE;
private:

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

@ -495,4 +495,10 @@ WMFVideoMFTManager::Shutdown()
DeleteOnMainThread(mDXVA2Manager);
}
bool
WMFVideoMFTManager::IsHardwareAccelerated() const
{
return mUseHwAccel;
}
} // namespace mozilla

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

@ -35,6 +35,8 @@ public:
virtual void Shutdown() MOZ_OVERRIDE;
virtual bool IsHardwareAccelerated() const MOZ_OVERRIDE;
private:
bool InitializeDXVA();

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

@ -60,7 +60,8 @@ MockMediaResource::ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount,
int64_t
MockMediaResource::GetLength()
{
return fseek(mFileHandle, 0, SEEK_END);
fseek(mFileHandle, 0, SEEK_END);
return ftell(mFileHandle);
}
void

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

@ -331,3 +331,34 @@ TEST(MP4Demuxer, CENCFrag)
}
EXPECT_EQ(ArrayLength(audio), i);
}
TEST(MP4Demuxer, GetNextKeyframe)
{
nsRefPtr<MP4DemuxerBinding> b = new MP4DemuxerBinding("gizmo-frag.mp4");
MonitorAutoLock mon(b->mMonitor);
MP4Demuxer* d = b->demuxer;
EXPECT_TRUE(d->Init());
// Insert a [0,end] buffered range, to simulate Moof's being buffered
// via MSE.
auto len = b->resource->GetLength();
b->resource->MockAddBufferedRange(0, len);
// Rebuild the index so that it can be used to find the keyframes.
nsTArray<MediaByteRange> ranges;
EXPECT_TRUE(NS_SUCCEEDED(b->resource->GetCachedRanges(ranges)));
d->UpdateIndex(ranges);
// gizmp-frag has two keyframes; one at dts=cts=0, and another at
// dts=cts=1000000. Verify we get expected results.
MP4Sample* sample;
size_t i = 0;
const int64_t keyframe = 1000000;
while (!!(sample = d->DemuxVideoSample())) {
int64_t expected = (sample->decode_timestamp < keyframe) ? keyframe : -1;
EXPECT_EQ(d->GetNextKeyframeTime(), expected);
i++;
}
}

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

@ -62,9 +62,8 @@ public:
// channels or size, but it's OK since we'll deal with the failure
// gracefully.
if (mInputChannels.SetLength(mNumberOfChannels)) {
static const fallible_t fallible = fallible_t();
for (uint32_t i = 0; i < mNumberOfChannels; ++i) {
mInputChannels[i] = new(fallible) float[mLength];
mInputChannels[i] = new (fallible) float[mLength];
if (!mInputChannels[i]) {
mInputChannels.Clear();
break;

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

@ -333,13 +333,12 @@ MediaDecodeTask::FinishDecode()
// Allocate the channel buffers. Note that if we end up resampling, we may
// write fewer bytes than mResampledFrames to the output buffer, in which
// case mWriteIndex will tell us how many valid samples we have.
static const fallible_t fallible = fallible_t();
bool memoryAllocationSuccess = true;
if (!mDecodeJob.mChannelBuffers.SetLength(channelCount)) {
memoryAllocationSuccess = false;
} else {
for (uint32_t i = 0; i < channelCount; ++i) {
mDecodeJob.mChannelBuffers[i] = new(fallible) float[resampledFrames];
mDecodeJob.mChannelBuffers[i] = new (fallible) float[resampledFrames];
if (!mDecodeJob.mChannelBuffers[i]) {
memoryAllocationSuccess = false;
break;

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

@ -259,7 +259,7 @@ static nsresult ConvertToUTF8(nsIUnicodeDecoder *aUnicodeDecoder,
nsresult rv = aUnicodeDecoder->GetMaxLength(aString.get(), numberOfBytes,
&outUnicodeLen);
NS_ENSURE_SUCCESS(rv, rv);
if (!buffer.SetLength(outUnicodeLen, fallible_t()))
if (!buffer.SetLength(outUnicodeLen, fallible))
return NS_ERROR_OUT_OF_MEMORY;
rv = aUnicodeDecoder->Convert(aString.get(), &numberOfBytes,
buffer.BeginWriting(), &outUnicodeLen);

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

@ -117,7 +117,7 @@ DOMStorage::SetItem(const nsAString& aKey, const nsAString& aData,
: Telemetry::SESSIONDOMSTORAGE_VALUE_SIZE_BYTES, aData.Length());
nsString data;
bool ok = data.Assign(aData, fallible_t());
bool ok = data.Assign(aData, fallible);
if (!ok) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;

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

@ -10,7 +10,6 @@
#define _USE_MATH_DEFINES
#include <math.h>
#include "mozilla/fallible.h"
#include "mozilla/gfx/2D.h" // for StrokeOptions
#include "mozilla/gfx/Matrix.h"
#include "mozilla/RangedPtr.h"
@ -111,8 +110,7 @@ public:
mDashPattern = mSmallArray;
return mSmallArray;
}
static const mozilla::fallible_t fallible = mozilla::fallible_t();
Float* nonConstArray = new (fallible) Float[aDashCount];
Float* nonConstArray = new (mozilla::fallible) Float[aDashCount];
mDashPattern = nonConstArray;
return nonConstArray;
}

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

@ -202,7 +202,6 @@ SVGFEConvolveMatrixElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstan
if (orderX > NS_SVG_OFFSCREEN_MAX_DIMENSION ||
orderY > NS_SVG_OFFSCREEN_MAX_DIMENSION)
return failureDescription;
const fallible_t fallible = fallible_t();
nsAutoArrayPtr<float> kernel(new (fallible) float[orderX * orderY]);
if (!kernel)
return failureDescription;

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

@ -179,7 +179,7 @@ void txDouble::toString(double aValue, nsAString& aDest)
++length;
// grow the string
uint32_t oldlength = aDest.Length();
if (!aDest.SetLength(oldlength + length, mozilla::fallible_t()))
if (!aDest.SetLength(oldlength + length, mozilla::fallible))
return; // out of memory
nsAString::iterator dest;
aDest.BeginWriting(dest).advance(int32_t(oldlength));

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

@ -514,7 +514,7 @@ txXPathNodeUtils::appendNodeValue(const txXPathNode& aNode, nsAString& aResult)
aNode.mNode->IsElement() ||
aNode.mNode->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT)) {
nsContentUtils::AppendNodeTextContent(aNode.mNode, true, aResult,
mozilla::fallible_t());
mozilla::fallible);
return;
}

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

@ -1198,7 +1198,7 @@ nsTextEditRules::TruncateInsertionIfNeeded(Selection* aSelection,
if (!aSelection || !aInString || !aOutString) {return NS_ERROR_NULL_POINTER;}
nsresult res = NS_OK;
if (!aOutString->Assign(*aInString, mozilla::fallible_t())) {
if (!aOutString->Assign(*aInString, mozilla::fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (aTruncated) {

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

@ -576,7 +576,7 @@ mozInlineSpellWordUtil::BuildSoftText()
DOMTextMapping(NodeOffset(node, firstOffsetInNode), mSoftText.Length(), len));
bool ok = textFragment->AppendTo(mSoftText, firstOffsetInNode, len,
mozilla::fallible_t());
mozilla::fallible);
if (!ok) {
// probably out of memory, remove from mSoftTextDOMMapping
mSoftTextDOMMapping.RemoveElementAt(mSoftTextDOMMapping.Length() - 1);

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

@ -355,16 +355,15 @@ APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput,
return input;
}
nsIntPoint
APZCCallbackHelper::ApplyCallbackTransform(const nsIntPoint& aPoint,
LayoutDeviceIntPoint
APZCCallbackHelper::ApplyCallbackTransform(const LayoutDeviceIntPoint& aPoint,
const ScrollableLayerGuid& aGuid,
const CSSToLayoutDeviceScale& aScale,
float aPresShellResolution)
{
LayoutDevicePoint point = LayoutDevicePoint(aPoint.x, aPoint.y);
point = ApplyCallbackTransform(point / aScale, aGuid, aPresShellResolution) * aScale;
LayoutDeviceIntPoint ret = gfx::RoundedToInt(point);
return nsIntPoint(ret.x, ret.y);
return gfx::RoundedToInt(point);
}
nsEventStatus

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

@ -99,13 +99,14 @@ public:
const ScrollableLayerGuid& aGuid,
float aPresShellResolution);
/* Same as above, but operates on nsIntPoint that are assumed to be in LayoutDevice
pixel space. Requires an additonal |aScale| parameter to convert between CSS and
/* Same as above, but operates on LayoutDeviceIntPoint.
Requires an additonal |aScale| parameter to convert between CSS and
LayoutDevice space. */
static nsIntPoint ApplyCallbackTransform(const nsIntPoint& aPoint,
const ScrollableLayerGuid& aGuid,
const CSSToLayoutDeviceScale& aScale,
float aPresShellResolution);
static mozilla::LayoutDeviceIntPoint
ApplyCallbackTransform(const LayoutDeviceIntPoint& aPoint,
const ScrollableLayerGuid& aGuid,
const CSSToLayoutDeviceScale& aScale,
float aPresShellResolution);
/* Dispatch a widget event via the widget stored in the event, if any.
* In a child process, allows the TabParent event-capture mechanism to

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

@ -674,8 +674,7 @@ bool
MemoryTextureClient::Allocate(uint32_t aSize)
{
MOZ_ASSERT(!mBuffer);
static const fallible_t fallible = fallible_t();
mBuffer = new(fallible) uint8_t[aSize];
mBuffer = new (fallible) uint8_t[aSize];
if (!mBuffer) {
NS_WARNING("Failed to allocate buffer");
return false;

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

@ -1096,7 +1096,6 @@ gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive,
uint32_t bufSize = item->RealSize();
// We use fallible allocation here; if there's not enough RAM, we'll simply
// ignore the bundled fonts and fall back to the device's installed fonts.
static const fallible_t fallible = fallible_t();
nsAutoArrayPtr<uint8_t> buf(new (fallible) uint8_t[bufSize]);
if (!buf) {
return;

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

@ -490,7 +490,7 @@ CreateBitmapInfo(BITMAPINFOHEADER* aHeader, size_t aColorTableSize)
{
BITMAPINFO* bmi = (BITMAPINFO*) ::operator new(sizeof(BITMAPINFOHEADER) +
aColorTableSize,
mozilla::fallible_t());
mozilla::fallible);
if (bmi) {
memcpy(bmi, aHeader, sizeof(BITMAPINFOHEADER));
memset(bmi->bmiColors, 0, aColorTableSize);

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

@ -185,7 +185,6 @@ nsBMPEncoder::AddImageFrame(const uint8_t* aData,
return NS_ERROR_INVALID_ARG;
}
static fallible_t fallible = fallible_t();
nsAutoArrayPtr<uint8_t> row(new (fallible)
uint8_t[mBMPInfoHeader.width *
BytesPerPixel(mBMPInfoHeader.bpp)]);

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

@ -272,7 +272,6 @@ private:
, mLength(0)
{
MOZ_ASSERT(aCapacity > 0, "Creating zero-capacity chunk");
static const fallible_t fallible = fallible_t();
mData = new (fallible) char[mCapacity];
}

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

@ -65,7 +65,7 @@ nsScriptableUnicodeConverter::ConvertFromUnicode(const nsAString& aSrc,
nsresult rv = ConvertFromUnicodeWithLength(aSrc, &len, &str);
if (NS_SUCCEEDED(rv)) {
// No Adopt on nsACString :(
if (!_retval.Assign(str, len, mozilla::fallible_t())) {
if (!_retval.Assign(str, len, mozilla::fallible)) {
rv = NS_ERROR_OUT_OF_MEMORY;
}
moz_free(str);
@ -114,7 +114,7 @@ nsScriptableUnicodeConverter::Finish(nsACString& _retval)
nsresult rv = FinishWithLength(&str, &len);
if (NS_SUCCEEDED(rv)) {
// No Adopt on nsACString :(
if (!_retval.Assign(str, len, mozilla::fallible_t())) {
if (!_retval.Assign(str, len, mozilla::fallible)) {
rv = NS_ERROR_OUT_OF_MEMORY;
}
moz_free(str);
@ -160,7 +160,7 @@ nsScriptableUnicodeConverter::ConvertFromByteArray(const uint8_t* aData,
if (NS_SUCCEEDED(rv))
{
buf[outLength] = 0;
if (!_retval.Assign(buf, outLength, mozilla::fallible_t())) {
if (!_retval.Assign(buf, outLength, mozilla::fallible)) {
rv = NS_ERROR_OUT_OF_MEMORY;
}
}

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

@ -363,6 +363,11 @@ ICStub::trace(JSTracer *trc)
}
break;
}
case ICStub::GetProp_Unboxed: {
ICGetProp_Unboxed *propStub = toGetProp_Unboxed();
MarkTypeObject(trc, &propStub->type(), "baseline-getprop-unboxed-stub-type");
break;
}
case ICStub::GetProp_TypedObject: {
ICGetProp_TypedObject *propStub = toGetProp_TypedObject();
MarkShape(trc, &propStub->shape(), "baseline-getprop-typedobject-stub-shape");
@ -437,6 +442,11 @@ ICStub::trace(JSTracer *trc)
}
break;
}
case ICStub::SetProp_Unboxed: {
ICSetProp_Unboxed *propStub = toSetProp_Unboxed();
MarkTypeObject(trc, &propStub->type(), "baseline-setprop-unboxed-stub-type");
break;
}
case ICStub::SetProp_TypedObject: {
ICSetProp_TypedObject *propStub = toSetProp_TypedObject();
MarkShape(trc, &propStub->shape(), "baseline-setprop-typedobject-stub-shape");
@ -1410,8 +1420,9 @@ DoTypeUpdateFallback(JSContext *cx, BaselineFrame *frame, ICUpdatedStub *stub, H
break;
}
case ICStub::SetProp_Native:
case ICStub::SetProp_NativeAdd: {
MOZ_ASSERT(obj->isNative());
case ICStub::SetProp_NativeAdd:
case ICStub::SetProp_Unboxed: {
MOZ_ASSERT(obj->isNative() || obj->is<UnboxedPlainObject>());
jsbytecode *pc = stub->getChainFallback()->icEntry()->pc(script);
if (*pc == JSOP_SETALIASEDVAR || *pc == JSOP_INITALIASEDLEXICAL)
id = NameToId(ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc));
@ -6598,6 +6609,40 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
return true;
}
static bool
TryAttachUnboxedGetPropStub(JSContext *cx, HandleScript script,
ICGetProp_Fallback *stub, HandlePropertyName name, HandleValue val,
bool *attached)
{
MOZ_ASSERT(!*attached);
if (!cx->runtime()->jitSupportsFloatingPoint)
return true;
if (!val.isObject() || !val.toObject().is<UnboxedPlainObject>())
return true;
Rooted<UnboxedPlainObject *> obj(cx, &val.toObject().as<UnboxedPlainObject>());
const UnboxedLayout::Property *property = obj->layout().lookup(name);
if (!property)
return true;
ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
ICGetProp_Unboxed::Compiler compiler(cx, monitorStub, obj->type(),
property->offset + UnboxedPlainObject::offsetOfData(),
property->type);
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
stub->addNewStub(newStub);
StripPreliminaryObjectStubs(cx, stub);
*attached = true;
return true;
}
static bool
TryAttachTypedObjectGetPropStub(JSContext *cx, HandleScript script,
ICGetProp_Fallback *stub, HandlePropertyName name, HandleValue val,
@ -6845,6 +6890,11 @@ DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub_
if (attached)
return true;
if (!TryAttachUnboxedGetPropStub(cx, script, stub, name, val, &attached))
return false;
if (attached)
return true;
if (!TryAttachTypedObjectGetPropStub(cx, script, stub, name, val, &attached))
return false;
if (attached)
@ -7755,6 +7805,39 @@ ICGetProp_Generic::Compiler::generateStubCode(MacroAssembler &masm)
return true;
}
bool
ICGetProp_Unboxed::Compiler::generateStubCode(MacroAssembler &masm)
{
Label failure;
GeneralRegisterSet regs(availableGeneralRegs(1));
Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
// Object and type guard.
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
Register object = masm.extractObject(R0, ExtractTemp0);
masm.loadPtr(Address(BaselineStubReg, ICGetProp_Unboxed::offsetOfType()), scratch);
masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfType()), scratch,
&failure);
// Get the address being read from.
masm.load32(Address(BaselineStubReg, ICGetProp_Unboxed::offsetOfFieldOffset()), scratch);
masm.loadUnboxedProperty(BaseIndex(object, scratch, TimesOne), fieldType_, TypedOrValueRegister(R0));
// Only monitor the result if its type might change.
if (fieldType_ == JSVAL_TYPE_OBJECT)
EmitEnterTypeMonitorIC(masm);
else
EmitReturnFromIC(masm);
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
bool
ICGetProp_TypedObject::Compiler::generateStubCode(MacroAssembler &masm)
{
@ -8009,6 +8092,40 @@ TryAttachSetAccessorPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
return true;
}
static bool
TryAttachUnboxedSetPropStub(JSContext *cx, HandleScript script,
ICSetProp_Fallback *stub, HandleId id,
HandleObject obj, HandleValue rhs, bool *attached)
{
MOZ_ASSERT(!*attached);
if (!cx->runtime()->jitSupportsFloatingPoint)
return true;
if (!obj->is<UnboxedPlainObject>())
return true;
const UnboxedLayout::Property *property = obj->as<UnboxedPlainObject>().layout().lookup(id);
if (!property)
return true;
ICSetProp_Unboxed::Compiler compiler(cx, obj->type(),
property->offset + UnboxedPlainObject::offsetOfData(),
property->type);
ICUpdatedStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
if (compiler.needsUpdateStubs() && !newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
return false;
stub->addNewStub(newStub);
StripPreliminaryObjectStubs(cx, stub);
*attached = true;
return true;
}
static bool
TryAttachTypedObjectSetPropStub(JSContext *cx, HandleScript script,
ICSetProp_Fallback *stub, HandleId id,
@ -8152,6 +8269,15 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_
if (attached)
return true;
if (!attached &&
lhs.isObject() &&
!TryAttachUnboxedSetPropStub(cx, script, stub, id, obj, rhs, &attached))
{
return false;
}
if (attached)
return true;
if (!attached &&
lhs.isObject() &&
!TryAttachTypedObjectSetPropStub(cx, script, stub, id, obj, rhs, &attached))
@ -8436,6 +8562,75 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler &masm)
return true;
}
bool
ICSetProp_Unboxed::Compiler::generateStubCode(MacroAssembler &masm)
{
Label failure;
// Guard input is an object.
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
GeneralRegisterSet regs(availableGeneralRegs(2));
Register scratch = regs.takeAny();
// Unbox and type guard.
Register object = masm.extractObject(R0, ExtractTemp0);
masm.loadPtr(Address(BaselineStubReg, ICSetProp_Unboxed::offsetOfType()), scratch);
masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfType()), scratch,
&failure);
if (needsUpdateStubs()) {
// Stow both R0 and R1 (object and value).
masm.push(object);
masm.push(BaselineStubReg);
EmitStowICValues(masm, 2);
// Move RHS into R0 for TypeUpdate check.
masm.moveValue(R1, R0);
// Call the type update stub.
if (!callTypeUpdateIC(masm, sizeof(Value)))
return false;
// Unstow R0 and R1 (object and key)
EmitUnstowICValues(masm, 2);
masm.pop(BaselineStubReg);
masm.pop(object);
// Trigger post barriers here on the values being written. Fields which
// objects can be written to also need update stubs.
GeneralRegisterSet saveRegs;
saveRegs.add(R0);
saveRegs.add(R1);
saveRegs.addUnchecked(object);
saveRegs.add(BaselineStubReg);
emitPostWriteBarrierSlot(masm, object, R1, scratch, saveRegs);
}
// Compute the address being written to.
masm.load32(Address(BaselineStubReg, ICSetProp_Unboxed::offsetOfFieldOffset()), scratch);
BaseIndex address(object, scratch, TimesOne);
if (fieldType_ == JSVAL_TYPE_OBJECT)
EmitPreBarrier(masm, address, MIRType_Object);
else if (fieldType_ == JSVAL_TYPE_STRING)
EmitPreBarrier(masm, address, MIRType_String);
else
MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(fieldType_));
masm.storeUnboxedProperty(address, fieldType_,
ConstantOrRegister(TypedOrValueRegister(R1)), &failure);
// The RHS has to be in R0.
masm.moveValue(R1, R0);
EmitReturnFromIC(masm);
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
bool
ICSetProp_TypedObject::Compiler::generateStubCode(MacroAssembler &masm)
{
@ -9066,27 +9261,26 @@ TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsb
// Remember the template object associated with any script being called
// as a constructor, for later use during Ion compilation.
RootedPlainObject templateObject(cx);
RootedObject templateObject(cx);
if (constructing) {
JSObject *thisObject = CreateThisForFunction(cx, fun, MaybeSingletonObject);
if (!thisObject)
return false;
if (thisObject->is<PlainObject>()) {
templateObject = &thisObject->as<PlainObject>();
if (thisObject->is<PlainObject>() || thisObject->is<UnboxedPlainObject>()) {
templateObject = thisObject;
// If we are calling a constructor for which the new script
// properties analysis has not been performed yet, don't attach a
// stub. After the analysis is performed, CreateThisForFunction may
// start returning objects with a different type, and the Ion
// compiler might get confused.
if (templateObject->type()->newScript() &&
!templateObject->type()->newScript()->analyzed())
{
types::TypeNewScript *newScript = templateObject->type()->newScript();
if (newScript && !newScript->analyzed()) {
// Clear the object just created from the preliminary objects
// on the TypeNewScript, as it will not be used or filled in by
// running code.
templateObject->type()->newScript()->unregisterNewObject(templateObject);
newScript->unregisterNewObject(&templateObject->as<PlainObject>());
return true;
}
}
@ -11713,7 +11907,7 @@ ICSetProp_CallNative::Clone(JSContext *cx, ICStubSpace *space, ICStub *,
}
ICCall_Scripted::ICCall_Scripted(JitCode *stubCode, ICStub *firstMonitorStub,
HandleScript calleeScript, HandleNativeObject templateObject,
HandleScript calleeScript, HandleObject templateObject,
uint32_t pcOffset)
: ICMonitoredStub(ICStub::Call_Scripted, stubCode, firstMonitorStub),
calleeScript_(calleeScript),
@ -11726,7 +11920,7 @@ ICCall_Scripted::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorSt
ICCall_Scripted &other)
{
RootedScript calleeScript(cx, other.calleeScript_);
RootedNativeObject templateObject(cx, other.templateObject_);
RootedObject templateObject(cx, other.templateObject_);
return New(space, other.jitCode(), firstMonitorStub, calleeScript, templateObject,
other.pcOffset_);
}

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

@ -430,6 +430,7 @@ class ICEntry
_(GetProp_Native) \
_(GetProp_NativeDoesNotExist) \
_(GetProp_NativePrototype) \
_(GetProp_Unboxed) \
_(GetProp_TypedObject) \
_(GetProp_CallScripted) \
_(GetProp_CallNative) \
@ -444,6 +445,7 @@ class ICEntry
_(SetProp_Fallback) \
_(SetProp_Native) \
_(SetProp_NativeAdd) \
_(SetProp_Unboxed) \
_(SetProp_TypedObject) \
_(SetProp_CallScripted) \
_(SetProp_CallNative) \
@ -4523,6 +4525,72 @@ class ICGetPropNativeDoesNotExistCompiler : public ICStubCompiler
ICStub *getStub(ICStubSpace *space);
};
class ICGetProp_Unboxed : public ICMonitoredStub
{
friend class ICStubSpace;
HeapPtrTypeObject type_;
uint32_t fieldOffset_;
ICGetProp_Unboxed(JitCode *stubCode, ICStub *firstMonitorStub, HandleTypeObject type,
uint32_t fieldOffset)
: ICMonitoredStub(ICStub::GetProp_Unboxed, stubCode, firstMonitorStub),
type_(type), fieldOffset_(fieldOffset)
{
(void) fieldOffset_; // Silence clang warning
}
public:
static inline ICGetProp_Unboxed *New(ICStubSpace *space, JitCode *code,
ICStub *firstMonitorStub, HandleTypeObject shape,
uint32_t fieldOffset)
{
if (!code)
return nullptr;
return space->allocate<ICGetProp_Unboxed>(code, firstMonitorStub, shape, fieldOffset);
}
HeapPtrTypeObject &type() {
return type_;
}
static size_t offsetOfType() {
return offsetof(ICGetProp_Unboxed, type_);
}
static size_t offsetOfFieldOffset() {
return offsetof(ICGetProp_Unboxed, fieldOffset_);
}
class Compiler : public ICStubCompiler {
protected:
ICStub *firstMonitorStub_;
RootedTypeObject type_;
uint32_t fieldOffset_;
JSValueType fieldType_;
bool generateStubCode(MacroAssembler &masm);
virtual int32_t getKey() const {
return static_cast<int32_t>(kind) | (static_cast<int32_t>(fieldType_)) << 16;
}
public:
Compiler(JSContext *cx, ICStub *firstMonitorStub,
types::TypeObject *type, uint32_t fieldOffset, JSValueType fieldType)
: ICStubCompiler(cx, ICStub::GetProp_Unboxed),
firstMonitorStub_(firstMonitorStub),
type_(cx, type),
fieldOffset_(fieldOffset),
fieldType_(fieldType)
{}
ICStub *getStub(ICStubSpace *space) {
return ICGetProp_Unboxed::New(space, getStubCode(), firstMonitorStub_,
type_, fieldOffset_);
}
};
};
static uint32_t
SimpleTypeDescrKey(SimpleTypeDescr *descr)
{
@ -5419,6 +5487,77 @@ class ICSetPropNativeAddCompiler : public ICStubCompiler
ICUpdatedStub *getStub(ICStubSpace *space);
};
class ICSetProp_Unboxed : public ICUpdatedStub
{
friend class ICStubSpace;
HeapPtrTypeObject type_;
uint32_t fieldOffset_;
ICSetProp_Unboxed(JitCode *stubCode, HandleTypeObject type, uint32_t fieldOffset)
: ICUpdatedStub(ICStub::SetProp_Unboxed, stubCode),
type_(type),
fieldOffset_(fieldOffset)
{
(void) fieldOffset_; // Silence clang warning
}
public:
static inline ICSetProp_Unboxed *New(ICStubSpace *space, JitCode *code,
HandleTypeObject type, uint32_t fieldOffset)
{
if (!code)
return nullptr;
return space->allocate<ICSetProp_Unboxed>(code, type, fieldOffset);
}
HeapPtrTypeObject &type() {
return type_;
}
static size_t offsetOfType() {
return offsetof(ICSetProp_Unboxed, type_);
}
static size_t offsetOfFieldOffset() {
return offsetof(ICSetProp_Unboxed, fieldOffset_);
}
class Compiler : public ICStubCompiler {
protected:
RootedTypeObject type_;
uint32_t fieldOffset_;
JSValueType fieldType_;
bool generateStubCode(MacroAssembler &masm);
virtual int32_t getKey() const {
return static_cast<int32_t>(kind) |
(static_cast<int32_t>(fieldType_) << 16);
}
public:
Compiler(JSContext *cx, types::TypeObject *type, uint32_t fieldOffset,
JSValueType fieldType)
: ICStubCompiler(cx, ICStub::SetProp_Unboxed),
type_(cx, type),
fieldOffset_(fieldOffset),
fieldType_(fieldType)
{}
ICUpdatedStub *getStub(ICStubSpace *space) {
ICUpdatedStub *stub = ICSetProp_Unboxed::New(space, getStubCode(),
type_, fieldOffset_);
if (!stub || !stub->initUpdatingChain(cx, space))
return nullptr;
return stub;
}
bool needsUpdateStubs() {
return fieldType_ == JSVAL_TYPE_OBJECT;
}
};
};
class ICSetProp_TypedObject : public ICUpdatedStub
{
friend class ICStubSpace;
@ -5799,17 +5938,17 @@ class ICCall_Scripted : public ICMonitoredStub
protected:
HeapPtrScript calleeScript_;
HeapPtrNativeObject templateObject_;
HeapPtrObject templateObject_;
uint32_t pcOffset_;
ICCall_Scripted(JitCode *stubCode, ICStub *firstMonitorStub,
HandleScript calleeScript, HandleNativeObject templateObject,
HandleScript calleeScript, HandleObject templateObject,
uint32_t pcOffset);
public:
static inline ICCall_Scripted *New(
ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
HandleScript calleeScript, HandleNativeObject templateObject,
HandleScript calleeScript, HandleObject templateObject,
uint32_t pcOffset)
{
if (!code)
@ -5824,7 +5963,7 @@ class ICCall_Scripted : public ICMonitoredStub
HeapPtrScript &calleeScript() {
return calleeScript_;
}
HeapPtrNativeObject &templateObject() {
HeapPtrObject &templateObject() {
return templateObject_;
}
@ -5872,7 +6011,7 @@ class ICCallScriptedCompiler : public ICCallStubCompiler {
bool isConstructing_;
bool isSpread_;
RootedScript calleeScript_;
RootedNativeObject templateObject_;
RootedObject templateObject_;
uint32_t pcOffset_;
bool generateStubCode(MacroAssembler &masm);
@ -5883,7 +6022,7 @@ class ICCallScriptedCompiler : public ICCallStubCompiler {
public:
ICCallScriptedCompiler(JSContext *cx, ICStub *firstMonitorStub,
HandleScript calleeScript, HandleNativeObject templateObject,
HandleScript calleeScript, HandleObject templateObject,
bool isConstructing, bool isSpread, uint32_t pcOffset)
: ICCallStubCompiler(cx, ICStub::Call_Scripted),
firstMonitorStub_(firstMonitorStub),

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

@ -80,12 +80,15 @@ SetElemICInspector::sawTypedArrayWrite() const
}
bool
BaselineInspector::maybeShapesForPropertyOp(jsbytecode *pc, ShapeVector &shapes)
BaselineInspector::maybeInfoForPropertyOp(jsbytecode *pc,
ShapeVector &nativeShapes,
TypeObjectVector &unboxedTypes)
{
// Return a list of shapes seen by the baseline IC for the current op.
// An empty list indicates no shapes are known, or there was an uncacheable
// access.
MOZ_ASSERT(shapes.empty());
// Return lists of native shapes and unboxed objects seen by the baseline
// IC for the current op. Empty lists indicate no shapes/types are known,
// or there was an uncacheable access.
MOZ_ASSERT(nativeShapes.empty());
MOZ_ASSERT(unboxedTypes.empty());
if (!hasBaselineScript())
return true;
@ -95,43 +98,66 @@ BaselineInspector::maybeShapesForPropertyOp(jsbytecode *pc, ShapeVector &shapes)
ICStub *stub = entry.firstStub();
while (stub->next()) {
Shape *shape;
Shape *shape = nullptr;
types::TypeObject *type = nullptr;
if (stub->isGetProp_Native()) {
shape = stub->toGetProp_Native()->shape();
} else if (stub->isSetProp_Native()) {
shape = stub->toSetProp_Native()->shape();
} else if (stub->isGetProp_Unboxed()) {
type = stub->toGetProp_Unboxed()->type();
} else if (stub->isSetProp_Unboxed()) {
type = stub->toSetProp_Unboxed()->type();
} else {
shapes.clear();
nativeShapes.clear();
unboxedTypes.clear();
return true;
}
// Don't add the same shape twice (this can happen if there are multiple
// SetProp_Native stubs with different TypeObject's).
bool found = false;
for (size_t i = 0; i < shapes.length(); i++) {
if (shapes[i] == shape) {
found = true;
break;
// Don't add the same shape/type twice (this can happen if there are
// multiple SetProp_Native stubs with different TypeObject's).
if (shape) {
bool found = false;
for (size_t i = 0; i < nativeShapes.length(); i++) {
if (nativeShapes[i] == shape) {
found = true;
break;
}
}
if (!found && !nativeShapes.append(shape))
return false;
} else {
bool found = false;
for (size_t i = 0; i < unboxedTypes.length(); i++) {
if (unboxedTypes[i] == type) {
found = true;
break;
}
}
if (!found && !unboxedTypes.append(type))
return false;
}
if (!found && !shapes.append(shape))
return false;
stub = stub->next();
}
if (stub->isGetProp_Fallback()) {
if (stub->toGetProp_Fallback()->hadUnoptimizableAccess())
shapes.clear();
if (stub->toGetProp_Fallback()->hadUnoptimizableAccess()) {
nativeShapes.clear();
unboxedTypes.clear();
}
} else {
if (stub->toSetProp_Fallback()->hadUnoptimizableAccess())
shapes.clear();
if (stub->toSetProp_Fallback()->hadUnoptimizableAccess()) {
nativeShapes.clear();
unboxedTypes.clear();
}
}
// Don't inline if there are more than 5 shapes.
if (shapes.length() > 5)
shapes.clear();
// Don't inline if there are more than 5 shapes/types.
if (nativeShapes.length() + unboxedTypes.length() > 5) {
nativeShapes.clear();
unboxedTypes.clear();
}
return true;
}
@ -413,7 +439,7 @@ BaselineInspector::hasSeenDoubleResult(jsbytecode *pc)
return false;
}
NativeObject *
JSObject *
BaselineInspector::getTemplateObject(jsbytecode *pc)
{
if (!hasBaselineScript())
@ -429,7 +455,7 @@ BaselineInspector::getTemplateObject(jsbytecode *pc)
case ICStub::Rest_Fallback:
return stub->toRest_Fallback()->templateObject();
case ICStub::Call_Scripted:
if (NativeObject *obj = stub->toCall_Scripted()->templateObject())
if (JSObject *obj = stub->toCall_Scripted()->templateObject())
return obj;
break;
default:

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

@ -93,7 +93,8 @@ class BaselineInspector
public:
typedef Vector<Shape *, 4, JitAllocPolicy> ShapeVector;
bool maybeShapesForPropertyOp(jsbytecode *pc, ShapeVector &shapes);
typedef Vector<types::TypeObject *, 4, JitAllocPolicy> TypeObjectVector;
bool maybeInfoForPropertyOp(jsbytecode *pc, ShapeVector &nativeShapes, TypeObjectVector &unboxedTypes);
SetElemICInspector setElemICInspector(jsbytecode *pc) {
return makeICInspector<SetElemICInspector>(pc, ICStub::SetElem_Fallback);
@ -109,7 +110,7 @@ class BaselineInspector
bool hasSeenDoubleResult(jsbytecode *pc);
bool hasSeenNonStringIterMore(jsbytecode *pc);
NativeObject *getTemplateObject(jsbytecode *pc);
JSObject *getTemplateObject(jsbytecode *pc);
JSObject *getTemplateObjectForNative(jsbytecode *pc, Native native);
JSObject *getTemplateObjectForClassHook(jsbytecode *pc, const Class *clasp);

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

@ -2233,33 +2233,62 @@ CodeGenerator::emitGetPropertyPolymorphic(LInstruction *ins, Register obj, Regis
const TypedOrValueRegister &output)
{
MGetPropertyPolymorphic *mir = ins->mirRaw()->toGetPropertyPolymorphic();
MOZ_ASSERT(mir->numShapes() > 1);
masm.loadObjShape(obj, scratch);
size_t total = mir->numUnboxedTypes() + mir->numShapes();
MOZ_ASSERT(total > 1);
bool typeInScratch = mir->numUnboxedTypes() > 1;
bool shapeInScratch = mir->numShapes() > 1;
Label done;
for (size_t i = 0; i < mir->numShapes(); i++) {
for (size_t i = 0; i < total; i++) {
bool unboxedType = i < mir->numUnboxedTypes();
ImmGCPtr comparePtr = unboxedType
? ImmGCPtr(mir->unboxedType(i))
: ImmGCPtr(mir->objShape(i - mir->numUnboxedTypes()));
Address addr(obj, unboxedType ? JSObject::offsetOfType() : JSObject::offsetOfShape());
if ((i == 0 && typeInScratch) || (i == mir->numUnboxedTypes() && shapeInScratch))
masm.loadPtr(addr, scratch);
bool inScratch = unboxedType ? typeInScratch : shapeInScratch;
Label next;
if (i == mir->numShapes() - 1) {
bailoutCmpPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)),
ins->snapshot());
if (i == total - 1) {
if (inScratch)
bailoutCmpPtr(Assembler::NotEqual, scratch, comparePtr, ins->snapshot());
else
bailoutCmpPtr(Assembler::NotEqual, addr, comparePtr, ins->snapshot());
} else {
masm.branchPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)), &next);
if (inScratch)
masm.branchPtr(Assembler::NotEqual, scratch, comparePtr, &next);
else
masm.branchPtr(Assembler::NotEqual, addr, comparePtr, &next);
}
Shape *shape = mir->shape(i);
if (shape->slot() < shape->numFixedSlots()) {
// Fixed slot.
masm.loadTypedOrValue(Address(obj, NativeObject::getFixedSlotOffset(shape->slot())),
output);
if (unboxedType) {
const UnboxedLayout::Property *property =
mir->unboxedType(i)->unboxedLayout().lookup(mir->name());
Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
masm.loadUnboxedProperty(propertyAddr, property->type, output);
} else {
// Dynamic slot.
uint32_t offset = (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value);
masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch);
masm.loadTypedOrValue(Address(scratch, offset), output);
Shape *shape = mir->shape(i - mir->numUnboxedTypes());
if (shape->slot() < shape->numFixedSlots()) {
// Fixed slot.
masm.loadTypedOrValue(Address(obj, NativeObject::getFixedSlotOffset(shape->slot())),
output);
} else {
// Dynamic slot.
uint32_t offset = (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value);
masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch);
masm.loadTypedOrValue(Address(scratch, offset), output);
}
}
if (i != mir->numShapes() - 1)
if (i != total - 1)
masm.jump(&done);
masm.bind(&next);
}
@ -2291,37 +2320,72 @@ CodeGenerator::emitSetPropertyPolymorphic(LInstruction *ins, Register obj, Regis
const ConstantOrRegister &value)
{
MSetPropertyPolymorphic *mir = ins->mirRaw()->toSetPropertyPolymorphic();
MOZ_ASSERT(mir->numShapes() > 1);
masm.loadObjShape(obj, scratch);
size_t total = mir->numUnboxedTypes() + mir->numShapes();
MOZ_ASSERT(total > 1);
bool typeInScratch = mir->numUnboxedTypes() > 1;
bool shapeInScratch = mir->numShapes() > 1;
Label done;
for (size_t i = 0; i < mir->numShapes(); i++) {
for (size_t i = 0; i < total; i++) {
bool unboxedType = i < mir->numUnboxedTypes();
ImmGCPtr comparePtr = unboxedType
? ImmGCPtr(mir->unboxedType(i))
: ImmGCPtr(mir->objShape(i - mir->numUnboxedTypes()));
Address addr(obj, unboxedType ? JSObject::offsetOfType() : JSObject::offsetOfShape());
if ((i == 0 && typeInScratch) || (i == mir->numUnboxedTypes() && shapeInScratch))
masm.loadPtr(addr, scratch);
bool inScratch = unboxedType ? typeInScratch : shapeInScratch;
Label next;
if (i == mir->numShapes() - 1) {
bailoutCmpPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)),
ins->snapshot());
if (i == total - 1) {
if (inScratch)
bailoutCmpPtr(Assembler::NotEqual, scratch, comparePtr, ins->snapshot());
else
bailoutCmpPtr(Assembler::NotEqual, addr, comparePtr, ins->snapshot());
} else {
masm.branchPtr(Assembler::NotEqual, scratch, ImmGCPtr(mir->objShape(i)), &next);
if (inScratch)
masm.branchPtr(Assembler::NotEqual, scratch, comparePtr, &next);
else
masm.branchPtr(Assembler::NotEqual, addr, comparePtr, &next);
}
Shape *shape = mir->shape(i);
if (shape->slot() < shape->numFixedSlots()) {
// Fixed slot.
Address addr(obj, NativeObject::getFixedSlotOffset(shape->slot()));
if (mir->needsBarrier())
emitPreBarrier(addr);
masm.storeConstantOrRegister(value, addr);
if (unboxedType) {
const UnboxedLayout::Property *property =
mir->unboxedType(i)->unboxedLayout().lookup(mir->name());
Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
if (property->type == JSVAL_TYPE_OBJECT)
masm.patchableCallPreBarrier(propertyAddr, MIRType_Object);
else if (property->type == JSVAL_TYPE_STRING)
masm.patchableCallPreBarrier(propertyAddr, MIRType_String);
else
MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(property->type));
masm.storeUnboxedProperty(propertyAddr, property->type, value, nullptr);
} else {
// Dynamic slot.
masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch);
Address addr(scratch, (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value));
if (mir->needsBarrier())
emitPreBarrier(addr);
masm.storeConstantOrRegister(value, addr);
Shape *shape = mir->shape(i - mir->numUnboxedTypes());
if (shape->slot() < shape->numFixedSlots()) {
// Fixed slot.
Address addr(obj, NativeObject::getFixedSlotOffset(shape->slot()));
if (mir->needsBarrier())
emitPreBarrier(addr);
masm.storeConstantOrRegister(value, addr);
} else {
// Dynamic slot.
masm.loadPtr(Address(obj, NativeObject::offsetOfSlots()), scratch);
Address addr(scratch, (shape->slot() - shape->numFixedSlots()) * sizeof(js::Value));
if (mir->needsBarrier())
emitPreBarrier(addr);
masm.storeConstantOrRegister(value, addr);
}
}
if (i != mir->numShapes() - 1)
if (i != total - 1)
masm.jump(&done);
masm.bind(&next);
}
@ -4573,7 +4637,7 @@ static const VMFunction NewGCObjectInfo =
void
CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate *lir)
{
PlainObject *templateObject = lir->mir()->templateObject();
JSObject *templateObject = lir->mir()->templateObject();
gc::AllocKind allocKind = templateObject->asTenured().getAllocKind();
gc::InitialHeap initialHeap = lir->mir()->initialHeap();
const js::Class *clasp = templateObject->type()->clasp();
@ -4591,7 +4655,8 @@ CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate *lir)
// Initialize based on the templateObject.
masm.bind(ool->rejoin());
bool initFixedSlots = ShouldInitFixedSlots(lir, templateObject);
bool initFixedSlots = !templateObject->is<PlainObject>() ||
ShouldInitFixedSlots(lir, &templateObject->as<PlainObject>());
masm.initGCThing(objReg, tempReg, templateObject, initFixedSlots);
}
@ -8373,8 +8438,8 @@ CodeGenerator::visitLoadUnboxedPointerT(LLoadUnboxedPointerT *lir)
bool bailOnNull;
int32_t offsetAdjustment;
if (lir->mir()->isLoadUnboxedObjectOrNull()) {
MOZ_ASSERT(lir->mir()->toLoadUnboxedObjectOrNull()->bailOnNull());
bailOnNull = true;
bailOnNull = lir->mir()->toLoadUnboxedObjectOrNull()->nullBehavior() !=
MLoadUnboxedObjectOrNull::NullNotPossible;
offsetAdjustment = lir->mir()->toLoadUnboxedObjectOrNull()->offsetAdjustment();
} else if (lir->mir()->isLoadUnboxedString()) {
bailOnNull = false;
@ -8411,11 +8476,13 @@ CodeGenerator::visitLoadTypedArrayElement(LLoadTypedArrayElement *lir)
Label fail;
if (lir->index()->isConstant()) {
Address source(elements, ToInt32(lir->index()) * width + lir->mir()->offsetAdjustment());
masm.loadFromTypedArray(arrayType, source, out, temp, &fail);
masm.loadFromTypedArray(arrayType, source, out, temp, &fail,
lir->mir()->canonicalizeDoubles());
} else {
BaseIndex source(elements, ToRegister(lir->index()), ScaleFromElemWidth(width),
lir->mir()->offsetAdjustment());
masm.loadFromTypedArray(arrayType, source, out, temp, &fail);
masm.loadFromTypedArray(arrayType, source, out, temp, &fail,
lir->mir()->canonicalizeDoubles());
}
if (fail.used())

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

@ -5514,7 +5514,9 @@ IonBuilder::createThisScriptedSingleton(JSFunction *target, MDefinition *callee)
return nullptr;
JSObject *templateObject = inspector->getTemplateObject(pc);
if (!templateObject || !templateObject->is<PlainObject>())
if (!templateObject)
return nullptr;
if (!templateObject->is<PlainObject>() && !templateObject->is<UnboxedPlainObject>())
return nullptr;
if (!templateObject->hasTenuredProto() || templateObject->getProto() != proto)
return nullptr;
@ -6181,7 +6183,7 @@ IonBuilder::jsop_compare(JSOp op)
bool
IonBuilder::jsop_newarray(uint32_t count)
{
NativeObject *templateObject = inspector->getTemplateObject(pc);
JSObject *templateObject = inspector->getTemplateObject(pc);
if (!templateObject) {
if (info().analysisMode() == Analysis_ArgumentsUsage) {
MUnknownValue *unknown = MUnknownValue::New(alloc());
@ -6218,9 +6220,9 @@ IonBuilder::jsop_newarray(uint32_t count)
ins->resultTypeSet()->convertDoubleElements(constraints());
if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
templateObject->setShouldConvertDoubleElements();
templateObject->as<ArrayObject>().setShouldConvertDoubleElements();
else
templateObject->clearShouldConvertDoubleElements();
templateObject->as<ArrayObject>().clearShouldConvertDoubleElements();
return true;
}
@ -6811,7 +6813,8 @@ IonBuilder::maybeInsertResume()
static bool
ClassHasEffectlessLookup(const Class *clasp, PropertyName *name)
{
return clasp->isNative() && !clasp->ops.lookupGeneric;
return (clasp == &UnboxedPlainObject::class_) ||
(clasp->isNative() && !clasp->ops.lookupGeneric);
}
static bool
@ -7741,9 +7744,13 @@ IonBuilder::pushReferenceLoadFromTypedObject(MDefinition *typedObj,
// there is no other barrier needed we include the null bailout with
// MLoadUnboxedObjectOrNull, which avoids the need to box the result
// for a type barrier instruction.
bool bailOnNull = barrier == BarrierKind::NoBarrier &&
!observedTypes->hasType(types::Type::NullType());
load = MLoadUnboxedObjectOrNull::New(alloc(), elements, scaledOffset, bailOnNull, adjustment);
MLoadUnboxedObjectOrNull::NullBehavior nullBehavior;
if (barrier == BarrierKind::NoBarrier && !observedTypes->hasType(types::Type::NullType()))
nullBehavior = MLoadUnboxedObjectOrNull::BailOnNull;
else
nullBehavior = MLoadUnboxedObjectOrNull::HandleNull;
load = MLoadUnboxedObjectOrNull::New(alloc(), elements, scaledOffset, nullBehavior,
adjustment);
break;
}
case ReferenceTypeDescr::TYPE_STRING: {
@ -9244,7 +9251,7 @@ IonBuilder::getDefiniteSlot(types::TemporaryTypeSet *types, PropertyName *name)
if (slot == UINT32_MAX) {
slot = propertySlot;
} else if (slot != propertySlot) {
trackOptimizationOutcome(TrackedOutcome::NotFixedSlot);
trackOptimizationOutcome(TrackedOutcome::InconsistentFixedSlot);
return UINT32_MAX;
}
}
@ -9252,6 +9259,58 @@ IonBuilder::getDefiniteSlot(types::TemporaryTypeSet *types, PropertyName *name)
return slot;
}
uint32_t
IonBuilder::getUnboxedOffset(types::TemporaryTypeSet *types, PropertyName *name, JSValueType *punboxedType)
{
if (!types || types->unknownObject()) {
trackOptimizationOutcome(TrackedOutcome::NoTypeInfo);
return UINT32_MAX;
}
uint32_t offset = UINT32_MAX;
for (size_t i = 0; i < types->getObjectCount(); i++) {
types::TypeObjectKey *type = types->getObject(i);
if (!type)
continue;
if (type->unknownProperties()) {
trackOptimizationOutcome(TrackedOutcome::UnknownProperties);
return UINT32_MAX;
}
if (type->singleton()) {
trackOptimizationOutcome(TrackedOutcome::Singleton);
return UINT32_MAX;
}
UnboxedLayout *layout = type->asTypeObject()->maybeUnboxedLayout();
if (!layout) {
trackOptimizationOutcome(TrackedOutcome::NotUnboxed);
return UINT32_MAX;
}
const UnboxedLayout::Property *property = layout->lookup(name);
if (!property) {
trackOptimizationOutcome(TrackedOutcome::StructNoField);
return UINT32_MAX;
}
if (offset == UINT32_MAX) {
offset = property->offset;
*punboxedType = property->type;
} else if (offset != property->offset) {
trackOptimizationOutcome(TrackedOutcome::InconsistentFieldOffset);
return UINT32_MAX;
} else if (*punboxedType != property->type) {
trackOptimizationOutcome(TrackedOutcome::InconsistentFieldType);
return UINT32_MAX;
}
}
return offset;
}
bool
IonBuilder::jsop_runonce()
{
@ -9679,6 +9738,11 @@ IonBuilder::jsop_getprop(PropertyName *name)
if (!getPropTryDefiniteSlot(&emitted, obj, name, barrier, types) || emitted)
return emitted;
// Try to emit loads from unboxed objects.
trackOptimizationAttempt(TrackedStrategy::GetProp_Unboxed);
if (!getPropTryUnboxed(&emitted, obj, name, barrier, types) || emitted)
return emitted;
// Try to inline a common property getter, or make a call.
trackOptimizationAttempt(TrackedStrategy::GetProp_CommonGetter);
if (!getPropTryCommonGetter(&emitted, obj, name, types) || emitted)
@ -10007,6 +10071,92 @@ IonBuilder::getPropTryDefiniteSlot(bool *emitted, MDefinition *obj, PropertyName
return true;
}
MInstruction *
IonBuilder::loadUnboxedProperty(MDefinition *obj, size_t offset, JSValueType unboxedType,
BarrierKind barrier, types::TemporaryTypeSet *types)
{
size_t scaledOffsetConstant = offset / UnboxedTypeSize(unboxedType);
MInstruction *scaledOffset = MConstant::New(alloc(), Int32Value(scaledOffsetConstant));
current->add(scaledOffset);
MInstruction *load;
switch (unboxedType) {
case JSVAL_TYPE_BOOLEAN:
load = MLoadTypedArrayElement::New(alloc(), obj, scaledOffset, Scalar::Uint8,
DoesNotRequireMemoryBarrier,
UnboxedPlainObject::offsetOfData());
load->setResultType(MIRType_Boolean);
break;
case JSVAL_TYPE_INT32:
load = MLoadTypedArrayElement::New(alloc(), obj, scaledOffset, Scalar::Int32,
DoesNotRequireMemoryBarrier,
UnboxedPlainObject::offsetOfData());
load->setResultType(MIRType_Int32);
break;
case JSVAL_TYPE_DOUBLE:
load = MLoadTypedArrayElement::New(alloc(), obj, scaledOffset, Scalar::Float64,
DoesNotRequireMemoryBarrier,
UnboxedPlainObject::offsetOfData(),
/* canonicalizeDoubles = */ false);
load->setResultType(MIRType_Double);
break;
case JSVAL_TYPE_STRING:
load = MLoadUnboxedString::New(alloc(), obj, scaledOffset,
UnboxedPlainObject::offsetOfData());
break;
case JSVAL_TYPE_OBJECT: {
MLoadUnboxedObjectOrNull::NullBehavior nullBehavior;
if (types->hasType(types::Type::NullType()) || barrier != BarrierKind::NoBarrier)
nullBehavior = MLoadUnboxedObjectOrNull::HandleNull;
else
nullBehavior = MLoadUnboxedObjectOrNull::NullNotPossible;
load = MLoadUnboxedObjectOrNull::New(alloc(), obj, scaledOffset, nullBehavior,
UnboxedPlainObject::offsetOfData());
break;
}
default:
MOZ_CRASH();
}
current->add(load);
return load;
}
bool
IonBuilder::getPropTryUnboxed(bool *emitted, MDefinition *obj, PropertyName *name,
BarrierKind barrier, types::TemporaryTypeSet *types)
{
MOZ_ASSERT(*emitted == false);
JSValueType unboxedType;
uint32_t offset = getUnboxedOffset(obj->resultTypeSet(), name, &unboxedType);
if (offset == UINT32_MAX)
return true;
if (obj->type() != MIRType_Object) {
MGuardObject *guard = MGuardObject::New(alloc(), obj);
current->add(guard);
obj = guard;
}
if (unboxedType != JSVAL_TYPE_OBJECT)
barrier = BarrierKind::NoBarrier;
MInstruction *load = loadUnboxedProperty(obj, offset, unboxedType, barrier, types);
current->push(load);
if (!pushTypeBarrier(load, types, barrier))
return false;
*emitted = true;
return true;
}
bool
IonBuilder::getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName *name,
types::TemporaryTypeSet *types)
@ -10135,16 +10285,24 @@ IonBuilder::getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName
return true;
}
static bool
CanInlinePropertyOpShapes(const BaselineInspector::ShapeVector &shapes)
bool
IonBuilder::canInlinePropertyOpShapes(const BaselineInspector::ShapeVector &nativeShapes,
const BaselineInspector::TypeObjectVector &unboxedTypes)
{
for (size_t i = 0; i < shapes.length(); i++) {
if (nativeShapes.empty() && unboxedTypes.empty()) {
trackOptimizationOutcome(TrackedOutcome::NoShapeInfo);
return false;
}
for (size_t i = 0; i < nativeShapes.length(); i++) {
// We inline the property access as long as the shape is not in
// dictionary mode. We cannot be sure that the shape is still a
// lastProperty, and calling Shape::search() on dictionary mode
// shapes that aren't lastProperty is invalid.
if (shapes[i]->inDictionary())
if (nativeShapes[i]->inDictionary()) {
trackOptimizationOutcome(TrackedOutcome::InDictionaryMode);
return false;
}
}
return true;
@ -10154,7 +10312,6 @@ static bool
GetPropertyShapes(jsid id, const BaselineInspector::ShapeVector &shapes,
BaselineInspector::ShapeVector &propShapes, bool *sameSlot)
{
MOZ_ASSERT(shapes.length() > 1);
MOZ_ASSERT(propShapes.empty());
if (!propShapes.reserve(shapes.length()))
@ -10190,30 +10347,24 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, MDefinition *obj, PropertyName
return true;
}
BaselineInspector::ShapeVector shapes(alloc());
if (!inspector->maybeShapesForPropertyOp(pc, shapes))
BaselineInspector::ShapeVector nativeShapes(alloc());
BaselineInspector::TypeObjectVector unboxedTypes(alloc());
if (!inspector->maybeInfoForPropertyOp(pc, nativeShapes, unboxedTypes))
return false;
if (shapes.empty()) {
trackOptimizationOutcome(TrackedOutcome::NoShapeInfo);
if (!canInlinePropertyOpShapes(nativeShapes, unboxedTypes))
return true;
}
if (!CanInlinePropertyOpShapes(shapes)) {
trackOptimizationOutcome(TrackedOutcome::InDictionaryMode);
return true;
}
MIRType rvalType = types->getKnownMIRType();
if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType))
rvalType = MIRType_Value;
if (shapes.length() == 1) {
if (nativeShapes.length() == 1 && unboxedTypes.empty()) {
// In the monomorphic case, use separate ShapeGuard and LoadSlot
// instructions.
spew("Inlining monomorphic GETPROP");
Shape *objShape = shapes[0];
Shape *objShape = nativeShapes[0];
obj = addShapeGuard(obj, objShape, Bailout_ShapeGuard);
Shape *shape = objShape->searchLinear(NameToId(name));
@ -10227,15 +10378,39 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, MDefinition *obj, PropertyName
return true;
}
MOZ_ASSERT(shapes.length() > 1);
if (nativeShapes.empty() && unboxedTypes.length() == 1) {
spew("Inlining monomorphic unboxed GETPROP");
types::TypeObject *unboxedType = unboxedTypes[0];
// Failures in this type guard should be treated the same as a shape guard failure.
obj = MGuardObjectType::New(alloc(), obj, unboxedType, /* bailOnEquality = */ false,
Bailout_ShapeGuard);
current->add(obj->toInstruction());
if (failedShapeGuard_)
obj->toGuardObjectType()->setNotMovable();
const UnboxedLayout::Property *property = unboxedType->unboxedLayout().lookup(name);
MInstruction *load = loadUnboxedProperty(obj, property->offset, property->type, barrier, types);
current->push(load);
if (!pushTypeBarrier(load, types, barrier))
return false;
*emitted = true;
return true;
}
MOZ_ASSERT(nativeShapes.length() + unboxedTypes.length() > 1);
spew("Inlining polymorphic GETPROP");
BaselineInspector::ShapeVector propShapes(alloc());
bool sameSlot;
if (!GetPropertyShapes(NameToId(name), shapes, propShapes, &sameSlot))
if (!GetPropertyShapes(NameToId(name), nativeShapes, propShapes, &sameSlot))
return false;
if (sameSlot) {
if (sameSlot && unboxedTypes.empty()) {
MGuardShapePolymorphic *guard = MGuardShapePolymorphic::New(alloc(), obj);
current->add(guard);
obj = guard;
@ -10243,8 +10418,8 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, MDefinition *obj, PropertyName
if (failedShapeGuard_)
guard->setNotMovable();
for (size_t i = 0; i < shapes.length(); i++) {
if (!guard->addShape(shapes[i]))
for (size_t i = 0; i < nativeShapes.length(); i++) {
if (!guard->addShape(nativeShapes[i]))
return false;
}
@ -10260,8 +10435,13 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, MDefinition *obj, PropertyName
current->add(load);
current->push(load);
for (size_t i = 0; i < shapes.length(); i++) {
if (!load->addShape(shapes[i], propShapes[i]))
for (size_t i = 0; i < nativeShapes.length(); i++) {
if (!load->addShape(nativeShapes[i], propShapes[i]))
return false;
}
for (size_t i = 0; i < unboxedTypes.length(); i++) {
if (!load->addUnboxedType(unboxedTypes[i]))
return false;
}
@ -10447,10 +10627,6 @@ IonBuilder::jsop_setprop(PropertyName *name)
return resumeAfter(ins);
}
// Add post barrier if needed.
if (NeedsPostBarrier(info(), value))
current->add(MPostWriteBarrier::New(alloc(), obj, value));
// Try to inline a common property setter, or make a call.
trackOptimizationAttempt(TrackedStrategy::SetProp_CommonSetter);
if (!setPropTryCommonSetter(&emitted, obj, name, value) || emitted)
@ -10465,6 +10641,16 @@ IonBuilder::jsop_setprop(PropertyName *name)
bool barrier = PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &obj, name, &value,
/* canModify = */ true);
// Try to emit stores to unboxed objects.
trackOptimizationAttempt(TrackedStrategy::SetProp_Unboxed);
if (!setPropTryUnboxed(&emitted, obj, name, value, barrier, objTypes) || emitted)
return emitted;
// Add post barrier if needed. The instructions above manage any post
// barriers they need directly.
if (NeedsPostBarrier(info(), value))
current->add(MPostWriteBarrier::New(alloc(), obj, value));
// Try to emit store from definite slots.
trackOptimizationAttempt(TrackedStrategy::SetProp_DefiniteSlot);
if (!setPropTryDefiniteSlot(&emitted, obj, name, value, barrier, objTypes) || emitted)
@ -10750,6 +10936,86 @@ IonBuilder::setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
return true;
}
MInstruction *
IonBuilder::storeUnboxedProperty(MDefinition *obj, size_t offset, JSValueType unboxedType,
MDefinition *value)
{
size_t scaledOffsetConstant = offset / UnboxedTypeSize(unboxedType);
MInstruction *scaledOffset = MConstant::New(alloc(), Int32Value(scaledOffsetConstant));
current->add(scaledOffset);
MInstruction *store;
switch (unboxedType) {
case JSVAL_TYPE_BOOLEAN:
store = MStoreTypedArrayElement::New(alloc(), obj, scaledOffset, value, Scalar::Uint8,
DoesNotRequireMemoryBarrier,
UnboxedPlainObject::offsetOfData());
break;
case JSVAL_TYPE_INT32:
store = MStoreTypedArrayElement::New(alloc(), obj, scaledOffset, value, Scalar::Int32,
DoesNotRequireMemoryBarrier,
UnboxedPlainObject::offsetOfData());
break;
case JSVAL_TYPE_DOUBLE:
store = MStoreTypedArrayElement::New(alloc(), obj, scaledOffset, value, Scalar::Float64,
DoesNotRequireMemoryBarrier,
UnboxedPlainObject::offsetOfData());
break;
case JSVAL_TYPE_STRING:
store = MStoreUnboxedString::New(alloc(), obj, scaledOffset, value,
UnboxedPlainObject::offsetOfData());
break;
case JSVAL_TYPE_OBJECT:
store = MStoreUnboxedObjectOrNull::New(alloc(), obj, scaledOffset, value, obj,
UnboxedPlainObject::offsetOfData());
break;
default:
MOZ_CRASH();
}
current->add(store);
return store;
}
bool
IonBuilder::setPropTryUnboxed(bool *emitted, MDefinition *obj,
PropertyName *name, MDefinition *value,
bool barrier, types::TemporaryTypeSet *objTypes)
{
MOZ_ASSERT(*emitted == false);
if (barrier) {
trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier);
return true;
}
JSValueType unboxedType;
uint32_t offset = getUnboxedOffset(obj->resultTypeSet(), name, &unboxedType);
if (offset == UINT32_MAX)
return true;
if (obj->type() != MIRType_Object) {
MGuardObject *guard = MGuardObject::New(alloc(), obj);
current->add(guard);
obj = guard;
}
MInstruction *store = storeUnboxedProperty(obj, offset, unboxedType, value);
current->push(value);
if (!resumeAfter(store))
return false;
*emitted = true;
return true;
}
bool
IonBuilder::setPropTryInlineAccess(bool *emitted, MDefinition *obj,
PropertyName *name, MDefinition *value,
@ -10762,28 +11028,22 @@ IonBuilder::setPropTryInlineAccess(bool *emitted, MDefinition *obj,
return true;
}
BaselineInspector::ShapeVector shapes(alloc());
if (!inspector->maybeShapesForPropertyOp(pc, shapes))
BaselineInspector::ShapeVector nativeShapes(alloc());
BaselineInspector::TypeObjectVector unboxedTypes(alloc());
if (!inspector->maybeInfoForPropertyOp(pc, nativeShapes, unboxedTypes))
return false;
if (shapes.empty()) {
trackOptimizationOutcome(TrackedOutcome::NoShapeInfo);
if (!canInlinePropertyOpShapes(nativeShapes, unboxedTypes))
return true;
}
if (!CanInlinePropertyOpShapes(shapes)) {
trackOptimizationOutcome(TrackedOutcome::InDictionaryMode);
return true;
}
if (shapes.length() == 1) {
if (nativeShapes.length() == 1 && unboxedTypes.empty()) {
spew("Inlining monomorphic SETPROP");
// The Baseline IC was monomorphic, so we inline the property access as
// long as the shape is not in dictionary mode. We cannot be sure
// that the shape is still a lastProperty, and calling Shape::search
// on dictionary mode shapes that aren't lastProperty is invalid.
Shape *objShape = shapes[0];
Shape *objShape = nativeShapes[0];
obj = addShapeGuard(obj, objShape, Bailout_ShapeGuard);
Shape *shape = objShape->searchLinear(NameToId(name));
@ -10798,15 +11058,37 @@ IonBuilder::setPropTryInlineAccess(bool *emitted, MDefinition *obj,
return true;
}
MOZ_ASSERT(shapes.length() > 1);
if (nativeShapes.empty() && unboxedTypes.length() == 1) {
spew("Inlining monomorphic unboxed SETPROP");
types::TypeObject *unboxedType = unboxedTypes[0];
// Failures in this type guard should be treated the same as a shape guard failure.
obj = MGuardObjectType::New(alloc(), obj, unboxedType, /* bailOnEquality = */ false,
Bailout_ShapeGuard);
current->add(obj->toInstruction());
if (failedShapeGuard_)
obj->toGuardObjectType()->setNotMovable();
const UnboxedLayout::Property *property = unboxedType->unboxedLayout().lookup(name);
storeUnboxedProperty(obj, property->offset, property->type, value);
current->push(value);
*emitted = true;
return true;
}
MOZ_ASSERT(nativeShapes.length() + unboxedTypes.length() > 1);
spew("Inlining polymorphic SETPROP");
BaselineInspector::ShapeVector propShapes(alloc());
bool sameSlot;
if (!GetPropertyShapes(NameToId(name), shapes, propShapes, &sameSlot))
if (!GetPropertyShapes(NameToId(name), nativeShapes, propShapes, &sameSlot))
return false;
if (sameSlot) {
if (sameSlot && unboxedTypes.empty()) {
MGuardShapePolymorphic *guard = MGuardShapePolymorphic::New(alloc(), obj);
current->add(guard);
obj = guard;
@ -10814,8 +11096,8 @@ IonBuilder::setPropTryInlineAccess(bool *emitted, MDefinition *obj,
if (failedShapeGuard_)
guard->setNotMovable();
for (size_t i = 0; i < shapes.length(); i++) {
if (!guard->addShape(shapes[i]))
for (size_t i = 0; i < nativeShapes.length(); i++) {
if (!guard->addShape(nativeShapes[i]))
return false;
}
@ -10828,18 +11110,23 @@ IonBuilder::setPropTryInlineAccess(bool *emitted, MDefinition *obj,
return true;
}
MSetPropertyPolymorphic *ins = MSetPropertyPolymorphic::New(alloc(), obj, value);
MSetPropertyPolymorphic *ins = MSetPropertyPolymorphic::New(alloc(), obj, value, name);
current->add(ins);
current->push(value);
for (size_t i = 0; i < shapes.length(); i++) {
Shape *objShape = shapes[i];
for (size_t i = 0; i < nativeShapes.length(); i++) {
Shape *objShape = nativeShapes[i];
Shape *shape = objShape->searchLinear(NameToId(name));
MOZ_ASSERT(shape);
if (!ins->addShape(objShape, shape))
return false;
}
for (size_t i = 0; i < unboxedTypes.length(); i++) {
if (!ins->addUnboxedType(unboxedTypes[i]))
return false;
}
if (objTypes->propertyNeedsBarrier(constraints(), NameToId(name)))
ins->setNeedsBarrier();

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

@ -12,6 +12,7 @@
#include "mozilla/LinkedList.h"
#include "jit/BaselineInspector.h"
#include "jit/BytecodeAnalysis.h"
#include "jit/IonAnalysis.h"
#include "jit/IonOptimizationLevels.h"
@ -25,7 +26,6 @@ namespace jit {
class CodeGenerator;
class CallInfo;
class BaselineInspector;
class BaselineFrameInspector;
// Records information about a baseline frame for compilation that is stable
@ -423,6 +423,8 @@ class IonBuilder
types::TemporaryTypeSet *types);
bool getPropTryDefiniteSlot(bool *emitted, MDefinition *obj, PropertyName *name,
BarrierKind barrier, types::TemporaryTypeSet *types);
bool getPropTryUnboxed(bool *emitted, MDefinition *obj, PropertyName *name,
BarrierKind barrier, types::TemporaryTypeSet *types);
bool getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName *name,
types::TemporaryTypeSet *types);
bool getPropTryInlineAccess(bool *emitted, MDefinition *obj, PropertyName *name,
@ -453,6 +455,9 @@ class IonBuilder
bool setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
PropertyName *name, MDefinition *value,
bool barrier, types::TemporaryTypeSet *objTypes);
bool setPropTryUnboxed(bool *emitted, MDefinition *obj,
PropertyName *name, MDefinition *value,
bool barrier, types::TemporaryTypeSet *objTypes);
bool setPropTryInlineAccess(bool *emitted, MDefinition *obj,
PropertyName *name, MDefinition *value,
bool barrier, types::TemporaryTypeSet *objTypes);
@ -878,8 +883,16 @@ class IonBuilder
bool testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton, PropertyName *name,
bool *testObject, bool *testString);
uint32_t getDefiniteSlot(types::TemporaryTypeSet *types, PropertyName *name);
uint32_t getUnboxedOffset(types::TemporaryTypeSet *types, PropertyName *name,
JSValueType *punboxedType);
MInstruction *loadUnboxedProperty(MDefinition *obj, size_t offset, JSValueType unboxedType,
BarrierKind barrier, types::TemporaryTypeSet *types);
MInstruction *storeUnboxedProperty(MDefinition *obj, size_t offset, JSValueType unboxedType,
MDefinition *value);
bool freezePropTypeSets(types::TemporaryTypeSet *types,
JSObject *foundProto, PropertyName *name);
bool canInlinePropertyOpShapes(const BaselineInspector::ShapeVector &nativeShapes,
const BaselineInspector::TypeObjectVector &unboxedTypes);
types::TemporaryTypeSet *bytecodeTypes(jsbytecode *pc);

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

@ -769,7 +769,6 @@ GenerateReadSlot(JSContext *cx, IonScript *ion, MacroAssembler &masm,
Shape *shape, Register object, TypedOrValueRegister output,
Label *failures = nullptr)
{
MOZ_ASSERT(obj->isNative());
// If there's a single jump to |failures|, we can patch the shape guard
// jump directly. Otherwise, jump to the end of the stub, so there's a
// common point to patch.
@ -781,11 +780,18 @@ GenerateReadSlot(JSContext *cx, IonScript *ion, MacroAssembler &masm,
if (multipleFailureJumps && !failures)
failures = &failures_;
// Guard on the shape of the object.
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
Address(object, JSObject::offsetOfShape()),
ImmGCPtr(obj->lastProperty()),
failures);
// Guard on the shape or type of the object, depending on whether it is native.
if (obj->isNative()) {
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
Address(object, JSObject::offsetOfShape()),
ImmGCPtr(obj->lastProperty()),
failures);
} else {
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
Address(object, JSObject::offsetOfType()),
ImmGCPtr(obj->type()),
failures);
}
// If we need a scratch register, use either an output register or the
// object register. After this point, we cannot jump directly to
@ -876,6 +882,24 @@ GenerateReadSlot(JSContext *cx, IonScript *ion, MacroAssembler &masm,
}
static void
GenerateReadUnboxed(JSContext *cx, IonScript *ion, MacroAssembler &masm,
IonCache::StubAttacher &attacher, JSObject *obj,
const UnboxedLayout::Property *property,
Register object, TypedOrValueRegister output)
{
// Guard on the type of the object.
attacher.branchNextStub(masm, Assembler::NotEqual,
Address(object, JSObject::offsetOfType()),
ImmGCPtr(obj->type()));
Address address(object, UnboxedPlainObject::offsetOfData() + property->offset);
masm.loadUnboxedProperty(address, property->type, output);
attacher.jumpRejoin(masm);
}
static bool
EmitGetterCall(JSContext *cx, MacroAssembler &masm,
IonCache::StubAttacher &attacher, JSObject *obj,
@ -1170,7 +1194,7 @@ CanAttachNativeGetProp(typename GetPropCache::Context cx, const GetPropCache &ca
MutableHandleNativeObject holder, MutableHandleShape shape,
bool skipArrayLen = false)
{
if (!obj || !obj->isNative())
if (!obj)
return GetPropertyIC::CanAttachNone;
// The lookup needs to be universally pure, otherwise we risk calling hooks out
@ -1305,6 +1329,30 @@ GetPropertyIC::tryAttachNative(JSContext *cx, HandleScript outerScript, IonScrip
return linkAndAttachStub(cx, masm, attacher, ion, attachKind);
}
bool
GetPropertyIC::tryAttachUnboxed(JSContext *cx, HandleScript outerScript, IonScript *ion,
HandleObject obj, HandlePropertyName name,
void *returnAddr, bool *emitted)
{
MOZ_ASSERT(canAttachStub());
MOZ_ASSERT(!*emitted);
MOZ_ASSERT(outerScript->ionScript() == ion);
if (!obj->is<UnboxedPlainObject>())
return true;
const UnboxedLayout::Property *property = obj->as<UnboxedPlainObject>().layout().lookup(name);
if (!property)
return true;
*emitted = true;
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
RepatchStubAppender attacher(*this);
GenerateReadUnboxed(cx, ion, masm, attacher, obj, property, object(), output());
return linkAndAttachStub(cx, masm, attacher, ion, "read unboxed");
}
bool
GetPropertyIC::tryAttachTypedArrayLength(JSContext *cx, HandleScript outerScript, IonScript *ion,
HandleObject obj, HandlePropertyName name, bool *emitted)
@ -1729,9 +1777,15 @@ GetPropertyIC::tryAttachStub(JSContext *cx, HandleScript outerScript, IonScript
if (!*emitted && !tryAttachNative(cx, outerScript, ion, obj, name, returnAddr, emitted))
return false;
if (!*emitted && !tryAttachUnboxed(cx, outerScript, ion, obj, name, returnAddr, emitted))
return false;
if (!*emitted && !tryAttachTypedArrayLength(cx, outerScript, ion, obj, name, emitted))
return false;
if (!*emitted)
JitSpew(JitSpew_IonIC, "Failed to attach GETPROP cache");
return true;
}
@ -1836,6 +1890,26 @@ IonCache::destroy()
{
}
// Jump to failure if a value being written is not a property for obj/id.
// This might clobber |object|.
static void
CheckTypeSetForWrite(MacroAssembler &masm, JSObject *obj, jsid id,
Register object, ConstantOrRegister value, Label *failure)
{
TypedOrValueRegister valReg = value.reg();
types::TypeObject *type = obj->type();
if (type->unknownProperties())
return;
types::HeapTypeSet *propTypes = type->maybeGetProperty(id);
MOZ_ASSERT(propTypes);
// guardTypeSet can read from type sets without triggering read barriers.
types::TypeSet::readBarrier(propTypes);
Register scratch = object;
masm.guardTypeSet(valReg, propTypes, BarrierKind::TypeSet, scratch, failure);
}
static void
GenerateSetSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
NativeObject *obj, Shape *shape, Register object, ConstantOrRegister value,
@ -1861,18 +1935,8 @@ GenerateSetSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att
ImmGCPtr(type), &failures);
if (checkTypeset) {
TypedOrValueRegister valReg = value.reg();
types::HeapTypeSet *propTypes = type->maybeGetProperty(shape->propid());
MOZ_ASSERT(propTypes);
MOZ_ASSERT(!propTypes->unknown());
// guardTypeSet can read from type sets without triggering read barriers.
types::TypeSet::readBarrier(propTypes);
Register scratchReg = object;
masm.push(scratchReg);
masm.guardTypeSet(valReg, propTypes, BarrierKind::TypeSet, scratchReg, &barrierFailure);
masm.push(object);
CheckTypeSetForWrite(masm, obj, shape->propid(), object, value, &barrierFailure);
masm.pop(object);
}
}
@ -2420,17 +2484,7 @@ GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att
// Guard that the incoming value is in the type set for the property
// if a type barrier is required.
if (checkTypeset) {
TypedOrValueRegister valReg = value.reg();
types::TypeObject *type = obj->type();
types::HeapTypeSet *propTypes = type->maybeGetProperty(obj->lastProperty()->propid());
MOZ_ASSERT(propTypes);
MOZ_ASSERT(!propTypes->unknown());
// guardTypeSet can read from type sets without triggering read barriers.
types::TypeSet::readBarrier(propTypes);
Register scratchReg = object;
masm.guardTypeSet(valReg, propTypes, BarrierKind::TypeSet, scratchReg, &failuresPopObject);
CheckTypeSetForWrite(masm, obj, obj->lastProperty()->propid(), object, value, &failuresPopObject);
masm.loadPtr(Address(StackPointer, 0), object);
}
@ -2684,6 +2738,85 @@ CanAttachNativeSetProp(JSContext *cx, HandleObject obj, HandleId id, ConstantOrR
return SetPropertyIC::CanAttachNone;
}
static void
GenerateSetUnboxed(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
JSObject *obj, jsid id, uint32_t unboxedOffset, JSValueType unboxedType,
Register object, ConstantOrRegister value, bool checkTypeset)
{
Label failure, failurePopObject;
// Guard on the type of the object.
masm.branchPtr(Assembler::NotEqual,
Address(object, JSObject::offsetOfType()),
ImmGCPtr(obj->type()), &failure);
if (checkTypeset) {
masm.push(object);
CheckTypeSetForWrite(masm, obj, id, object, value, &failurePopObject);
masm.pop(object);
}
Address address(object, UnboxedPlainObject::offsetOfData() + unboxedOffset);
if (cx->zone()->needsIncrementalBarrier()) {
if (unboxedType == JSVAL_TYPE_OBJECT)
masm.callPreBarrier(address, MIRType_Object);
else if (unboxedType == JSVAL_TYPE_STRING)
masm.callPreBarrier(address, MIRType_String);
else
MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(unboxedType));
}
// If the unboxed object's type has known properties, then instances have
// never been converted to native objects and the type set check performed
// above ensures the value being written can be stored in the unboxed
// object.
Label *storeFailure = obj->type()->unknownProperties() ? &failure : nullptr;
masm.storeUnboxedProperty(address, unboxedType, value, storeFailure);
attacher.jumpRejoin(masm);
masm.bind(&failurePopObject);
masm.pop(object);
masm.bind(&failure);
attacher.jumpNextStub(masm);
}
bool
SetPropertyIC::attachSetUnboxed(JSContext *cx, HandleScript outerScript, IonScript *ion,
HandleObject obj, HandleId id,
uint32_t unboxedOffset, JSValueType unboxedType,
bool checkTypeset)
{
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
RepatchStubAppender attacher(*this);
GenerateSetUnboxed(cx, masm, attacher, obj, id, unboxedOffset, unboxedType,
object(), value(), needsTypeBarrier());
return linkAndAttachStub(cx, masm, attacher, ion, "set_unboxed");
}
static bool
CanAttachSetUnboxed(JSContext *cx, HandleObject obj, HandleId id, ConstantOrRegister val,
bool needsTypeBarrier, bool *checkTypeset,
uint32_t *unboxedOffset, JSValueType *unboxedType)
{
if (!obj->is<UnboxedPlainObject>())
return false;
const UnboxedLayout::Property *property = obj->as<UnboxedPlainObject>().layout().lookup(id);
if (property) {
if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, id, val, checkTypeset))
return false;
*unboxedOffset = property->offset;
*unboxedType = property->type;
return true;
}
return false;
}
bool
SetPropertyIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
HandleValue value)
@ -2748,6 +2881,21 @@ SetPropertyIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
return false;
addedSetterStub = true;
}
checkTypeset = false;
uint32_t unboxedOffset;
JSValueType unboxedType;
if (!addedSetterStub && CanAttachSetUnboxed(cx, obj, id, cache.value(),
cache.needsTypeBarrier(),
&checkTypeset, &unboxedOffset, &unboxedType))
{
if (!cache.attachSetUnboxed(cx, script, ion, obj, id, unboxedOffset, unboxedType,
checkTypeset))
{
return false;
}
addedSetterStub = true;
}
}
uint32_t oldSlots = obj->is<NativeObject>() ? obj->as<NativeObject>().numDynamicSlots() : 0;
@ -2767,8 +2915,12 @@ SetPropertyIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
RootedNativeObject nobj(cx, &obj->as<NativeObject>());
if (!cache.attachAddSlot(cx, script, ion, nobj, oldShape, oldType, checkTypeset))
return false;
addedSetterStub = true;
}
if (!addedSetterStub)
JitSpew(JitSpew_IonIC, "Failed to attach SETPROP cache");
return true;
}

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

@ -669,6 +669,10 @@ class GetPropertyIC : public RepatchIonCache
HandleObject obj, HandlePropertyName name,
void *returnAddr, bool *emitted);
bool tryAttachUnboxed(JSContext *cx, HandleScript outerScript, IonScript *ion,
HandleObject obj, HandlePropertyName name,
void *returnAddr, bool *emitted);
bool tryAttachTypedArrayLength(JSContext *cx, HandleScript outerScript, IonScript *ion,
HandleObject obj, HandlePropertyName name, bool *emitted);
@ -747,6 +751,11 @@ class SetPropertyIC : public RepatchIonCache
HandleNativeObject obj, HandleShape oldShape, HandleTypeObject oldType,
bool checkTypeset);
bool attachSetUnboxed(JSContext *cx, HandleScript outerScript, IonScript *ion,
HandleObject obj, HandleId id,
uint32_t unboxedOffset, JSValueType unboxedType,
bool checkTypeset);
bool attachGenericProxy(JSContext *cx, HandleScript outerScript, IonScript *ion,
void *returnAddr);

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

@ -2619,12 +2619,12 @@ LIRGenerator::visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull *ins)
if (ins->type() == MIRType_Object) {
LLoadUnboxedPointerT *lir = new(alloc()) LLoadUnboxedPointerT(useRegister(ins->elements()),
useRegisterOrConstant(ins->index()));
if (ins->bailOnNull())
if (ins->nullBehavior() == MLoadUnboxedObjectOrNull::BailOnNull)
assignSnapshot(lir, Bailout_TypeBarrierO);
define(lir, ins);
} else {
MOZ_ASSERT(ins->type() == MIRType_Value);
MOZ_ASSERT(!ins->bailOnNull());
MOZ_ASSERT(ins->nullBehavior() != MLoadUnboxedObjectOrNull::BailOnNull);
LLoadUnboxedPointerV *lir = new(alloc()) LLoadUnboxedPointerV(useRegister(ins->elements()),
useRegisterOrConstant(ins->index()));
@ -2848,7 +2848,7 @@ LIRGenerator::visitLoadTypedArrayElement(MLoadTypedArrayElement *ins)
const LUse elements = useRegister(ins->elements());
const LAllocation index = useRegisterOrConstant(ins->index());
MOZ_ASSERT(IsNumberType(ins->type()));
MOZ_ASSERT(IsNumberType(ins->type()) || ins->type() == MIRType_Boolean);
// We need a temp register for Uint32Array with known double result.
LDefinition tempDef = LDefinition::BogusTemp();

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

@ -3647,8 +3647,9 @@ MNewObject::shouldUseVM() const
bool
MCreateThisWithTemplate::canRecoverOnBailout() const
{
MOZ_ASSERT(!templateObject()->denseElementsAreCopyOnWrite());
MOZ_ASSERT(!templateObject()->is<ArrayObject>());
MOZ_ASSERT(templateObject()->is<PlainObject>() || templateObject()->is<UnboxedPlainObject>());
MOZ_ASSERT_IF(templateObject()->is<PlainObject>(),
!templateObject()->as<PlainObject>().denseElementsAreCopyOnWrite());
return true;
}
@ -3661,7 +3662,7 @@ MObjectState::MObjectState(MDefinition *obj)
if (obj->isNewObject())
templateObject = obj->toNewObject()->templateObject();
else if (obj->isCreateThisWithTemplate())
templateObject = obj->toCreateThisWithTemplate()->templateObject();
templateObject = &obj->toCreateThisWithTemplate()->templateObject()->as<PlainObject>();
else
templateObject = obj->toNewCallObject()->templateObject();
numSlots_ = templateObject->slotSpan();
@ -4727,10 +4728,12 @@ AddTypeGuard(TempAllocator &alloc, MBasicBlock *current, MDefinition *obj,
{
MInstruction *guard;
if (type->isTypeObject())
guard = MGuardObjectType::New(alloc, obj, type->asTypeObject(), bailOnEquality);
else
if (type->isTypeObject()) {
guard = MGuardObjectType::New(alloc, obj, type->asTypeObject(), bailOnEquality,
Bailout_ObjectIdentityOrTypeGuard);
} else {
guard = MGuardObjectIdentity::New(alloc, obj, type->asSingleObject(), bailOnEquality);
}
current->add(guard);

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

@ -4273,8 +4273,8 @@ class MCreateThisWithTemplate
}
// Template for |this|, provided by TI.
PlainObject *templateObject() const {
return &getOperand(0)->toConstant()->value().toObject().as<PlainObject>();
JSObject *templateObject() const {
return &getOperand(0)->toConstant()->value().toObject();
}
gc::InitialHeap initialHeap() const {
@ -8059,21 +8059,29 @@ class MLoadUnboxedObjectOrNull
: public MBinaryInstruction,
public SingleObjectPolicy::Data
{
bool bailOnNull_;
public:
enum NullBehavior {
HandleNull,
BailOnNull,
NullNotPossible
};
private:
NullBehavior nullBehavior_;
int32_t offsetAdjustment_;
MLoadUnboxedObjectOrNull(MDefinition *elements, MDefinition *index,
bool bailOnNull, int32_t offsetAdjustment)
NullBehavior nullBehavior, int32_t offsetAdjustment)
: MBinaryInstruction(elements, index),
bailOnNull_(bailOnNull),
nullBehavior_(nullBehavior),
offsetAdjustment_(offsetAdjustment)
{
if (bailOnNull) {
if (nullBehavior == BailOnNull) {
// Don't eliminate loads which bail out on a null pointer, for the
// same reason as MLoadElement.
setGuard();
}
setResultType(bailOnNull ? MIRType_Object : MIRType_Value);
setResultType(nullBehavior == HandleNull ? MIRType_Value : MIRType_Object);
setMovable();
MOZ_ASSERT(IsValidElementsType(elements, offsetAdjustment));
MOZ_ASSERT(index->type() == MIRType_Int32);
@ -8084,8 +8092,9 @@ class MLoadUnboxedObjectOrNull
static MLoadUnboxedObjectOrNull *New(TempAllocator &alloc,
MDefinition *elements, MDefinition *index,
bool bailOnNull, int32_t offsetAdjustment) {
return new(alloc) MLoadUnboxedObjectOrNull(elements, index, bailOnNull, offsetAdjustment);
NullBehavior nullBehavior, int32_t offsetAdjustment) {
return new(alloc) MLoadUnboxedObjectOrNull(elements, index, nullBehavior,
offsetAdjustment);
}
MDefinition *elements() const {
@ -8094,20 +8103,20 @@ class MLoadUnboxedObjectOrNull
MDefinition *index() const {
return getOperand(1);
}
bool bailOnNull() const {
return bailOnNull_;
NullBehavior nullBehavior() const {
return nullBehavior_;
}
int32_t offsetAdjustment() const {
return offsetAdjustment_;
}
bool fallible() const {
return bailOnNull();
return nullBehavior() == BailOnNull;
}
bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE {
if (!ins->isLoadUnboxedObjectOrNull())
return false;
const MLoadUnboxedObjectOrNull *other = ins->toLoadUnboxedObjectOrNull();
if (bailOnNull() != other->bailOnNull())
if (nullBehavior() != other->nullBehavior())
return false;
if (offsetAdjustment() != other->offsetAdjustment())
return false;
@ -8140,7 +8149,8 @@ class MLoadUnboxedString
INSTRUCTION_HEADER(LoadUnboxedString)
static MLoadUnboxedString *New(TempAllocator &alloc,
MDefinition *elements, MDefinition *index, int32_t offsetAdjustment) {
MDefinition *elements, MDefinition *index,
int32_t offsetAdjustment = 0) {
return new(alloc) MLoadUnboxedString(elements, index, offsetAdjustment);
}
@ -8331,7 +8341,7 @@ class MStoreUnboxedObjectOrNull
static MStoreUnboxedObjectOrNull *New(TempAllocator &alloc,
MDefinition *elements, MDefinition *index,
MDefinition *value, MDefinition *typedObj,
int32_t offsetAdjustment) {
int32_t offsetAdjustment = 0) {
return new(alloc) MStoreUnboxedObjectOrNull(elements, index, value, typedObj,
offsetAdjustment);
}
@ -8386,7 +8396,7 @@ class MStoreUnboxedString
static MStoreUnboxedString *New(TempAllocator &alloc,
MDefinition *elements, MDefinition *index,
MDefinition *value, int32_t offsetAdjustment) {
MDefinition *value, int32_t offsetAdjustment = 0) {
return new(alloc) MStoreUnboxedString(elements, index, value, offsetAdjustment);
}
MDefinition *elements() const {
@ -8581,14 +8591,16 @@ class MLoadTypedArrayElement
Scalar::Type arrayType_;
bool requiresBarrier_;
int32_t offsetAdjustment_;
bool canonicalizeDoubles_;
MLoadTypedArrayElement(MDefinition *elements, MDefinition *index,
Scalar::Type arrayType, MemoryBarrierRequirement requiresBarrier,
int32_t offsetAdjustment)
int32_t offsetAdjustment, bool canonicalizeDoubles)
: MBinaryInstruction(elements, index),
arrayType_(arrayType),
requiresBarrier_(requiresBarrier == DoesRequireMemoryBarrier),
offsetAdjustment_(offsetAdjustment)
offsetAdjustment_(offsetAdjustment),
canonicalizeDoubles_(canonicalizeDoubles)
{
setResultType(MIRType_Value);
if (requiresBarrier_)
@ -8606,10 +8618,12 @@ class MLoadTypedArrayElement
static MLoadTypedArrayElement *New(TempAllocator &alloc, MDefinition *elements, MDefinition *index,
Scalar::Type arrayType,
MemoryBarrierRequirement requiresBarrier=DoesNotRequireMemoryBarrier,
int32_t offsetAdjustment = 0)
int32_t offsetAdjustment = 0,
bool canonicalizeDoubles = true)
{
return new(alloc) MLoadTypedArrayElement(elements, index, arrayType,
requiresBarrier, offsetAdjustment);
requiresBarrier, offsetAdjustment,
canonicalizeDoubles);
}
Scalar::Type arrayType() const {
@ -8622,6 +8636,9 @@ class MLoadTypedArrayElement
bool requiresMemoryBarrier() const {
return requiresBarrier_;
}
bool canonicalizeDoubles() const {
return canonicalizeDoubles_;
}
MDefinition *elements() const {
return getOperand(0);
}
@ -8649,6 +8666,8 @@ class MLoadTypedArrayElement
return false;
if (offsetAdjustment() != other->offsetAdjustment())
return false;
if (canonicalizeDoubles() != other->canonicalizeDoubles())
return false;
return congruentIfOperandsEqual(other);
}
@ -9340,8 +9359,8 @@ class MGetPropertyCache
bool updateForReplacement(MDefinition *ins) MOZ_OVERRIDE;
};
// Emit code to load a value from an object's slots if its shape matches
// one of the shapes observed by the baseline IC, else bails out.
// Emit code to load a value from an object if its shape/type matches one of
// the shapes/types observed by the baseline IC, else bails out.
class MGetPropertyPolymorphic
: public MUnaryInstruction,
public SingleObjectPolicy::Data
@ -9354,12 +9373,14 @@ class MGetPropertyPolymorphic
Shape *shape;
};
Vector<Entry, 4, JitAllocPolicy> shapes_;
Vector<Entry, 4, JitAllocPolicy> nativeShapes_;
Vector<types::TypeObject *, 4, JitAllocPolicy> unboxedTypes_;
AlwaysTenuredPropertyName name_;
MGetPropertyPolymorphic(TempAllocator &alloc, MDefinition *obj, PropertyName *name)
: MUnaryInstruction(obj),
shapes_(alloc),
nativeShapes_(alloc),
unboxedTypes_(alloc),
name_(name)
{
setGuard();
@ -9367,10 +9388,6 @@ class MGetPropertyPolymorphic
setResultType(MIRType_Value);
}
PropertyName *name() const {
return name_;
}
public:
INSTRUCTION_HEADER(GetPropertyPolymorphic)
@ -9390,22 +9407,35 @@ class MGetPropertyPolymorphic
Entry entry;
entry.objShape = objShape;
entry.shape = shape;
return shapes_.append(entry);
return nativeShapes_.append(entry);
}
bool addUnboxedType(types::TypeObject *type) {
return unboxedTypes_.append(type);
}
size_t numShapes() const {
return shapes_.length();
return nativeShapes_.length();
}
Shape *objShape(size_t i) const {
return shapes_[i].objShape;
return nativeShapes_[i].objShape;
}
Shape *shape(size_t i) const {
return shapes_[i].shape;
return nativeShapes_[i].shape;
}
size_t numUnboxedTypes() const {
return unboxedTypes_.length();
}
types::TypeObject *unboxedType(size_t i) const {
return unboxedTypes_[i];
}
PropertyName *name() const {
return name_;
}
MDefinition *obj() const {
return getOperand(0);
}
AliasSet getAliasSet() const MOZ_OVERRIDE {
return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | AliasSet::DynamicSlot);
return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | AliasSet::DynamicSlot |
(unboxedTypes_.empty() ? 0 : (AliasSet::TypedArrayElement | AliasSet::Element)));
}
bool mightAlias(const MDefinition *store) const MOZ_OVERRIDE;
@ -9425,12 +9455,17 @@ class MSetPropertyPolymorphic
Shape *shape;
};
Vector<Entry, 4, JitAllocPolicy> shapes_;
Vector<Entry, 4, JitAllocPolicy> nativeShapes_;
Vector<types::TypeObject *, 4, JitAllocPolicy> unboxedTypes_;
AlwaysTenuredPropertyName name_;
bool needsBarrier_;
MSetPropertyPolymorphic(TempAllocator &alloc, MDefinition *obj, MDefinition *value)
MSetPropertyPolymorphic(TempAllocator &alloc, MDefinition *obj, MDefinition *value,
PropertyName *name)
: MBinaryInstruction(obj, value),
shapes_(alloc),
nativeShapes_(alloc),
unboxedTypes_(alloc),
name_(name),
needsBarrier_(false)
{
}
@ -9438,24 +9473,37 @@ class MSetPropertyPolymorphic
public:
INSTRUCTION_HEADER(SetPropertyPolymorphic)
static MSetPropertyPolymorphic *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value) {
return new(alloc) MSetPropertyPolymorphic(alloc, obj, value);
static MSetPropertyPolymorphic *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value,
PropertyName *name) {
return new(alloc) MSetPropertyPolymorphic(alloc, obj, value, name);
}
bool addShape(Shape *objShape, Shape *shape) {
Entry entry;
entry.objShape = objShape;
entry.shape = shape;
return shapes_.append(entry);
return nativeShapes_.append(entry);
}
bool addUnboxedType(types::TypeObject *type) {
return unboxedTypes_.append(type);
}
size_t numShapes() const {
return shapes_.length();
return nativeShapes_.length();
}
Shape *objShape(size_t i) const {
return shapes_[i].objShape;
return nativeShapes_[i].objShape;
}
Shape *shape(size_t i) const {
return shapes_[i].shape;
return nativeShapes_[i].shape;
}
size_t numUnboxedTypes() const {
return unboxedTypes_.length();
}
types::TypeObject *unboxedType(size_t i) const {
return unboxedTypes_[i];
}
PropertyName *name() const {
return name_;
}
MDefinition *obj() const {
return getOperand(0);
@ -9470,7 +9518,8 @@ class MSetPropertyPolymorphic
needsBarrier_ = true;
}
AliasSet getAliasSet() const MOZ_OVERRIDE {
return AliasSet::Store(AliasSet::ObjectFields | AliasSet::FixedSlot | AliasSet::DynamicSlot);
return AliasSet::Store(AliasSet::ObjectFields | AliasSet::FixedSlot | AliasSet::DynamicSlot |
(unboxedTypes_.empty() ? 0 : (AliasSet::TypedArrayElement | AliasSet::Element)));
}
};
@ -9805,11 +9854,14 @@ class MGuardObjectType
{
AlwaysTenured<types::TypeObject *> typeObject_;
bool bailOnEquality_;
BailoutKind bailoutKind_;
MGuardObjectType(MDefinition *obj, types::TypeObject *typeObject, bool bailOnEquality)
MGuardObjectType(MDefinition *obj, types::TypeObject *typeObject, bool bailOnEquality,
BailoutKind bailoutKind)
: MUnaryInstruction(obj),
typeObject_(typeObject),
bailOnEquality_(bailOnEquality)
bailOnEquality_(bailOnEquality),
bailoutKind_(bailoutKind)
{
setGuard();
setMovable();
@ -9820,8 +9872,8 @@ class MGuardObjectType
INSTRUCTION_HEADER(GuardObjectType)
static MGuardObjectType *New(TempAllocator &alloc, MDefinition *obj, types::TypeObject *typeObject,
bool bailOnEquality) {
return new(alloc) MGuardObjectType(obj, typeObject, bailOnEquality);
bool bailOnEquality, BailoutKind bailoutKind) {
return new(alloc) MGuardObjectType(obj, typeObject, bailOnEquality, bailoutKind);
}
MDefinition *obj() const {
@ -9833,6 +9885,9 @@ class MGuardObjectType
bool bailOnEquality() const {
return bailOnEquality_;
}
BailoutKind bailoutKind() const {
return bailoutKind_;
}
bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE {
if (!ins->isGuardObjectType())
return false;
@ -9840,6 +9895,8 @@ class MGuardObjectType
return false;
if (bailOnEquality() != ins->toGuardObjectType()->bailOnEquality())
return false;
if (bailoutKind() != ins->toGuardObjectType()->bailoutKind())
return false;
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const MOZ_OVERRIDE {

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

@ -306,7 +306,7 @@ MacroAssembler::storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister val
template<typename T>
void
MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const T &src, AnyRegister dest, Register temp,
Label *fail)
Label *fail, bool canonicalizeDoubles)
{
switch (arrayType) {
case Scalar::Int8:
@ -344,7 +344,8 @@ MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const T &src, AnyRegi
break;
case Scalar::Float64:
loadDouble(src, dest.fpu());
canonicalizeDouble(dest.fpu());
if (canonicalizeDoubles)
canonicalizeDouble(dest.fpu());
break;
default:
MOZ_CRASH("Invalid typed array type");
@ -352,9 +353,9 @@ MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const T &src, AnyRegi
}
template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const Address &src, AnyRegister dest,
Register temp, Label *fail);
Register temp, Label *fail, bool canonicalizeDoubles);
template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const BaseIndex &src, AnyRegister dest,
Register temp, Label *fail);
Register temp, Label *fail, bool canonicalizeDoubles);
template<typename T>
void
@ -621,6 +622,214 @@ MacroAssembler::atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type arrayType,
const Register &value, const BaseIndex &mem,
Register temp1, Register temp2, AnyRegister output);
template <typename T>
void
MacroAssembler::loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output)
{
switch (type) {
case JSVAL_TYPE_BOOLEAN:
case JSVAL_TYPE_INT32:
case JSVAL_TYPE_STRING: {
Register outReg;
if (output.hasValue()) {
outReg = output.valueReg().scratchReg();
} else {
MOZ_ASSERT(output.type() == MIRTypeFromValueType(type));
outReg = output.typedReg().gpr();
}
switch (type) {
case JSVAL_TYPE_BOOLEAN:
load8ZeroExtend(address, outReg);
break;
case JSVAL_TYPE_INT32:
load32(address, outReg);
break;
case JSVAL_TYPE_STRING:
loadPtr(address, outReg);
break;
default:
MOZ_CRASH();
}
if (output.hasValue())
tagValue(type, outReg, output.valueReg());
break;
}
case JSVAL_TYPE_OBJECT:
if (output.hasValue()) {
Register scratch = output.valueReg().scratchReg();
loadPtr(address, scratch);
Label notNull, done;
branchPtr(Assembler::NotEqual, scratch, ImmWord(0), &notNull);
moveValue(NullValue(), output.valueReg());
jump(&done);
bind(&notNull);
tagValue(JSVAL_TYPE_OBJECT, scratch, output.valueReg());
bind(&done);
} else {
// Reading null can't be possible here, as otherwise the result
// would be a value (either because null has been read before or
// because there is a barrier).
Register reg = output.typedReg().gpr();
loadPtr(address, reg);
#ifdef DEBUG
Label ok;
branchTestPtr(Assembler::NonZero, reg, reg, &ok);
assumeUnreachable("Null not possible");
bind(&ok);
#endif
}
break;
case JSVAL_TYPE_DOUBLE:
// Note: doubles in unboxed objects are not accessed through other
// views and do not need canonicalization.
if (output.hasValue())
loadValue(address, output.valueReg());
else
loadDouble(address, output.typedReg().fpu());
break;
default:
MOZ_CRASH();
}
}
template void
MacroAssembler::loadUnboxedProperty(Address address, JSValueType type,
TypedOrValueRegister output);
template void
MacroAssembler::loadUnboxedProperty(BaseIndex address, JSValueType type,
TypedOrValueRegister output);
template <typename T>
void
MacroAssembler::storeUnboxedProperty(T address, JSValueType type,
ConstantOrRegister value, Label *failure)
{
switch (type) {
case JSVAL_TYPE_BOOLEAN:
if (value.constant()) {
if (value.value().isBoolean())
store8(Imm32(value.value().toBoolean()), address);
else
jump(failure);
} else if (value.reg().hasTyped()) {
if (value.reg().type() == MIRType_Boolean)
store8(value.reg().typedReg().gpr(), address);
else
jump(failure);
} else {
if (failure)
branchTestBoolean(Assembler::NotEqual, value.reg().valueReg(), failure);
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 1);
}
break;
case JSVAL_TYPE_INT32:
if (value.constant()) {
if (value.value().isInt32())
store32(Imm32(value.value().toInt32()), address);
else
jump(failure);
} else if (value.reg().hasTyped()) {
if (value.reg().type() == MIRType_Int32)
store32(value.reg().typedReg().gpr(), address);
else
jump(failure);
} else {
if (failure)
branchTestInt32(Assembler::NotEqual, value.reg().valueReg(), failure);
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 4);
}
break;
case JSVAL_TYPE_DOUBLE:
if (value.constant()) {
if (value.value().isNumber()) {
loadConstantDouble(value.value().toNumber(), ScratchDoubleReg);
storeDouble(ScratchDoubleReg, address);
} else {
jump(failure);
}
} else if (value.reg().hasTyped()) {
if (value.reg().type() == MIRType_Int32) {
convertInt32ToDouble(value.reg().typedReg().gpr(), ScratchDoubleReg);
storeDouble(ScratchDoubleReg, address);
} else if (value.reg().type() == MIRType_Double) {
storeDouble(value.reg().typedReg().fpu(), address);
} else {
jump(failure);
}
} else {
if (failure)
branchTestNumber(Assembler::NotEqual, value.reg().valueReg(), failure);
unboxValue(value.reg().valueReg(), AnyRegister(ScratchDoubleReg));
storeDouble(ScratchDoubleReg, address);
}
break;
case JSVAL_TYPE_OBJECT:
if (value.constant()) {
if (value.value().isObjectOrNull())
storePtr(ImmGCPtr(value.value().toObjectOrNull()), address);
else
jump(failure);
} else if (value.reg().hasTyped()) {
MOZ_ASSERT(value.reg().type() != MIRType_Null);
if (value.reg().type() == MIRType_Object)
storePtr(value.reg().typedReg().gpr(), address);
else
jump(failure);
} else {
if (failure) {
Label ok;
branchTestNull(Assembler::Equal, value.reg().valueReg(), &ok);
branchTestObject(Assembler::NotEqual, value.reg().valueReg(), failure);
bind(&ok);
}
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ sizeof(uintptr_t));
}
break;
case JSVAL_TYPE_STRING:
if (value.constant()) {
if (value.value().isString())
storePtr(ImmGCPtr(value.value().toString()), address);
else
jump(failure);
} else if (value.reg().hasTyped()) {
if (value.reg().type() == MIRType_String)
storePtr(value.reg().typedReg().gpr(), address);
else
jump(failure);
} else {
if (failure)
branchTestString(Assembler::NotEqual, value.reg().valueReg(), failure);
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ sizeof(uintptr_t));
}
break;
default:
MOZ_CRASH();
}
}
template void
MacroAssembler::storeUnboxedProperty(Address address, JSValueType type,
ConstantOrRegister value, Label *failure);
template void
MacroAssembler::storeUnboxedProperty(BaseIndex address, JSValueType type,
ConstantOrRegister value, Label *failure);
// Inlined version of gc::CheckAllocatorState that checks the bare essentials
// and bails for anything that cannot be handled with our jit allocators.
void
@ -780,22 +989,22 @@ MacroAssembler::allocateObject(Register result, Register slots, gc::AllocKind al
callFreeStub(slots);
jump(fail);
bind(&success);
breakpoint();
}
void
MacroAssembler::newGCThing(Register result, Register temp, NativeObject *templateObj,
gc::InitialHeap initialHeap, Label *fail)
MacroAssembler::newGCThing(Register result, Register temp, JSObject *templateObj,
gc::InitialHeap initialHeap, Label *fail)
{
// This method does not initialize the object: if external slots get
// allocated into |temp|, there is no easy way for us to ensure the caller
// frees them. Instead just assert this case does not happen.
MOZ_ASSERT(!templateObj->numDynamicSlots());
MOZ_ASSERT_IF(templateObj->isNative(), !templateObj->as<NativeObject>().numDynamicSlots());
gc::AllocKind allocKind = templateObj->asTenured().getAllocKind();
MOZ_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
allocateObject(result, temp, allocKind, templateObj->numDynamicSlots(), initialHeap, fail);
allocateObject(result, temp, allocKind, 0, initialHeap, fail);
}
void
@ -1030,18 +1239,37 @@ MacroAssembler::initGCThing(Register obj, Register slots, JSObject *templateObj,
}
}
} else if (templateObj->is<InlineTypedObject>()) {
InlineTypedObject *ntemplate = &templateObj->as<InlineTypedObject>();
size_t nbytes = templateObj->as<InlineTypedObject>().size();
const uint8_t *memory = templateObj->as<InlineTypedObject>().inlineTypedMem();
// Memcpy the contents of the template object to the new object.
size_t nbytes = ntemplate->size();
size_t offset = 0;
while (nbytes) {
uintptr_t value = *(uintptr_t *)(ntemplate->inlineTypedMem() + offset);
uintptr_t value = *(uintptr_t *)(memory + offset);
storePtr(ImmWord(value),
Address(obj, InlineTypedObject::offsetOfDataStart() + offset));
nbytes = (nbytes < sizeof(uintptr_t)) ? 0 : nbytes - sizeof(uintptr_t);
offset += sizeof(uintptr_t);
}
} else if (templateObj->is<UnboxedPlainObject>()) {
const UnboxedLayout &layout = templateObj->as<UnboxedPlainObject>().layout();
// Initialize reference fields of the object, per UnboxedPlainObject::create.
if (const int32_t *list = layout.traceList()) {
while (*list != -1) {
storePtr(ImmGCPtr(GetJitContext()->runtime->names().empty),
Address(obj, UnboxedPlainObject::offsetOfData() + *list));
list++;
}
list++;
while (*list != -1) {
storePtr(ImmWord(0),
Address(obj, UnboxedPlainObject::offsetOfData() + *list));
list++;
}
// Unboxed objects don't have Values to initialize.
MOZ_ASSERT(*(list + 1) == -1);
}
} else {
MOZ_CRASH("Unknown object");
}

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

@ -694,7 +694,8 @@ class MacroAssembler : public MacroAssemblerSpecific
}
template<typename T>
void loadFromTypedArray(Scalar::Type arrayType, const T &src, AnyRegister dest, Register temp, Label *fail);
void loadFromTypedArray(Scalar::Type arrayType, const T &src, AnyRegister dest, Register temp, Label *fail,
bool canonicalizeDoubles = true);
template<typename T>
void loadFromTypedArray(Scalar::Type arrayType, const T &src, const ValueOperand &dest, bool allowDouble,
@ -732,6 +733,17 @@ class MacroAssembler : public MacroAssemblerSpecific
void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const BaseIndex &dest);
void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const Address &dest);
// Load a property from an UnboxedPlainObject.
template <typename T>
void loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output);
// Store a property to an UnboxedPlainObject, without triggering barriers.
// If failure is null, the value definitely has a type suitable for storing
// in the property.
template <typename T>
void storeUnboxedProperty(T address, JSValueType type,
ConstantOrRegister value, Label *failure);
Register extractString(const Address &address, Register scratch) {
return extractObject(address, scratch);
}
@ -804,7 +816,7 @@ class MacroAssembler : public MacroAssemblerSpecific
void createGCObject(Register result, Register temp, JSObject *templateObj,
gc::InitialHeap initialHeap, Label *fail, bool initFixedSlots = true);
void newGCThing(Register result, Register temp, NativeObject *templateObj,
void newGCThing(Register result, Register temp, JSObject *templateObj,
gc::InitialHeap initialHeap, Label *fail);
void initGCThing(Register obj, Register temp, JSObject *templateObj,
bool initFixedSlots = true);

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

@ -32,6 +32,8 @@ namespace jit {
"getprop TypedObject") \
_(GetProp_DefiniteSlot, \
"getprop definite slot") \
_(GetProp_Unboxed, \
"getprop unboxed object") \
_(GetProp_CommonGetter, \
"getprop common getter") \
_(GetProp_InlineAccess, \
@ -47,6 +49,8 @@ namespace jit {
"setprop TypedObject") \
_(SetProp_DefiniteSlot, \
"setprop definite slot") \
_(SetProp_Unboxed, \
"setprop unboxed object") \
_(SetProp_InlineAccess, \
"setprop inline access") \
\
@ -108,12 +112,20 @@ namespace jit {
"is not singleton") \
_(NotFixedSlot, \
"property not in fixed slot") \
_(InconsistentFixedSlot, \
"property not in a consistent fixed slot") \
_(NotObject, \
"not definitely an object") \
_(NotStruct, \
"not definitely a TypedObject struct") \
_(NotUnboxed, \
"not definitely an unboxed object") \
_(StructNoField, \
"struct doesn't definitely have field") \
_(InconsistentFieldType, \
"unboxed property does not consistent type") \
_(InconsistentFieldOffset, \
"unboxed property does not consistent offset") \
_(NeedsTypeBarrier, \
"needs type barrier") \
_(InDictionaryMode, \

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

@ -112,6 +112,10 @@ IsObjectEscaped(MInstruction *ins, JSObject *objDefault = nullptr)
else
obj = objDefault;
// Don't optimize unboxed objects, which aren't handled by MObjectState.
if (obj->is<UnboxedPlainObject>())
return true;
// Check if the object is escaped. If the object is not the first argument
// of either a known Store / Load, then we consider it as escaped. This is a
// cheap and conservative escape analysis.

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

@ -393,7 +393,7 @@ LIRGeneratorARM::visitGuardObjectType(MGuardObjectType *ins)
LDefinition tempObj = temp(LDefinition::OBJECT);
LGuardObjectType *guard = new(alloc()) LGuardObjectType(useRegister(ins->obj()), tempObj);
assignSnapshot(guard, Bailout_ObjectIdentityOrTypeGuard);
assignSnapshot(guard, ins->bailoutKind());
add(guard, ins);
redefine(ins, ins->obj());
}

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

@ -2685,6 +2685,20 @@ MacroAssemblerARMCompat::cmpPtr(const Address &lhs, ImmPtr rhs)
cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
}
void
MacroAssemblerARMCompat::cmpPtr(const Address &lhs, ImmGCPtr rhs)
{
loadPtr(lhs, secondScratchReg_);
ma_cmp(secondScratchReg_, rhs);
}
void
MacroAssemblerARMCompat::cmpPtr(const Address &lhs, Imm32 rhs)
{
loadPtr(lhs, secondScratchReg_);
ma_cmp(secondScratchReg_, rhs);
}
void
MacroAssemblerARMCompat::setStackArg(Register reg, uint32_t arg)
{

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

@ -1129,6 +1129,19 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T &dest,
MIRType slotType);
template <typename T>
void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
switch (nbytes) {
case 4:
storePtr(value.payloadReg(), address);
return;
case 1:
store8(value.payloadReg(), address);
return;
default: MOZ_CRASH("Bad payload width");
}
}
void moveValue(const Value &val, const ValueOperand &dest);
void moveValue(const ValueOperand &src, const ValueOperand &dest) {
@ -1622,14 +1635,16 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
void cmp32(const Operand &lhs, Imm32 rhs);
void cmp32(const Operand &lhs, Register rhs);
void cmpPtr(Register lhs, Register rhs);
void cmpPtr(Register lhs, ImmWord rhs);
void cmpPtr(Register lhs, ImmPtr rhs);
void cmpPtr(Register lhs, Register rhs);
void cmpPtr(Register lhs, ImmGCPtr rhs);
void cmpPtr(Register lhs, Imm32 rhs);
void cmpPtr(const Address &lhs, Register rhs);
void cmpPtr(const Address &lhs, ImmWord rhs);
void cmpPtr(const Address &lhs, ImmPtr rhs);
void cmpPtr(const Address &lhs, ImmGCPtr rhs);
void cmpPtr(const Address &lhs, Imm32 rhs);
void subPtr(Imm32 imm, const Register dest);
void subPtr(const Address &addr, const Register dest);

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

@ -384,7 +384,7 @@ LIRGeneratorMIPS::visitGuardObjectType(MGuardObjectType *ins)
LDefinition tempObj = temp(LDefinition::OBJECT);
LGuardObjectType *guard = new(alloc()) LGuardObjectType(useRegister(ins->obj()), tempObj);
assignSnapshot(guard, Bailout_ObjectIdentityOrTypeGuard);
assignSnapshot(guard, ins->bailoutKind());
add(guard, ins);
redefine(ins, ins->obj());
}

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

@ -869,6 +869,19 @@ public:
void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T &dest,
MIRType slotType);
template <typename T>
void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
switch (nbytes) {
case 4:
storePtr(value.payloadReg(), address);
return;
case 1:
store8(value.payloadReg(), address);
return;
default: MOZ_CRASH("Bad payload width");
}
}
void moveValue(const Value &val, const ValueOperand &dest);
void moveValue(const ValueOperand &src, const ValueOperand &dest) {

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

@ -400,6 +400,7 @@ class MacroAssemblerNone : public Assembler
template <typename T> void loadUnboxedValue(T, MIRType, AnyRegister) { MOZ_CRASH(); }
template <typename T> void storeUnboxedValue(ConstantOrRegister, MIRType, T, MIRType) { MOZ_CRASH(); }
template <typename T> void storeUnboxedPayload(ValueOperand value, T, size_t) { MOZ_CRASH(); }
void rshiftPtr(Imm32, Register) { MOZ_CRASH(); }
void rshiftPtrArithmetic(Imm32, Register) { MOZ_CRASH(); }

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

@ -49,7 +49,7 @@ LIRGeneratorX86Shared::visitGuardObjectType(MGuardObjectType *ins)
MOZ_ASSERT(ins->obj()->type() == MIRType_Object);
LGuardObjectType *guard = new(alloc()) LGuardObjectType(useRegisterAtStart(ins->obj()));
assignSnapshot(guard, Bailout_ObjectIdentityOrTypeGuard);
assignSnapshot(guard, ins->bailoutKind());
add(guard, ins);
redefine(ins, ins->obj());
}

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

@ -650,6 +650,44 @@ class MacroAssemblerX86Shared : public Assembler
Condition cond = testDoubleTruthy(truthy, reg);
j(cond, label);
}
// Class which ensures that registers used in byte ops are compatible with
// such instructions, even if the original register passed in wasn't. This
// only applies to x86, as on x64 all registers are valid single byte regs.
// This doesn't lead to great code but helps to simplify code generation.
class AutoEnsureByteRegister {
MacroAssemblerX86Shared *masm;
Register reg_;
bool read_;
public:
template <typename T>
AutoEnsureByteRegister(MacroAssemblerX86Shared *masm, T address, Register reg, bool read)
: masm(masm), reg_(reg), read_(read)
{
if (!GeneralRegisterSet(Registers::SingleByteRegs).has(reg_)) {
MOZ_ASSERT(address.base != StackPointer);
masm->push(eax);
if (read)
masm->mov(reg_, eax);
}
}
~AutoEnsureByteRegister() {
if (!GeneralRegisterSet(Registers::SingleByteRegs).has(reg_)) {
if (!read_)
masm->mov(eax, reg_);
masm->pop(eax);
}
}
Register reg() {
if (!GeneralRegisterSet(Registers::SingleByteRegs).has(reg_))
return eax;
return reg_;
}
};
void load8ZeroExtend(const Address &src, Register dest) {
movzbl(Operand(src), dest);
}
@ -662,11 +700,16 @@ class MacroAssemblerX86Shared : public Assembler
void load8SignExtend(const BaseIndex &src, Register dest) {
movsbl(Operand(src), dest);
}
template <typename S, typename T>
void store8(const S &src, const T &dest) {
template <typename T>
void store8(Imm32 src, const T &dest) {
movb(src, Operand(dest));
}
template <typename T>
void store8(Register src, const T &dest) {
AutoEnsureByteRegister ensure(this, dest, src, /* read = */ true);
movb(ensure.reg(), Operand(dest));
}
template <typename T>
void compareExchange8ZeroExtend(const T &mem, Register oldval, Register newval, Register output) {
MOZ_ASSERT(output == eax);
MOZ_ASSERT(newval == ebx || newval == ecx || newval == edx);

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

@ -1342,6 +1342,23 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
template <typename T>
void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T &dest, MIRType slotType);
template <typename T>
void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
switch (nbytes) {
case 8:
unboxNonDouble(value, ScratchReg);
storePtr(ScratchReg, address);
return;
case 4:
store32(value.valueReg(), address);
return;
case 1:
store8(value.valueReg(), address);
return;
default: MOZ_CRASH("Bad payload width");
}
}
void loadInstructionPointerAfterCall(Register dest) {
loadPtr(Address(StackPointer, 0x0), dest);
}

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

@ -550,6 +550,9 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
void cmpPtr(const Address &lhs, const ImmPtr rhs) {
cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
}
void cmpPtr(const Address &lhs, const ImmGCPtr rhs) {
cmpPtr(Operand(lhs), rhs);
}
void cmpPtr(Register lhs, Register rhs) {
cmp32(lhs, rhs);
}
@ -1065,6 +1068,19 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T &dest,
MIRType slotType);
template <typename T>
void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
switch (nbytes) {
case 4:
storePtr(value.payloadReg(), address);
return;
case 1:
store8(value.payloadReg(), address);
return;
default: MOZ_CRASH("Bad payload width");
}
}
void rshiftPtr(Imm32 imm, Register dest) {
shrl(imm, dest);
}

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

@ -161,7 +161,7 @@ SelectionCarets::HandleEvent(WidgetEvent* aEvent)
}
WidgetTouchEvent *touchEvent = aEvent->AsTouchEvent();
nsIntPoint movePoint;
LayoutDeviceIntPoint movePoint;
int32_t nowTouchId = -1;
if (touchEvent && !touchEvent->touches.IsEmpty()) {
// If touch happened, just grab event with same identifier
@ -183,7 +183,7 @@ SelectionCarets::HandleEvent(WidgetEvent* aEvent)
nowTouchId = touchEvent->touches[0]->Identifier();
}
} else if (mouseEvent) {
movePoint = LayoutDeviceIntPoint::ToUntyped(mouseEvent->AsGUIEvent()->refPoint);
movePoint = mouseEvent->AsGUIEvent()->refPoint;
}
// Get event coordinate relative to root frame

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

@ -629,7 +629,7 @@ TouchCaret::GetEventPosition(WidgetTouchEvent* aEvent, int32_t aIdentifier)
if (aEvent->touches[i]->mIdentifier == aIdentifier) {
// Get event coordinate relative to canvas frame.
nsIFrame* canvasFrame = GetCanvasFrame();
nsIntPoint touchIntPoint = aEvent->touches[i]->mRefPoint;
LayoutDeviceIntPoint touchIntPoint = aEvent->touches[i]->mRefPoint;
return nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
touchIntPoint,
canvasFrame);
@ -643,8 +643,7 @@ TouchCaret::GetEventPosition(WidgetMouseEvent* aEvent)
{
// Get event coordinate relative to canvas frame.
nsIFrame* canvasFrame = GetCanvasFrame();
nsIntPoint mouseIntPoint =
LayoutDeviceIntPoint::ToUntyped(aEvent->AsGUIEvent()->refPoint);
LayoutDeviceIntPoint mouseIntPoint = aEvent->AsGUIEvent()->refPoint;
return nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
mouseIntPoint,
canvasFrame);

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

@ -2220,7 +2220,7 @@ void nsBidiPresUtils::CopyLogicalToVisual(const nsAString& aSource,
uint32_t srcLength = aSource.Length();
if (srcLength == 0)
return;
if (!aDest.SetLength(srcLength, fallible_t())) {
if (!aDest.SetLength(srcLength, fallible)) {
return;
}
nsAString::const_iterator fromBegin, fromEnd;

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

@ -5207,11 +5207,13 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
aAppUnitsPerPixel, nullptr,
aOutAncestor, !frame->IsTransformed());
result.ChangeBasis(offsetBetweenOrigins);
result = result * parent;
if (aOffsetByOrigin) {
result.Translate(roundedOrigin);
result.Translate(-aProperties.mToTransformOrigin);
result.TranslatePost(offsetBetweenOrigins);
} else {
result.ChangeBasis(offsetBetweenOrigins);
}
result = result * parent;
return result;
}

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

@ -1912,13 +1912,13 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(const WidgetEvent* aEvent,
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
return GetEventCoordinatesRelativeTo(aEvent,
LayoutDeviceIntPoint::ToUntyped(aEvent->AsGUIEvent()->refPoint),
aEvent->AsGUIEvent()->refPoint,
aFrame);
}
nsPoint
nsLayoutUtils::GetEventCoordinatesRelativeTo(const WidgetEvent* aEvent,
const nsIntPoint aPoint,
const LayoutDeviceIntPoint& aPoint,
nsIFrame* aFrame)
{
if (!aFrame) {
@ -1935,7 +1935,7 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(const WidgetEvent* aEvent,
nsPoint
nsLayoutUtils::GetEventCoordinatesRelativeTo(nsIWidget* aWidget,
const nsIntPoint aPoint,
const LayoutDeviceIntPoint& aPoint,
nsIFrame* aFrame)
{
if (!aFrame || !aWidget) {
@ -2658,7 +2658,7 @@ static nsIntPoint WidgetToWidgetOffset(nsIWidget* aFrom, nsIWidget* aTo) {
nsPoint
nsLayoutUtils::TranslateWidgetToView(nsPresContext* aPresContext,
nsIWidget* aWidget, nsIntPoint aPt,
nsIWidget* aWidget, const LayoutDeviceIntPoint& aPt,
nsView* aView)
{
nsPoint viewOffset;
@ -2667,7 +2667,8 @@ nsLayoutUtils::TranslateWidgetToView(nsPresContext* aPresContext,
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
}
nsIntPoint widgetPoint = aPt + WidgetToWidgetOffset(aWidget, viewWidget);
LayoutDeviceIntPoint widgetPoint = aPt +
LayoutDeviceIntPoint::FromUntyped(WidgetToWidgetOffset(aWidget, viewWidget));
nsPoint widgetAppUnits(aPresContext->DevPixelsToAppUnits(widgetPoint.x),
aPresContext->DevPixelsToAppUnits(widgetPoint.y));
return widgetAppUnits - viewOffset;
@ -7646,15 +7647,8 @@ nsLayoutUtils::CalculateExpandedScrollableRect(nsIFrame* aFrame)
/* static */ bool
nsLayoutUtils::WantSubAPZC()
{
// TODO Turn this on for inprocess OMTC on all platforms
bool wantSubAPZC = gfxPrefs::AsyncPanZoomEnabled() &&
gfxPrefs::APZSubframeEnabled();
#ifdef MOZ_WIDGET_GONK
if (XRE_GetProcessType() != GeckoProcessType_Content) {
wantSubAPZC = false;
}
#endif
return wantSubAPZC;
return gfxPrefs::AsyncPanZoomEnabled() &&
gfxPrefs::APZSubframeEnabled();
}
/* static */ bool

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

@ -679,7 +679,7 @@ public:
*/
static nsPoint GetEventCoordinatesRelativeTo(
const mozilla::WidgetEvent* aEvent,
const nsIntPoint aPoint,
const mozilla::LayoutDeviceIntPoint& aPoint,
nsIFrame* aFrame);
/**
@ -693,7 +693,7 @@ public:
* the event is not a GUI event).
*/
static nsPoint GetEventCoordinatesRelativeTo(nsIWidget* aWidget,
const nsIntPoint aPoint,
const mozilla::LayoutDeviceIntPoint& aPoint,
nsIFrame* aFrame);
/**
@ -716,7 +716,8 @@ public:
* @return the point in the view's coordinates
*/
static nsPoint TranslateWidgetToView(nsPresContext* aPresContext,
nsIWidget* aWidget, nsIntPoint aPt,
nsIWidget* aWidget,
const mozilla::LayoutDeviceIntPoint& aPt,
nsView* aView);
/**

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

@ -6753,8 +6753,7 @@ PresShell::RecordMouseLocation(WidgetGUIEvent* aEvent)
if (!rootFrame) {
nsView* rootView = mViewManager->GetRootView();
mMouseLocation = nsLayoutUtils::TranslateWidgetToView(mPresContext,
aEvent->widget, LayoutDeviceIntPoint::ToUntyped(aEvent->refPoint),
rootView);
aEvent->widget, aEvent->refPoint, rootView);
} else {
mMouseLocation =
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame);
@ -8518,12 +8517,12 @@ PresShell::AdjustContextMenuKeyEvent(WidgetMouseEvent* aEvent)
}
// see if we should use the caret position for the popup
nsIntPoint caretPoint;
LayoutDeviceIntPoint caretPoint;
// Beware! This may flush notifications via synchronous
// ScrollSelectionIntoView.
if (PrepareToUseCaretPosition(aEvent->widget, caretPoint)) {
// caret position is good
aEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(caretPoint);
aEvent->refPoint = caretPoint;
return true;
}
@ -8564,7 +8563,8 @@ PresShell::AdjustContextMenuKeyEvent(WidgetMouseEvent* aEvent)
// relative to. The returned point is in device pixels realtive to the
// widget passed in.
bool
PresShell::PrepareToUseCaretPosition(nsIWidget* aEventWidget, nsIntPoint& aTargetPt)
PresShell::PrepareToUseCaretPosition(nsIWidget* aEventWidget,
LayoutDeviceIntPoint& aTargetPt)
{
nsresult rv;

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

@ -690,7 +690,8 @@ protected:
bool AdjustContextMenuKeyEvent(mozilla::WidgetMouseEvent* aEvent);
//
bool PrepareToUseCaretPosition(nsIWidget* aEventWidget, nsIntPoint& aTargetPt);
bool PrepareToUseCaretPosition(nsIWidget* aEventWidget,
mozilla::LayoutDeviceIntPoint& aTargetPt);
// Get the selected item and coordinates in device pixels relative to root
// document's root view for element, first ensuring the element is onscreen

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