#ifndef vm_UnboxedObject_h
#define vm_UnboxedObject_h
#include "gc/DeletePolicy.h"
#include "vm/JSObject.h"
#include "vm/Runtime.h"
namespace js {
struct AutoEnterAnalysis;
class PreliminaryObjectArray;
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_STRING || type == JSVAL_TYPE_OBJECT;
}
class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout> {
public:
struct Property {
PropertyName* name = nullptr;
uint32_t offset = UINT32_MAX;
JSValueType type = JSVAL_TYPE_MAGIC;
Property() = default;
};
using PropertyVector = Vector<Property, 0, SystemAllocPolicy>;
private:
JS::Zone* zone_;
GCPtrObjectGroup nativeGroup_ = {};
GCPtrShape nativeShape_ = {};
GCPtrScript allocationScript_ = {};
jsbytecode* allocationPc_ = {};
GCPtrObjectGroup replacementGroup_ = {};
PropertyVector properties_;
size_t size_ = 0;
TypeNewScript* newScript_ = nullptr;
int32_t* traceList_ = nullptr;
GCPtrJitCode constructorCode_ = {};
public:
explicit UnboxedLayout(JS::Zone* zone) : zone_(zone) {}
inline ~UnboxedLayout();
JS::Zone* zone() const { return zone_; }
bool initProperties(const PropertyVector& properties, size_t size) {
size_ = size;
return properties_.appendAll(properties);
}
void detachFromRealm();
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 UnboxedObject : public JSObject {
protected:
static JS::Result<UnboxedObject*, JS::OOM&> createInternal(
JSContext* cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
js::HandleObjectGroup group);
};
class UnboxedExpandoObject : public NativeObject {
public:
static const Class class_;
};
class UnboxedPlainObject : public UnboxedObject {
uint8_t data_[1];
public:
static const Class class_;
static bool obj_lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
MutableHandleObject objp,
MutableHandle<PropertyResult> 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 newEnumerate(JSContext* cx, HandleObject obj,
AutoIdVector& properties, bool enumerableOnly);
inline const UnboxedLayout& layout() const;
const UnboxedLayout& layoutDontCheckGeneration() const {
return group()->unboxedLayoutDontCheckGeneration();
}
uint8_t* data() { return &data_[0]; }
UnboxedExpandoObject* maybeExpando() const {
return static_cast<UnboxedExpandoObject*>(shapeOrExpando_);
}
void setExpandoUnsafe(UnboxedExpandoObject* expando) {
shapeOrExpando_ = expando;
}
void initExpando() { shapeOrExpando_ = nullptr; }
JSObject** addressOfExpando() {
return reinterpret_cast<JSObject**>(&shapeOrExpando_);
}
bool containsUnboxedOrExpandoProperty(JSContext* cx, jsid id) const;
static UnboxedExpandoObject* ensureExpando(JSContext* cx,
Handle<UnboxedPlainObject*> obj);
bool setValue(JSContext* cx, const UnboxedLayout::Property& property,
const Value& v);
Value getValue(const UnboxedLayout::Property& property,
bool maybeUninitialized = false);
static NativeObject* convertToNative(JSContext* cx, JSObject* obj);
static UnboxedPlainObject* create(JSContext* cx, HandleObjectGroup group,
NewObjectKind newKind);
static JSObject* createWithProperties(JSContext* cx, HandleObjectGroup group,
NewObjectKind newKind,
IdValuePair* properties);
void fillAfterConvert(JSContext* cx, Handle<GCVector<Value>> values,
size_t* valueCursor);
static void trace(JSTracer* trc, JSObject* object);
static size_t offsetOfExpando() { return offsetOfShapeOrExpando(); }
static size_t offsetOfData() {
return offsetof(UnboxedPlainObject, data_[0]);
}
};
inline bool IsUnboxedObjectClass(const Class* class_) {
return class_ == &UnboxedPlainObject::class_;
}
bool TryConvertToUnboxedLayout(JSContext* cx, AutoEnterAnalysis& enter,
Shape* templateShape, ObjectGroup* group,
PreliminaryObjectArray* objects);
}
namespace JS {
template <>
struct DeletePolicy<js::UnboxedLayout>
: public js::GCManagedDeletePolicy<js::UnboxedLayout> {};
}
#endif