| /* -*- 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_ObjectGroup_h |
| #define vm_ObjectGroup_h |
| |
| #include "jsbytecode.h" |
| #include "jsfriendapi.h" |
| |
| #include "ds/IdValuePair.h" |
| #include "gc/Barrier.h" |
| #include "vm/TaggedProto.h" |
| #include "vm/TypeInference.h" |
| |
| namespace js { |
| |
| class TypeDescr; |
| class UnboxedLayout; |
| |
| class PreliminaryObjectArrayWithTemplate; |
| class TypeNewScript; |
| class HeapTypeSet; |
| class AutoClearTypeInferenceStateOnOOM; |
| class CompilerConstraintList; |
| |
| namespace gc { |
| void MergeCompartments(JSCompartment* source, JSCompartment* target); |
| } // namespace gc |
| |
| /* |
| * The NewObjectKind allows an allocation site to specify the type properties |
| * and lifetime requirements that must be fixed at allocation time. |
| */ |
| enum NewObjectKind { |
| /* This is the default. Most objects are generic. */ |
| GenericObject, |
| |
| /* |
| * Singleton objects are treated specially by the type system. This flag |
| * ensures that the new object is automatically set up correctly as a |
| * singleton and is allocated in the tenured heap. |
| */ |
| SingletonObject, |
| |
| /* |
| * Objects which will not benefit from being allocated in the nursery |
| * (e.g. because they are known to have a long lifetime) may be allocated |
| * with this kind to place them immediately into the tenured generation. |
| */ |
| TenuredObject |
| }; |
| |
| /* |
| * Lazy object groups overview. |
| * |
| * Object groups which represent at most one JS object are constructed lazily. |
| * These include groups for native functions, standard classes, scripted |
| * functions defined at the top level of global/eval scripts, objects which |
| * dynamically become the prototype of some other object, and in some other |
| * cases. Typical web workloads often create many windows (and many copies of |
| * standard natives) and many scripts, with comparatively few non-singleton |
| * groups. |
| * |
| * We can recover the type information for the object from examining it, |
| * so don't normally track the possible types of its properties as it is |
| * updated. Property type sets for the object are only constructed when an |
| * analyzed script attaches constraints to it: the script is querying that |
| * property off the object or another which delegates to it, and the analysis |
| * information is sensitive to changes in the property's type. Future changes |
| * to the property (whether those uncovered by analysis or those occurring |
| * in the VM) will treat these properties like those of any other object group. |
| */ |
| |
| /* Type information about an object accessed by a script. */ |
| class ObjectGroup : public gc::TenuredCell |
| { |
| friend void gc::MergeCompartments(JSCompartment* source, JSCompartment* target); |
| |
| /* Class shared by objects in this group. */ |
| const Class* clasp_; |
| |
| /* Prototype shared by objects in this group. */ |
| HeapPtr<TaggedProto> proto_; |
| |
| /* Compartment shared by objects in this group. */ |
| JSCompartment* compartment_; |
| |
| public: |
| |
| const Class* clasp() const { |
| return clasp_; |
| } |
| |
| void setClasp(const Class* clasp) { |
| clasp_ = clasp; |
| } |
| |
| const HeapPtr<TaggedProto>& proto() const { |
| return proto_; |
| } |
| |
| HeapPtr<TaggedProto>& proto() { |
| return proto_; |
| } |
| |
| void setProto(TaggedProto proto); |
| void setProtoUnchecked(TaggedProto proto); |
| |
| bool singleton() const { |
| return flagsDontCheckGeneration() & OBJECT_FLAG_SINGLETON; |
| } |
| |
| bool lazy() const { |
| bool res = flagsDontCheckGeneration() & OBJECT_FLAG_LAZY_SINGLETON; |
| MOZ_ASSERT_IF(res, singleton()); |
| return res; |
| } |
| |
| JSCompartment* compartment() const { return compartment_; } |
| JSCompartment* maybeCompartment() const { return compartment(); } |
| |
| private: |
| /* Flags for this group. */ |
| ObjectGroupFlags flags_; |
| |
| // Kinds of addendums which can be attached to ObjectGroups. |
| enum AddendumKind { |
| Addendum_None, |
| |
| // When used by interpreted function, the addendum stores the |
| // canonical JSFunction object. |
| Addendum_InterpretedFunction, |
| |
| // When used by the 'new' group when constructing an interpreted |
| // function, the addendum stores a TypeNewScript. |
| Addendum_NewScript, |
| |
| // 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. |
| Addendum_OriginalUnboxedGroup, |
| |
| // When used by typed objects, the addendum stores a TypeDescr. |
| Addendum_TypeDescr |
| }; |
| |
| // If non-null, holds additional information about this object, whose |
| // format is indicated by the object's addendum kind. |
| void* addendum_; |
| |
| void setAddendum(AddendumKind kind, void* addendum, bool writeBarrier = true); |
| |
| AddendumKind addendumKind() const { |
| return (AddendumKind) |
| ((flags_ & OBJECT_FLAG_ADDENDUM_MASK) >> OBJECT_FLAG_ADDENDUM_SHIFT); |
| } |
| |
| TypeNewScript* newScriptDontCheckGeneration() const { |
| if (addendumKind() == Addendum_NewScript) |
| return reinterpret_cast<TypeNewScript*>(addendum_); |
| return nullptr; |
| } |
| |
| TypeNewScript* anyNewScript(); |
| void detachNewScript(bool writeBarrier, ObjectGroup* replacement); |
| |
| ObjectGroupFlags flagsDontCheckGeneration() const { |
| return flags_; |
| } |
| |
| public: |
| |
| inline ObjectGroupFlags flags(); |
| inline void addFlags(ObjectGroupFlags flags); |
| inline void clearFlags(ObjectGroupFlags flags); |
| inline TypeNewScript* newScript(); |
| |
| void setNewScript(TypeNewScript* newScript) { |
| setAddendum(Addendum_NewScript, newScript); |
| } |
| |
| inline PreliminaryObjectArrayWithTemplate* maybePreliminaryObjects(); |
| |
| PreliminaryObjectArrayWithTemplate* maybePreliminaryObjectsDontCheckGeneration() { |
| if (addendumKind() == Addendum_PreliminaryObjects) |
| return reinterpret_cast<PreliminaryObjectArrayWithTemplate*>(addendum_); |
| return nullptr; |
| } |
| |
| void setPreliminaryObjects(PreliminaryObjectArrayWithTemplate* preliminaryObjects) { |
| setAddendum(Addendum_PreliminaryObjects, preliminaryObjects); |
| } |
| |
| void detachPreliminaryObjects() { |
| MOZ_ASSERT(maybePreliminaryObjectsDontCheckGeneration()); |
| setAddendum(Addendum_None, nullptr); |
| } |
| |
| bool hasUnanalyzedPreliminaryObjects() { |
| return (newScriptDontCheckGeneration() && !newScriptDontCheckGeneration()->analyzed()) || |
| 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_); |
| return nullptr; |
| } |
| |
| void setOriginalUnboxedGroup(ObjectGroup* group) { |
| setAddendum(Addendum_OriginalUnboxedGroup, group); |
| } |
| |
| TypeDescr* maybeTypeDescr() { |
| // Note: there is no need to sweep when accessing the type descriptor |
| // of an object, as it is strongly held and immutable. |
| if (addendumKind() == Addendum_TypeDescr) |
| return reinterpret_cast<TypeDescr*>(addendum_); |
| return nullptr; |
| } |
| |
| TypeDescr& typeDescr() { |
| MOZ_ASSERT(addendumKind() == Addendum_TypeDescr); |
| return *maybeTypeDescr(); |
| } |
| |
| void setTypeDescr(TypeDescr* descr) { |
| setAddendum(Addendum_TypeDescr, descr); |
| } |
| |
| JSFunction* maybeInterpretedFunction() { |
| // Note: as with type descriptors, there is no need to sweep when |
| // accessing the interpreted function associated with an object. |
| if (addendumKind() == Addendum_InterpretedFunction) |
| return reinterpret_cast<JSFunction*>(addendum_); |
| return nullptr; |
| } |
| |
| void setInterpretedFunction(JSFunction* fun) { |
| setAddendum(Addendum_InterpretedFunction, fun); |
| } |
| |
| class Property |
| { |
| public: |
| // Identifier for this property, JSID_VOID for the aggregate integer |
| // index property, or JSID_EMPTY for properties holding constraints |
| // listening to changes in the group's state. |
| HeapId id; |
| |
| // Possible own types for this property. |
| HeapTypeSet types; |
| |
| explicit Property(jsid id) |
| : id(id) |
| {} |
| |
| Property(const Property& o) |
| : id(o.id.get()), types(o.types) |
| {} |
| |
| static uint32_t keyBits(jsid id) { return uint32_t(JSID_BITS(id)); } |
| static jsid getKey(Property* p) { return p->id; } |
| }; |
| |
| private: |
| /* |
| * Properties of this object. |
| * |
| * The type sets in the properties of a group describe the possible values |
| * that can be read out of that property in actual JS objects. In native |
| * objects, property types account for plain data properties (those with a |
| * slot and no getter or setter hook) and dense elements. In typed objects |
| * and unboxed objects, property types account for object and value |
| * properties and elements in the object, and expando properties in unboxed |
| * objects. |
| * |
| * For accesses on these properties, the correspondence is as follows: |
| * |
| * 1. If the group has unknownProperties(), the possible properties and |
| * value types for associated JSObjects are unknown. |
| * |
| * 2. Otherwise, for any |obj| in |group|, and any |id| which is a property |
| * in |obj|, before obj->getProperty(id) the property in |group| for |
| * |id| must reflect the result of the getProperty. |
| * |
| * There are several exceptions to this: |
| * |
| * 1. For properties of global JS objects which are undefined at the point |
| * where the property was (lazily) generated, the property type set will |
| * remain empty, and the 'undefined' type will only be added after a |
| * subsequent assignment or deletion. After these properties have been |
| * assigned a defined value, the only way they can become undefined |
| * again is after such an assign or deletion. |
| * |
| * 2. Array lengths are special cased by the compiler and VM and are not |
| * reflected in property types. |
| * |
| * 3. In typed objects (but not unboxed objects), the initial values of |
| * properties (null pointers and undefined values) are not reflected in |
| * the property types. These values are always possible when reading the |
| * property. |
| * |
| * We establish these by using write barriers on calls to setProperty and |
| * defineProperty which are on native properties, and on any jitcode which |
| * might update the property with a new type. |
| */ |
| Property** propertySet; |
| public: |
| |
| inline ObjectGroup(const Class* clasp, TaggedProto proto, JSCompartment* comp, |
| ObjectGroupFlags initialFlags); |
| |
| inline bool hasAnyFlags(ObjectGroupFlags flags); |
| inline bool hasAllFlags(ObjectGroupFlags flags); |
| |
| bool hasAllFlagsDontCheckGeneration(ObjectGroupFlags flags) { |
| MOZ_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); |
| return (this->flagsDontCheckGeneration() & flags) == flags; |
| } |
| |
| inline bool unknownProperties(); |
| |
| bool unknownPropertiesDontCheckGeneration() { |
| MOZ_ASSERT_IF(flagsDontCheckGeneration() & OBJECT_FLAG_UNKNOWN_PROPERTIES, |
| hasAllFlagsDontCheckGeneration(OBJECT_FLAG_DYNAMIC_MASK)); |
| return !!(flagsDontCheckGeneration() & OBJECT_FLAG_UNKNOWN_PROPERTIES); |
| } |
| |
| inline bool shouldPreTenure(); |
| |
| gc::InitialHeap initialHeap(CompilerConstraintList* constraints); |
| |
| inline bool canPreTenure(); |
| inline bool fromAllocationSite(); |
| inline void setShouldPreTenure(ExclusiveContext* cx); |
| |
| /* |
| * Get or create a property of this object. Only call this for properties which |
| * a script accesses explicitly. |
| */ |
| inline HeapTypeSet* getProperty(ExclusiveContext* cx, JSObject* obj, jsid id); |
| |
| /* Get a property only if it already exists. */ |
| inline HeapTypeSet* maybeGetProperty(jsid id); |
| |
| /* |
| * Iterate through the group's properties. getPropertyCount overapproximates |
| * in the hash case (see SET_ARRAY_SIZE in TypeInference-inl.h), and |
| * getProperty may return nullptr. |
| */ |
| inline unsigned getPropertyCount(); |
| inline Property* getProperty(unsigned i); |
| |
| /* Helpers */ |
| |
| void updateNewPropertyTypes(ExclusiveContext* cx, JSObject* obj, jsid id, HeapTypeSet* types); |
| void addDefiniteProperties(ExclusiveContext* cx, Shape* shape); |
| bool matchDefiniteProperties(HandleObject obj); |
| void markPropertyNonData(ExclusiveContext* cx, JSObject* obj, jsid id); |
| void markPropertyNonWritable(ExclusiveContext* cx, JSObject* obj, jsid id); |
| void markStateChange(ExclusiveContext* cx); |
| void setFlags(ExclusiveContext* cx, ObjectGroupFlags flags); |
| void markUnknown(ExclusiveContext* cx); |
| void maybeClearNewScriptOnOOM(); |
| void clearNewScript(ExclusiveContext* cx, ObjectGroup* replacement = nullptr); |
| |
| void print(); |
| |
| inline void clearProperties(); |
| void traceChildren(JSTracer* trc); |
| |
| inline bool needsSweep(); |
| inline void maybeSweep(AutoClearTypeInferenceStateOnOOM* oom); |
| |
| private: |
| void sweep(AutoClearTypeInferenceStateOnOOM* oom); |
| |
| uint32_t generation() { |
| return (flags_ & OBJECT_FLAG_GENERATION_MASK) >> OBJECT_FLAG_GENERATION_SHIFT; |
| } |
| |
| public: |
| void setGeneration(uint32_t generation) { |
| MOZ_ASSERT(generation <= (OBJECT_FLAG_GENERATION_MASK >> OBJECT_FLAG_GENERATION_SHIFT)); |
| flags_ &= ~OBJECT_FLAG_GENERATION_MASK; |
| flags_ |= generation << OBJECT_FLAG_GENERATION_SHIFT; |
| } |
| |
| size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; |
| |
| void finalize(FreeOp* fop); |
| void fixupAfterMovingGC() {} |
| |
| static inline ThingRootKind rootKind() { return THING_ROOT_OBJECT_GROUP; } |
| |
| static inline uint32_t offsetOfClasp() { |
| return offsetof(ObjectGroup, clasp_); |
| } |
| |
| static inline uint32_t offsetOfProto() { |
| return offsetof(ObjectGroup, proto_); |
| } |
| |
| static inline uint32_t offsetOfAddendum() { |
| return offsetof(ObjectGroup, addendum_); |
| } |
| |
| static inline uint32_t offsetOfFlags() { |
| return offsetof(ObjectGroup, flags_); |
| } |
| |
| const ObjectGroupFlags* addressOfFlags() const { |
| return &flags_; |
| } |
| |
| // Get the bit pattern stored in an object's addendum when it has an |
| // original unboxed group. |
| static inline int32_t addendumOriginalUnboxedGroupValue() { |
| return Addendum_OriginalUnboxedGroup << OBJECT_FLAG_ADDENDUM_SHIFT; |
| } |
| |
| inline uint32_t basePropertyCount(); |
| |
| private: |
| inline void setBasePropertyCount(uint32_t count); |
| |
| static void staticAsserts() { |
| JS_STATIC_ASSERT(offsetof(ObjectGroup, proto_) == offsetof(js::shadow::ObjectGroup, proto)); |
| } |
| |
| public: |
| // Whether to make a deep cloned singleton when cloning fun. |
| static bool useSingletonForClone(JSFunction* fun); |
| |
| // Whether to make a singleton when calling 'new' at script/pc. |
| static bool useSingletonForNewObject(JSContext* cx, JSScript* script, jsbytecode* pc); |
| |
| // Whether to make a singleton object at an allocation site. |
| static bool useSingletonForAllocationSite(JSScript* script, jsbytecode* pc, |
| JSProtoKey key); |
| static bool useSingletonForAllocationSite(JSScript* script, jsbytecode* pc, |
| const Class* clasp); |
| |
| // Static accessors for ObjectGroupCompartment NewTable. |
| |
| static ObjectGroup* defaultNewGroup(ExclusiveContext* cx, const Class* clasp, |
| TaggedProto proto, |
| JSObject* associated = nullptr); |
| static ObjectGroup* lazySingletonGroup(ExclusiveContext* cx, const Class* clasp, |
| TaggedProto proto); |
| |
| static void setDefaultNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj); |
| |
| #ifdef DEBUG |
| static bool hasDefaultNewGroup(JSObject* proto, const Class* clasp, ObjectGroup* group); |
| #endif |
| |
| // Static accessors for ObjectGroupCompartment ArrayObjectTable and PlainObjectTable. |
| |
| enum class NewArrayKind { |
| Normal, // Specialize array group based on its element type. |
| CopyOnWrite, // Make an array with copy-on-write elements. |
| UnknownIndex // Make an array with an unknown element type. |
| }; |
| |
| // Create an ArrayObject or UnboxedArrayObject with the specified elements |
| // and a group specialized for the elements. |
| static JSObject* newArrayObject(ExclusiveContext* cx, const Value* vp, size_t length, |
| NewObjectKind newKind, |
| NewArrayKind arrayKind = NewArrayKind::Normal); |
| |
| // Create a PlainObject or UnboxedPlainObject with the specified properties |
| // and a group specialized for those properties. |
| static JSObject* newPlainObject(ExclusiveContext* cx, |
| IdValuePair* properties, size_t nproperties, |
| NewObjectKind newKind); |
| |
| // Static accessors for ObjectGroupCompartment AllocationSiteTable. |
| |
| // Get a non-singleton group to use for objects created at the specified |
| // allocation site. |
| static ObjectGroup* allocationSiteGroup(JSContext* cx, JSScript* script, jsbytecode* pc, |
| JSProtoKey key, HandleObject proto = nullptr); |
| |
| // Get a non-singleton group to use for objects created in a JSNative call. |
| static ObjectGroup* callingAllocationSiteGroup(JSContext* cx, JSProtoKey key, |
| HandleObject proto = nullptr); |
| |
| // Set the group or singleton-ness of an object created for an allocation site. |
| static bool |
| setAllocationSiteObjectGroup(JSContext* cx, HandleScript script, jsbytecode* pc, |
| HandleObject obj, bool singleton); |
| |
| static ArrayObject* getOrFixupCopyOnWriteObject(JSContext* cx, HandleScript script, |
| jsbytecode* pc); |
| static ArrayObject* getCopyOnWriteObject(JSScript* script, jsbytecode* pc); |
| |
| // Returns false if not found. |
| static bool findAllocationSite(JSContext* cx, ObjectGroup* group, |
| JSScript** script, uint32_t* offset); |
| |
| private: |
| static ObjectGroup* defaultNewGroup(JSContext* cx, JSProtoKey key); |
| }; |
| |
| // Structure used to manage the groups in a compartment. |
| class ObjectGroupCompartment |
| { |
| friend class ObjectGroup; |
| |
| struct NewEntry; |
| typedef HashSet<NewEntry, NewEntry, SystemAllocPolicy> NewTable; |
| class NewTableRef; |
| |
| // Set of default 'new' or lazy groups in the compartment. |
| NewTable* defaultNewTable; |
| NewTable* lazyTable; |
| |
| struct ArrayObjectKey; |
| typedef HashMap<ArrayObjectKey, |
| ReadBarrieredObjectGroup, |
| ArrayObjectKey, |
| SystemAllocPolicy> ArrayObjectTable; |
| |
| struct PlainObjectKey; |
| struct PlainObjectEntry; |
| typedef HashMap<PlainObjectKey, |
| PlainObjectEntry, |
| PlainObjectKey, |
| SystemAllocPolicy> PlainObjectTable; |
| |
| // Tables for managing groups common to the contents of large script |
| // singleton objects and JSON objects. These are vanilla ArrayObjects and |
| // PlainObjects, so we distinguish the groups of different ones by looking |
| // at the types of their properties. |
| // |
| // All singleton/JSON arrays which have the same prototype, are homogenous |
| // and of the same element type will share a group. All singleton/JSON |
| // objects which have the same shape and property types will also share a |
| // group. We don't try to collate arrays or objects with type mismatches. |
| ArrayObjectTable* arrayObjectTable; |
| PlainObjectTable* plainObjectTable; |
| |
| struct AllocationSiteKey; |
| typedef HashMap<AllocationSiteKey, |
| ReadBarrieredObjectGroup, |
| AllocationSiteKey, |
| SystemAllocPolicy> AllocationSiteTable; |
| |
| // Table for referencing types of objects keyed to an allocation site. |
| AllocationSiteTable* allocationSiteTable; |
| |
| public: |
| ObjectGroupCompartment(); |
| ~ObjectGroupCompartment(); |
| |
| void replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc, |
| JSProtoKey kind, ObjectGroup* group); |
| |
| void removeDefaultNewGroup(const Class* clasp, TaggedProto proto, JSObject* associated); |
| void replaceDefaultNewGroup(const Class* clasp, TaggedProto proto, JSObject* associated, |
| ObjectGroup* group); |
| |
| static ObjectGroup* makeGroup(ExclusiveContext* cx, const Class* clasp, |
| Handle<TaggedProto> proto, |
| ObjectGroupFlags initialFlags = 0); |
| |
| void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, |
| size_t* allocationSiteTables, |
| size_t* arrayGroupTables, |
| size_t* plainObjectGroupTables, |
| size_t* compartmentTables); |
| |
| void clearTables(); |
| |
| void sweep(FreeOp* fop); |
| |
| #ifdef JSGC_HASH_TABLE_CHECKS |
| void checkTablesAfterMovingGC() { |
| checkNewTableAfterMovingGC(defaultNewTable); |
| checkNewTableAfterMovingGC(lazyTable); |
| } |
| #endif |
| |
| void fixupTablesAfterMovingGC() { |
| fixupNewTableAfterMovingGC(defaultNewTable); |
| fixupNewTableAfterMovingGC(lazyTable); |
| } |
| |
| private: |
| #ifdef JSGC_HASH_TABLE_CHECKS |
| void checkNewTableAfterMovingGC(NewTable* table); |
| #endif |
| |
| void sweepNewTable(NewTable* table); |
| void fixupNewTableAfterMovingGC(NewTable* table); |
| |
| static void newTablePostBarrier(ExclusiveContext* cx, NewTable* table, |
| const Class* clasp, TaggedProto proto, JSObject* associated); |
| }; |
| |
| PlainObject* |
| NewPlainObjectWithProperties(ExclusiveContext* cx, IdValuePair* properties, size_t nproperties, |
| NewObjectKind newKind); |
| |
| bool |
| CombineArrayElementTypes(ExclusiveContext* cx, JSObject* newObj, |
| const Value* compare, size_t ncompare); |
| |
| bool |
| CombinePlainObjectPropertyTypes(ExclusiveContext* cx, JSObject* newObj, |
| const Value* compare, size_t ncompare); |
| |
| } // namespace js |
| |
| #endif /* vm_ObjectGroup_h */ |