Bug 1091010 - Optimize accesses to TypedObject.length, r=nmatsakis.

This commit is contained in:
Brian Hackett 2014-10-30 08:45:28 -07:00
Родитель 91aaa3e40b
Коммит 55aad7d841
5 изменённых файлов: 45 добавлений и 22 удалений

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

@ -1636,8 +1636,7 @@ OutlineTypedObject::attach(JSContext *cx, ArrayBufferObject &buffer, int32_t off
MOZ_ASSERT(offset >= 0);
MOZ_ASSERT((size_t) (offset + size()) <= buffer.byteLength());
if (typeDescr().is<SizedTypeDescr>())
buffer.setHasSizedObjectViews();
buffer.setHasTypedObjectViews();
if (!buffer.addView(cx, this))
CrashAtUnhandlableOOM("TypedObject::attach");
@ -2439,7 +2438,7 @@ InlineTransparentTypedObject::getOrCreateBuffer(JSContext *cx)
JS_ALWAYS_TRUE(buffer->addView(cx, this));
buffer->setForInlineTypedObject();
buffer->setHasSizedObjectViews();
buffer->setHasTypedObjectViews();
if (!table->addBuffer(cx, this, buffer))
return nullptr;

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

@ -7262,7 +7262,7 @@ IonBuilder::checkTypedObjectIndexInBounds(int32_t elemSize,
// If we are not loading the length from the object itself, only
// optimize if the array buffer can't have been neutered.
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;
} else if (objPrediction.kind() == type::UnsizedArray) {
// 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)) {
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
// Compute the length for array objects.
if (objTypes &&
objTypes->getKnownClass() == &ArrayObject::class_ &&
!objTypes->hasObjectFlags(constraints(), types::OBJECT_FLAG_LENGTH_OVERFLOW))
@ -8577,6 +8578,30 @@ IonBuilder::jsop_length_fastPath()
current->push(length);
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;
@ -9308,7 +9333,7 @@ IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted, MDefinition *typedO
// Don't optimize if the typed object might be neutered.
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;
// OK, perform the optimization.
@ -9325,7 +9350,7 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
{
// Don't optimize if the typed object might be neutered.
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;
// OK, perform the optimization
@ -9984,7 +10009,7 @@ IonBuilder::setPropTryScalarPropOfTypedObject(bool *emitted,
// Don't optimize if the typed object might be neutered.
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;
// 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
* sized typed object views have been neutered. Sized typed objects have
* different neutering checks from other array buffer views.
* typed object views have been neutered.
*/
OBJECT_FLAG_SIZED_OBJECT_NEUTERED = 0x00400000,
OBJECT_FLAG_TYPED_OBJECT_NEUTERED = 0x00400000,
/*
* Whether objects with this type should be allocated directly in the

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

@ -515,21 +515,21 @@ ArrayBufferObject::neuter(JSContext *cx, Handle<ArrayBufferObject*> buffer,
return false;
// 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
// not have a length property to mutate when neutering.
// match the old data. All missing views are typed objects, which do not
// expect their data to ever change.
MOZ_ASSERT_IF(buffer->forInlineTypedObject(),
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
// performed. This is done by setting a compartment wide flag indicating
// that buffers with sized object views have been neutered.
if (buffer->hasSizedObjectViews()) {
// that buffers with typed object views have been neutered.
if (buffer->hasTypedObjectViews()) {
// Make sure the global object's type has been instantiated, so the
// flag change will be observed.
if (!cx->global()->getType(cx))
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

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

@ -140,11 +140,11 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
// 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
// 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,
// Views of this buffer might include sized typed objects.
SIZED_OBJECT_VIEWS = 0x20
// Views of this buffer might include typed objects.
TYPED_OBJECT_VIEWS = 0x20
};
public:
@ -325,8 +325,8 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
void setForInlineTypedObject() {
setFlags(flags() | FOR_INLINE_TYPED_OBJECT);
}
void setHasSizedObjectViews() {
setFlags(flags() | SIZED_OBJECT_VIEWS);
void setHasTypedObjectViews() {
setFlags(flags() | TYPED_OBJECT_VIEWS);
}
protected:
@ -342,7 +342,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
}
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 setIsNeutered() { setFlags(flags() | NEUTERED); }