зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to b2g-inbound
This commit is contained in:
Коммит
d21b001eef
2
CLOBBER
2
CLOBBER
|
@ -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);
|
||||
|
||||
|
|
151
js/src/jit/MIR.h
151
js/src/jit/MIR.h
|
@ -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), ¬Null);
|
||||
|
||||
moveValue(NullValue(), output.valueReg());
|
||||
jump(&done);
|
||||
|
||||
bind(¬Null);
|
||||
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
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче