зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1091010 - Optimize accesses to TypedObject.length, r=nmatsakis.
This commit is contained in:
Родитель
91aaa3e40b
Коммит
55aad7d841
|
@ -1636,8 +1636,7 @@ OutlineTypedObject::attach(JSContext *cx, ArrayBufferObject &buffer, int32_t off
|
||||||
MOZ_ASSERT(offset >= 0);
|
MOZ_ASSERT(offset >= 0);
|
||||||
MOZ_ASSERT((size_t) (offset + size()) <= buffer.byteLength());
|
MOZ_ASSERT((size_t) (offset + size()) <= buffer.byteLength());
|
||||||
|
|
||||||
if (typeDescr().is<SizedTypeDescr>())
|
buffer.setHasTypedObjectViews();
|
||||||
buffer.setHasSizedObjectViews();
|
|
||||||
|
|
||||||
if (!buffer.addView(cx, this))
|
if (!buffer.addView(cx, this))
|
||||||
CrashAtUnhandlableOOM("TypedObject::attach");
|
CrashAtUnhandlableOOM("TypedObject::attach");
|
||||||
|
@ -2439,7 +2438,7 @@ InlineTransparentTypedObject::getOrCreateBuffer(JSContext *cx)
|
||||||
JS_ALWAYS_TRUE(buffer->addView(cx, this));
|
JS_ALWAYS_TRUE(buffer->addView(cx, this));
|
||||||
|
|
||||||
buffer->setForInlineTypedObject();
|
buffer->setForInlineTypedObject();
|
||||||
buffer->setHasSizedObjectViews();
|
buffer->setHasTypedObjectViews();
|
||||||
|
|
||||||
if (!table->addBuffer(cx, this, buffer))
|
if (!table->addBuffer(cx, this, buffer))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -7262,7 +7262,7 @@ IonBuilder::checkTypedObjectIndexInBounds(int32_t elemSize,
|
||||||
// If we are not loading the length from the object itself, only
|
// If we are not loading the length from the object itself, only
|
||||||
// optimize if the array buffer can't have been neutered.
|
// optimize if the array buffer can't have been neutered.
|
||||||
types::TypeObjectKey *globalType = types::TypeObjectKey::get(&script()->global());
|
types::TypeObjectKey *globalType = types::TypeObjectKey::get(&script()->global());
|
||||||
if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_SIZED_OBJECT_NEUTERED))
|
if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED))
|
||||||
return false;
|
return false;
|
||||||
} else if (objPrediction.kind() == type::UnsizedArray) {
|
} else if (objPrediction.kind() == type::UnsizedArray) {
|
||||||
// Note: unsized arrays will have their length set to zero if they are
|
// Note: unsized arrays will have their length set to zero if they are
|
||||||
|
@ -8563,6 +8563,7 @@ IonBuilder::jsop_length_fastPath()
|
||||||
if (obj->mightBeType(MIRType_Object)) {
|
if (obj->mightBeType(MIRType_Object)) {
|
||||||
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
|
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
|
||||||
|
|
||||||
|
// Compute the length for array objects.
|
||||||
if (objTypes &&
|
if (objTypes &&
|
||||||
objTypes->getKnownClass() == &ArrayObject::class_ &&
|
objTypes->getKnownClass() == &ArrayObject::class_ &&
|
||||||
!objTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_LENGTH_OVERFLOW))
|
!objTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_LENGTH_OVERFLOW))
|
||||||
|
@ -8577,6 +8578,30 @@ IonBuilder::jsop_length_fastPath()
|
||||||
current->push(length);
|
current->push(length);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compute the length for array typed objects.
|
||||||
|
TypedObjectPrediction prediction = typedObjectPrediction(obj);
|
||||||
|
if (!prediction.isUseless()) {
|
||||||
|
types::TypeObjectKey *globalType = types::TypeObjectKey::get(&script()->global());
|
||||||
|
if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
MInstruction *length;
|
||||||
|
int32_t sizedLength;
|
||||||
|
if (prediction.hasKnownArrayLength(&sizedLength)) {
|
||||||
|
obj->setImplicitlyUsedUnchecked();
|
||||||
|
length = MConstant::New(alloc(), Int32Value(sizedLength));
|
||||||
|
} else if (prediction.kind() == type::UnsizedArray) {
|
||||||
|
length = MTypedObjectUnsizedLength::New(alloc(), obj);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
current->pop();
|
||||||
|
current->add(length);
|
||||||
|
current->push(length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -9308,7 +9333,7 @@ IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted, MDefinition *typedO
|
||||||
|
|
||||||
// Don't optimize if the typed object might be neutered.
|
// Don't optimize if the typed object might be neutered.
|
||||||
types::TypeObjectKey *globalType = types::TypeObjectKey::get(&script()->global());
|
types::TypeObjectKey *globalType = types::TypeObjectKey::get(&script()->global());
|
||||||
if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_SIZED_OBJECT_NEUTERED))
|
if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// OK, perform the optimization.
|
// OK, perform the optimization.
|
||||||
|
@ -9325,7 +9350,7 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
|
||||||
{
|
{
|
||||||
// Don't optimize if the typed object might be neutered.
|
// Don't optimize if the typed object might be neutered.
|
||||||
types::TypeObjectKey *globalType = types::TypeObjectKey::get(&script()->global());
|
types::TypeObjectKey *globalType = types::TypeObjectKey::get(&script()->global());
|
||||||
if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_SIZED_OBJECT_NEUTERED))
|
if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// OK, perform the optimization
|
// OK, perform the optimization
|
||||||
|
@ -9984,7 +10009,7 @@ IonBuilder::setPropTryScalarPropOfTypedObject(bool *emitted,
|
||||||
|
|
||||||
// Don't optimize if the typed object might be neutered.
|
// Don't optimize if the typed object might be neutered.
|
||||||
types::TypeObjectKey *globalType = types::TypeObjectKey::get(&script()->global());
|
types::TypeObjectKey *globalType = types::TypeObjectKey::get(&script()->global());
|
||||||
if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_SIZED_OBJECT_NEUTERED))
|
if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// OK! Perform the optimization.
|
// OK! Perform the optimization.
|
||||||
|
|
|
@ -484,10 +484,9 @@ enum MOZ_ENUM_TYPE(uint32_t) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For a global object, whether any array buffers in this compartment with
|
* For a global object, whether any array buffers in this compartment with
|
||||||
* sized typed object views have been neutered. Sized typed objects have
|
* typed object views have been neutered.
|
||||||
* different neutering checks from other array buffer views.
|
|
||||||
*/
|
*/
|
||||||
OBJECT_FLAG_SIZED_OBJECT_NEUTERED = 0x00400000,
|
OBJECT_FLAG_TYPED_OBJECT_NEUTERED = 0x00400000,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Whether objects with this type should be allocated directly in the
|
* Whether objects with this type should be allocated directly in the
|
||||||
|
|
|
@ -515,21 +515,21 @@ ArrayBufferObject::neuter(JSContext *cx, Handle<ArrayBufferObject*> buffer,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// When neutering buffers where we don't know all views, the new data must
|
// When neutering buffers where we don't know all views, the new data must
|
||||||
// match the old data. All missing views are sized typed objects, which do
|
// match the old data. All missing views are typed objects, which do not
|
||||||
// not have a length property to mutate when neutering.
|
// expect their data to ever change.
|
||||||
MOZ_ASSERT_IF(buffer->forInlineTypedObject(),
|
MOZ_ASSERT_IF(buffer->forInlineTypedObject(),
|
||||||
newContents.data() == buffer->dataPointer());
|
newContents.data() == buffer->dataPointer());
|
||||||
|
|
||||||
// When neutering a buffer with sized typed object views, any jitcode which
|
// When neutering a buffer with typed object views, any jitcode which
|
||||||
// accesses such views needs to be deoptimized so that neuter checks are
|
// accesses such views needs to be deoptimized so that neuter checks are
|
||||||
// performed. This is done by setting a compartment wide flag indicating
|
// performed. This is done by setting a compartment wide flag indicating
|
||||||
// that buffers with sized object views have been neutered.
|
// that buffers with typed object views have been neutered.
|
||||||
if (buffer->hasSizedObjectViews()) {
|
if (buffer->hasTypedObjectViews()) {
|
||||||
// Make sure the global object's type has been instantiated, so the
|
// Make sure the global object's type has been instantiated, so the
|
||||||
// flag change will be observed.
|
// flag change will be observed.
|
||||||
if (!cx->global()->getType(cx))
|
if (!cx->global()->getType(cx))
|
||||||
CrashAtUnhandlableOOM("ArrayBufferObject::neuter");
|
CrashAtUnhandlableOOM("ArrayBufferObject::neuter");
|
||||||
types::MarkTypeObjectFlags(cx, cx->global(), types::OBJECT_FLAG_SIZED_OBJECT_NEUTERED);
|
types::MarkTypeObjectFlags(cx, cx->global(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Neuter all views on the buffer, clear out the list of views and the
|
// Neuter all views on the buffer, clear out the list of views and the
|
||||||
|
|
|
@ -140,11 +140,11 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
|
||||||
// This array buffer was created lazily for a typed object with inline
|
// This array buffer was created lazily for a typed object with inline
|
||||||
// data. This implies both that the typed object owns the buffer's data
|
// data. This implies both that the typed object owns the buffer's data
|
||||||
// and that the list of views sharing this buffer's data might be
|
// and that the list of views sharing this buffer's data might be
|
||||||
// incomplete. Any missing views will be sized typed objects.
|
// incomplete. Any missing views will be typed objects.
|
||||||
FOR_INLINE_TYPED_OBJECT = 0x10,
|
FOR_INLINE_TYPED_OBJECT = 0x10,
|
||||||
|
|
||||||
// Views of this buffer might include sized typed objects.
|
// Views of this buffer might include typed objects.
|
||||||
SIZED_OBJECT_VIEWS = 0x20
|
TYPED_OBJECT_VIEWS = 0x20
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -325,8 +325,8 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
|
||||||
void setForInlineTypedObject() {
|
void setForInlineTypedObject() {
|
||||||
setFlags(flags() | FOR_INLINE_TYPED_OBJECT);
|
setFlags(flags() | FOR_INLINE_TYPED_OBJECT);
|
||||||
}
|
}
|
||||||
void setHasSizedObjectViews() {
|
void setHasTypedObjectViews() {
|
||||||
setFlags(flags() | SIZED_OBJECT_VIEWS);
|
setFlags(flags() | TYPED_OBJECT_VIEWS);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -342,7 +342,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
|
||||||
}
|
}
|
||||||
|
|
||||||
bool forInlineTypedObject() const { return flags() & FOR_INLINE_TYPED_OBJECT; }
|
bool forInlineTypedObject() const { return flags() & FOR_INLINE_TYPED_OBJECT; }
|
||||||
bool hasSizedObjectViews() const { return flags() & SIZED_OBJECT_VIEWS; }
|
bool hasTypedObjectViews() const { return flags() & TYPED_OBJECT_VIEWS; }
|
||||||
|
|
||||||
void setIsAsmJSMalloced() { setFlags((flags() & ~KIND_MASK) | ASMJS_MALLOCED); }
|
void setIsAsmJSMalloced() { setFlags((flags() & ~KIND_MASK) | ASMJS_MALLOCED); }
|
||||||
void setIsNeutered() { setFlags(flags() | NEUTERED); }
|
void setIsNeutered() { setFlags(flags() | NEUTERED); }
|
||||||
|
|
Загрузка…
Ссылка в новой задаче