summaryrefslogtreecommitdiffstats
path: root/js/src/jsobj.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jsobj.cpp')
-rw-r--r--js/src/jsobj.cpp119
1 files changed, 87 insertions, 32 deletions
diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp
index ef1291079..d4379bd7d 100644
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -42,7 +42,6 @@
#include "frontend/BytecodeCompiler.h"
#include "gc/Marking.h"
#include "gc/Policy.h"
-#include "gc/StoreBuffer-inl.h"
#include "jit/BaselineJIT.h"
#include "js/MemoryMetrics.h"
#include "js/Proxy.h"
@@ -869,6 +868,9 @@ static inline JSObject*
CreateThisForFunctionWithGroup(JSContext* cx, HandleObjectGroup group,
NewObjectKind newKind)
{
+ if (group->maybeUnboxedLayout() && newKind != SingletonObject)
+ return UnboxedPlainObject::create(cx, group, newKind);
+
if (TypeNewScript* newScript = group->newScript()) {
if (newScript->analyzed()) {
// The definite properties analysis has been performed for this
@@ -1136,18 +1138,19 @@ js::CloneObject(JSContext* cx, HandleObject obj, Handle<js::TaggedProto> proto)
}
static bool
-GetScriptArrayObjectElements(JSContext* cx, HandleArrayObject arr, MutableHandle<GCVector<Value>> values)
+GetScriptArrayObjectElements(JSContext* cx, HandleObject obj, MutableHandle<GCVector<Value>> values)
{
- MOZ_ASSERT(!arr->isSingleton());
- MOZ_ASSERT(!arr->isIndexed());
+ MOZ_ASSERT(!obj->isSingleton());
+ MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
+ MOZ_ASSERT(!obj->isIndexed());
- size_t length = arr->length();
+ size_t length = GetAnyBoxedOrUnboxedArrayLength(obj);
if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), length))
return false;
- size_t initlen = arr->getDenseInitializedLength();
+ size_t initlen = GetAnyBoxedOrUnboxedInitializedLength(obj);
for (size_t i = 0; i < initlen; i++)
- values[i].set(arr->getDenseElement(i));
+ values[i].set(GetAnyBoxedOrUnboxedDenseElement(obj, i));
return true;
}
@@ -1156,27 +1159,46 @@ static bool
GetScriptPlainObjectProperties(JSContext* cx, HandleObject obj,
MutableHandle<IdValueVector> properties)
{
- MOZ_ASSERT(obj->is<PlainObject>());
- PlainObject* nobj = &obj->as<PlainObject>();
+ if (obj->is<PlainObject>()) {
+ PlainObject* nobj = &obj->as<PlainObject>();
- if (!properties.appendN(IdValuePair(), nobj->slotSpan()))
- return false;
+ if (!properties.appendN(IdValuePair(), nobj->slotSpan()))
+ return false;
+
+ for (Shape::Range<NoGC> r(nobj->lastProperty()); !r.empty(); r.popFront()) {
+ Shape& shape = r.front();
+ MOZ_ASSERT(shape.isDataDescriptor());
+ uint32_t slot = shape.slot();
+ properties[slot].get().id = shape.propid();
+ properties[slot].get().value = nobj->getSlot(slot);
+ }
+
+ for (size_t i = 0; i < nobj->getDenseInitializedLength(); i++) {
+ Value v = nobj->getDenseElement(i);
+ if (!v.isMagic(JS_ELEMENTS_HOLE) && !properties.append(IdValuePair(INT_TO_JSID(i), v)))
+ return false;
+ }
- for (Shape::Range<NoGC> r(nobj->lastProperty()); !r.empty(); r.popFront()) {
- Shape& shape = r.front();
- MOZ_ASSERT(shape.isDataDescriptor());
- uint32_t slot = shape.slot();
- properties[slot].get().id = shape.propid();
- properties[slot].get().value = nobj->getSlot(slot);
+ return true;
}
- for (size_t i = 0; i < nobj->getDenseInitializedLength(); i++) {
- Value v = nobj->getDenseElement(i);
- if (!v.isMagic(JS_ELEMENTS_HOLE) && !properties.append(IdValuePair(INT_TO_JSID(i), v)))
+ if (obj->is<UnboxedPlainObject>()) {
+ UnboxedPlainObject* nobj = &obj->as<UnboxedPlainObject>();
+
+ const UnboxedLayout& layout = nobj->layout();
+ if (!properties.appendN(IdValuePair(), layout.properties().length()))
return false;
+
+ for (size_t i = 0; i < layout.properties().length(); i++) {
+ const UnboxedLayout::Property& property = layout.properties()[i];
+ properties[i].get().id = NameToId(property.name);
+ properties[i].get().value = nobj->getValue(property);
+ }
+
+ return true;
}
- return true;
+ MOZ_CRASH("Bad object kind");
}
static bool
@@ -1198,13 +1220,13 @@ js::DeepCloneObjectLiteral(JSContext* cx, HandleObject obj, NewObjectKind newKin
/* NB: Keep this in sync with XDRObjectLiteral. */
MOZ_ASSERT_IF(obj->isSingleton(),
cx->compartment()->behaviors().getSingletonsAsTemplates());
- MOZ_ASSERT(obj->is<PlainObject>() ||
- obj->is<ArrayObject>());
+ MOZ_ASSERT(obj->is<PlainObject>() || obj->is<UnboxedPlainObject>() ||
+ obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
MOZ_ASSERT(newKind != SingletonObject);
- if (obj->is<ArrayObject>()) {
+ if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) {
Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
- if (!GetScriptArrayObjectElements(cx, obj.as<ArrayObject>(), &values))
+ if (!GetScriptArrayObjectElements(cx, obj, &values))
return nullptr;
// Deep clone any elements.
@@ -1318,8 +1340,10 @@ js::XDRObjectLiteral(XDRState<mode>* xdr, MutableHandleObject obj)
{
if (mode == XDR_ENCODE) {
MOZ_ASSERT(obj->is<PlainObject>() ||
- obj->is<ArrayObject>());
- isArray = obj->is<ArrayObject>() ? 1 : 0;
+ obj->is<UnboxedPlainObject>() ||
+ obj->is<ArrayObject>() ||
+ obj->is<UnboxedArrayObject>());
+ isArray = (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) ? 1 : 0;
}
if (!xdr->codeUint32(&isArray))
@@ -1331,11 +1355,8 @@ js::XDRObjectLiteral(XDRState<mode>* xdr, MutableHandleObject obj)
if (isArray) {
Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
- if (mode == XDR_ENCODE) {
- RootedArrayObject arr(cx, &obj->as<ArrayObject>());
- if (!GetScriptArrayObjectElements(cx, arr, &values))
- return false;
- }
+ if (mode == XDR_ENCODE && !GetScriptArrayObjectElements(cx, obj, &values))
+ return false;
uint32_t initialized;
if (mode == XDR_ENCODE)
@@ -2315,6 +2336,16 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape**
// us the resolve hook won't define a property with this id.
if (ClassMayResolveId(cx->names(), obj->getClass(), id, obj))
return false;
+ } else if (obj->is<UnboxedPlainObject>()) {
+ if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) {
+ MarkNonNativePropertyFound<NoGC>(propp);
+ return true;
+ }
+ } else if (obj->is<UnboxedArrayObject>()) {
+ if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
+ MarkNonNativePropertyFound<NoGC>(propp);
+ return true;
+ }
} else if (obj->is<TypedObject>()) {
if (obj->as<TypedObject>().typeDescr().hasProperty(cx->names(), id)) {
MarkNonNativePropertyFound<NoGC>(propp);
@@ -2571,6 +2602,11 @@ js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::Object
break;
}
+ // Convert unboxed objects to their native representations before changing
+ // their prototype/group, as they depend on the group for their layout.
+ if (!MaybeConvertUnboxedObjectToNative(cx, obj))
+ return false;
+
Rooted<TaggedProto> taggedProto(cx, TaggedProto(proto));
if (!SetClassAndProto(cx, obj, obj->getClass(), taggedProto))
return false;
@@ -2594,6 +2630,9 @@ js::PreventExtensions(JSContext* cx, HandleObject obj, ObjectOpResult& result, I
if (!obj->nonProxyIsExtensible())
return result.succeed();
+ if (!MaybeConvertUnboxedObjectToNative(cx, obj))
+ return false;
+
// Force lazy properties to be resolved.
AutoIdVector props(cx);
if (!js::GetPropertyKeys(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, &props))
@@ -3606,6 +3645,22 @@ JSObject::allocKindForTenure(const js::Nursery& nursery) const
if (IsProxy(this))
return as<ProxyObject>().allocKindForTenure();
+ // Unboxed plain objects are sized according to the data they store.
+ if (is<UnboxedPlainObject>()) {
+ size_t nbytes = as<UnboxedPlainObject>().layoutDontCheckGeneration().size();
+ return GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + nbytes);
+ }
+
+ // Unboxed arrays use inline data if their size is small enough.
+ if (is<UnboxedArrayObject>()) {
+ const UnboxedArrayObject* nobj = &as<UnboxedArrayObject>();
+ size_t nbytes = UnboxedArrayObject::offsetOfInlineElements() +
+ nobj->capacity() * nobj->elementSize();
+ if (nbytes <= JSObject::MAX_BYTE_SIZE)
+ return GetGCObjectKindForBytes(nbytes);
+ return AllocKind::OBJECT0;
+ }
+
// Inlined typed objects are followed by their data, so make sure we copy
// it all over to the new object.
if (is<InlineTypedObject>()) {