Bug 966575 Part 13 -- Remove type repr completely, replacing with atomized strings r=sfink

This commit is contained in:
Nicholas D. Matsakis 2014-02-16 06:48:03 -05:00
parent ad08b39137
commit 464bac9d95
12 changed files with 665 additions and 1805 deletions

View File

@ -137,7 +137,7 @@ class Float32x4Defn {
} // namespace js
const JSFunctionSpec js::Float32x4Defn::TypeDescriptorMethods[] = {
JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
JS_FS_END
@ -158,7 +158,7 @@ const JSFunctionSpec js::Float32x4Defn::TypedObjectMethods[] = {
};
const JSFunctionSpec js::Int32x4Defn::TypeDescriptorMethods[] = {
JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
JS_FS_END,
@ -180,19 +180,16 @@ const JSFunctionSpec js::Int32x4Defn::TypedObjectMethods[] = {
template<typename T>
static JSObject *
CreateX4Class(JSContext *cx, Handle<GlobalObject*> global)
CreateX4Class(JSContext *cx,
Handle<GlobalObject*> global,
HandlePropertyName stringRepr)
{
const X4TypeDescr::Type type = T::type;
RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx));
if (!funcProto)
return nullptr;
// Create type representation.
RootedObject typeReprObj(cx);
typeReprObj = X4TypeRepresentation::Create(cx, T::type);
if (!typeReprObj)
return nullptr;
// Create prototype property, which inherits from Object.prototype.
RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
@ -207,12 +204,20 @@ CreateX4Class(JSContext *cx, Handle<GlobalObject*> global)
Rooted<X4TypeDescr*> x4(cx);
x4 = NewObjectWithProto<X4TypeDescr>(cx, funcProto, global, TenuredObject);
if (!x4 || !InitializeCommonTypeDescriptorProperties(cx, x4, typeReprObj))
if (!x4)
return nullptr;
x4->initReservedSlot(JS_DESCR_SLOT_TYPE_REPR, ObjectValue(*typeReprObj));
x4->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(TypeDescr::X4));
x4->initReservedSlot(JS_DESCR_SLOT_STRING_REPR, StringValue(stringRepr));
x4->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(X4TypeDescr::size(type)));
x4->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(X4TypeDescr::alignment(type)));
x4->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(false));
x4->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(T::type));
x4->initReservedSlot(JS_DESCR_SLOT_PROTO, ObjectValue(*proto));
if (!CreateUserSizeAndAlignmentProperties(cx, x4))
return nullptr;
// Link constructor to prototype and install properties.
if (!JS_DefineFunctions(cx, x4, T::TypeDescriptorMethods))
@ -310,7 +315,9 @@ SIMDObject::initClass(JSContext *cx, Handle<GlobalObject *> global)
// float32x4
RootedObject float32x4Object(cx, CreateX4Class<Float32x4Defn>(cx, global));
RootedObject float32x4Object(cx);
float32x4Object = CreateX4Class<Float32x4Defn>(cx, global,
cx->names().float32x4);
if (!float32x4Object)
return nullptr;
@ -325,7 +332,9 @@ SIMDObject::initClass(JSContext *cx, Handle<GlobalObject *> global)
// int32x4
RootedObject int32x4Object(cx, CreateX4Class<Int32x4Defn>(cx, global));
RootedObject int32x4Object(cx);
int32x4Object = CreateX4Class<Int32x4Defn>(cx, global,
cx->names().int32x4);
if (!int32x4Object)
return nullptr;

View File

@ -1,858 +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 "builtin/TypeRepresentation.h"
#include "mozilla/HashFunctions.h"
#include "jscntxt.h"
#include "jsnum.h"
#include "jsutil.h"
#include "builtin/TypedObject.h"
#include "js/HashTable.h"
#include "vm/Runtime.h"
#include "vm/StringBuffer.h"
#include "jsgcinlines.h"
#include "jsobjinlines.h"
using namespace js;
using namespace mozilla;
///////////////////////////////////////////////////////////////////////////
// Class def'n for the owner object
const Class TypeRepresentation::class_ = {
"TypeRepresentation",
JSCLASS_IMPLEMENTS_BARRIERS |
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_RESERVED_SLOTS(JS_TYPEREPR_SLOTS),
JS_PropertyStub, /* addProperty */
JS_DeletePropertyStub, /* delProperty */
JS_PropertyStub, /* getProperty */
JS_StrictPropertyStub, /* setProperty */
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
obj_finalize,
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
obj_trace,
};
///////////////////////////////////////////////////////////////////////////
// Hashing
bool
TypeRepresentationHasher::match(TypeRepresentation *key1,
TypeRepresentation *key2)
{
if (key1->kind() != key2->kind())
return false;
switch (key1->kind()) {
case TypeDescr::Scalar:
return matchScalars(key1->asScalar(), key2->asScalar());
case TypeDescr::Reference:
return matchReferences(key1->asReference(), key2->asReference());
case TypeDescr::X4:
return matchX4s(key1->asX4(), key2->asX4());
case TypeDescr::Struct:
return matchStructs(key1->asStruct(), key2->asStruct());
case TypeDescr::SizedArray:
return matchSizedArrays(key1->asSizedArray(),
key2->asSizedArray());
case TypeDescr::UnsizedArray:
return matchUnsizedArrays(key1->asUnsizedArray(),
key2->asUnsizedArray());
}
MOZ_ASSUME_UNREACHABLE("Invalid kind");
}
bool
TypeRepresentationHasher::matchScalars(ScalarTypeRepresentation *key1,
ScalarTypeRepresentation *key2)
{
return key1->type() == key2->type();
}
bool
TypeRepresentationHasher::matchReferences(ReferenceTypeRepresentation *key1,
ReferenceTypeRepresentation *key2)
{
return key1->type() == key2->type();
}
bool
TypeRepresentationHasher::matchX4s(X4TypeRepresentation *key1,
X4TypeRepresentation *key2)
{
return key1->type() == key2->type();
}
bool
TypeRepresentationHasher::matchStructs(StructTypeRepresentation *key1,
StructTypeRepresentation *key2)
{
if (key1->fieldCount() != key2->fieldCount())
return false;
for (size_t i = 0; i < key1->fieldCount(); i++) {
if (key1->field(i).propertyName != key2->field(i).propertyName)
return false;
if (key1->field(i).typeRepr != key2->field(i).typeRepr)
return false;
}
return true;
}
bool
TypeRepresentationHasher::matchSizedArrays(SizedArrayTypeRepresentation *key1,
SizedArrayTypeRepresentation *key2)
{
// We assume that these pointers have been canonicalized:
return key1->element() == key2->element() &&
key1->length() == key2->length();
}
bool
TypeRepresentationHasher::matchUnsizedArrays(UnsizedArrayTypeRepresentation *key1,
UnsizedArrayTypeRepresentation *key2)
{
// We assume that these pointers have been canonicalized:
return key1->element() == key2->element();
}
HashNumber
TypeRepresentationHasher::hash(TypeRepresentation *key) {
switch (key->kind()) {
case TypeDescr::Scalar:
return hashScalar(key->asScalar());
case TypeDescr::Reference:
return hashReference(key->asReference());
case TypeDescr::X4:
return hashX4(key->asX4());
case TypeDescr::Struct:
return hashStruct(key->asStruct());
case TypeDescr::UnsizedArray:
return hashUnsizedArray(key->asUnsizedArray());
case TypeDescr::SizedArray:
return hashSizedArray(key->asSizedArray());
}
MOZ_ASSUME_UNREACHABLE("Invalid kind");
}
HashNumber
TypeRepresentationHasher::hashScalar(ScalarTypeRepresentation *key)
{
return HashGeneric(key->kind(), key->type());
}
HashNumber
TypeRepresentationHasher::hashReference(ReferenceTypeRepresentation *key)
{
return HashGeneric(key->kind(), key->type());
}
HashNumber
TypeRepresentationHasher::hashX4(X4TypeRepresentation *key)
{
return HashGeneric(key->kind(), key->type());
}
HashNumber
TypeRepresentationHasher::hashStruct(StructTypeRepresentation *key)
{
HashNumber hash = HashGeneric(key->kind());
for (HashNumber i = 0; i < key->fieldCount(); i++) {
hash = AddToHash(hash, key->field(i).propertyName.get());
hash = AddToHash(hash, key->field(i).typeRepr);
}
return hash;
}
HashNumber
TypeRepresentationHasher::hashSizedArray(SizedArrayTypeRepresentation *key)
{
return HashGeneric(key->kind(), key->element(), key->length());
}
HashNumber
TypeRepresentationHasher::hashUnsizedArray(UnsizedArrayTypeRepresentation *key)
{
return HashGeneric(key->kind(), key->element());
}
///////////////////////////////////////////////////////////////////////////
// Constructors
TypeRepresentation::TypeRepresentation(TypeDescr::Kind kind,
size_t align,
bool opaque)
: kind_(kind),
opaque_(opaque),
alignment_(align)
{}
SizedTypeRepresentation::SizedTypeRepresentation(SizedTypeDescr::Kind kind,
bool opaque,
size_t size,
size_t align)
: TypeRepresentation(kind, align, opaque),
size_(size)
{}
ScalarTypeRepresentation::ScalarTypeRepresentation(ScalarTypeDescr::Type type)
: SizedTypeRepresentation(TypeDescr::Scalar,
false,
ScalarTypeDescr::size(type),
ScalarTypeDescr::alignment(type)),
type_(type)
{
}
static size_t X4Sizes[] = {
#define X4_SIZE(_kind, _type, _name) \
sizeof(_type) * 4,
JS_FOR_EACH_X4_TYPE_REPR(X4_SIZE) 0
#undef X4_SIZE
};
X4TypeRepresentation::X4TypeRepresentation(X4TypeDescr::Type type)
: SizedTypeRepresentation(X4TypeDescr::X4, false, X4Sizes[type], X4Sizes[type]),
type_(type)
{
}
ReferenceTypeRepresentation::ReferenceTypeRepresentation(ReferenceTypeDescr::Type type)
: SizedTypeRepresentation(TypeDescr::Reference, true, 0, 1),
type_(type)
{
switch (type) {
case ReferenceTypeDescr::TYPE_ANY:
size_ = sizeof(js::HeapValue);
alignment_ = MOZ_ALIGNOF(js::HeapValue);
break;
case ReferenceTypeDescr::TYPE_OBJECT:
case ReferenceTypeDescr::TYPE_STRING:
size_ = sizeof(js::HeapPtrObject);
alignment_ = MOZ_ALIGNOF(js::HeapPtrObject);
break;
}
}
SizedArrayTypeRepresentation::SizedArrayTypeRepresentation(SizedTypeRepresentation *element,
size_t length)
: SizedTypeRepresentation(TypeDescr::SizedArray, element->opaque(),
element->size() * length, element->alignment()),
element_(element),
length_(length)
{
}
UnsizedArrayTypeRepresentation::UnsizedArrayTypeRepresentation(SizedTypeRepresentation *element)
: TypeRepresentation(TypeDescr::UnsizedArray, element->alignment(),
element->opaque()),
element_(element)
{
}
static inline size_t alignTo(size_t address, size_t align) {
JS_ASSERT(IsPowerOfTwo(align));
return (address + align - 1) & -align;
}
StructField::StructField(size_t index,
PropertyName *propertyName,
SizedTypeRepresentation *typeRepr,
size_t offset)
: index(index),
propertyName(propertyName),
typeRepr(typeRepr),
offset(offset)
{}
StructTypeRepresentation::StructTypeRepresentation()
: SizedTypeRepresentation(TypeDescr::Struct, false, 0, 1),
fieldCount_(0) // see ::init() below!
{
// note: size_, alignment_, and opaque_ are computed in ::init() below
}
bool
StructTypeRepresentation::init(JSContext *cx,
AutoPropertyNameVector &names,
AutoObjectVector &typeReprOwners)
{
JS_ASSERT(names.length() == typeReprOwners.length());
fieldCount_ = names.length();
// We compute alignment into the field `align_` directly in the
// loop below, but not `size_` because we have to very careful
// about overflow. For now, we always use a int32_t for
// consistency across build environments.
int32_t totalSize = 0;
// These will be adjusted in the loop below:
alignment_ = 1;
opaque_ = false;
for (size_t i = 0; i < names.length(); i++) {
SizedTypeRepresentation *fieldTypeRepr =
fromOwnerObject(*typeReprOwners[i])->asSized();
if (fieldTypeRepr->opaque())
opaque_ = true;
int32_t alignedSize = alignTo(totalSize, fieldTypeRepr->alignment());
if (alignedSize < totalSize) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_TYPEDOBJECT_TOO_BIG);
return false;
}
new(fields() + i) StructField(i, names[i],
fieldTypeRepr, alignedSize);
alignment_ = js::Max(alignment_, fieldTypeRepr->alignment());
int32_t incrementedSize = alignedSize + fieldTypeRepr->size();
if (incrementedSize < alignedSize) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_TYPEDOBJECT_TOO_BIG);
return false;
}
totalSize = incrementedSize;
}
int32_t alignedSize = alignTo(totalSize, alignment_);
if (alignedSize < totalSize) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_TYPEDOBJECT_TOO_BIG);
return false;
}
size_ = alignedSize;
return true;
}
///////////////////////////////////////////////////////////////////////////
// Interning
JSObject *
TypeRepresentation::addToTableOrFree(JSContext *cx,
TypeRepresentationHash::AddPtr &p)
{
JS_ASSERT(!ownerObject_);
Rooted<GlobalObject*> global(cx, cx->global());
JSCompartment *comp = cx->compartment();
// First, attempt to add the type representation to the table.
if (!comp->typeReprs.relookupOrAdd(p, this, this)) {
js_ReportOutOfMemory(cx);
js_free(this); // do not finalize, not present in the table
return nullptr;
}
RootedObject objectProto(cx, global->getOrCreateObjectPrototype(cx));
if (!objectProto)
return nullptr;
// Now that the object is in the table, try to make the owner
// object. If this succeeds, then the owner will remove from the
// table once it is finalized. Otherwise, if this fails, we must
// remove ourselves from the table ourselves and report an error.
RootedObject ownerObject(cx);
ownerObject = NewObjectWithGivenProto(cx, &class_, objectProto,
cx->global(), TenuredObject);
if (!ownerObject) {
comp->typeReprs.remove(this);
js_free(this);
return nullptr;
}
ownerObject->setPrivate(this);
ownerObject->initReservedSlot(JS_TYPEREPR_SLOT_KIND, Int32Value(kind()));
ownerObject_.init(ownerObject);
return &*ownerObject;
}
namespace js {
class TypeRepresentationHelper {
public:
template<typename D, typename T>
static JSObject *CreateSimple(JSContext *cx, typename D::Type type) {
JSCompartment *comp = cx->compartment();
TypeRepresentationHash::AddPtr p;
{
T sample(type);
p = comp->typeReprs.lookupForAdd(&sample);
}
if (p)
return (*p)->ownerObject();
// Note: cannot use cx->new_ because constructor is private.
T *ptr = (T *) cx->malloc_(sizeof(T));
if (!ptr)
return nullptr;
new(ptr) T(type);
return ptr->addToTableOrFree(cx, p);
}
};
} // namespace js
/*static*/
JSObject *
ScalarTypeRepresentation::Create(JSContext *cx,
ScalarTypeDescr::Type type)
{
return TypeRepresentationHelper::CreateSimple<ScalarTypeDescr,
ScalarTypeRepresentation>(cx, type);
}
/*static*/
JSObject *
X4TypeRepresentation::Create(JSContext *cx,
X4TypeDescr::Type type)
{
return TypeRepresentationHelper::CreateSimple<X4TypeDescr,
X4TypeRepresentation>(cx, type);
}
/*static*/
JSObject *
ReferenceTypeRepresentation::Create(JSContext *cx,
ReferenceTypeDescr::Type type)
{
JSCompartment *comp = cx->compartment();
TypeRepresentationHash::AddPtr p;
{
ReferenceTypeRepresentation sample(type);
p = comp->typeReprs.lookupForAdd(&sample);
}
if (p)
return (*p)->ownerObject();
// Note: cannot use cx->new_ because constructor is private.
ReferenceTypeRepresentation *ptr =
(ReferenceTypeRepresentation *) cx->malloc_(
sizeof(ReferenceTypeRepresentation));
if (!ptr)
return nullptr;
new(ptr) ReferenceTypeRepresentation(type);
return ptr->addToTableOrFree(cx, p);
}
/*static*/
JSObject *
SizedArrayTypeRepresentation::Create(JSContext *cx,
SizedTypeRepresentation *element,
size_t length)
{
JSCompartment *comp = cx->compartment();
// Overly conservative, since we are using `size_t` to represent
// size, but `SafeMul` operators on `int32_t` types. Still, it
// should be good enough for now.
int32_t temp;
if (!SafeMul(element->size(), length, &temp)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_TYPEDOBJECT_TOO_BIG);
return nullptr;
}
TypeRepresentationHash::AddPtr p;
{
SizedArrayTypeRepresentation sample(element, length);
p = comp->typeReprs.lookupForAdd(&sample);
}
if (p)
return (*p)->ownerObject();
// Note: cannot use cx->new_ because constructor is private.
SizedArrayTypeRepresentation *ptr =
(SizedArrayTypeRepresentation *) cx->malloc_(
sizeof(SizedArrayTypeRepresentation));
if (!ptr)
return nullptr;
new(ptr) SizedArrayTypeRepresentation(element, length);
return ptr->addToTableOrFree(cx, p);
}
/*static*/
JSObject *
UnsizedArrayTypeRepresentation::Create(JSContext *cx,
SizedTypeRepresentation *element)
{
JSCompartment *comp = cx->compartment();
TypeRepresentationHash::AddPtr p;
{
UnsizedArrayTypeRepresentation sample(element);
p = comp->typeReprs.lookupForAdd(&sample);
}
if (p)
return (*p)->ownerObject();
// Note: cannot use cx->new_ because constructor is private.
UnsizedArrayTypeRepresentation *ptr =
(UnsizedArrayTypeRepresentation *) cx->malloc_(
sizeof(UnsizedArrayTypeRepresentation));
if (!ptr)
return nullptr;
new(ptr) UnsizedArrayTypeRepresentation(element);
return ptr->addToTableOrFree(cx, p);
}
/*static*/
JSObject *
StructTypeRepresentation::Create(JSContext *cx,
AutoPropertyNameVector &names,
AutoObjectVector &typeReprOwners)
{
size_t count = names.length();
JSCompartment *comp = cx->compartment();
// Note: cannot use cx->new_ because constructor is private.
size_t size = sizeof(StructTypeRepresentation) + count * sizeof(StructField);
StructTypeRepresentation *ptr =
(StructTypeRepresentation *) cx->malloc_(size);
new(ptr) StructTypeRepresentation();
if (!ptr->init(cx, names, typeReprOwners))
return nullptr;
TypeRepresentationHash::AddPtr p = comp->typeReprs.lookupForAdd(ptr);
if (p) {
js_free(ptr); // do not finalize, not present in the table
return (*p)->ownerObject();
}
return ptr->addToTableOrFree(cx, p);
}
///////////////////////////////////////////////////////////////////////////
// Tracing
void
TypeRepresentation::mark(JSTracer *trace)
{
// Push our owner object onto the mark stack. When our owner
// object's trace callback is called, we will trace its
// contents. This is the typical scheme for marking objects. See
// gc/Marking.cpp for more details.
gc::MarkObject(trace, &ownerObject_, "typeRepresentation_ownerObject");
}
/*static*/ void
TypeRepresentation::obj_trace(JSTracer *trace, JSObject *object)
{
fromOwnerObject(*object)->traceFields(trace);
}
void
TypeRepresentation::traceFields(JSTracer *trace)
{
mark(trace); // don't forget to mark the self-reference here!
switch (kind()) {
case TypeDescr::Scalar:
case TypeDescr::Reference:
case TypeDescr::X4:
break;
case TypeDescr::Struct:
asStruct()->traceStructFields(trace);
break;
case TypeDescr::SizedArray:
asSizedArray()->traceSizedArrayFields(trace);
break;
case TypeDescr::UnsizedArray:
asUnsizedArray()->traceUnsizedArrayFields(trace);
break;
}
}
void
StructTypeRepresentation::traceStructFields(JSTracer *trace)
{
for (size_t i = 0; i < fieldCount(); i++) {
gc::MarkString(trace, &fields()[i].propertyName, "typerepr_field_propertyName");
fields()[i].typeRepr->mark(trace);
}
}
void
SizedArrayTypeRepresentation::traceSizedArrayFields(JSTracer *trace)
{
this->mark(trace);
element_->mark(trace);
}
void
UnsizedArrayTypeRepresentation::traceUnsizedArrayFields(JSTracer *trace)
{
this->mark(trace);
element_->mark(trace);
}
///////////////////////////////////////////////////////////////////////////
// Finalization
/*static*/ void
TypeRepresentation::obj_finalize(js::FreeOp *fop, JSObject *object)
{
JSCompartment *comp = object->compartment();
TypeRepresentation *typeRepr = fromOwnerObject(*object);
comp->typeReprs.remove(typeRepr);
js_free(typeRepr);
}
///////////////////////////////////////////////////////////////////////////
// Walking memory
template<typename V>
static void
visitReferences(SizedTypeRepresentation *repr,
uint8_t *mem,
V& visitor)
{
if (repr->transparent())
return;
switch (repr->kind()) {
case TypeDescr::Scalar:
case TypeDescr::X4:
return;
case TypeDescr::Reference:
visitor.visitReference(repr->asReference(), mem);
return;
case TypeDescr::SizedArray:
{
SizedArrayTypeRepresentation *arrayRepr = repr->asSizedArray();
SizedTypeRepresentation *elementRepr = arrayRepr->element();
for (size_t i = 0; i < arrayRepr->length(); i++) {
visitReferences(elementRepr, mem, visitor);
mem += elementRepr->size();
}
return;
}
case TypeDescr::UnsizedArray:
{
MOZ_ASSUME_UNREACHABLE("Only Sized Type representations");
}
case TypeDescr::Struct:
{
StructTypeRepresentation *structRepr = repr->asStruct();
for (size_t i = 0; i < structRepr->fieldCount(); i++) {
const StructField &f = structRepr->field(i);
visitReferences(f.typeRepr, mem + f.offset, visitor);
}
return;
}
}
MOZ_ASSUME_UNREACHABLE("Invalid type repr kind");
}
///////////////////////////////////////////////////////////////////////////
// Initializing instances
namespace js {
class MemoryInitVisitor {
const JSRuntime *rt_;
public:
MemoryInitVisitor(const JSRuntime *rt)
: rt_(rt)
{}
void visitReference(ReferenceTypeRepresentation *repr, uint8_t *mem);
};
} // namespace js
void
js::MemoryInitVisitor::visitReference(ReferenceTypeRepresentation *repr, uint8_t *mem)
{
switch (repr->type()) {
case ReferenceTypeDescr::TYPE_ANY:
{
js::HeapValue *heapValue = reinterpret_cast<js::HeapValue *>(mem);
heapValue->init(UndefinedValue());
return;
}
case ReferenceTypeDescr::TYPE_OBJECT:
{
js::HeapPtrObject *objectPtr =
reinterpret_cast<js::HeapPtrObject *>(mem);
objectPtr->init(nullptr);
return;
}
case ReferenceTypeDescr::TYPE_STRING:
{
js::HeapPtrString *stringPtr =
reinterpret_cast<js::HeapPtrString *>(mem);
stringPtr->init(rt_->emptyString);
return;
}
}
MOZ_ASSUME_UNREACHABLE("Invalid kind");
}
void
SizedTypeRepresentation::initInstance(const JSRuntime *rt,
uint8_t *mem,
size_t length)
{
JS_ASSERT(length >= 1);
MemoryInitVisitor visitor(rt);
// Initialize the 0th instance
memset(mem, 0, size());
if (opaque())
visitReferences(this, mem, visitor);
// Stamp out N copies of later instances
uint8_t *target = mem;
for (size_t i = 1; i < length; i++) {
target += size();
memcpy(target, mem, size());
}
}
///////////////////////////////////////////////////////////////////////////
// Tracing instances
namespace js {
class MemoryTracingVisitor {
JSTracer *trace_;
public:
MemoryTracingVisitor(JSTracer *trace)
: trace_(trace)
{}
void visitReference(ReferenceTypeRepresentation *repr, uint8_t *mem);
};
} // namespace js
void
js::MemoryTracingVisitor::visitReference(ReferenceTypeRepresentation *repr, uint8_t *mem)
{
switch (repr->type()) {
case ReferenceTypeDescr::TYPE_ANY:
{
js::HeapValue *heapValue = reinterpret_cast<js::HeapValue *>(mem);
gc::MarkValue(trace_, heapValue, "reference-val");
return;
}
case ReferenceTypeDescr::TYPE_OBJECT:
{
js::HeapPtrObject *objectPtr =
reinterpret_cast<js::HeapPtrObject *>(mem);
if (*objectPtr)
gc::MarkObject(trace_, objectPtr, "reference-obj");
return;
}
case ReferenceTypeDescr::TYPE_STRING:
{
js::HeapPtrString *stringPtr =
reinterpret_cast<js::HeapPtrString *>(mem);
if (*stringPtr)
gc::MarkString(trace_, stringPtr, "reference-str");
return;
}
}
MOZ_ASSUME_UNREACHABLE("Invalid kind");
}
void
SizedTypeRepresentation::traceInstance(JSTracer *trace,
uint8_t *mem,
size_t length)
{
MemoryTracingVisitor visitor(trace);
for (size_t i = 0; i < length; i++) {
visitReferences(this, mem, visitor);
mem += size();
}
}
///////////////////////////////////////////////////////////////////////////
// Misc
const StructField *
StructTypeRepresentation::fieldNamed(jsid id) const
{
if (!JSID_IS_ATOM(id))
return nullptr;
uint32_t unused;
JSAtom *atom = JSID_TO_ATOM(id);
if (atom->isIndex(&unused))
return nullptr;
PropertyName *name = atom->asPropertyName();
for (size_t i = 0; i < fieldCount(); i++) {
if (field(i).propertyName.get() == name)
return &field(i);
}
return nullptr;
}
/*static*/ bool
TypeRepresentation::isOwnerObject(JSObject &obj)
{
return obj.getClass() == &class_;
}
/*static*/ TypeRepresentation *
TypeRepresentation::fromOwnerObject(JSObject &obj)
{
JS_ASSERT(obj.getClass() == &class_);
return (TypeRepresentation*) obj.getPrivate();
}

View File

@ -1,433 +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 builtin_TypeRepresentation_h
#define builtin_TypeRepresentation_h
/*
* Type Representations are canonical versions of user-defined type
* descriptors. Using the typed objects API, users are free to define
* new type descriptors representing C-like type definitions. Each such
* type descriptor has a distinct prototype and identity, even if it
* describes the same logical type as another type
* descriptor. Generally speaking, though, the only thing the compiler
* cares about is the binary data layout implied by a type descriptor.
*
* Therefore, we link each such type descriptor to one canonical *type
* representation*. The type representation is itself an object, but
* this object is never exposed to user code (it is used by self-hosted
* code). Type representations are interned into a hashset in the
* compartment (typeReprs), meaning that you can compare two type
* representations for equality just using `==`. If they are equal,
* it means that they represent the same binary layout.
*
* # Creation and canonicalization:
*
* Each kind of `TypeRepresentation` object includes a `New` method
* that will create a canonical instance of it. So, for example, you
* can do `ScalarTypeRepresentation::Create(Uint8)` to get the
* canonical representation of uint8. The object that is returned is
* designed to be immutable, and the API permits only read access.
*
* # Integration with TI:
*
* Each TypeRepresentation has an associated Type Object. This Type
* Object is used as the type object for all type descriptors with this
* representation. The type object has an associated addendum linking
* to the type representation, thus allowing the jit to deduce
* information about type descriptors that appear in expressions.
*
* # Memory management:
*
* Each TypeRepresentations has an associated JSObject, called its
* owned object. When this object is finalized, the TypeRepresentation*
* will be freed (and removed from the interning table, see
* below). Therefore, if you reference a TypeRepresentation*, you must
* ensure this owner object is traced. In type objects, this is done by
* invoking TypeRepresentation::mark(); in binary data type
* descriptors, the owner object for the type is stored in
* `SLOT_TYPE_REPR`.
*
* The canonicalization table maintains *weak references* to the
* TypeRepresentation* pointers. That is, the table is not traced.
* Instead, whenever an object is created, it is paired with its owner
* object, and the finalizer of the owner object removes the pointer
* from the table and then frees the pointer.
*
* # Opacity
*
* A type representation is considered "opaque" if it contains
* references (strings, objects, any). In those cases we have to be
* more limited with respect to aliasing etc to preserve portability
* across engines (for example, we don't want to expose sizeof(Any))
* and memory safety.
*/
#include "jsalloc.h"
#include "jscntxt.h"
#include "jspubtd.h"
#include "builtin/TypedObject.h"
#include "builtin/TypedObjectConstants.h"
#include "gc/Barrier.h"
#include "js/HashTable.h"
namespace js {
class TypeRepresentation;
class SizedTypeRepresentation;
class ScalarTypeRepresentation;
class ReferenceTypeRepresentation;
class X4TypeRepresentation;
class SizedArrayTypeRepresentation;
class UnsizedArrayTypeRepresentation;
class StructTypeRepresentation;
struct Class;
class StringBuffer;
struct TypeRepresentationHasher
{
typedef TypeRepresentation *Lookup;
static HashNumber hash(TypeRepresentation *key);
static bool match(TypeRepresentation *key1, TypeRepresentation *key2);
private:
static HashNumber hashScalar(ScalarTypeRepresentation *key);
static HashNumber hashReference(ReferenceTypeRepresentation *key);
static HashNumber hashX4(X4TypeRepresentation *key);
static HashNumber hashStruct(StructTypeRepresentation *key);
static HashNumber hashUnsizedArray(UnsizedArrayTypeRepresentation *key);
static HashNumber hashSizedArray(SizedArrayTypeRepresentation *key);
static bool matchScalars(ScalarTypeRepresentation *key1,
ScalarTypeRepresentation *key2);
static bool matchReferences(ReferenceTypeRepresentation *key1,
ReferenceTypeRepresentation *key2);
static bool matchX4s(X4TypeRepresentation *key1,
X4TypeRepresentation *key2);
static bool matchStructs(StructTypeRepresentation *key1,
StructTypeRepresentation *key2);
static bool matchSizedArrays(SizedArrayTypeRepresentation *key1,
SizedArrayTypeRepresentation *key2);
static bool matchUnsizedArrays(UnsizedArrayTypeRepresentation *key1,
UnsizedArrayTypeRepresentation *key2);
};
typedef js::HashSet<TypeRepresentation *,
TypeRepresentationHasher,
RuntimeAllocPolicy> TypeRepresentationHash;
class TypeRepresentationHelper;
class TypeRepresentation {
protected:
TypeRepresentation(TypeDescr::Kind kind, size_t alignment, bool opaque);
// in order to call addToTableOrFree()
friend class TypeRepresentationHelper;
TypeDescr::Kind kind_;
bool opaque_;
size_t alignment_;
JSObject *addToTableOrFree(JSContext *cx, TypeRepresentationHash::AddPtr &p);
private:
static const Class class_;
static void obj_trace(JSTracer *trace, JSObject *object);
static void obj_finalize(js::FreeOp *fop, JSObject *object);
HeapPtrObject ownerObject_;
void traceFields(JSTracer *tracer);
public:
TypeDescr::Kind kind() const { return kind_; }
bool opaque() const { return opaque_; }
bool transparent() const { return !opaque_; }
JSObject *ownerObject() const { return ownerObject_.get(); }
size_t alignment() const { return alignment_; }
static bool isOwnerObject(JSObject &obj);
static TypeRepresentation *fromOwnerObject(JSObject &obj);
bool isSized() const {
return TypeDescr::isSized(kind());
}
inline SizedTypeRepresentation *asSized();
bool isScalar() const {
return kind() == TypeDescr::Scalar;
}
inline ScalarTypeRepresentation *asScalar();
bool isReference() const {
return kind() == TypeDescr::Reference;
}
inline ReferenceTypeRepresentation *asReference();
bool isX4() const {
return kind() == TypeDescr::X4;
}
inline X4TypeRepresentation *asX4();
bool isSizedArray() const {
return kind() == TypeDescr::SizedArray;
}
inline SizedArrayTypeRepresentation *asSizedArray();
bool isUnsizedArray() const {
return kind() == TypeDescr::UnsizedArray;
}
inline UnsizedArrayTypeRepresentation *asUnsizedArray();
bool isAnyArray() const {
return isSizedArray() || isUnsizedArray();
}
bool isStruct() const {
return kind() == TypeDescr::Struct;
}
inline StructTypeRepresentation *asStruct();
void mark(JSTracer *tracer);
};
class SizedTypeRepresentation : public TypeRepresentation {
protected:
SizedTypeRepresentation(TypeDescr::Kind kind, bool opaque, size_t size, size_t align);
size_t size_;
public:
size_t size() const { return size_; }
// Initializes memory that contains `count` instances of this type.
// `count` must be at least 1.
void initInstance(const JSRuntime *rt, uint8_t *mem, size_t count);
// Traces memory that contains `count` instances of this type.
void traceInstance(JSTracer *trace, uint8_t *mem, size_t count);
};
class ScalarTypeRepresentation : public SizedTypeRepresentation {
private:
// in order to call constructor
friend class TypeRepresentationHelper;
const ScalarTypeDescr::Type type_;
explicit ScalarTypeRepresentation(ScalarTypeDescr::Type type);
public:
ScalarTypeDescr::Type type() const {
return type_;
}
const char *typeName() const {
return ScalarTypeDescr::typeName(type());
}
static JSObject *Create(JSContext *cx, ScalarTypeDescr::Type type);
};
class ReferenceTypeRepresentation : public SizedTypeRepresentation {
private:
ReferenceTypeDescr::Type type_;
explicit ReferenceTypeRepresentation(ReferenceTypeDescr::Type type);
public:
ReferenceTypeDescr::Type type() const {
return type_;
}
const char *typeName() const {
return ReferenceTypeDescr::typeName(type());
}
static JSObject *Create(JSContext *cx, ReferenceTypeDescr::Type type);
};
class X4TypeRepresentation : public SizedTypeRepresentation {
private:
// in order to call constructor
friend class TypeRepresentationHelper;
const X4TypeDescr::Type type_;
explicit X4TypeRepresentation(X4TypeDescr::Type type);
public:
X4TypeDescr::Type type() const {
return type_;
}
static JSObject *Create(JSContext *cx, X4TypeDescr::Type type);
};
class UnsizedArrayTypeRepresentation : public TypeRepresentation {
private:
// so TypeRepresentation can call tracing routines
friend class TypeRepresentation;
SizedTypeRepresentation *element_;
UnsizedArrayTypeRepresentation(SizedTypeRepresentation *element);
// See TypeRepresentation::traceFields()
void traceUnsizedArrayFields(JSTracer *trace);
public:
SizedTypeRepresentation *element() {
return element_;
}
static JSObject *Create(JSContext *cx,
SizedTypeRepresentation *elementTypeRepr);
};
class SizedArrayTypeRepresentation : public SizedTypeRepresentation {
private:
// so TypeRepresentation can call traceSizedArrayFields()
friend class TypeRepresentation;
SizedTypeRepresentation *element_;
size_t length_;
SizedArrayTypeRepresentation(SizedTypeRepresentation *element,
size_t length);
// See TypeRepresentation::traceFields()
void traceSizedArrayFields(JSTracer *trace);
public:
SizedTypeRepresentation *element() {
return element_;
}
size_t length() {
return length_;
}
static JSObject *Create(JSContext *cx,
SizedTypeRepresentation *elementTypeRepr,
size_t length);
};
struct StructField {
size_t index;
HeapPtrPropertyName propertyName;
SizedTypeRepresentation *typeRepr;
size_t offset;
explicit StructField(size_t index,
PropertyName *propertyName,
SizedTypeRepresentation *typeRepr,
size_t offset);
};
class StructTypeRepresentation : public SizedTypeRepresentation {
private:
// so TypeRepresentation can call traceStructFields() etc
friend class TypeRepresentation;
size_t fieldCount_;
// StructTypeRepresentations are allocated with extra space to
// store the contents of the fields array.
StructField* fields() {
return (StructField*) (this+1);
}
const StructField* fields() const {
return (StructField*) (this+1);
}
StructTypeRepresentation();
bool init(JSContext *cx,
AutoPropertyNameVector &names,
AutoObjectVector &typeReprOwners);
// See TypeRepresentation::traceFields()
void traceStructFields(JSTracer *trace);
public:
size_t fieldCount() const {
return fieldCount_;
}
const StructField &field(size_t i) const {
JS_ASSERT(i < fieldCount());
return fields()[i];
}
const StructField *fieldNamed(jsid id) const;
// Creates a struct type from two parallel arrays:
// - `names`: the names of the struct type fields.
// - `typeReprOwners`: the types of each field, which are assumed
// to be the owner objects for sized type representations.
static JSObject *Create(JSContext *cx,
AutoPropertyNameVector &names,
AutoObjectVector &typeReprOwners);
};
// Definitions of the casting methods. These are pulled out of the
// main class definition because both the super- and subtypes must be
// defined for C++ to permit the static_cast.
SizedTypeRepresentation *
TypeRepresentation::asSized() {
JS_ASSERT(isSized());
return static_cast<SizedTypeRepresentation*>(this);
}
ScalarTypeRepresentation *
TypeRepresentation::asScalar() {
JS_ASSERT(isScalar());
return static_cast<ScalarTypeRepresentation*>(this);
}
ReferenceTypeRepresentation *
TypeRepresentation::asReference() {
JS_ASSERT(isReference());
return static_cast<ReferenceTypeRepresentation*>(this);
}
X4TypeRepresentation *
TypeRepresentation::asX4() {
JS_ASSERT(isX4());
return static_cast<X4TypeRepresentation*>(this);
}
SizedArrayTypeRepresentation *
TypeRepresentation::asSizedArray() {
JS_ASSERT(isSizedArray());
return static_cast<SizedArrayTypeRepresentation*>(this);
}
UnsizedArrayTypeRepresentation *
TypeRepresentation::asUnsizedArray() {
JS_ASSERT(isUnsizedArray());
return static_cast<UnsizedArrayTypeRepresentation*>(this);
}
StructTypeRepresentation *
TypeRepresentation::asStruct() {
JS_ASSERT(isStruct());
return static_cast<StructTypeRepresentation*>(this);
}
} // namespace js
#endif

File diff suppressed because it is too large Load Diff

View File

@ -106,12 +106,6 @@
namespace js {
class TypeRepresentation;
class ScalarTypeRepresentation;
class ReferenceTypeRepresentation;
class X4TypeRepresentation;
class StructTypeDescr;
/*
* Helper method for converting a double into other scalar
* types in the same way that JavaScript would. In particular,
@ -156,18 +150,24 @@ class TypeDescr : public JSObject
return kind > JS_TYPEREPR_MAX_UNSIZED_KIND;
}
JSObject &typeRepresentationOwnerObj() const {
return getReservedSlot(JS_DESCR_SLOT_TYPE_REPR).toObject();
JSAtom &stringRepr() const {
return getReservedSlot(JS_DESCR_SLOT_STRING_REPR).toString()->asAtom();
}
TypeRepresentation *typeRepresentation() const;
TypeDescr::Kind kind() const {
return (TypeDescr::Kind) getReservedSlot(JS_DESCR_SLOT_KIND).toInt32();
}
TypeDescr::Kind kind() const;
bool opaque() const {
return getReservedSlot(JS_DESCR_SLOT_OPAQUE).toBoolean();
}
bool opaque() const;
bool transparent() const {
return !opaque();
}
size_t alignment() {
return getReservedSlot(JS_DESCR_SLOT_ALIGNMENT).toInt32();
return (size_t) getReservedSlot(JS_DESCR_SLOT_ALIGNMENT).toInt32();
}
};
@ -177,8 +177,11 @@ class SizedTypeDescr : public TypeDescr
{
public:
size_t size() {
return getReservedSlot(JS_DESCR_SLOT_SIZE).toInt32();
return (size_t) getReservedSlot(JS_DESCR_SLOT_SIZE).toInt32();
}
void initInstances(const JSRuntime *rt, uint8_t *mem, size_t length);
void traceInstances(JSTracer *trace, uint8_t *mem, size_t length);
};
typedef Handle<SizedTypeDescr*> HandleSizedTypeDescr;
@ -213,13 +216,14 @@ class ScalarTypeDescr : public SimpleTypeDescr
};
static const int32_t TYPE_MAX = TYPE_UINT8_CLAMPED + 1;
static size_t size(Type t);
static size_t alignment(Type t);
static const TypeDescr::Kind Kind = TypeDescr::Scalar;
static const bool Opaque = false;
static int32_t size(Type t);
static int32_t alignment(Type t);
static const char *typeName(Type type);
static const Class class_;
static const JSFunctionSpec typeObjectMethods[];
typedef ScalarTypeRepresentation TypeRepr;
ScalarTypeDescr::Type type() const {
return (ScalarTypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
@ -261,14 +265,21 @@ class ReferenceTypeDescr : public SimpleTypeDescr
static const int32_t TYPE_MAX = TYPE_STRING + 1;
static const char *typeName(Type type);
static const TypeDescr::Kind Kind = TypeDescr::Reference;
static const bool Opaque = true;
static const Class class_;
static int32_t size(Type t);
static int32_t alignment(Type t);
static const JSFunctionSpec typeObjectMethods[];
typedef ReferenceTypeRepresentation TypeRepr;
ReferenceTypeDescr::Type type() const {
return (ReferenceTypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
}
const char *typeName() const {
return typeName(type());
}
static bool call(JSContext *cx, unsigned argc, Value *vp);
};
@ -300,8 +311,11 @@ class X4TypeDescr : public ComplexTypeDescr
TYPE_FLOAT32 = JS_X4TYPEREPR_FLOAT32,
};
static const TypeDescr::Kind Kind = TypeDescr::X4;
static const bool Opaque = false;
static const Class class_;
typedef X4TypeRepresentation TypeRepr;
static int32_t size(Type t);
static int32_t alignment(Type t);
X4TypeDescr::Type type() const {
return (X4TypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
@ -318,9 +332,7 @@ class X4TypeDescr : public ComplexTypeDescr
bool IsTypedObjectClass(const Class *clasp); // Defined below
bool IsTypedObjectArray(JSObject& obj);
bool InitializeCommonTypeDescriptorProperties(JSContext *cx,
HandleTypeDescr obj,
HandleObject typeReprOwnerObj);
bool CreateUserSizeAndAlignmentProperties(JSContext *cx, HandleTypeDescr obj);
/*
* Properties and methods of the `ArrayType` meta type object. There
@ -340,13 +352,15 @@ class ArrayMetaTypeDescr : public JSObject
// either ArrayType.prototype or
// unsizedArrayType.__proto__ depending on
// whether this is a sized or unsized array
// - `arrayTypeReprObj` - a type representation object for the array
// - `elementType` - type object for the elements in the array
// - `stringRepr` - canonical string representation for the array
// - `size` - length of the array (0 if unsized)
template<class T>
static T *create(JSContext *cx,
HandleObject arrayTypePrototype,
HandleObject arrayTypeReprObj,
HandleSizedTypeDescr elementType);
HandleSizedTypeDescr elementType,
HandleAtom stringRepr,
int32_t size);
public:
// Properties and methods to be installed on ArrayType.prototype,
@ -376,6 +390,7 @@ class UnsizedArrayTypeDescr : public TypeDescr
{
public:
static const Class class_;
static const TypeDescr::Kind Kind = TypeDescr::UnsizedArray;
// This is the sized method on unsized array type objects. It
// produces a sized variant.
@ -393,6 +408,7 @@ class SizedArrayTypeDescr : public ComplexTypeDescr
{
public:
static const Class class_;
static const TypeDescr::Kind Kind = TypeDescr::SizedArray;
SizedTypeDescr &elementType() {
return getReservedSlot(JS_DESCR_SLOT_ARRAY_ELEM_TYPE).toObject().as<SizedTypeDescr>();
@ -414,14 +430,6 @@ class StructMetaTypeDescr : public JSObject
static JSObject *create(JSContext *cx, HandleObject structTypeGlobal,
HandleObject fields);
/*
* Sets up structType slots based on calculated memory size
* and alignment and stores fieldmap as well.
*/
static bool layout(JSContext *cx,
Handle<StructTypeDescr*> structType,
HandleObject fields);
public:
// Properties and methods to be installed on StructType.prototype,
// and hence inherited by all struct type objects:
@ -443,10 +451,16 @@ class StructTypeDescr : public ComplexTypeDescr
public:
static const Class class_;
// Returns the number of fields defined in this struct.
size_t fieldCount();
// Set `*out` to the index of the field named `id` and returns true,
// or return false if no such field exists.
bool fieldIndex(jsid id, size_t *out);
// Return the name of the field at index `index`.
JSAtom &fieldName(size_t index);
// Return the type descr of the field at index `index`.
SizedTypeDescr &fieldDescr(size_t index);
@ -630,10 +644,6 @@ class TypedObject : public ArrayBufferViewObject
return getReservedSlot(JS_TYPEDOBJ_SLOT_TYPE_DESCR).toObject().as<TypeDescr>();
}
TypeRepresentation *typeRepresentation() const {
return typeDescr().typeRepresentation();
}
uint8_t *typedMem() const {
return (uint8_t*) getPrivate();
}

View File

@ -3,23 +3,24 @@
///////////////////////////////////////////////////////////////////////////
// Getters and setters for various slots.
// Type repr slots
#define REPR_KIND(obj) \
TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEREPR_SLOT_KIND))
// Type object slots
#define DESCR_TYPE_REPR(obj) \
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_TYPE_REPR)
#define DESCR_KIND(obj) \
REPR_KIND(DESCR_TYPE_REPR(obj))
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_KIND)
#define DESCR_STRING_REPR(obj) \
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRING_REPR)
#define DESCR_ALIGNMENT(obj) \
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_ALIGNMENT)
#define DESCR_SIZE(obj) \
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_SIZE)
#define DESCR_SIZED_ARRAY_LENGTH(obj) \
TO_INT32(UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_SIZED_ARRAY_LENGTH))
#define DESCR_OPAQUE(obj) \
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_OPAQUE)
#define DESCR_TYPE(obj) \
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_TYPE)
#define DESCR_ARRAY_ELEMENT_TYPE(obj) \
TO_INT32(UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_ARRAY_ELEM_TYPE))
#define DESCR_SIZED_ARRAY_LENGTH(obj) \
TO_INT32(UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_SIZED_ARRAY_LENGTH))
#define DESCR_STRUCT_FIELD_NAMES(obj) \
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_NAMES)
#define DESCR_STRUCT_FIELD_TYPES(obj) \
@ -43,96 +44,11 @@
#define HAS_PROPERTY(obj, prop) \
callFunction(std_Object_hasOwnProperty, obj, prop)
function TYPEDOBJ_TYPE_REPR(obj) {
// Eventually this will be a slot on typed objects
return DESCR_TYPE_REPR(TYPEDOBJ_TYPE_DESCR(obj));
}
///////////////////////////////////////////////////////////////////////////
// DescrToSource
//
// Converts a type descriptor to a descriptive string
// toSource() for type descriptors.
//
// Warning: user exposed!
function DescrToSourceMethod() {
if (!IsObject(this) || !ObjectIsTypeDescr(this))
ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Type", "toSource", "value");
return DescrToSource(this);
}
function DescrToSource(descr) {
assert(IsObject(descr) && ObjectIsTypeDescr(descr),
"DescrToSource: not type descr");
switch (DESCR_KIND(descr)) {
case JS_TYPEREPR_SCALAR_KIND:
switch (DESCR_TYPE(descr)) {
case JS_SCALARTYPEREPR_INT8: return "int8";
case JS_SCALARTYPEREPR_UINT8: return "uint8";
case JS_SCALARTYPEREPR_UINT8_CLAMPED: return "uint8Clamped";
case JS_SCALARTYPEREPR_INT16: return "int16";
case JS_SCALARTYPEREPR_UINT16: return "uint16";
case JS_SCALARTYPEREPR_INT32: return "int32";
case JS_SCALARTYPEREPR_UINT32: return "uint32";
case JS_SCALARTYPEREPR_FLOAT32: return "float32";
case JS_SCALARTYPEREPR_FLOAT64: return "float64";
}
assert(false, "Unhandled type: " + DESCR_TYPE(descr));
return undefined;
case JS_TYPEREPR_REFERENCE_KIND:
switch (DESCR_TYPE(descr)) {
case JS_REFERENCETYPEREPR_ANY: return "any";
case JS_REFERENCETYPEREPR_OBJECT: return "Object";
case JS_REFERENCETYPEREPR_STRING: return "string";
}
assert(false, "Unhandled type: " + DESCR_TYPE(descr));
return undefined;
case JS_TYPEREPR_X4_KIND:
switch (DESCR_TYPE(descr)) {
case JS_X4TYPEREPR_FLOAT32: return "float32x4";
case JS_X4TYPEREPR_INT32: return "int32x4";
}
assert(false, "Unhandled type: " + DESCR_TYPE(descr));
return undefined;
case JS_TYPEREPR_STRUCT_KIND:
var result = "new StructType({";
var fieldNames = DESCR_STRUCT_FIELD_NAMES(descr);
var fieldTypes = DESCR_STRUCT_FIELD_TYPES(descr);
for (var i = 0; i < fieldNames.length; i++) {
if (i != 0)
result += ", ";
result += fieldNames[i];
result += ": ";
result += DescrToSource(fieldTypes[i]);
}
result += "})";
return result;
case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
return "new ArrayType(" + DescrToSource(descr.elementType) + ")";
case JS_TYPEREPR_SIZED_ARRAY_KIND:
var result = ".array";
var sep = "(";
while (DESCR_KIND(descr) == JS_TYPEREPR_SIZED_ARRAY_KIND) {
result += sep + DESCR_SIZED_ARRAY_LENGTH(descr);
descr = descr.elementType;
sep = ", ";
}
return DescrToSource(descr) + result + ")";
}
assert(false, "Unhandled kind: " + DESCR_KIND(descr));
return undefined;
}
///////////////////////////////////////////////////////////////////////////
// TypedObjectPointer
//
@ -170,7 +86,7 @@ TypedObjectPointer.fromTypedObject = function(typed) {
#ifdef DEBUG
TypedObjectPointer.prototype.toString = function() {
return "Ptr(" + DescrToSource(this.descr) + " @ " + this.offset + ")";
return "Ptr(" + DESCR_STRING_REPR(this.descr) + " @ " + this.offset + ")";
};
#endif
@ -454,7 +370,7 @@ function SetTypedObjectValue(descr, typedObj, offset, fromValue) {
}
// Writes `fromValue` into the memory pointed at by `this`, adapting
// it to `typeRepr` as needed. This is the most general entry point
// it to `this.descr` as needed. This is the most general entry point
// and works for any type.
TypedObjectPointer.prototype.set = function(fromValue) {
assert(TypedObjectIsAttached(this.typedObj), "set() called with unattached typedObj");
@ -463,8 +379,7 @@ TypedObjectPointer.prototype.set = function(fromValue) {
// representation as the destination. In that case, we can just do a
// memcpy.
if (IsObject(fromValue) && ObjectIsTypedObject(fromValue)) {
var typeRepr = DESCR_TYPE_REPR(this.descr);
if (!this.descr.variable && TYPEDOBJ_TYPE_REPR(fromValue) === typeRepr) {
if (!this.descr.variable && DescrsEquiv(this.descr, TYPEDOBJ_TYPE_DESCR(fromValue))) {
if (!TypedObjectIsAttached(fromValue))
ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
@ -513,7 +428,7 @@ TypedObjectPointer.prototype.set = function(fromValue) {
ThrowError(JSMSG_CANT_CONVERT_TO,
typeof(fromValue),
DescrToSource(this.descr));
DESCR_STRING_REPR(this.descr));
}
TypedObjectPointer.prototype.setArray = function(fromValue, length) {
@ -609,7 +524,7 @@ TypedObjectPointer.prototype.setX4 = function(fromValue) {
// to "adapt" fromValue, but there are no legal adaptions.
ThrowError(JSMSG_CANT_CONVERT_TO,
typeof(fromValue),
DescrToSource(this.descr));
DESCR_STRING_REPR(this.descr));
}
///////////////////////////////////////////////////////////////////////////
@ -679,7 +594,7 @@ function TypeDescrEquivalent(otherDescr) {
ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
if (!IsObject(otherDescr) || !ObjectIsTypeDescr(otherDescr))
ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
return DESCR_TYPE_REPR(this) === DESCR_TYPE_REPR(otherDescr);
return DescrsEquiv(this, otherDescr);
}
// TypedArray.redimension(newArrayType)
@ -747,7 +662,7 @@ function TypedArrayRedimension(newArrayType) {
}
// Check that the element types are equivalent.
if (DESCR_TYPE_REPR(oldElementType) !== DESCR_TYPE_REPR(newElementType)) {
if (!DescrsEquiv(oldElementType, newElementType)) {
ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
}
@ -790,6 +705,29 @@ function X4ToSource() {
///////////////////////////////////////////////////////////////////////////
// Miscellaneous
function DescrsEquiv(descr1, descr2) {
assert(IsObject(descr1) && ObjectIsTypeDescr(descr1), "descr1 not descr");
assert(IsObject(descr2) && ObjectIsTypeDescr(descr2), "descr2 not descr");
// Potential optimization: these two strings are guaranteed to be
// atoms, and hence this string comparison can just be a pointer
// comparison. However, I don't think ion knows that. If this ever
// becomes a bottleneck, we can add a intrinsic at some point that
// is treated specially by Ion. (Bug 976688)
return DESCR_STRING_REPR(descr1) === DESCR_STRING_REPR(descr2);
}
// toSource() for type descriptors.
//
// Warning: user exposed!
function DescrToSource() {
if (!IsObject(this) || !ObjectIsTypeDescr(this))
ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Type", "toSource", "value");
return DESCR_STRING_REPR(this);
}
// Warning: user exposed!
function ArrayShorthand(...dims) {
if (!IsObject(this) || !ObjectIsTypeDescr(this))

View File

@ -18,50 +18,29 @@
// working with, even though this is mildly wasteful.
// Slots on all type objects
#define JS_DESCR_SLOT_TYPE_REPR 0 // Associated Type Representation
#define JS_DESCR_SLOT_ALIGNMENT 1 // Alignment in bytes
#define JS_DESCR_SLOT_SIZE 2 // Size in bytes, if sized, else 0
#define JS_DESCR_SLOT_PROTO 3 // Prototype for instances, if any
#define JS_DESCR_SLOT_KIND 0 // Atomized string representation
#define JS_DESCR_SLOT_STRING_REPR 1 // Atomized string representation
#define JS_DESCR_SLOT_ALIGNMENT 2 // Alignment in bytes
#define JS_DESCR_SLOT_SIZE 3 // Size in bytes, if sized, else 0
#define JS_DESCR_SLOT_OPAQUE 4 // Atomized string representation
#define JS_DESCR_SLOT_PROTO 5 // Prototype for instances, if any
// Slots on scalars, references, and x4s
#define JS_DESCR_SLOT_TYPE 4 // Type code
#define JS_DESCR_SLOT_TYPE 6 // Type code
// Slots on all array descriptors
#define JS_DESCR_SLOT_ARRAY_ELEM_TYPE 4
#define JS_DESCR_SLOT_ARRAY_ELEM_TYPE 6
// Slots on sized array descriptors
#define JS_DESCR_SLOT_SIZED_ARRAY_LENGTH 5
#define JS_DESCR_SLOT_SIZED_ARRAY_LENGTH 7
// Slots on struct type objects
#define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 4
#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 5
#define JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS 6
#define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 6
#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 7
#define JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS 8
// Maximum number of slots for any descriptor
#define JS_DESCR_SLOTS 7
///////////////////////////////////////////////////////////////////////////
// Slots for type representation objects
//
// Some slots apply to all type representations and some are specific
// to particular kinds of type representations. Because all type
// representations share the same class, however, they always have the
// same number of slots, though not all of them will be initialized or
// used in the same way.
// Slots on *all* type representations:
#define JS_TYPEREPR_SLOT_KIND 0 // One of the `kind` constants below
#define JS_TYPEREPR_SLOT_SIZE 1 // Size in bytes.
#define JS_TYPEREPR_SLOT_ALIGNMENT 2 // Alignment in bytes.
// Slots on sized arrays:
#define JS_TYPEREPR_SLOT_LENGTH 3 // Length of the array
// Slots on scalars, references, and X4s:
#define JS_TYPEREPR_SLOT_TYPE 3 // One of the constants below
// Maximum number of slots for any type representation
#define JS_TYPEREPR_SLOTS 4
#define JS_DESCR_SLOTS 9
// These constants are for use exclusively in JS code. In C++ code,
// prefer TypeRepresentation::Scalar etc, which allows you to

View File

@ -53,7 +53,6 @@ JSCompartment::JSCompartment(Zone *zone, const JS::CompartmentOptions &options =
objectMetadataCallback(nullptr),
lastAnimationTime(0),
regExps(runtime_),
typeReprs(runtime_),
globalWriteBarriered(false),
propertyTree(thisForCtor()),
selfHostingScriptSource(nullptr),
@ -110,9 +109,6 @@ JSCompartment::init(JSContext *cx)
if (!regExps.init(cx))
return false;
if (!typeReprs.init())
return false;
enumerators = NativeIterator::allocateSentinel(cx);
if (!enumerators)
return false;

View File

@ -10,7 +10,6 @@
#include "mozilla/MemoryReporting.h"
#include "builtin/TypedObject.h"
#include "builtin/TypeRepresentation.h"
#include "gc/Zone.h"
#include "vm/GlobalObject.h"
#include "vm/PIC.h"
@ -207,9 +206,6 @@ struct JSCompartment
js::RegExpCompartment regExps;
/* Set of all currently living type representations. */
js::TypeRepresentationHash typeReprs;
/*
* For generational GC, record whether a write barrier has added this
* compartment's global to the store buffer since the last minor GC.

View File

@ -102,7 +102,6 @@ UNIFIED_SOURCES += [
'builtin/SIMD.cpp',
'builtin/TestingFunctions.cpp',
'builtin/TypedObject.cpp',
'builtin/TypeRepresentation.cpp',
'devtools/sharkctl.cpp',
'ds/LifoAlloc.cpp',
'frontend/BytecodeCompiler.cpp',

View File

@ -33,7 +33,7 @@ function runTests() {
assertEq(A.length, 10);
assertEq(A.elementType, uint8);
assertEq(A.byteLength, 10);
assertEq(A.toSource(), "uint8.array(10)");
assertEq(A.toSource(), "new ArrayType(uint8).dimension(10)");
assertEq(A.prototype.__proto__.__proto__, ArrayType.prototype.prototype);

View File

@ -48,7 +48,6 @@
macro(DateTimeFormatFormatGet, DateTimeFormatFormatGet, "Intl_DateTimeFormat_format_get") \
macro(decodeURI, decodeURI, "decodeURI") \
macro(decodeURIComponent, decodeURIComponent, "decodeURIComponent") \
macro(DescrToSource, DescrToSource, "DescrToSource") \
macro(default_, default_, "default") \
macro(defineProperty, defineProperty, "defineProperty") \
macro(defineGetter, defineGetter, "__defineGetter__") \