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(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); }