diff options
-rw-r--r-- | js/src/jsarray.cpp | 1 | ||||
-rw-r--r-- | js/src/jscompartment.h | 3 | ||||
-rw-r--r-- | js/src/jsfriendapi.cpp | 2 | ||||
-rw-r--r-- | js/src/jsobj.cpp | 1 | ||||
-rw-r--r-- | js/src/jsobjinlines.h | 15 | ||||
-rw-r--r-- | js/src/moz.build | 1 | ||||
-rw-r--r-- | js/src/vm/Interpreter.cpp | 5 | ||||
-rw-r--r-- | js/src/vm/NativeObject.cpp | 27 | ||||
-rw-r--r-- | js/src/vm/NativeObject.h | 5 | ||||
-rw-r--r-- | js/src/vm/ObjectGroup-inl.h | 14 | ||||
-rw-r--r-- | js/src/vm/ObjectGroup.cpp | 55 | ||||
-rw-r--r-- | js/src/vm/ObjectGroup.h | 28 | ||||
-rw-r--r-- | js/src/vm/ReceiverGuard.cpp | 14 | ||||
-rw-r--r-- | js/src/vm/TypeInference-inl.h | 5 | ||||
-rw-r--r-- | js/src/vm/TypeInference.cpp | 142 | ||||
-rw-r--r-- | js/src/vm/UnboxedObject-inl.h | 177 | ||||
-rw-r--r-- | js/src/vm/UnboxedObject.cpp | 759 | ||||
-rw-r--r-- | js/src/vm/UnboxedObject.h | 319 |
18 files changed, 13 insertions, 1560 deletions
diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 5854fda4c3..ec65bce64e 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -45,7 +45,6 @@ #include "vm/Caches-inl.h" #include "vm/Interpreter-inl.h" #include "vm/NativeObject-inl.h" -#include "vm/UnboxedObject-inl.h" using namespace js; using namespace js::gc; diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 98c8fe200d..83c15da3b5 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -529,9 +529,6 @@ struct JSCompartment // table manages references from such typed objects to their buffers. js::ObjectWeakMap* lazyArrayBuffers; - // All unboxed layouts in the compartment. - mozilla::LinkedList<js::UnboxedLayout> unboxedLayouts; - // WebAssembly state for the compartment. js::wasm::Compartment wasm; diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 1fd9d1d287..5baba0beb0 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -269,7 +269,7 @@ js::GetBuiltinClass(JSContext* cx, HandleObject obj, ESClass* cls) if (MOZ_UNLIKELY(obj->is<ProxyObject>())) return Proxy::getBuiltinClass(cx, obj, cls); - if (obj->is<PlainObject>() || obj->is<UnboxedPlainObject>()) + if (obj->is<PlainObject>()) *cls = ESClass::Object; else if (obj->is<ArrayObject>()) *cls = ESClass::Array; diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index deaa1d53e3..58988739bf 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -54,7 +54,6 @@ #include "vm/RegExpStaticsObject.h" #include "vm/Shape.h" #include "vm/TypedArrayCommon.h" -#include "vm/UnboxedObject-inl.h" #include "jsatominlines.h" #include "jsboolinlines.h" diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 26f9eacce3..b1d817bcab 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -32,19 +32,6 @@ #include "vm/ShapedObject-inl.h" #include "vm/TypeInference-inl.h" -namespace js { - -// This is needed here for ensureShape() below. -inline bool -MaybeConvertUnboxedObjectToNative(ExclusiveContext* cx, JSObject* obj) -{ - if (obj->is<UnboxedPlainObject>()) - return UnboxedPlainObject::convertToNative(cx->asJSContext(), obj); - return true; -} - -} // namespace js - inline js::Shape* JSObject::maybeShape() const { @@ -57,8 +44,6 @@ JSObject::maybeShape() const inline js::Shape* JSObject::ensureShape(js::ExclusiveContext* cx) { - if (!js::MaybeConvertUnboxedObjectToNative(cx, this)) - return nullptr; js::Shape* shape = maybeShape(); MOZ_ASSERT(shape); return shape; diff --git a/js/src/moz.build b/js/src/moz.build index 8887411384..eb30866c8e 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -355,7 +355,6 @@ UNIFIED_SOURCES += [ 'vm/UbiNode.cpp', 'vm/UbiNodeCensus.cpp', 'vm/UbiNodeShortestPaths.cpp', - 'vm/UnboxedObject.cpp', 'vm/Unicode.cpp', 'vm/Value.cpp', 'vm/WeakMapPtr.cpp', diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 74a1ef3e9e..0f83c34352 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -4970,11 +4970,6 @@ js::NewObjectOperationWithTemplate(JSContext* cx, HandleObject templateObject) NewObjectKind newKind = templateObject->group()->shouldPreTenure() ? TenuredObject : GenericObject; - if (templateObject->group()->maybeUnboxedLayout()) { - RootedObjectGroup group(cx, templateObject->group()); - return UnboxedPlainObject::create(cx, group, newKind); - } - JSObject* obj = CopyInitializerObject(cx, templateObject.as<PlainObject>(), newKind); if (!obj) return nullptr; diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index 21f73f4a91..a3f28653a3 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -390,33 +390,6 @@ NativeObject::setLastPropertyMakeNonNative(Shape* shape) shape_ = shape; } -void -NativeObject::setLastPropertyMakeNative(ExclusiveContext* cx, Shape* shape) -{ - MOZ_ASSERT(getClass()->isNative()); - MOZ_ASSERT(shape->getObjectClass()->isNative()); - MOZ_ASSERT(!shape->inDictionary()); - - // This method is used to convert unboxed objects into native objects. In - // this case, the shape_ field was previously used to store other data and - // this should be treated as an initialization. - shape_.init(shape); - - slots_ = nullptr; - elements_ = emptyObjectElements; - - size_t oldSpan = shape->numFixedSlots(); - size_t newSpan = shape->slotSpan(); - - initializeSlotRange(0, oldSpan); - - // A failure at this point will leave the object as a mutant, and we - // can't recover. - AutoEnterOOMUnsafeRegion oomUnsafe; - if (oldSpan != newSpan && !updateSlotsForSpan(cx, oldSpan, newSpan)) - oomUnsafe.crash("NativeObject::setLastPropertyMakeNative"); -} - bool NativeObject::setSlotSpan(ExclusiveContext* cx, uint32_t span) { diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index da4f873a63..d9d8b8aec2 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -470,11 +470,6 @@ class NativeObject : public ShapedObject // that are (temporarily) inconsistent. void setLastPropertyMakeNonNative(Shape* shape); - // As for setLastProperty(), but changes the class associated with the - // object to a native one. The object's type has already been changed, and - // this brings the shape into sync with it. - void setLastPropertyMakeNative(ExclusiveContext* cx, Shape* shape); - // Newly-created TypedArrays that map a SharedArrayBuffer are // marked as shared by giving them an ObjectElements that has the // ObjectElements::SHARED_MEMORY flag set. diff --git a/js/src/vm/ObjectGroup-inl.h b/js/src/vm/ObjectGroup-inl.h index 9074f4d974..d41343be64 100644 --- a/js/src/vm/ObjectGroup-inl.h +++ b/js/src/vm/ObjectGroup-inl.h @@ -108,20 +108,6 @@ ObjectGroup::maybePreliminaryObjects() return maybePreliminaryObjectsDontCheckGeneration(); } -inline UnboxedLayout* -ObjectGroup::maybeUnboxedLayout() -{ - maybeSweep(nullptr); - return maybeUnboxedLayoutDontCheckGeneration(); -} - -inline UnboxedLayout& -ObjectGroup::unboxedLayout() -{ - maybeSweep(nullptr); - return unboxedLayoutDontCheckGeneration(); -} - } // namespace js #endif /* vm_ObjectGroup_inl_h */ diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 63ac33eea5..676792379e 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -18,11 +18,10 @@ #include "vm/ArrayObject.h" #include "vm/Shape.h" #include "vm/TaggedProto.h" -#include "vm/UnboxedObject.h" #include "jsobjinlines.h" -#include "vm/UnboxedObject-inl.h" +#include "vm/NativeObject-inl.h" using namespace js; @@ -56,7 +55,6 @@ ObjectGroup::finalize(FreeOp* fop) if (newScriptDontCheckGeneration()) newScriptDontCheckGeneration()->clear(); fop->delete_(newScriptDontCheckGeneration()); - fop->delete_(maybeUnboxedLayoutDontCheckGeneration()); if (maybePreliminaryObjectsDontCheckGeneration()) maybePreliminaryObjectsDontCheckGeneration()->clear(); fop->delete_(maybePreliminaryObjectsDontCheckGeneration()); @@ -83,8 +81,6 @@ 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; } @@ -530,8 +526,7 @@ 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_ || - group->clasp() == &UnboxedPlainObject::class_); + MOZ_ASSERT_IF(!clasp, group->clasp() == &PlainObject::class_); MOZ_ASSERT(group->proto() == proto); return group; } @@ -971,46 +966,6 @@ 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; @@ -1234,12 +1189,6 @@ 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. diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h index 553cb83667..bf8398742d 100644 --- a/js/src/vm/ObjectGroup.h +++ b/js/src/vm/ObjectGroup.h @@ -20,7 +20,6 @@ namespace js { class TypeDescr; -class UnboxedLayout; class PreliminaryObjectArrayWithTemplate; class TypeNewScript; @@ -154,11 +153,6 @@ class ObjectGroup : public gc::TenuredCell // For some plain objects, the addendum stores a PreliminaryObjectArrayWithTemplate. Addendum_PreliminaryObjects, - // When objects in this group have an unboxed representation, the - // addendum stores an UnboxedLayout (which might have a TypeNewScript - // as well, if the group is also constructed using 'new'). - Addendum_UnboxedLayout, - // If this group is used by objects that have been converted from an // unboxed representation and/or have the same allocation kind as such // objects, the addendum points to that unboxed group. @@ -225,24 +219,6 @@ class ObjectGroup : public gc::TenuredCell maybePreliminaryObjectsDontCheckGeneration(); } - inline UnboxedLayout* maybeUnboxedLayout(); - inline UnboxedLayout& unboxedLayout(); - - UnboxedLayout* maybeUnboxedLayoutDontCheckGeneration() const { - if (addendumKind() == Addendum_UnboxedLayout) - return reinterpret_cast<UnboxedLayout*>(addendum_); - return nullptr; - } - - UnboxedLayout& unboxedLayoutDontCheckGeneration() const { - MOZ_ASSERT(addendumKind() == Addendum_UnboxedLayout); - return *maybeUnboxedLayoutDontCheckGeneration(); - } - - void setUnboxedLayout(UnboxedLayout* layout) { - setAddendum(Addendum_UnboxedLayout, layout); - } - ObjectGroup* maybeOriginalUnboxedGroup() const { if (addendumKind() == Addendum_OriginalUnboxedGroup) return reinterpret_cast<ObjectGroup*>(addendum_); @@ -511,8 +487,8 @@ class ObjectGroup : public gc::TenuredCell NewObjectKind newKind, NewArrayKind arrayKind = NewArrayKind::Normal); - // Create a PlainObject or UnboxedPlainObject with the specified properties - // and a group specialized for those properties. + // Create a PlainObject with the specified properties and a group specialized + // for those properties. static JSObject* newPlainObject(ExclusiveContext* cx, IdValuePair* properties, size_t nproperties, NewObjectKind newKind); diff --git a/js/src/vm/ReceiverGuard.cpp b/js/src/vm/ReceiverGuard.cpp index e37bf8ee52..e95e8a208a 100644 --- a/js/src/vm/ReceiverGuard.cpp +++ b/js/src/vm/ReceiverGuard.cpp @@ -15,11 +15,7 @@ ReceiverGuard::ReceiverGuard(JSObject* obj) : group(nullptr), shape(nullptr) { if (obj) { - if (obj->is<UnboxedPlainObject>()) { - group = obj->group(); - if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando()) - shape = expando->lastProperty(); - } else if (obj->is<TypedObject>()) { + if (obj->is<TypedObject>()) { group = obj->group(); } else { shape = obj->maybeShape(); @@ -32,9 +28,7 @@ ReceiverGuard::ReceiverGuard(ObjectGroup* group, Shape* shape) { if (group) { const Class* clasp = group->clasp(); - if (clasp == &UnboxedPlainObject::class_) { - // Keep both group and shape. - } else if (IsTypedObjectClass(clasp)) { + if (IsTypedObjectClass(clasp)) { this->shape = nullptr; } else { this->group = nullptr; @@ -45,10 +39,6 @@ ReceiverGuard::ReceiverGuard(ObjectGroup* group, Shape* shape) /* static */ int32_t HeapReceiverGuard::keyBits(JSObject* obj) { - if (obj->is<UnboxedPlainObject>()) { - // Both the group and shape need to be guarded for unboxed plain objects. - return obj->as<UnboxedPlainObject>().maybeExpando() ? 0 : 1; - } if (obj->is<TypedObject>()) { // Only the group needs to be guarded for typed objects. return 2; diff --git a/js/src/vm/TypeInference-inl.h b/js/src/vm/TypeInference-inl.h index da47fa898b..2af252cea1 100644 --- a/js/src/vm/TypeInference-inl.h +++ b/js/src/vm/TypeInference-inl.h @@ -23,7 +23,6 @@ #include "vm/SharedArrayObject.h" #include "vm/StringObject.h" #include "vm/TypedArrayObject.h" -#include "vm/UnboxedObject.h" #include "jscntxtinlines.h" @@ -285,10 +284,6 @@ TypeIdString(jsid id) */ struct AutoEnterAnalysis { - // For use when initializing an UnboxedLayout. The UniquePtr's destructor - // must run when GC is not suppressed. - UniquePtr<UnboxedLayout> unboxedLayoutToCleanUp; - // Prevent GC activity in the middle of analysis. gc::AutoSuppressGC suppressGC; diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 0551e2c585..26ade29480 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -35,7 +35,6 @@ #include "vm/Opcodes.h" #include "vm/Shape.h" #include "vm/Time.h" -#include "vm/UnboxedObject.h" #include "jsatominlines.h" #include "jsscriptinlines.h" @@ -297,9 +296,6 @@ js::ObjectGroupHasProperty(JSContext* cx, ObjectGroup* group, jsid id, const Val return true; } } - JSObject* obj = &value.toObject(); - if (!obj->hasLazyGroup() && obj->group()->maybeOriginalUnboxedGroup()) - return true; } if (!types->hasType(type)) { @@ -1944,33 +1940,6 @@ class ConstraintDataFreezeObjectForTypedArrayData } }; -// Constraint which triggers recompilation if an unboxed object in some group -// is converted to a native object. -class ConstraintDataFreezeObjectForUnboxedConvertedToNative -{ - public: - ConstraintDataFreezeObjectForUnboxedConvertedToNative() - {} - - const char* kind() { return "freezeObjectForUnboxedConvertedToNative"; } - - bool invalidateOnNewType(TypeSet::Type type) { return false; } - bool invalidateOnNewPropertyState(TypeSet* property) { return false; } - bool invalidateOnNewObjectState(ObjectGroup* group) { - return group->unboxedLayout().nativeGroup() != nullptr; - } - - bool constraintHolds(JSContext* cx, - const HeapTypeSetKey& property, TemporaryTypeSet* expected) - { - return !invalidateOnNewObjectState(property.object()->maybeGroup()); - } - - bool shouldSweep() { return false; } - - JSCompartment* maybeCompartment() { return nullptr; } -}; - } /* anonymous namespace */ void @@ -2505,8 +2474,6 @@ TemporaryTypeSet::propertyNeedsBarrier(CompilerConstraintList* constraints, jsid bool js::ClassCanHaveExtraProperties(const Class* clasp) { - if (clasp == &UnboxedPlainObject::class_) - return false; return clasp->getResolve() || clasp->getOpsLookupProperty() || clasp->getOpsGetProperty() @@ -2805,15 +2772,6 @@ js::AddTypePropertyId(ExclusiveContext* cx, ObjectGroup* group, JSObject* obj, j // from acquiring the fully initialized group. if (group->newScript() && group->newScript()->initializedGroup()) AddTypePropertyId(cx, group->newScript()->initializedGroup(), nullptr, id, type); - - // Maintain equivalent type information for unboxed object groups and their - // corresponding native group. Since type sets might contain the unboxed - // group but not the native group, this ensures optimizations based on the - // unboxed group are valid for the native group. - if (group->maybeUnboxedLayout() && group->maybeUnboxedLayout()->nativeGroup()) - AddTypePropertyId(cx, group->maybeUnboxedLayout()->nativeGroup(), nullptr, id, type); - if (ObjectGroup* unboxedGroup = group->maybeOriginalUnboxedGroup()) - AddTypePropertyId(cx, unboxedGroup, nullptr, id, type); } void @@ -2885,12 +2843,6 @@ ObjectGroup::setFlags(ExclusiveContext* cx, ObjectGroupFlags flags) // acquired properties analysis. if (newScript() && newScript()->initializedGroup()) newScript()->initializedGroup()->setFlags(cx, flags); - - // Propagate flag changes between unboxed and corresponding native groups. - if (maybeUnboxedLayout() && maybeUnboxedLayout()->nativeGroup()) - maybeUnboxedLayout()->nativeGroup()->setFlags(cx, flags); - if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup()) - unboxedGroup->setFlags(cx, flags); } void @@ -2923,13 +2875,6 @@ ObjectGroup::markUnknown(ExclusiveContext* cx) prop->types.setNonDataProperty(cx); } } - - if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup()) - MarkObjectGroupUnknownProperties(cx, unboxedGroup); - if (maybeUnboxedLayout() && maybeUnboxedLayout()->nativeGroup()) - MarkObjectGroupUnknownProperties(cx, maybeUnboxedLayout()->nativeGroup()); - if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup()) - MarkObjectGroupUnknownProperties(cx, unboxedGroup); } TypeNewScript* @@ -2937,8 +2882,6 @@ ObjectGroup::anyNewScript() { if (newScript()) return newScript(); - if (maybeUnboxedLayout()) - return unboxedLayout().newScript(); return nullptr; } @@ -2968,10 +2911,7 @@ ObjectGroup::detachNewScript(bool writeBarrier, ObjectGroup* replacement) MOZ_ASSERT(!replacement); } - if (this->newScript()) - setAddendum(Addendum_None, nullptr, writeBarrier); - else - unboxedLayout().setNewScript(nullptr, writeBarrier); + setAddendum(Addendum_None, nullptr, writeBarrier); } void @@ -3451,22 +3391,6 @@ PreliminaryObjectArray::sweep() for (size_t i = 0; i < COUNT; i++) { JSObject** ptr = &objects[i]; if (*ptr && IsAboutToBeFinalizedUnbarriered(ptr)) { - // Before we clear this reference, change the object's group to the - // Object.prototype group. This is done to ensure JSObject::finalize - // sees a NativeObject Class even if we change the current group's - // Class to one of the unboxed object classes in the meantime. If - // the compartment's global is dead, we don't do anything as the - // group's Class is not going to change in that case. - JSObject* obj = *ptr; - GlobalObject* global = obj->compartment()->unsafeUnbarrieredMaybeGlobal(); - if (global && !obj->isSingleton()) { - JSObject* objectProto = GetBuiltinPrototypePure(global, JSProto_Object); - obj->setGroup(objectProto->groupRaw()); - MOZ_ASSERT(obj->is<NativeObject>()); - MOZ_ASSERT(obj->getClass() == objectProto->getClass()); - MOZ_ASSERT(!obj->getClass()->hasFinalize()); - } - *ptr = nullptr; } } @@ -3566,16 +3490,11 @@ PreliminaryObjectArrayWithTemplate::maybeAnalyze(ExclusiveContext* cx, ObjectGro } } - if (group->maybeUnboxedLayout()) - return; - - if (shape()) { - // We weren't able to use an unboxed layout, but since the preliminary - // objects still reflect the template object's properties, and all - // objects in the future will be created with those properties, the - // properties can be marked as definite for objects in the group. - group->addDefiniteProperties(cx, shape()); - } + // Since the preliminary objects still reflect the template object's + // properties, and all objects in the future will be created with those + // properties, the properties can be marked as definitive for objects in + // the group. + group->addDefiniteProperties(cx, shape()); } ///////////////////////////////////////////////////////////////////// @@ -3589,7 +3508,6 @@ TypeNewScript::make(JSContext* cx, ObjectGroup* group, JSFunction* fun) { MOZ_ASSERT(cx->zone()->types.activeAnalysis); MOZ_ASSERT(!group->newScript()); - MOZ_ASSERT(!group->maybeUnboxedLayout()); // rollbackPartiallyInitializedObjects expects function_ to be // canonicalized. @@ -3852,27 +3770,6 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, js_delete(preliminaryObjects); preliminaryObjects = nullptr; - if (group->maybeUnboxedLayout()) { - // An unboxed layout was constructed for the group, and this has already - // been hooked into it. - MOZ_ASSERT(group->unboxedLayout().newScript() == this); - destroyNewScript.group = nullptr; - - // Clear out the template object, which is not used for TypeNewScripts - // with an unboxed layout. Currently it is a mutant object with a - // non-native group and native shape, so make it safe for GC by changing - // its group to the default for its prototype. - AutoEnterOOMUnsafeRegion oomUnsafe; - ObjectGroup* plainGroup = ObjectGroup::defaultNewGroup(cx, &PlainObject::class_, - group->proto()); - if (!plainGroup) - oomUnsafe.crash("TypeNewScript::maybeAnalyze"); - templateObject_->setGroup(plainGroup); - templateObject_ = nullptr; - - return true; - } - if (prefixShape->slotSpan() == templateObject()->slotSpan()) { // The definite properties analysis found exactly the properties that // are held in common by the preliminary objects. No further analysis @@ -3968,12 +3865,6 @@ TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* g continue; } - if (thisv.toObject().is<UnboxedPlainObject>()) { - AutoEnterOOMUnsafeRegion oomUnsafe; - if (!UnboxedPlainObject::convertToNative(cx, &thisv.toObject())) - oomUnsafe.crash("rollbackPartiallyInitializedObjects"); - } - // Found a matching frame. RootedPlainObject obj(cx, &thisv.toObject().as<PlainObject>()); @@ -4167,12 +4058,6 @@ ConstraintTypeSet::sweep(Zone* zone, AutoClearTypeInferenceStateOnOOM& oom) // Object sets containing objects with unknown properties might // not be complete. Mark the type set as unknown, which it will // be treated as during Ion compilation. - // - // Note that we don't have to do this when the type set might - // be missing the native group corresponding to an unboxed - // object group. In this case, the native group points to the - // unboxed object group via its addendum, so as long as objects - // with either group exist, neither group will be finalized. flags |= TYPE_FLAG_ANYOBJECT; clearObjects(); objectCount = 0; @@ -4256,21 +4141,6 @@ ObjectGroup::sweep(AutoClearTypeInferenceStateOnOOM* oom) Maybe<AutoClearTypeInferenceStateOnOOM> fallbackOOM; EnsureHasAutoClearTypeInferenceStateOnOOM(oom, zone(), fallbackOOM); - if (maybeUnboxedLayout()) { - // Remove unboxed layouts that are about to be finalized from the - // compartment wide list while we are still on the main thread. - ObjectGroup* group = this; - if (IsAboutToBeFinalizedUnbarriered(&group)) - unboxedLayout().detachFromCompartment(); - - if (unboxedLayout().newScript()) - unboxedLayout().newScript()->sweep(); - - // Discard constructor code to avoid holding onto ExecutablePools. - if (zone()->isGCCompacting()) - unboxedLayout().setConstructorCode(nullptr); - } - if (maybePreliminaryObjects()) maybePreliminaryObjects()->sweep(); diff --git a/js/src/vm/UnboxedObject-inl.h b/js/src/vm/UnboxedObject-inl.h deleted file mode 100644 index c1468a5b18..0000000000 --- a/js/src/vm/UnboxedObject-inl.h +++ /dev/null @@ -1,177 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef vm_UnboxedObject_inl_h -#define vm_UnboxedObject_inl_h - -#include "vm/UnboxedObject.h" - -#include "gc/StoreBuffer-inl.h" -#include "vm/ArrayObject-inl.h" -#include "vm/NativeObject-inl.h" - -namespace js { - -static inline Value -GetUnboxedValue(uint8_t* p, JSValueType type, bool maybeUninitialized) -{ - switch (type) { - case JSVAL_TYPE_BOOLEAN: - return BooleanValue(*p != 0); - - case JSVAL_TYPE_INT32: - return Int32Value(*reinterpret_cast<int32_t*>(p)); - - case JSVAL_TYPE_DOUBLE: { - // During unboxed plain object creation, non-GC thing properties are - // left uninitialized. This is normally fine, since the properties will - // be filled in shortly, but if they are read before that happens we - // need to make sure that doubles are canonical. - double d = *reinterpret_cast<double*>(p); - if (maybeUninitialized) - return DoubleValue(JS::CanonicalizeNaN(d)); - return DoubleValue(d); - } - - case JSVAL_TYPE_STRING: - return StringValue(*reinterpret_cast<JSString**>(p)); - - case JSVAL_TYPE_OBJECT: - return ObjectOrNullValue(*reinterpret_cast<JSObject**>(p)); - - default: - MOZ_CRASH("Invalid type for unboxed value"); - } -} - -static inline void -SetUnboxedValueNoTypeChange(JSObject* unboxedObject, - uint8_t* p, JSValueType type, const Value& v, - bool preBarrier) -{ - switch (type) { - case JSVAL_TYPE_BOOLEAN: - *p = v.toBoolean(); - return; - - case JSVAL_TYPE_INT32: - *reinterpret_cast<int32_t*>(p) = v.toInt32(); - return; - - case JSVAL_TYPE_DOUBLE: - *reinterpret_cast<double*>(p) = v.toNumber(); - return; - - case JSVAL_TYPE_STRING: { - MOZ_ASSERT(!IsInsideNursery(v.toString())); - JSString** np = reinterpret_cast<JSString**>(p); - if (preBarrier) - JSString::writeBarrierPre(*np); - *np = v.toString(); - return; - } - - case JSVAL_TYPE_OBJECT: { - JSObject** np = reinterpret_cast<JSObject**>(p); - - // Manually trigger post barriers on the whole object. If we treat - // the pointer as a HeapPtrObject we will get confused later if the - // object is converted to its native representation. - JSObject* obj = v.toObjectOrNull(); - if (IsInsideNursery(obj) && !IsInsideNursery(unboxedObject)) { - JSRuntime* rt = unboxedObject->runtimeFromMainThread(); - rt->gc.storeBuffer.putWholeCell(unboxedObject); - } - - if (preBarrier) - JSObject::writeBarrierPre(*np); - *np = obj; - return; - } - - default: - MOZ_CRASH("Invalid type for unboxed value"); - } -} - -static inline bool -SetUnboxedValue(ExclusiveContext* cx, JSObject* unboxedObject, jsid id, - uint8_t* p, JSValueType type, const Value& v, bool preBarrier) -{ - switch (type) { - case JSVAL_TYPE_BOOLEAN: - if (v.isBoolean()) { - *p = v.toBoolean(); - return true; - } - return false; - - case JSVAL_TYPE_INT32: - if (v.isInt32()) { - *reinterpret_cast<int32_t*>(p) = v.toInt32(); - return true; - } - return false; - - case JSVAL_TYPE_DOUBLE: - if (v.isNumber()) { - *reinterpret_cast<double*>(p) = v.toNumber(); - return true; - } - return false; - - case JSVAL_TYPE_STRING: - if (v.isString()) { - MOZ_ASSERT(!IsInsideNursery(v.toString())); - JSString** np = reinterpret_cast<JSString**>(p); - if (preBarrier) - JSString::writeBarrierPre(*np); - *np = v.toString(); - return true; - } - return false; - - case JSVAL_TYPE_OBJECT: - if (v.isObjectOrNull()) { - JSObject** np = reinterpret_cast<JSObject**>(p); - - // Update property types when writing object properties. Types for - // other properties were captured when the unboxed layout was - // created. - AddTypePropertyId(cx, unboxedObject, id, v); - - // As above, trigger post barriers on the whole object. - JSObject* obj = v.toObjectOrNull(); - if (IsInsideNursery(v.toObjectOrNull()) && !IsInsideNursery(unboxedObject)) { - JSRuntime* rt = unboxedObject->runtimeFromMainThread(); - rt->gc.storeBuffer.putWholeCell(unboxedObject); - } - - if (preBarrier) - JSObject::writeBarrierPre(*np); - *np = obj; - return true; - } - return false; - - default: - MOZ_CRASH("Invalid type for unboxed value"); - } -} - -///////////////////////////////////////////////////////////////////// -// UnboxedPlainObject -///////////////////////////////////////////////////////////////////// - -inline const UnboxedLayout& -UnboxedPlainObject::layout() const -{ - return group()->unboxedLayout(); -} - -} // namespace js - -#endif // vm_UnboxedObject_inl_h diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp deleted file mode 100644 index a96fb58a8e..0000000000 --- a/js/src/vm/UnboxedObject.cpp +++ /dev/null @@ -1,759 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "vm/UnboxedObject-inl.h" - -#include "jit/BaselineIC.h" -#include "jit/ExecutableAllocator.h" -#include "jit/JitCommon.h" -#include "jit/Linker.h" - -#include "jsobjinlines.h" - -#include "gc/Nursery-inl.h" -#include "jit/MacroAssembler-inl.h" -#include "vm/Shape-inl.h" - -using mozilla::ArrayLength; -using mozilla::DebugOnly; -using mozilla::PodCopy; - -using namespace js; - -///////////////////////////////////////////////////////////////////// -// UnboxedLayout -///////////////////////////////////////////////////////////////////// - -void -UnboxedLayout::trace(JSTracer* trc) -{ - for (size_t i = 0; i < properties_.length(); i++) - TraceManuallyBarrieredEdge(trc, &properties_[i].name, "unboxed_layout_name"); - - if (newScript()) - newScript()->trace(trc); - - TraceNullableEdge(trc, &nativeGroup_, "unboxed_layout_nativeGroup"); - TraceNullableEdge(trc, &nativeShape_, "unboxed_layout_nativeShape"); - TraceNullableEdge(trc, &allocationScript_, "unboxed_layout_allocationScript"); - TraceNullableEdge(trc, &replacementGroup_, "unboxed_layout_replacementGroup"); - TraceNullableEdge(trc, &constructorCode_, "unboxed_layout_constructorCode"); -} - -size_t -UnboxedLayout::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) -{ - return mallocSizeOf(this) - + properties_.sizeOfExcludingThis(mallocSizeOf) - + (newScript() ? newScript()->sizeOfIncludingThis(mallocSizeOf) : 0) - + mallocSizeOf(traceList()); -} - -void -UnboxedLayout::setNewScript(TypeNewScript* newScript, bool writeBarrier /* = true */) -{ - if (newScript_ && writeBarrier) - TypeNewScript::writeBarrierPre(newScript_); - newScript_ = newScript; -} - -// Constructor code returns a 0x1 value to indicate the constructor code should -// be cleared. -static const uintptr_t CLEAR_CONSTRUCTOR_CODE_TOKEN = 0x1; - -/* static */ bool -UnboxedLayout::makeConstructorCode(JSContext* cx, HandleObjectGroup group) -{ - // *** STUB *** - return false; -} - -void -UnboxedLayout::detachFromCompartment() -{ - if (isInList()) - remove(); -} - -///////////////////////////////////////////////////////////////////// -// UnboxedPlainObject -///////////////////////////////////////////////////////////////////// - -bool -UnboxedPlainObject::setValue(ExclusiveContext* cx, const UnboxedLayout::Property& property, - const Value& v) -{ - uint8_t* p = &data_[property.offset]; - return SetUnboxedValue(cx, this, NameToId(property.name), p, property.type, v, - /* preBarrier = */ true); -} - -Value -UnboxedPlainObject::getValue(const UnboxedLayout::Property& property, - bool maybeUninitialized /* = false */) -{ - uint8_t* p = &data_[property.offset]; - return GetUnboxedValue(p, property.type, maybeUninitialized); -} - -void -UnboxedPlainObject::trace(JSTracer* trc, JSObject* obj) -{ - if (obj->as<UnboxedPlainObject>().expando_) { - TraceManuallyBarrieredEdge(trc, - reinterpret_cast<NativeObject**>(&obj->as<UnboxedPlainObject>().expando_), - "unboxed_expando"); - } - - const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layoutDontCheckGeneration(); - const int32_t* list = layout.traceList(); - if (!list) - return; - - uint8_t* data = obj->as<UnboxedPlainObject>().data(); - while (*list != -1) { - GCPtrString* heap = reinterpret_cast<GCPtrString*>(data + *list); - TraceEdge(trc, heap, "unboxed_string"); - list++; - } - list++; - while (*list != -1) { - GCPtrObject* heap = reinterpret_cast<GCPtrObject*>(data + *list); - TraceNullableEdge(trc, heap, "unboxed_object"); - list++; - } - - // Unboxed objects don't have Values to trace. - MOZ_ASSERT(*(list + 1) == -1); -} - -/* static */ UnboxedExpandoObject* -UnboxedPlainObject::ensureExpando(JSContext* cx, Handle<UnboxedPlainObject*> obj) -{ - if (obj->expando_) - return obj->expando_; - - UnboxedExpandoObject* expando = - NewObjectWithGivenProto<UnboxedExpandoObject>(cx, nullptr, gc::AllocKind::OBJECT4); - if (!expando) - return nullptr; - - // Don't track property types for expando objects. This allows Baseline - // and Ion AddSlot ICs to guard on the unboxed group without guarding on - // the expando group. - MarkObjectGroupUnknownProperties(cx, expando->group()); - - // If the expando is tenured then the original object must also be tenured. - // Otherwise barriers triggered on the original object for writes to the - // expando (as can happen in the JIT) won't see the tenured->nursery edge. - // See WholeCellEdges::mark. - MOZ_ASSERT_IF(!IsInsideNursery(expando), !IsInsideNursery(obj)); - - // As with setValue(), we need to manually trigger post barriers on the - // whole object. If we treat the field as a GCPtrObject and later - // convert the object to its native representation, we will end up with a - // corrupted store buffer entry. - if (IsInsideNursery(expando) && !IsInsideNursery(obj)) - cx->runtime()->gc.storeBuffer.putWholeCell(obj); - - obj->expando_ = expando; - return expando; -} - -bool -UnboxedPlainObject::containsUnboxedOrExpandoProperty(ExclusiveContext* cx, jsid id) const -{ - if (layout().lookup(id)) - return true; - - if (maybeExpando() && maybeExpando()->containsShapeOrElement(cx, id)) - return true; - - return false; -} - -static bool -PropagatePropertyTypes(JSContext* cx, jsid id, ObjectGroup* oldGroup, ObjectGroup* newGroup) -{ - HeapTypeSet* typeProperty = oldGroup->maybeGetProperty(id); - TypeSet::TypeList types; - if (!typeProperty->enumerateTypes(&types)) { - ReportOutOfMemory(cx); - return false; - } - for (size_t j = 0; j < types.length(); j++) - AddTypePropertyId(cx, newGroup, nullptr, id, types[j]); - return true; -} - -static PlainObject* -MakeReplacementTemplateObject(JSContext* cx, HandleObjectGroup group, const UnboxedLayout &layout) -{ - PlainObject* obj = NewObjectWithGroup<PlainObject>(cx, group, layout.getAllocKind(), - TenuredObject); - if (!obj) - return nullptr; - - for (size_t i = 0; i < layout.properties().length(); i++) { - const UnboxedLayout::Property& property = layout.properties()[i]; - if (!obj->addDataProperty(cx, NameToId(property.name), i, JSPROP_ENUMERATE)) - return nullptr; - MOZ_ASSERT(obj->slotSpan() == i + 1); - MOZ_ASSERT(!obj->inDictionaryMode()); - } - - return obj; -} - -/* static */ bool -UnboxedLayout::makeNativeGroup(JSContext* cx, ObjectGroup* group) -{ - AutoEnterAnalysis enter(cx); - - UnboxedLayout& layout = group->unboxedLayout(); - Rooted<TaggedProto> proto(cx, group->proto()); - - MOZ_ASSERT(!layout.nativeGroup()); - - RootedObjectGroup replacementGroup(cx); - - // Immediately clear any new script on the group. This is done by replacing - // the existing new script with one for a replacement default new group. - // This is done so that the size of the replacment group's objects is the - // same as that for the unboxed group, so that we do not see polymorphic - // slot accesses later on for sites that see converted objects from this - // group and objects that were allocated using the replacement new group. - if (layout.newScript()) { - replacementGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto); - if (!replacementGroup) - return false; - - PlainObject* templateObject = MakeReplacementTemplateObject(cx, replacementGroup, layout); - if (!templateObject) - return false; - - TypeNewScript* replacementNewScript = - TypeNewScript::makeNativeVersion(cx, layout.newScript(), templateObject); - if (!replacementNewScript) - return false; - - replacementGroup->setNewScript(replacementNewScript); - gc::TraceTypeNewScript(replacementGroup); - - group->clearNewScript(cx, replacementGroup); - } - - // Similarly, if this group is keyed to an allocation site, replace its - // entry with a new group that has no unboxed layout. - if (layout.allocationScript()) { - RootedScript script(cx, layout.allocationScript()); - jsbytecode* pc = layout.allocationPc(); - - replacementGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto); - if (!replacementGroup) - return false; - - PlainObject* templateObject = &script->getObject(pc)->as<PlainObject>(); - replacementGroup->addDefiniteProperties(cx, templateObject->lastProperty()); - - cx->compartment()->objectGroups.replaceAllocationSiteGroup(script, pc, JSProto_Object, - replacementGroup); - - // Clear any baseline information at this opcode which might use the old group. - if (script->hasBaselineScript()) { - jit::ICEntry& entry = script->baselineScript()->icEntryFromPCOffset(script->pcToOffset(pc)); - jit::ICFallbackStub* fallback = entry.fallbackStub(); - for (jit::ICStubIterator iter = fallback->beginChain(); !iter.atEnd(); iter++) - iter.unlink(cx); - if (fallback->isNewObject_Fallback()) - fallback->toNewObject_Fallback()->setTemplateObject(nullptr); - else if (fallback->isNewArray_Fallback()) - fallback->toNewArray_Fallback()->setTemplateGroup(replacementGroup); - } - } - - size_t nfixed = gc::GetGCKindSlots(layout.getAllocKind()); - - RootedShape shape(cx, EmptyShape::getInitialShape(cx, &PlainObject::class_, proto, nfixed, 0)); - if (!shape) - return false; - - // Add shapes for each property, if this is for a plain object. - for (size_t i = 0; i < layout.properties().length(); i++) { - const UnboxedLayout::Property& property = layout.properties()[i]; - - Rooted<StackShape> child(cx, StackShape(shape->base()->unowned(), NameToId(property.name), - i, JSPROP_ENUMERATE, 0)); - shape = cx->zone()->propertyTree.getChild(cx, shape, child); - if (!shape) - return false; - } - - ObjectGroup* nativeGroup = - ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto, - group->flags() & OBJECT_FLAG_DYNAMIC_MASK); - if (!nativeGroup) - return false; - - // No sense propagating if we don't know what we started with. - if (!group->unknownProperties()) { - // Propagate all property types from the old group to the new group. - for (size_t i = 0; i < layout.properties().length(); i++) { - const UnboxedLayout::Property& property = layout.properties()[i]; - jsid id = NameToId(property.name); - if (!PropagatePropertyTypes(cx, id, group, nativeGroup)) - return false; - - // If we are OOM we may not be able to propagate properties. - if (nativeGroup->unknownProperties()) - break; - - HeapTypeSet* nativeProperty = nativeGroup->maybeGetProperty(id); - if (nativeProperty && nativeProperty->canSetDefinite(i)) - nativeProperty->setDefinite(i); - } - } else { - // If we skip, though, the new group had better agree. - MOZ_ASSERT(nativeGroup->unknownProperties()); - } - - layout.nativeGroup_ = nativeGroup; - layout.nativeShape_ = shape; - layout.replacementGroup_ = replacementGroup; - - nativeGroup->setOriginalUnboxedGroup(group); - - group->markStateChange(cx); - - return true; -} - -/* static */ bool -UnboxedPlainObject::convertToNative(JSContext* cx, JSObject* obj) -{ - const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout(); - UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando(); - - if (!layout.nativeGroup()) { - if (!UnboxedLayout::makeNativeGroup(cx, obj->group())) - return false; - - // makeNativeGroup can reentrantly invoke this method. - if (obj->is<PlainObject>()) - return true; - } - - AutoValueVector values(cx); - for (size_t i = 0; i < layout.properties().length(); i++) { - // We might be reading properties off the object which have not been - // initialized yet. Make sure any double values we read here are - // canonicalized. - if (!values.append(obj->as<UnboxedPlainObject>().getValue(layout.properties()[i], true))) - return false; - } - - // We are eliminating the expando edge with the conversion, so trigger a - // pre barrier. - JSObject::writeBarrierPre(expando); - - // Additionally trigger a post barrier on the expando itself. Whole cell - // store buffer entries can be added on the original unboxed object for - // writes to the expando (see WholeCellEdges::trace), so after conversion - // we need to make sure the expando itself will still be traced. - if (expando && !IsInsideNursery(expando)) - cx->runtime()->gc.storeBuffer.putWholeCell(expando); - - obj->setGroup(layout.nativeGroup()); - obj->as<PlainObject>().setLastPropertyMakeNative(cx, layout.nativeShape()); - - for (size_t i = 0; i < values.length(); i++) - obj->as<PlainObject>().initSlotUnchecked(i, values[i]); - - if (expando) { - // Add properties from the expando object to the object, in order. - // Suppress GC here, so that callers don't need to worry about this - // method collecting. The stuff below can only fail due to OOM, in - // which case the object will not have been completely filled back in. - gc::AutoSuppressGC suppress(cx); - - Vector<jsid> ids(cx); - for (Shape::Range<NoGC> r(expando->lastProperty()); !r.empty(); r.popFront()) { - if (!ids.append(r.front().propid())) - return false; - } - for (size_t i = 0; i < expando->getDenseInitializedLength(); i++) { - if (!expando->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) { - if (!ids.append(INT_TO_JSID(i))) - return false; - } - } - ::Reverse(ids.begin(), ids.end()); - - RootedPlainObject nobj(cx, &obj->as<PlainObject>()); - Rooted<UnboxedExpandoObject*> nexpando(cx, expando); - RootedId id(cx); - Rooted<PropertyDescriptor> desc(cx); - for (size_t i = 0; i < ids.length(); i++) { - id = ids[i]; - if (!GetOwnPropertyDescriptor(cx, nexpando, id, &desc)) - return false; - ObjectOpResult result; - if (!DefineProperty(cx, nobj, id, desc, result)) - return false; - MOZ_ASSERT(result.ok()); - } - } - - return true; -} - -/* static */ -UnboxedPlainObject* -UnboxedPlainObject::create(ExclusiveContext* cx, HandleObjectGroup group, NewObjectKind newKind) -{ - AutoSetNewObjectMetadata metadata(cx); - - MOZ_ASSERT(group->clasp() == &class_); - gc::AllocKind allocKind = group->unboxedLayout().getAllocKind(); - - UnboxedPlainObject* res = - NewObjectWithGroup<UnboxedPlainObject>(cx, group, allocKind, newKind); - if (!res) - return nullptr; - - // Overwrite the dummy shape which was written to the object's expando field. - res->initExpando(); - - // Initialize reference fields of the object. All fields in the object will - // be overwritten shortly, but references need to be safe for the GC. - const int32_t* list = res->layout().traceList(); - if (list) { - uint8_t* data = res->data(); - while (*list != -1) { - GCPtrString* heap = reinterpret_cast<GCPtrString*>(data + *list); - heap->init(cx->names().empty); - list++; - } - list++; - while (*list != -1) { - GCPtrObject* heap = reinterpret_cast<GCPtrObject*>(data + *list); - heap->init(nullptr); - list++; - } - // Unboxed objects don't have Values to initialize. - MOZ_ASSERT(*(list + 1) == -1); - } - - return res; -} - -/* static */ JSObject* -UnboxedPlainObject::createWithProperties(ExclusiveContext* cx, HandleObjectGroup group, - NewObjectKind newKind, IdValuePair* properties) -{ - MOZ_ASSERT(newKind == GenericObject || newKind == TenuredObject); - - UnboxedLayout& layout = group->unboxedLayout(); - - if (layout.constructorCode()) { - MOZ_ASSERT(cx->isJSContext()); - - typedef JSObject* (*ConstructorCodeSignature)(IdValuePair*, NewObjectKind); - ConstructorCodeSignature function = - reinterpret_cast<ConstructorCodeSignature>(layout.constructorCode()->raw()); - - JSObject* obj; - { - JS::AutoSuppressGCAnalysis nogc; - obj = reinterpret_cast<JSObject*>(CALL_GENERATED_2(function, properties, newKind)); - } - if (obj > reinterpret_cast<JSObject*>(CLEAR_CONSTRUCTOR_CODE_TOKEN)) - return obj; - - if (obj == reinterpret_cast<JSObject*>(CLEAR_CONSTRUCTOR_CODE_TOKEN)) - layout.setConstructorCode(nullptr); - } - - UnboxedPlainObject* obj = UnboxedPlainObject::create(cx, group, newKind); - if (!obj) - return nullptr; - - for (size_t i = 0; i < layout.properties().length(); i++) { - if (!obj->setValue(cx, layout.properties()[i], properties[i].value)) - return NewPlainObjectWithProperties(cx, properties, layout.properties().length(), newKind); - } - -#ifndef JS_CODEGEN_NONE - if (cx->isJSContext() && - !group->unknownProperties() && - !layout.constructorCode() && - cx->asJSContext()->runtime()->jitSupportsFloatingPoint && - jit::CanLikelyAllocateMoreExecutableMemory()) - { - if (!UnboxedLayout::makeConstructorCode(cx->asJSContext(), group)) - return nullptr; - } -#endif - - return obj; -} - -/* static */ bool -UnboxedPlainObject::obj_lookupProperty(JSContext* cx, HandleObject obj, - HandleId id, MutableHandleObject objp, - MutableHandleShape propp) -{ - if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) { - MarkNonNativePropertyFound<CanGC>(propp); - objp.set(obj); - return true; - } - - RootedObject proto(cx, obj->staticPrototype()); - if (!proto) { - objp.set(nullptr); - propp.set(nullptr); - return true; - } - - return LookupProperty(cx, proto, id, objp, propp); -} - -/* static */ bool -UnboxedPlainObject::obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, - Handle<PropertyDescriptor> desc, - ObjectOpResult& result) -{ - const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout(); - - if (const UnboxedLayout::Property* property = layout.lookup(id)) { - if (!desc.getter() && !desc.setter() && desc.attributes() == JSPROP_ENUMERATE) { - // This define is equivalent to setting an existing property. - if (obj->as<UnboxedPlainObject>().setValue(cx, *property, desc.value())) - return result.succeed(); - } - - // Trying to incompatibly redefine an existing property requires the - // object to be converted to a native object. - if (!convertToNative(cx, obj)) - return false; - - return DefineProperty(cx, obj, id, desc, result); - } - - // Define the property on the expando object. - Rooted<UnboxedExpandoObject*> expando(cx, ensureExpando(cx, obj.as<UnboxedPlainObject>())); - if (!expando) - return false; - - // Update property types on the unboxed object as well. - AddTypePropertyId(cx, obj, id, desc.value()); - - return DefineProperty(cx, expando, id, desc, result); -} - -/* static */ bool -UnboxedPlainObject::obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp) -{ - if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) { - *foundp = true; - return true; - } - - RootedObject proto(cx, obj->staticPrototype()); - if (!proto) { - *foundp = false; - return true; - } - - return HasProperty(cx, proto, id, foundp); -} - -/* static */ bool -UnboxedPlainObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver, - HandleId id, MutableHandleValue vp) -{ - const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout(); - - if (const UnboxedLayout::Property* property = layout.lookup(id)) { - vp.set(obj->as<UnboxedPlainObject>().getValue(*property)); - return true; - } - - if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando()) { - if (expando->containsShapeOrElement(cx, id)) { - RootedObject nexpando(cx, expando); - return GetProperty(cx, nexpando, receiver, id, vp); - } - } - - RootedObject proto(cx, obj->staticPrototype()); - if (!proto) { - vp.setUndefined(); - return true; - } - - return GetProperty(cx, proto, receiver, id, vp); -} - -/* static */ bool -UnboxedPlainObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result) -{ - const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout(); - - if (const UnboxedLayout::Property* property = layout.lookup(id)) { - if (receiver.isObject() && obj == &receiver.toObject()) { - if (obj->as<UnboxedPlainObject>().setValue(cx, *property, v)) - return result.succeed(); - - if (!convertToNative(cx, obj)) - return false; - return SetProperty(cx, obj, id, v, receiver, result); - } - - return SetPropertyByDefining(cx, id, v, receiver, result); - } - - if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando()) { - if (expando->containsShapeOrElement(cx, id)) { - // Update property types on the unboxed object as well. - AddTypePropertyId(cx, obj, id, v); - - RootedObject nexpando(cx, expando); - return SetProperty(cx, nexpando, id, v, receiver, result); - } - } - - return SetPropertyOnProto(cx, obj, id, v, receiver, result); -} - -/* static */ bool -UnboxedPlainObject::obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle<PropertyDescriptor> desc) -{ - const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout(); - - if (const UnboxedLayout::Property* property = layout.lookup(id)) { - desc.value().set(obj->as<UnboxedPlainObject>().getValue(*property)); - desc.setAttributes(JSPROP_ENUMERATE); - desc.object().set(obj); - return true; - } - - if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando()) { - if (expando->containsShapeOrElement(cx, id)) { - RootedObject nexpando(cx, expando); - if (!GetOwnPropertyDescriptor(cx, nexpando, id, desc)) - return false; - if (desc.object() == nexpando) - desc.object().set(obj); - return true; - } - } - - desc.object().set(nullptr); - return true; -} - -/* static */ bool -UnboxedPlainObject::obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id, - ObjectOpResult& result) -{ - if (!convertToNative(cx, obj)) - return false; - return DeleteProperty(cx, obj, id, result); -} - -/* static */ bool -UnboxedPlainObject::obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable) -{ - if (!convertToNative(cx, obj)) - return false; - return WatchProperty(cx, obj, id, callable); -} - -/* static */ bool -UnboxedPlainObject::obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties, - bool enumerableOnly) -{ - // Ignore expando properties here, they are special-cased by the property - // enumeration code. - - const UnboxedLayout::PropertyVector& unboxed = obj->as<UnboxedPlainObject>().layout().properties(); - for (size_t i = 0; i < unboxed.length(); i++) { - if (!properties.append(NameToId(unboxed[i].name))) - return false; - } - - return true; -} - -const Class UnboxedExpandoObject::class_ = { - "UnboxedExpandoObject", - 0 -}; - -static const ClassOps UnboxedPlainObjectClassOps = { - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - UnboxedPlainObject::trace, -}; - -static const ObjectOps UnboxedPlainObjectObjectOps = { - UnboxedPlainObject::obj_lookupProperty, - UnboxedPlainObject::obj_defineProperty, - UnboxedPlainObject::obj_hasProperty, - UnboxedPlainObject::obj_getProperty, - UnboxedPlainObject::obj_setProperty, - UnboxedPlainObject::obj_getOwnPropertyDescriptor, - UnboxedPlainObject::obj_deleteProperty, - UnboxedPlainObject::obj_watch, - nullptr, /* No unwatch needed, as watch() converts the object to native */ - nullptr, /* getElements */ - UnboxedPlainObject::obj_enumerate, - nullptr /* funToString */ -}; - -const Class UnboxedPlainObject::class_ = { - js_Object_str, - Class::NON_NATIVE | - JSCLASS_HAS_CACHED_PROTO(JSProto_Object) | - JSCLASS_DELAY_METADATA_BUILDER, - &UnboxedPlainObjectClassOps, - JS_NULL_CLASS_SPEC, - JS_NULL_CLASS_EXT, - &UnboxedPlainObjectObjectOps -}; - -///////////////////////////////////////////////////////////////////// -// API -///////////////////////////////////////////////////////////////////// - -static inline Value -NextValue(Handle<GCVector<Value>> values, size_t* valueCursor) -{ - return values[(*valueCursor)++]; -} - -void -UnboxedPlainObject::fillAfterConvert(ExclusiveContext* cx, - Handle<GCVector<Value>> values, size_t* valueCursor) -{ - initExpando(); - memset(data(), 0, layout().size()); - for (size_t i = 0; i < layout().properties().length(); i++) - JS_ALWAYS_TRUE(setValue(cx, layout().properties()[i], NextValue(values, valueCursor))); -} diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h deleted file mode 100644 index ba66434bc2..0000000000 --- a/js/src/vm/UnboxedObject.h +++ /dev/null @@ -1,319 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef vm_UnboxedObject_h -#define vm_UnboxedObject_h - -#include "jsgc.h" -#include "jsobj.h" - -#include "vm/Runtime.h" -#include "vm/TypeInference.h" - -namespace js { - -// Memory required for an unboxed value of a given type. Returns zero for types -// which can't be used for unboxed objects. -static inline size_t -UnboxedTypeSize(JSValueType type) -{ - switch (type) { - case JSVAL_TYPE_BOOLEAN: return 1; - case JSVAL_TYPE_INT32: return 4; - case JSVAL_TYPE_DOUBLE: return 8; - case JSVAL_TYPE_STRING: return sizeof(void*); - case JSVAL_TYPE_OBJECT: return sizeof(void*); - default: return 0; - } -} - -static inline bool -UnboxedTypeNeedsPreBarrier(JSValueType type) -{ - return type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_OBJECT; -} - -static inline bool -UnboxedTypeNeedsPostBarrier(JSValueType type) -{ - return type == JSVAL_TYPE_OBJECT; -} - -// Class tracking information specific to unboxed objects. -class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout> -{ - public: - struct Property { - PropertyName* name; - uint32_t offset; - JSValueType type; - - Property() - : name(nullptr), offset(UINT32_MAX), type(JSVAL_TYPE_MAGIC) - {} - }; - - typedef Vector<Property, 0, SystemAllocPolicy> PropertyVector; - - private: - // If objects in this group have ever been converted to native objects, - // these store the corresponding native group and initial shape for such - // objects. Type information for this object is reflected in nativeGroup. - GCPtrObjectGroup nativeGroup_; - GCPtrShape nativeShape_; - - // Any script/pc which the associated group is created for. - GCPtrScript allocationScript_; - jsbytecode* allocationPc_; - - // If nativeGroup is set and this object originally had a TypeNewScript or - // was keyed to an allocation site, this points to the group which replaced - // this one. This link is only needed to keep the replacement group from - // being GC'ed. If it were GC'ed and a new one regenerated later, that new - // group might have a different allocation kind from this group. - GCPtrObjectGroup replacementGroup_; - - // The following members are only used for unboxed plain objects. - - // All properties on objects with this layout, in enumeration order. - PropertyVector properties_; - - // Byte size of the data for objects with this layout. - size_t size_; - - // Any 'new' script information associated with this layout. - TypeNewScript* newScript_; - - // List for use in tracing objects with this layout. This has the same - // structure as the trace list on a TypeDescr. - int32_t* traceList_; - - // If this layout has been used to construct script or JSON constant - // objects, this code might be filled in to more quickly fill in objects - // from an array of values. - GCPtrJitCode constructorCode_; - - public: - UnboxedLayout() - : nativeGroup_(nullptr), nativeShape_(nullptr), - allocationScript_(nullptr), allocationPc_(nullptr), replacementGroup_(nullptr), - size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr) - {} - - bool initProperties(const PropertyVector& properties, size_t size) { - size_ = size; - return properties_.appendAll(properties); - } - - ~UnboxedLayout() { - if (newScript_) - newScript_->clear(); - js_delete(newScript_); - js_free(traceList_); - - nativeGroup_.init(nullptr); - nativeShape_.init(nullptr); - replacementGroup_.init(nullptr); - constructorCode_.init(nullptr); - } - - void detachFromCompartment(); - - const PropertyVector& properties() const { - return properties_; - } - - TypeNewScript* newScript() const { - return newScript_; - } - - void setNewScript(TypeNewScript* newScript, bool writeBarrier = true); - - JSScript* allocationScript() const { - return allocationScript_; - } - - jsbytecode* allocationPc() const { - return allocationPc_; - } - - void setAllocationSite(JSScript* script, jsbytecode* pc) { - allocationScript_ = script; - allocationPc_ = pc; - } - - const int32_t* traceList() const { - return traceList_; - } - - void setTraceList(int32_t* traceList) { - traceList_ = traceList; - } - - const Property* lookup(JSAtom* atom) const { - for (size_t i = 0; i < properties_.length(); i++) { - if (properties_[i].name == atom) - return &properties_[i]; - } - return nullptr; - } - - const Property* lookup(jsid id) const { - if (JSID_IS_STRING(id)) - return lookup(JSID_TO_ATOM(id)); - return nullptr; - } - - size_t size() const { - return size_; - } - - ObjectGroup* nativeGroup() const { - return nativeGroup_; - } - - Shape* nativeShape() const { - return nativeShape_; - } - - jit::JitCode* constructorCode() const { - return constructorCode_; - } - - void setConstructorCode(jit::JitCode* code) { - constructorCode_ = code; - } - - inline gc::AllocKind getAllocKind() const; - - void trace(JSTracer* trc); - - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); - - static bool makeNativeGroup(JSContext* cx, ObjectGroup* group); - static bool makeConstructorCode(JSContext* cx, HandleObjectGroup group); -}; - -// Class for expando objects holding extra properties given to an unboxed plain -// object. These objects behave identically to normal native plain objects, and -// have a separate Class to distinguish them for memory usage reporting. -class UnboxedExpandoObject : public NativeObject -{ - public: - static const Class class_; -}; - -// Class for a plain object using an unboxed representation. The physical -// layout of these objects is identical to that of an InlineTypedObject, though -// these objects use an UnboxedLayout instead of a TypeDescr to keep track of -// how their properties are stored. -class UnboxedPlainObject : public JSObject -{ - // Optional object which stores extra properties on this object. This is - // not automatically barriered to avoid problems if the object is converted - // to a native. See ensureExpando(). - UnboxedExpandoObject* expando_; - - // Start of the inline data, which immediately follows the group and extra properties. - uint8_t data_[1]; - - public: - static const Class class_; - - static bool obj_lookupProperty(JSContext* cx, HandleObject obj, - HandleId id, MutableHandleObject objp, - MutableHandleShape propp); - - static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, - Handle<PropertyDescriptor> desc, - ObjectOpResult& result); - - static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp); - - static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver, - HandleId id, MutableHandleValue vp); - - static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, - HandleValue receiver, ObjectOpResult& result); - - static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle<PropertyDescriptor> desc); - - static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id, - ObjectOpResult& result); - - static bool obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties, - bool enumerableOnly); - static bool obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable); - - inline const UnboxedLayout& layout() const; - - const UnboxedLayout& layoutDontCheckGeneration() const { - return group()->unboxedLayoutDontCheckGeneration(); - } - - uint8_t* data() { - return &data_[0]; - } - - UnboxedExpandoObject* maybeExpando() const { - return expando_; - } - - void initExpando() { - expando_ = nullptr; - } - - // For use during GC. - JSObject** addressOfExpando() { - return reinterpret_cast<JSObject**>(&expando_); - } - - bool containsUnboxedOrExpandoProperty(ExclusiveContext* cx, jsid id) const; - - static UnboxedExpandoObject* ensureExpando(JSContext* cx, Handle<UnboxedPlainObject*> obj); - - bool setValue(ExclusiveContext* cx, const UnboxedLayout::Property& property, const Value& v); - Value getValue(const UnboxedLayout::Property& property, bool maybeUninitialized = false); - - static bool convertToNative(JSContext* cx, JSObject* obj); - static UnboxedPlainObject* create(ExclusiveContext* cx, HandleObjectGroup group, - NewObjectKind newKind); - static JSObject* createWithProperties(ExclusiveContext* cx, HandleObjectGroup group, - NewObjectKind newKind, IdValuePair* properties); - - void fillAfterConvert(ExclusiveContext* cx, - Handle<GCVector<Value>> values, size_t* valueCursor); - - static void trace(JSTracer* trc, JSObject* object); - - static size_t offsetOfExpando() { - return offsetof(UnboxedPlainObject, expando_); - } - - static size_t offsetOfData() { - return offsetof(UnboxedPlainObject, data_[0]); - } -}; - -inline gc::AllocKind -UnboxedLayout::getAllocKind() const -{ - MOZ_ASSERT(size()); - return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size()); -} - -} // namespace js - -namespace JS { - -template <> -struct DeletePolicy<js::UnboxedLayout> : public js::GCManagedDeletePolicy<js::UnboxedLayout> -{}; - -} /* namespace JS */ - -#endif /* vm_UnboxedObject_h */ |