From 55aad7d84147dac35c9edb2aa29530f2f07f46fb Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Thu, 30 Oct 2014 08:45:28 -0700 Subject: [PATCH] Bug 1091010 - Optimize accesses to TypedObject.length, r=nmatsakis. --- js/src/builtin/TypedObject.cpp | 5 ++--- js/src/jit/IonBuilder.cpp | 33 +++++++++++++++++++++++++++++---- js/src/jsinfer.h | 5 ++--- js/src/vm/ArrayBufferObject.cpp | 12 ++++++------ js/src/vm/ArrayBufferObject.h | 12 ++++++------ 5 files changed, 45 insertions(+), 22 deletions(-) diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 31998e8bda8c..d9c8ea66f543 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -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()) - 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; diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index b735b0125bf9..7062439c5592 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -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. diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index d3cba0a6ad32..dc18e236d068 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -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 diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index 6e3981878dab..de69d0540995 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -515,21 +515,21 @@ ArrayBufferObject::neuter(JSContext *cx, Handle 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 diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h index 403f48bcd657..60f96cd15cdb 100644 --- a/js/src/vm/ArrayBufferObject.h +++ b/js/src/vm/ArrayBufferObject.h @@ -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); }