diff options
Diffstat (limited to 'js/src/vm/ObjectGroup.cpp')
-rw-r--r-- | js/src/vm/ObjectGroup.cpp | 158 |
1 files changed, 149 insertions, 9 deletions
diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 91070b3f6..d05a48646 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -18,10 +18,11 @@ #include "vm/ArrayObject.h" #include "vm/Shape.h" #include "vm/TaggedProto.h" +#include "vm/UnboxedObject.h" #include "jsobjinlines.h" -#include "vm/NativeObject-inl.h" +#include "vm/UnboxedObject-inl.h" using namespace js; @@ -55,6 +56,7 @@ ObjectGroup::finalize(FreeOp* fop) if (newScriptDontCheckGeneration()) newScriptDontCheckGeneration()->clear(); fop->delete_(newScriptDontCheckGeneration()); + fop->delete_(maybeUnboxedLayoutDontCheckGeneration()); if (maybePreliminaryObjectsDontCheckGeneration()) maybePreliminaryObjectsDontCheckGeneration()->clear(); fop->delete_(maybePreliminaryObjectsDontCheckGeneration()); @@ -81,6 +83,8 @@ ObjectGroup::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const size_t n = 0; if (TypeNewScript* newScript = newScriptDontCheckGeneration()) n += newScript->sizeOfIncludingThis(mallocSizeOf); + if (UnboxedLayout* layout = maybeUnboxedLayoutDontCheckGeneration()) + n += layout->sizeOfIncludingThis(mallocSizeOf); return n; } @@ -529,7 +533,8 @@ ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp, if (p) { ObjectGroup* group = p->group; MOZ_ASSERT_IF(clasp, group->clasp() == clasp); - MOZ_ASSERT_IF(!clasp, group->clasp() == &PlainObject::class_); + MOZ_ASSERT_IF(!clasp, group->clasp() == &PlainObject::class_ || + group->clasp() == &UnboxedPlainObject::class_); MOZ_ASSERT(group->proto() == proto); return group; } @@ -772,7 +777,7 @@ GetValueTypeForTable(const Value& v) return type; } -/* static */ ArrayObject* +/* static */ JSObject* ObjectGroup::newArrayObject(ExclusiveContext* cx, const Value* vp, size_t length, NewObjectKind newKind, NewArrayKind arrayKind) @@ -836,13 +841,56 @@ ObjectGroup::newArrayObject(ExclusiveContext* cx, AddTypePropertyId(cx, group, nullptr, JSID_VOID, elementType); + if (elementType != TypeSet::UnknownType()) { + // Keep track of the initial objects we create with this type. + // If the initial ones have a consistent shape and property types, we + // will try to use an unboxed layout for the group. + PreliminaryObjectArrayWithTemplate* preliminaryObjects = + cx->new_<PreliminaryObjectArrayWithTemplate>(nullptr); + if (!preliminaryObjects) + return nullptr; + group->setPreliminaryObjects(preliminaryObjects); + } + if (!p.add(cx, *table, ObjectGroupCompartment::ArrayObjectKey(elementType), group)) return nullptr; } // The type of the elements being added will already be reflected in type - // information. + // information, but make sure when creating an unboxed array that the + // common element type is suitable for the unboxed representation. ShouldUpdateTypes updateTypes = ShouldUpdateTypes::DontUpdate; + if (!MaybeAnalyzeBeforeCreatingLargeArray(cx, group, vp, length)) + return nullptr; + if (group->maybePreliminaryObjects()) + group->maybePreliminaryObjects()->maybeAnalyze(cx, group); + if (group->maybeUnboxedLayout()) { + switch (group->unboxedLayout().elementType()) { + case JSVAL_TYPE_BOOLEAN: + if (elementType != TypeSet::BooleanType()) + updateTypes = ShouldUpdateTypes::Update; + break; + case JSVAL_TYPE_INT32: + if (elementType != TypeSet::Int32Type()) + updateTypes = ShouldUpdateTypes::Update; + break; + case JSVAL_TYPE_DOUBLE: + if (elementType != TypeSet::Int32Type() && elementType != TypeSet::DoubleType()) + updateTypes = ShouldUpdateTypes::Update; + break; + case JSVAL_TYPE_STRING: + if (elementType != TypeSet::StringType()) + updateTypes = ShouldUpdateTypes::Update; + break; + case JSVAL_TYPE_OBJECT: + if (elementType != TypeSet::NullType() && !elementType.get().isObjectUnchecked()) + updateTypes = ShouldUpdateTypes::Update; + break; + default: + MOZ_CRASH(); + } + } + return NewCopiedArrayTryUseGroup(cx, group, vp, length, newKind, updateTypes); } @@ -852,15 +900,49 @@ GiveObjectGroup(ExclusiveContext* cx, JSObject* source, JSObject* target) { MOZ_ASSERT(source->group() != target->group()); - if (!target->is<ArrayObject>() || !source->is<ArrayObject>()) { + if (!target->is<ArrayObject>() && !target->is<UnboxedArrayObject>()) + return true; + + if (target->group()->maybePreliminaryObjects()) { + bool force = IsInsideNursery(source); + target->group()->maybePreliminaryObjects()->maybeAnalyze(cx, target->group(), force); + } + + if (target->is<ArrayObject>()) { + ObjectGroup* sourceGroup = source->group(); + + if (source->is<UnboxedArrayObject>()) { + Shape* shape = target->as<ArrayObject>().lastProperty(); + if (!UnboxedArrayObject::convertToNativeWithGroup(cx, source, target->group(), shape)) + return false; + } else if (source->is<ArrayObject>()) { + source->setGroup(target->group()); + } else { + return true; + } + + if (sourceGroup->maybePreliminaryObjects()) + sourceGroup->maybePreliminaryObjects()->unregisterObject(source); + if (target->group()->maybePreliminaryObjects()) + target->group()->maybePreliminaryObjects()->registerNewObject(source); + + for (size_t i = 0; i < source->as<ArrayObject>().getDenseInitializedLength(); i++) { + Value v = source->as<ArrayObject>().getDenseElement(i); + AddTypePropertyId(cx, source->group(), source, JSID_VOID, v); + } + return true; } - source->setGroup(target->group()); + if (target->is<UnboxedArrayObject>()) { + if (!source->is<UnboxedArrayObject>()) + return true; + if (source->as<UnboxedArrayObject>().elementType() != JSVAL_TYPE_INT32) + return true; + if (target->as<UnboxedArrayObject>().elementType() != JSVAL_TYPE_DOUBLE) + return true; - for (size_t i = 0; i < source->as<ArrayObject>().getDenseInitializedLength(); i++) { - Value v = source->as<ArrayObject>().getDenseElement(i); - AddTypePropertyId(cx, source->group(), source, JSID_VOID, v); + return source->as<UnboxedArrayObject>().convertInt32ToDouble(cx, target->group()); } return true; @@ -969,6 +1051,46 @@ js::CombinePlainObjectPropertyTypes(ExclusiveContext* cx, JSObject* newObj, } } } + } else if (newObj->is<UnboxedPlainObject>()) { + const UnboxedLayout& layout = newObj->as<UnboxedPlainObject>().layout(); + const int32_t* traceList = layout.traceList(); + if (!traceList) + return true; + + uint8_t* newData = newObj->as<UnboxedPlainObject>().data(); + uint8_t* oldData = oldObj->as<UnboxedPlainObject>().data(); + + for (; *traceList != -1; traceList++) {} + traceList++; + for (; *traceList != -1; traceList++) { + JSObject* newInnerObj = *reinterpret_cast<JSObject**>(newData + *traceList); + JSObject* oldInnerObj = *reinterpret_cast<JSObject**>(oldData + *traceList); + + if (!newInnerObj || !oldInnerObj || SameGroup(oldInnerObj, newInnerObj)) + continue; + + if (!GiveObjectGroup(cx, newInnerObj, oldInnerObj)) + return false; + + if (SameGroup(oldInnerObj, newInnerObj)) + continue; + + if (!GiveObjectGroup(cx, oldInnerObj, newInnerObj)) + return false; + + if (SameGroup(oldInnerObj, newInnerObj)) { + for (size_t i = 1; i < ncompare; i++) { + if (compare[i].isObject() && SameGroup(&compare[i].toObject(), newObj)) { + uint8_t* otherData = compare[i].toObject().as<UnboxedPlainObject>().data(); + JSObject* otherInnerObj = *reinterpret_cast<JSObject**>(otherData + *traceList); + if (otherInnerObj && !SameGroup(otherInnerObj, newInnerObj)) { + if (!GiveObjectGroup(cx, otherInnerObj, newInnerObj)) + return false; + } + } + } + } + } } return true; @@ -1192,6 +1314,12 @@ ObjectGroup::newPlainObject(ExclusiveContext* cx, IdValuePair* properties, size_ RootedObjectGroup group(cx, p->value().group); + // Watch for existing groups which now use an unboxed layout. + if (group->maybeUnboxedLayout()) { + MOZ_ASSERT(group->unboxedLayout().properties().length() == nproperties); + return UnboxedPlainObject::createWithProperties(cx, group, newKind, properties); + } + // Update property types according to the properties we are about to add. // Do this before we do anything which can GC, which might move or remove // this table entry. @@ -1378,6 +1506,18 @@ ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* scriptArg, jsbytecode* } } + if (kind == JSProto_Array && + (JSOp(*pc) == JSOP_NEWARRAY || IsCallPC(pc)) && + cx->options().unboxedArrays()) + { + PreliminaryObjectArrayWithTemplate* preliminaryObjects = + cx->new_<PreliminaryObjectArrayWithTemplate>(nullptr); + if (preliminaryObjects) + res->setPreliminaryObjects(preliminaryObjects); + else + cx->recoverFromOutOfMemory(); + } + if (!table->add(p, key, res)) { ReportOutOfMemory(cx); return nullptr; |