summaryrefslogtreecommitdiffstats
path: root/js/src/jit/MIR.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/MIR.cpp')
-rw-r--r--js/src/jit/MIR.cpp245
1 files changed, 222 insertions, 23 deletions
diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp
index 0cf31adb3..b9e5e8d61 100644
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -2630,6 +2630,40 @@ jit::EqualTypes(MIRType type1, TemporaryTypeSet* typeset1,
return typeset1->equals(typeset2);
}
+// Tests whether input/inputTypes can always be stored to an unboxed
+// object/array property with the given unboxed type.
+bool
+jit::CanStoreUnboxedType(TempAllocator& alloc,
+ JSValueType unboxedType, MIRType input, TypeSet* inputTypes)
+{
+ TemporaryTypeSet types;
+
+ switch (unboxedType) {
+ case JSVAL_TYPE_BOOLEAN:
+ case JSVAL_TYPE_INT32:
+ case JSVAL_TYPE_DOUBLE:
+ case JSVAL_TYPE_STRING:
+ types.addType(TypeSet::PrimitiveType(unboxedType), alloc.lifoAlloc());
+ break;
+
+ case JSVAL_TYPE_OBJECT:
+ types.addType(TypeSet::AnyObjectType(), alloc.lifoAlloc());
+ types.addType(TypeSet::NullType(), alloc.lifoAlloc());
+ break;
+
+ default:
+ MOZ_CRASH("Bad unboxed type");
+ }
+
+ return TypeSetIncludes(&types, input, inputTypes);
+}
+
+static bool
+CanStoreUnboxedType(TempAllocator& alloc, JSValueType unboxedType, MDefinition* value)
+{
+ return CanStoreUnboxedType(alloc, unboxedType, value->type(), value->resultTypeSet());
+}
+
bool
MPhi::specializeType(TempAllocator& alloc)
{
@@ -4776,31 +4810,67 @@ MBeta::printOpcode(GenericPrinter& out) const
bool
MCreateThisWithTemplate::canRecoverOnBailout() const
{
- MOZ_ASSERT(templateObject()->is<PlainObject>());
- MOZ_ASSERT(!templateObject()->as<PlainObject>().denseElementsAreCopyOnWrite());
+ MOZ_ASSERT(templateObject()->is<PlainObject>() || templateObject()->is<UnboxedPlainObject>());
+ MOZ_ASSERT_IF(templateObject()->is<PlainObject>(),
+ !templateObject()->as<PlainObject>().denseElementsAreCopyOnWrite());
+ return true;
+}
+
+bool
+OperandIndexMap::init(TempAllocator& alloc, JSObject* templateObject)
+{
+ const UnboxedLayout& layout =
+ templateObject->as<UnboxedPlainObject>().layoutDontCheckGeneration();
+
+ const UnboxedLayout::PropertyVector& properties = layout.properties();
+ MOZ_ASSERT(properties.length() < 255);
+
+ // Allocate an array of indexes, where the top of each field correspond to
+ // the index of the operand in the MObjectState instance.
+ if (!map.init(alloc, layout.size()))
+ return false;
+
+ // Reset all indexes to 0, which is an error code.
+ for (size_t i = 0; i < map.length(); i++)
+ map[i] = 0;
+
+ // Map the property offsets to the indexes of MObjectState operands.
+ uint8_t index = 1;
+ for (size_t i = 0; i < properties.length(); i++, index++)
+ map[properties[i].offset] = index;
+
return true;
}
MObjectState::MObjectState(MObjectState* state)
: numSlots_(state->numSlots_),
- numFixedSlots_(state->numFixedSlots_)
+ numFixedSlots_(state->numFixedSlots_),
+ operandIndex_(state->operandIndex_)
{
// This instruction is only used as a summary for bailout paths.
setResultType(MIRType::Object);
setRecoveredOnBailout();
}
-MObjectState::MObjectState(JSObject* templateObject)
+MObjectState::MObjectState(JSObject *templateObject, OperandIndexMap* operandIndex)
{
// This instruction is only used as a summary for bailout paths.
setResultType(MIRType::Object);
setRecoveredOnBailout();
- MOZ_ASSERT(templateObject->is<NativeObject>());
+ if (templateObject->is<NativeObject>()) {
+ NativeObject* nativeObject = &templateObject->as<NativeObject>();
+ numSlots_ = nativeObject->slotSpan();
+ numFixedSlots_ = nativeObject->numFixedSlots();
+ } else {
+ const UnboxedLayout& layout =
+ templateObject->as<UnboxedPlainObject>().layoutDontCheckGeneration();
+ // Same as UnboxedLayout::makeNativeGroup
+ numSlots_ = layout.properties().length();
+ numFixedSlots_ = gc::GetGCKindSlots(layout.getAllocKind());
+ }
- NativeObject* nativeObject = &templateObject->as<NativeObject>();
- numSlots_ = nativeObject->slotSpan();
- numFixedSlots_ = nativeObject->numFixedSlots();
+ operandIndex_ = operandIndex;
}
JSObject*
@@ -4835,21 +4905,39 @@ MObjectState::initFromTemplateObject(TempAllocator& alloc, MDefinition* undefine
// the template object. This is needed to account values which are baked in
// the template objects and not visible in IonMonkey, such as the
// uninitialized-lexical magic value of call objects.
- NativeObject& nativeObject = templateObject->as<NativeObject>();
- MOZ_ASSERT(nativeObject.slotSpan() == numSlots());
-
- MOZ_ASSERT(templateObject->is<NativeObject>());
- for (size_t i = 0; i < numSlots(); i++) {
- Value val = nativeObject.getSlot(i);
- MDefinition *def = undefinedVal;
- if (!val.isUndefined()) {
- MConstant* ins = val.isObject() ?
- MConstant::NewConstraintlessObject(alloc, &val.toObject()) :
- MConstant::New(alloc, val);
- block()->insertBefore(this, ins);
- def = ins;
+ if (templateObject->is<UnboxedPlainObject>()) {
+ UnboxedPlainObject& unboxedObject = templateObject->as<UnboxedPlainObject>();
+ const UnboxedLayout& layout = unboxedObject.layoutDontCheckGeneration();
+ const UnboxedLayout::PropertyVector& properties = layout.properties();
+
+ for (size_t i = 0; i < properties.length(); i++) {
+ Value val = unboxedObject.getValue(properties[i], /* maybeUninitialized = */ true);
+ MDefinition *def = undefinedVal;
+ if (!val.isUndefined()) {
+ MConstant* ins = val.isObject() ?
+ MConstant::NewConstraintlessObject(alloc, &val.toObject()) :
+ MConstant::New(alloc, val);
+ block()->insertBefore(this, ins);
+ def = ins;
+ }
+ initSlot(i, def);
+ }
+ } else {
+ NativeObject& nativeObject = templateObject->as<NativeObject>();
+ MOZ_ASSERT(nativeObject.slotSpan() == numSlots());
+
+ for (size_t i = 0; i < numSlots(); i++) {
+ Value val = nativeObject.getSlot(i);
+ MDefinition *def = undefinedVal;
+ if (!val.isUndefined()) {
+ MConstant* ins = val.isObject() ?
+ MConstant::NewConstraintlessObject(alloc, &val.toObject()) :
+ MConstant::New(alloc, val);
+ block()->insertBefore(this, ins);
+ def = ins;
+ }
+ initSlot(i, def);
}
- initSlot(i, def);
}
return true;
}
@@ -4860,7 +4948,14 @@ MObjectState::New(TempAllocator& alloc, MDefinition* obj)
JSObject* templateObject = templateObjectOf(obj);
MOZ_ASSERT(templateObject, "Unexpected object creation.");
- MObjectState* res = new(alloc) MObjectState(templateObject);
+ OperandIndexMap* operandIndex = nullptr;
+ if (templateObject->is<UnboxedPlainObject>()) {
+ operandIndex = new(alloc) OperandIndexMap;
+ if (!operandIndex || !operandIndex->init(alloc, templateObject))
+ return nullptr;
+ }
+
+ MObjectState* res = new(alloc) MObjectState(templateObject, operandIndex);
if (!res || !res->init(alloc, obj))
return nullptr;
return res;
@@ -5767,6 +5862,35 @@ MGetFirstDollarIndex::foldsTo(TempAllocator& alloc)
return MConstant::New(alloc, Int32Value(index));
}
+MConvertUnboxedObjectToNative*
+MConvertUnboxedObjectToNative::New(TempAllocator& alloc, MDefinition* obj, ObjectGroup* group)
+{
+ MConvertUnboxedObjectToNative* res = new(alloc) MConvertUnboxedObjectToNative(obj, group);
+
+ ObjectGroup* nativeGroup = group->unboxedLayout().nativeGroup();
+
+ // Make a new type set for the result of this instruction which replaces
+ // the input group with the native group we will convert it to.
+ TemporaryTypeSet* types = obj->resultTypeSet();
+ if (types && !types->unknownObject()) {
+ TemporaryTypeSet* newTypes = types->cloneWithoutObjects(alloc.lifoAlloc());
+ if (newTypes) {
+ for (size_t i = 0; i < types->getObjectCount(); i++) {
+ TypeSet::ObjectKey* key = types->getObject(i);
+ if (!key)
+ continue;
+ if (key->unknownProperties() || !key->isGroup() || key->group() != group)
+ newTypes->addType(TypeSet::ObjectType(key), alloc.lifoAlloc());
+ else
+ newTypes->addType(TypeSet::ObjectType(nativeGroup), alloc.lifoAlloc());
+ }
+ res->setResultTypeSet(newTypes);
+ }
+ }
+
+ return res;
+}
+
bool
jit::ElementAccessIsDenseNative(CompilerConstraintList* constraints,
MDefinition* obj, MDefinition* id)
@@ -5786,6 +5910,48 @@ jit::ElementAccessIsDenseNative(CompilerConstraintList* constraints,
return clasp && clasp->isNative() && !IsTypedArrayClass(clasp);
}
+JSValueType
+jit::UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj,
+ MDefinition* id)
+{
+ if (obj->mightBeType(MIRType::String))
+ return JSVAL_TYPE_MAGIC;
+
+ if (id && id->type() != MIRType::Int32 && id->type() != MIRType::Double)
+ return JSVAL_TYPE_MAGIC;
+
+ TemporaryTypeSet* types = obj->resultTypeSet();
+ if (!types || types->unknownObject())
+ return JSVAL_TYPE_MAGIC;
+
+ JSValueType elementType = JSVAL_TYPE_MAGIC;
+ for (unsigned i = 0; i < types->getObjectCount(); i++) {
+ TypeSet::ObjectKey* key = types->getObject(i);
+ if (!key)
+ continue;
+
+ if (key->unknownProperties() || !key->isGroup())
+ return JSVAL_TYPE_MAGIC;
+
+ if (key->clasp() != &UnboxedArrayObject::class_)
+ return JSVAL_TYPE_MAGIC;
+
+ const UnboxedLayout &layout = key->group()->unboxedLayout();
+
+ if (layout.nativeGroup())
+ return JSVAL_TYPE_MAGIC;
+
+ if (elementType == layout.elementType() || elementType == JSVAL_TYPE_MAGIC)
+ elementType = layout.elementType();
+ else
+ return JSVAL_TYPE_MAGIC;
+
+ key->watchStateChangeForUnboxedConvertedToNative(constraints);
+ }
+
+ return elementType;
+}
+
bool
jit::ElementAccessIsTypedArray(CompilerConstraintList* constraints,
MDefinition* obj, MDefinition* id,
@@ -5945,6 +6111,11 @@ ObjectSubsumes(TypeSet::ObjectKey* first, TypeSet::ObjectKey* second)
firstElements.maybeTypes()->equals(secondElements.maybeTypes());
}
+ if (first->clasp() == &UnboxedArrayObject::class_) {
+ return first->group()->unboxedLayout().elementType() ==
+ second->group()->unboxedLayout().elementType();
+ }
+
return false;
}
@@ -6399,6 +6570,23 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList*
}
}
+ // Perform additional filtering to make sure that any unboxed property
+ // being written can accommodate the value.
+ for (size_t i = 0; i < types->getObjectCount(); i++) {
+ TypeSet::ObjectKey* key = types->getObject(i);
+ if (key && key->isGroup() && key->group()->maybeUnboxedLayout()) {
+ const UnboxedLayout& layout = key->group()->unboxedLayout();
+ if (name) {
+ const UnboxedLayout::Property* property = layout.lookup(name);
+ if (property && !CanStoreUnboxedType(alloc, property->type, *pvalue))
+ return true;
+ } else {
+ if (layout.isArray() && !CanStoreUnboxedType(alloc, layout.elementType(), *pvalue))
+ return true;
+ }
+ }
+ }
+
if (success)
return false;
@@ -6429,6 +6617,17 @@ jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, CompilerConstraintList*
MOZ_ASSERT(excluded);
+ // If the excluded object is a group with an unboxed layout, make sure it
+ // does not have a corresponding native group. Objects with the native
+ // group might appear even though they are not in the type set.
+ if (excluded->isGroup()) {
+ if (UnboxedLayout* layout = excluded->group()->maybeUnboxedLayout()) {
+ if (layout->nativeGroup())
+ return true;
+ excluded->watchStateChangeForUnboxedConvertedToNative(constraints);
+ }
+ }
+
*pobj = AddGroupGuard(alloc, current, *pobj, excluded, /* bailOnEquality = */ true);
return false;
}