diff --git a/js/src/frontend/ObjLiteral.cpp b/js/src/frontend/ObjLiteral.cpp index f40eb743fffd..872ce5c55fc8 100644 --- a/js/src/frontend/ObjLiteral.cpp +++ b/js/src/frontend/ObjLiteral.cpp @@ -24,9 +24,10 @@ #include "vm/PlainObject.h" // PlainObject #include "vm/Printer.h" // js::Fprinter -#include "gc/ObjectKind-inl.h" // gc::GetGCObjectKind -#include "vm/JSAtom-inl.h" // AtomToId -#include "vm/JSObject-inl.h" // NewBuiltinClassInstance +#include "gc/ObjectKind-inl.h" // gc::GetGCObjectKind +#include "vm/JSAtom-inl.h" // AtomToId +#include "vm/JSObject-inl.h" // NewBuiltinClassInstance +#include "vm/NativeObject-inl.h" // AddDataPropertyNonDelegate namespace js { @@ -61,28 +62,29 @@ static void InterpretObjLiteralValue( } } -static JSObject* InterpretObjLiteralObj( - JSContext* cx, const frontend::CompilationAtomCache& atomCache, - const mozilla::Span literalInsns, ObjLiteralFlags flags, - uint32_t propertyCount) { +enum class PropertySetKind { + UniqueNames, + Normal, +}; + +template +bool InterpretObjLiteralObj(JSContext* cx, HandlePlainObject obj, + const frontend::CompilationAtomCache& atomCache, + const mozilla::Span literalInsns, + ObjLiteralFlags flags) { bool singleton = flags.contains(ObjLiteralFlag::Singleton); ObjLiteralReader reader(literalInsns); ObjLiteralInsn insn; - gc::AllocKind allocKind = gc::GetGCObjectKind(propertyCount); - RootedPlainObject obj( - cx, NewBuiltinClassInstance(cx, allocKind, TenuredObject)); - if (!obj) { - return nullptr; - } - RootedId propId(cx); RootedValue propVal(cx); while (reader.readInsn(&insn)) { MOZ_ASSERT(insn.isValid()); + MOZ_ASSERT_IF(kind == PropertySetKind::UniqueNames, + !insn.getKey().isArrayIndex()); - if (insn.getKey().isArrayIndex()) { + if (kind == PropertySetKind::Normal && insn.getKey().isArrayIndex()) { propId = INT_TO_JSID(insn.getKey().getArrayIndex()); } else { JSAtom* jsatom = @@ -97,11 +99,42 @@ static JSObject* InterpretObjLiteralObj( propVal.setUndefined(); } - if (!NativeDefineDataProperty(cx, obj, propId, propVal, JSPROP_ENUMERATE)) { + if (kind == PropertySetKind::UniqueNames) { + if (!AddDataPropertyNonDelegate(cx, obj, propId, propVal)) { + return false; + } + } else { + if (!NativeDefineDataProperty(cx, obj, propId, propVal, + JSPROP_ENUMERATE)) { + return false; + } + } + } + return true; +} + +static JSObject* InterpretObjLiteralObj( + JSContext* cx, const frontend::CompilationAtomCache& atomCache, + const mozilla::Span literalInsns, ObjLiteralFlags flags, + uint32_t propertyCount) { + gc::AllocKind allocKind = gc::GetGCObjectKind(propertyCount); + RootedPlainObject obj( + cx, NewBuiltinClassInstance(cx, allocKind, TenuredObject)); + if (!obj) { + return nullptr; + } + + if (!flags.contains(ObjLiteralFlag::HasIndexOrDuplicatePropName)) { + if (!InterpretObjLiteralObj( + cx, obj, atomCache, literalInsns, flags)) { + return nullptr; + } + } else { + if (!InterpretObjLiteralObj(cx, obj, atomCache, + literalInsns, flags)) { return nullptr; } } - return obj; } diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h index 98db3f12923b..efa2f0dd36ff 100644 --- a/js/src/vm/NativeObject-inl.h +++ b/js/src/vm/NativeObject-inl.h @@ -864,6 +864,25 @@ inline bool IsPackedArray(JSObject* obj) { return true; } +MOZ_ALWAYS_INLINE bool AddDataPropertyNonDelegate(JSContext* cx, + HandlePlainObject obj, + HandleId id, HandleValue v) { + MOZ_ASSERT(!JSID_IS_INT(id)); + MOZ_ASSERT(!obj->isDelegate()); + + // If we know this is a new property we can call addProperty instead of + // the slower putProperty. + Shape* shape = NativeObject::addEnumerableDataProperty(cx, obj, id); + if (!shape) { + return false; + } + + obj->setSlot(shape->slot(), v); + + MOZ_ASSERT(!obj->getClass()->getAddProperty()); + return true; +} + } // namespace js #endif /* vm_NativeObject_inl_h */ diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index 9e4aef3b9693..e13d77b4bffe 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -1377,26 +1377,6 @@ static MOZ_ALWAYS_INLINE bool AddDataProperty(JSContext* cx, return CallAddPropertyHook(cx, obj, id, v); } -static MOZ_ALWAYS_INLINE bool AddDataPropertyNonDelegate(JSContext* cx, - HandlePlainObject obj, - HandleId id, - HandleValue v) { - MOZ_ASSERT(!JSID_IS_INT(id)); - MOZ_ASSERT(!obj->isDelegate()); - - // If we know this is a new property we can call addProperty instead of - // the slower putProperty. - Shape* shape = NativeObject::addEnumerableDataProperty(cx, obj, id); - if (!shape) { - return false; - } - - obj->setSlot(shape->slot(), v); - - MOZ_ASSERT(!obj->getClass()->getAddProperty()); - return true; -} - static bool IsConfigurable(unsigned attrs) { return (attrs & JSPROP_PERMANENT) == 0; }