зеркало из https://github.com/mozilla/gecko-dev.git
Bug 898359 - Implement reference types in typed objects r=sfink
This commit is contained in:
Родитель
bafb6b3389
Коммит
c000e8b96a
|
@ -687,16 +687,9 @@ CountHeap(JSContext *cx, unsigned argc, jsval *vp)
|
|||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
jsval v;
|
||||
int32_t traceKind;
|
||||
JSString *str;
|
||||
JSCountHeapTracer countTracer;
|
||||
JSCountHeapNode *node;
|
||||
size_t counter;
|
||||
|
||||
RootedValue startValue(cx, UndefinedValue());
|
||||
if (args.length() > 0) {
|
||||
v = args[0];
|
||||
jsval v = args[0];
|
||||
if (JSVAL_IS_TRACEABLE(v)) {
|
||||
startValue = v;
|
||||
} else if (!JSVAL_IS_NULL(v)) {
|
||||
|
@ -707,28 +700,45 @@ CountHeap(JSContext *cx, unsigned argc, jsval *vp)
|
|||
}
|
||||
}
|
||||
|
||||
traceKind = -1;
|
||||
RootedValue traceValue(cx);
|
||||
int32_t traceKind = -1;
|
||||
void *traceThing = NULL;
|
||||
if (args.length() > 1) {
|
||||
str = ToString(cx, args[0]);
|
||||
JSString *str = ToString(cx, args[1]);
|
||||
if (!str)
|
||||
return false;
|
||||
JSFlatString *flatStr = JS_FlattenString(cx, str);
|
||||
if (!flatStr)
|
||||
return false;
|
||||
for (size_t i = 0; ;) {
|
||||
if (JS_FlatStringEqualsAscii(flatStr, traceKindNames[i].name)) {
|
||||
traceKind = traceKindNames[i].kind;
|
||||
break;
|
||||
}
|
||||
if (++i == ArrayLength(traceKindNames)) {
|
||||
JSAutoByteString bytes(cx, str);
|
||||
if (!!bytes)
|
||||
JS_ReportError(cx, "trace kind name '%s' is unknown", bytes.ptr());
|
||||
if (JS_FlatStringEqualsAscii(flatStr, "specific")) {
|
||||
if (args.length() < 3) {
|
||||
JS_ReportError(cx, "tracing of specific value requested "
|
||||
"but no value provided");
|
||||
return false;
|
||||
}
|
||||
traceValue = args[2];
|
||||
if (!JSVAL_IS_TRACEABLE(traceValue)){
|
||||
JS_ReportError(cx, "cannot trace this kind of value");
|
||||
return false;
|
||||
}
|
||||
traceThing = JSVAL_TO_TRACEABLE(traceValue);
|
||||
} else {
|
||||
for (size_t i = 0; ;) {
|
||||
if (JS_FlatStringEqualsAscii(flatStr, traceKindNames[i].name)) {
|
||||
traceKind = traceKindNames[i].kind;
|
||||
break;
|
||||
}
|
||||
if (++i == ArrayLength(traceKindNames)) {
|
||||
JSAutoByteString bytes(cx, str);
|
||||
if (!!bytes)
|
||||
JS_ReportError(cx, "trace kind name '%s' is unknown", bytes.ptr());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSCountHeapTracer countTracer;
|
||||
JS_TracerInit(&countTracer.base, JS_GetRuntime(cx), CountHeapNotify);
|
||||
if (!countTracer.visited.init()) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
|
@ -744,10 +754,18 @@ CountHeap(JSContext *cx, unsigned argc, jsval *vp)
|
|||
JS_CallValueTracer(&countTracer.base, startValue.address(), "root");
|
||||
}
|
||||
|
||||
counter = 0;
|
||||
JSCountHeapNode *node;
|
||||
size_t counter = 0;
|
||||
while ((node = countTracer.traceList) != nullptr) {
|
||||
if (traceKind == -1 || node->kind == traceKind)
|
||||
counter++;
|
||||
if (traceThing == nullptr) {
|
||||
// We are looking for all nodes with a specific kind
|
||||
if (traceKind == -1 || node->kind == traceKind)
|
||||
counter++;
|
||||
} else {
|
||||
// We are looking for some specific thing
|
||||
if (node->thing == traceThing)
|
||||
counter++;
|
||||
}
|
||||
countTracer.traceList = node->next;
|
||||
node->next = countTracer.recycleList;
|
||||
countTracer.recycleList = node;
|
||||
|
@ -1359,11 +1377,13 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = {
|
|||
" was built with."),
|
||||
|
||||
JS_FN_HELP("countHeap", CountHeap, 0, 0,
|
||||
"countHeap([start[, kind]])",
|
||||
"countHeap([start[, kind[, thing]]])",
|
||||
" Count the number of live GC things in the heap or things reachable from\n"
|
||||
" start when it is given and is not null. kind is either 'all' (default) to\n"
|
||||
" count all things or one of 'object', 'double', 'string', 'function'\n"
|
||||
" to count only things of that kind."),
|
||||
" to count only things of that kind. If kind is the string 'specific',\n"
|
||||
" then you can provide an extra argument with some specific traceable\n"
|
||||
" thing to count.\n"),
|
||||
|
||||
#ifdef DEBUG
|
||||
JS_FN_HELP("oomAfterAllocations", OOMAfterAllocations, 1, 0,
|
||||
|
|
|
@ -59,6 +59,9 @@ TypeRepresentationHasher::match(TypeRepresentation *key1,
|
|||
case TypeRepresentation::Scalar:
|
||||
return matchScalars(key1->asScalar(), key2->asScalar());
|
||||
|
||||
case TypeRepresentation::Reference:
|
||||
return matchReferences(key1->asReference(), key2->asReference());
|
||||
|
||||
case TypeRepresentation::Struct:
|
||||
return matchStructs(key1->asStruct(), key2->asStruct());
|
||||
|
||||
|
@ -76,6 +79,13 @@ TypeRepresentationHasher::matchScalars(ScalarTypeRepresentation *key1,
|
|||
return key1->type() == key2->type();
|
||||
}
|
||||
|
||||
bool
|
||||
TypeRepresentationHasher::matchReferences(ReferenceTypeRepresentation *key1,
|
||||
ReferenceTypeRepresentation *key2)
|
||||
{
|
||||
return key1->type() == key2->type();
|
||||
}
|
||||
|
||||
bool
|
||||
TypeRepresentationHasher::matchStructs(StructTypeRepresentation *key1,
|
||||
StructTypeRepresentation *key2)
|
||||
|
@ -109,6 +119,9 @@ TypeRepresentationHasher::hash(TypeRepresentation *key) {
|
|||
case TypeRepresentation::Scalar:
|
||||
return hashScalar(key->asScalar());
|
||||
|
||||
case TypeRepresentation::Reference:
|
||||
return hashReference(key->asReference());
|
||||
|
||||
case TypeRepresentation::Struct:
|
||||
return hashStruct(key->asStruct());
|
||||
|
||||
|
@ -125,6 +138,12 @@ TypeRepresentationHasher::hashScalar(ScalarTypeRepresentation *key)
|
|||
return HashGeneric(key->kind(), key->type());
|
||||
}
|
||||
|
||||
HashNumber
|
||||
TypeRepresentationHasher::hashReference(ReferenceTypeRepresentation *key)
|
||||
{
|
||||
return HashGeneric(key->kind(), key->type());
|
||||
}
|
||||
|
||||
HashNumber
|
||||
TypeRepresentationHasher::hashStruct(StructTypeRepresentation *key)
|
||||
{
|
||||
|
@ -145,14 +164,16 @@ TypeRepresentationHasher::hashArray(ArrayTypeRepresentation *key)
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// Constructors
|
||||
|
||||
TypeRepresentation::TypeRepresentation(Kind kind, size_t size, size_t align)
|
||||
TypeRepresentation::TypeRepresentation(Kind kind, size_t size,
|
||||
size_t align, bool opaque)
|
||||
: size_(size),
|
||||
alignment_(align),
|
||||
kind_(kind)
|
||||
kind_(kind),
|
||||
opaque_(opaque)
|
||||
{}
|
||||
|
||||
ScalarTypeRepresentation::ScalarTypeRepresentation(Type type)
|
||||
: TypeRepresentation(Scalar, 0, 1),
|
||||
: TypeRepresentation(Scalar, 0, 1, false),
|
||||
type_(type)
|
||||
{
|
||||
switch (type) {
|
||||
|
@ -179,9 +200,28 @@ ScalarTypeRepresentation::ScalarTypeRepresentation(Type type)
|
|||
}
|
||||
}
|
||||
|
||||
ReferenceTypeRepresentation::ReferenceTypeRepresentation(Type type)
|
||||
: TypeRepresentation(Reference, 0, 1, true),
|
||||
type_(type)
|
||||
{
|
||||
switch (type) {
|
||||
case TYPE_ANY:
|
||||
size_ = sizeof(js::HeapValue);
|
||||
alignment_ = MOZ_ALIGNOF(js::HeapValue);
|
||||
break;
|
||||
|
||||
case TYPE_OBJECT:
|
||||
case TYPE_STRING:
|
||||
size_ = sizeof(js::HeapPtrObject);
|
||||
alignment_ = MOZ_ALIGNOF(js::HeapPtrObject);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ArrayTypeRepresentation::ArrayTypeRepresentation(TypeRepresentation *element,
|
||||
size_t length)
|
||||
: TypeRepresentation(Array, element->size() * length, element->alignment()),
|
||||
: TypeRepresentation(Array, element->size() * length,
|
||||
element->alignment(), element->opaque()),
|
||||
element_(element),
|
||||
length_(length)
|
||||
{
|
||||
|
@ -203,9 +243,10 @@ StructField::StructField(size_t index,
|
|||
{}
|
||||
|
||||
StructTypeRepresentation::StructTypeRepresentation()
|
||||
: TypeRepresentation(Struct, 0, 1),
|
||||
: TypeRepresentation(Struct, 0, 1, false),
|
||||
fieldCount_(0) // see ::init() below!
|
||||
{
|
||||
// note: size_, alignment_, and opaque_ are computed in ::init() below
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -222,9 +263,16 @@ StructTypeRepresentation::init(JSContext *cx,
|
|||
// consistency across build environments.
|
||||
uint32_t totalSize = 0;
|
||||
|
||||
// These will be adjusted in the loop below:
|
||||
alignment_ = 1;
|
||||
opaque_ = false;
|
||||
|
||||
for (size_t i = 0; i < ids.length(); i++) {
|
||||
TypeRepresentation *fieldTypeRepr = fromOwnerObject(*typeReprOwners[i]);
|
||||
|
||||
if (fieldTypeRepr->opaque())
|
||||
opaque_ = true;
|
||||
|
||||
uint32_t alignedSize = alignTo(totalSize, fieldTypeRepr->alignment());
|
||||
if (alignedSize < totalSize) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
|
||||
|
@ -305,6 +353,11 @@ TypeRepresentation::addToTableOrFree(JSContext *cx,
|
|||
Int32Value(asScalar()->type()));
|
||||
break;
|
||||
|
||||
case Reference:
|
||||
ownerObject->initReservedSlot(JS_TYPEREPR_SLOT_TYPE,
|
||||
Int32Value(asReference()->type()));
|
||||
break;
|
||||
|
||||
case Struct:
|
||||
break;
|
||||
}
|
||||
|
@ -336,6 +389,29 @@ ScalarTypeRepresentation::Create(JSContext *cx,
|
|||
return ptr->addToTableOrFree(cx, p);
|
||||
}
|
||||
|
||||
/*static*/
|
||||
JSObject *
|
||||
ReferenceTypeRepresentation::Create(JSContext *cx,
|
||||
ReferenceTypeRepresentation::Type type)
|
||||
{
|
||||
JSCompartment *comp = cx->compartment();
|
||||
|
||||
ReferenceTypeRepresentation sample(type);
|
||||
TypeRepresentationHash::AddPtr 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 *
|
||||
ArrayTypeRepresentation::Create(JSContext *cx,
|
||||
|
@ -422,6 +498,7 @@ TypeRepresentation::traceFields(JSTracer *trace)
|
|||
|
||||
switch (kind()) {
|
||||
case Scalar:
|
||||
case Reference:
|
||||
break;
|
||||
|
||||
case Struct:
|
||||
|
@ -472,6 +549,9 @@ TypeRepresentation::appendString(JSContext *cx, StringBuffer &contents)
|
|||
case Scalar:
|
||||
return asScalar()->appendStringScalar(cx, contents);
|
||||
|
||||
case Reference:
|
||||
return asReference()->appendStringReference(cx, contents);
|
||||
|
||||
case Array:
|
||||
return asArray()->appendStringArray(cx, contents);
|
||||
|
||||
|
@ -505,6 +585,28 @@ ScalarTypeRepresentation::appendStringScalar(JSContext *cx, StringBuffer &conten
|
|||
MOZ_ASSUME_UNREACHABLE("Invalid type");
|
||||
}
|
||||
|
||||
/*static*/ const char *
|
||||
ReferenceTypeRepresentation::typeName(Type type)
|
||||
{
|
||||
switch (type) {
|
||||
#define NUMERIC_TYPE_TO_STRING(constant_, type_, name_) \
|
||||
case constant_: return #name_;
|
||||
JS_FOR_EACH_REFERENCE_TYPE_REPR(NUMERIC_TYPE_TO_STRING)
|
||||
}
|
||||
MOZ_ASSUME_UNREACHABLE("Invalid type");
|
||||
}
|
||||
|
||||
bool
|
||||
ReferenceTypeRepresentation::appendStringReference(JSContext *cx, StringBuffer &contents)
|
||||
{
|
||||
switch (type()) {
|
||||
#define NUMERIC_TYPE_APPEND_STRING(constant_, type_, name_) \
|
||||
case constant_: return contents.append(#name_);
|
||||
JS_FOR_EACH_REFERENCE_TYPE_REPR(NUMERIC_TYPE_APPEND_STRING)
|
||||
}
|
||||
MOZ_ASSUME_UNREACHABLE("Invalid type");
|
||||
}
|
||||
|
||||
bool
|
||||
ArrayTypeRepresentation::appendStringArray(JSContext *cx, StringBuffer &contents)
|
||||
{
|
||||
|
@ -558,6 +660,162 @@ StructTypeRepresentation::appendStringStruct(JSContext *cx, StringBuffer &conten
|
|||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Walking memory
|
||||
|
||||
template<typename V>
|
||||
static void
|
||||
visitReferences(TypeRepresentation *repr, uint8_t *mem, V& visitor)
|
||||
{
|
||||
if (repr->transparent())
|
||||
return;
|
||||
|
||||
switch (repr->kind()) {
|
||||
case TypeRepresentation::Scalar:
|
||||
return;
|
||||
|
||||
case TypeRepresentation::Reference:
|
||||
visitor.visitReference(repr->asReference(), mem);
|
||||
return;
|
||||
|
||||
case TypeRepresentation::Array:
|
||||
{
|
||||
ArrayTypeRepresentation *arrayRepr = repr->asArray();
|
||||
TypeRepresentation *elementRepr = arrayRepr->element();
|
||||
for (size_t i = 0; i < arrayRepr->length(); i++) {
|
||||
visitReferences(elementRepr, mem, visitor);
|
||||
mem += elementRepr->size();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case TypeRepresentation::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 ReferenceTypeRepresentation::TYPE_ANY:
|
||||
{
|
||||
js::HeapValue *heapValue = reinterpret_cast<js::HeapValue *>(mem);
|
||||
heapValue->init(UndefinedValue());
|
||||
return;
|
||||
}
|
||||
|
||||
case ReferenceTypeRepresentation::TYPE_OBJECT:
|
||||
{
|
||||
js::HeapPtrObject *objectPtr =
|
||||
reinterpret_cast<js::HeapPtrObject *>(mem);
|
||||
objectPtr->init(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
case ReferenceTypeRepresentation::TYPE_STRING:
|
||||
{
|
||||
js::HeapPtrString *stringPtr =
|
||||
reinterpret_cast<js::HeapPtrString *>(mem);
|
||||
stringPtr->init(rt_->emptyString);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSUME_UNREACHABLE("Invalid kind");
|
||||
}
|
||||
|
||||
void
|
||||
TypeRepresentation::initInstance(const JSRuntime *rt, uint8_t *mem)
|
||||
{
|
||||
MemoryInitVisitor visitor(rt);
|
||||
memset(mem, 0, size());
|
||||
if (opaque())
|
||||
visitReferences(this, mem, visitor);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 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 ReferenceTypeRepresentation::TYPE_ANY:
|
||||
{
|
||||
js::HeapValue *heapValue = reinterpret_cast<js::HeapValue *>(mem);
|
||||
gc::MarkValue(trace_, heapValue, "reference-val");
|
||||
return;
|
||||
}
|
||||
|
||||
case ReferenceTypeRepresentation::TYPE_OBJECT:
|
||||
{
|
||||
js::HeapPtrObject *objectPtr =
|
||||
reinterpret_cast<js::HeapPtrObject *>(mem);
|
||||
if (*objectPtr)
|
||||
gc::MarkObject(trace_, objectPtr, "reference-obj");
|
||||
return;
|
||||
}
|
||||
|
||||
case ReferenceTypeRepresentation::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
|
||||
TypeRepresentation::traceInstance(JSTracer *trace, uint8_t *mem)
|
||||
{
|
||||
MemoryTracingVisitor visitor(trace);
|
||||
visitReferences(this, mem, visitor);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Misc
|
||||
|
||||
|
|
|
@ -39,6 +39,14 @@
|
|||
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.
|
||||
|
||||
# Future plans:
|
||||
|
||||
The owner object will eventually be exposed to self-hosted script
|
||||
|
@ -59,6 +67,7 @@ namespace js {
|
|||
|
||||
class TypeRepresentation;
|
||||
class ScalarTypeRepresentation;
|
||||
class ReferenceTypeRepresentation;
|
||||
class ArrayTypeRepresentation;
|
||||
class StructTypeRepresentation;
|
||||
|
||||
|
@ -73,11 +82,14 @@ struct TypeRepresentationHasher
|
|||
|
||||
private:
|
||||
static HashNumber hashScalar(ScalarTypeRepresentation *key);
|
||||
static HashNumber hashReference(ReferenceTypeRepresentation *key);
|
||||
static HashNumber hashStruct(StructTypeRepresentation *key);
|
||||
static HashNumber hashArray(ArrayTypeRepresentation *key);
|
||||
|
||||
static bool matchScalars(ScalarTypeRepresentation *key1,
|
||||
ScalarTypeRepresentation *key2);
|
||||
static bool matchReferences(ReferenceTypeRepresentation *key1,
|
||||
ReferenceTypeRepresentation *key2);
|
||||
static bool matchStructs(StructTypeRepresentation *key1,
|
||||
StructTypeRepresentation *key2);
|
||||
static bool matchArrays(ArrayTypeRepresentation *key1,
|
||||
|
@ -92,16 +104,18 @@ class TypeRepresentation {
|
|||
public:
|
||||
enum Kind {
|
||||
Scalar = JS_TYPEREPR_SCALAR_KIND,
|
||||
Reference = JS_TYPEREPR_REFERENCE_KIND,
|
||||
Struct = JS_TYPEREPR_STRUCT_KIND,
|
||||
Array = JS_TYPEREPR_ARRAY_KIND
|
||||
};
|
||||
|
||||
protected:
|
||||
TypeRepresentation(Kind kind, size_t size, size_t align);
|
||||
TypeRepresentation(Kind kind, size_t size, size_t align, bool opaque);
|
||||
|
||||
size_t size_;
|
||||
size_t alignment_;
|
||||
Kind kind_;
|
||||
bool opaque_;
|
||||
|
||||
JSObject *addToTableOrFree(JSContext *cx, TypeRepresentationHash::AddPtr &p);
|
||||
|
||||
|
@ -117,12 +131,21 @@ class TypeRepresentation {
|
|||
size_t size() const { return size_; }
|
||||
size_t alignment() const { return alignment_; }
|
||||
Kind kind() const { return kind_; }
|
||||
bool opaque() const { return opaque_; }
|
||||
bool transparent() const { return !opaque_; }
|
||||
JSObject *ownerObject() const { return ownerObject_.get(); }
|
||||
|
||||
// Appends a stringified form of this type representation onto
|
||||
// buffer, for use in error messages and the like.
|
||||
bool appendString(JSContext *cx, StringBuffer &buffer);
|
||||
|
||||
// Initializes memory that contains an instance of this type
|
||||
// with appropriate default values (typically 0).
|
||||
void initInstance(const JSRuntime *rt, uint8_t *mem);
|
||||
|
||||
// Traces memory that contains an instance of this type.
|
||||
void traceInstance(JSTracer *trace, uint8_t *mem);
|
||||
|
||||
static bool isOwnerObject(JSObject &obj);
|
||||
static TypeRepresentation *fromOwnerObject(JSObject &obj);
|
||||
|
||||
|
@ -135,6 +158,15 @@ class TypeRepresentation {
|
|||
return (ScalarTypeRepresentation*) this;
|
||||
}
|
||||
|
||||
bool isReference() const {
|
||||
return kind() == Reference;
|
||||
}
|
||||
|
||||
ReferenceTypeRepresentation *asReference() {
|
||||
JS_ASSERT(isReference());
|
||||
return (ReferenceTypeRepresentation*) this;
|
||||
}
|
||||
|
||||
bool isArray() const {
|
||||
return kind() == Array;
|
||||
}
|
||||
|
@ -193,7 +225,9 @@ class ScalarTypeRepresentation : public TypeRepresentation {
|
|||
return type_;
|
||||
}
|
||||
|
||||
bool convertValue(JSContext *cx, HandleValue value, MutableHandleValue vp);
|
||||
const char *typeName() const {
|
||||
return typeName(type());
|
||||
}
|
||||
|
||||
static const char *typeName(Type type);
|
||||
static JSObject *Create(JSContext *cx, Type type);
|
||||
|
@ -217,6 +251,45 @@ class ScalarTypeRepresentation : public TypeRepresentation {
|
|||
JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_) \
|
||||
macro_(ScalarTypeRepresentation::TYPE_UINT8_CLAMPED, uint8_t, uint8Clamped)
|
||||
|
||||
class ReferenceTypeRepresentation : public TypeRepresentation {
|
||||
public:
|
||||
// Must match order of JS_FOR_EACH_REFERENCE_TYPE_REPR below
|
||||
enum Type {
|
||||
TYPE_ANY = JS_REFERENCETYPEREPR_ANY,
|
||||
TYPE_OBJECT = JS_REFERENCETYPEREPR_OBJECT,
|
||||
TYPE_STRING = JS_REFERENCETYPEREPR_STRING,
|
||||
};
|
||||
static const int32_t TYPE_MAX = TYPE_STRING + 1;
|
||||
|
||||
private:
|
||||
// so TypeRepresentation can call appendStringScalar() etc
|
||||
friend class TypeRepresentation;
|
||||
|
||||
Type type_;
|
||||
|
||||
explicit ReferenceTypeRepresentation(Type type);
|
||||
|
||||
// See TypeRepresentation::appendString()
|
||||
bool appendStringReference(JSContext *cx, StringBuffer &buffer);
|
||||
|
||||
public:
|
||||
Type type() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
const char *typeName() const {
|
||||
return typeName(type());
|
||||
}
|
||||
|
||||
static const char *typeName(Type type);
|
||||
static JSObject *Create(JSContext *cx, Type type);
|
||||
};
|
||||
|
||||
#define JS_FOR_EACH_REFERENCE_TYPE_REPR(macro_) \
|
||||
macro_(ReferenceTypeRepresentation::TYPE_ANY, HeapValue, Any) \
|
||||
macro_(ReferenceTypeRepresentation::TYPE_OBJECT, HeapPtrObject, Object) \
|
||||
macro_(ReferenceTypeRepresentation::TYPE_STRING, HeapPtrString, string)
|
||||
|
||||
class ArrayTypeRepresentation : public TypeRepresentation {
|
||||
private:
|
||||
// so TypeRepresentation can call appendStringArray() etc
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -103,22 +103,32 @@ namespace js {
|
|||
*/
|
||||
extern const Class TypedObjectClass;
|
||||
|
||||
template <ScalarTypeRepresentation::Type type, typename T>
|
||||
class NumericType
|
||||
// Type for scalar type constructors like `uint8`. All such type
|
||||
// constructors share a common js::Class and JSFunctionSpec. Scalar
|
||||
// types are non-opaque (their storage is visible unless combined with
|
||||
// an opaque reference type.)
|
||||
class ScalarType
|
||||
{
|
||||
private:
|
||||
static const Class * typeToClass();
|
||||
public:
|
||||
static bool reify(JSContext *cx, void *mem, MutableHandleValue vp);
|
||||
static const Class class_;
|
||||
static const JSFunctionSpec typeObjectMethods[];
|
||||
typedef ScalarTypeRepresentation TypeRepr;
|
||||
|
||||
static bool call(JSContext *cx, unsigned argc, Value *vp);
|
||||
};
|
||||
|
||||
/*
|
||||
* These are the classes of the scalar type descriptors, like `uint8`,
|
||||
* `uint16` etc. Each of these classes has exactly one instance that
|
||||
* is pre-created.
|
||||
*/
|
||||
extern const Class NumericTypeClasses[ScalarTypeRepresentation::TYPE_MAX];
|
||||
// Type for reference type constructors like `Any`, `String`, and
|
||||
// `Object`. All such type constructors share a common js::Class and
|
||||
// JSFunctionSpec. All these types are opaque.
|
||||
class ReferenceType
|
||||
{
|
||||
public:
|
||||
static const Class class_;
|
||||
static const JSFunctionSpec typeObjectMethods[];
|
||||
typedef ReferenceTypeRepresentation TypeRepr;
|
||||
|
||||
static bool call(JSContext *cx, unsigned argc, Value *vp);
|
||||
};
|
||||
|
||||
/*
|
||||
* Type descriptor created by `new ArrayType(...)`
|
||||
|
@ -148,8 +158,6 @@ class ArrayType : public JSObject
|
|||
static bool repeat(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool subarray(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool toSource(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static JSObject *elementType(JSContext *cx, HandleObject obj);
|
||||
};
|
||||
|
||||
|
@ -186,8 +194,6 @@ class StructType : public JSObject
|
|||
// does `new StructType(...)`. It produces a struct type object.
|
||||
static bool construct(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool toSource(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static bool convertAndCopyTo(JSContext *cx,
|
||||
StructTypeRepresentation *typeRepr,
|
||||
HandleValue from, uint8_t *mem);
|
||||
|
@ -278,8 +284,12 @@ class TypedDatum : public JSObject
|
|||
MutableHandleValue statep, MutableHandleId idp);
|
||||
|
||||
public:
|
||||
// Returns the offset in bytes within the object where the `void*`
|
||||
// pointer can be found.
|
||||
// Each typed object contains a void* pointer pointing at the
|
||||
// binary data that it represents. (That data may be owned by this
|
||||
// object or this object may alias data owned by someone else.)
|
||||
// This function returns the offset in bytes within the object
|
||||
// where the `void*` pointer can be found. It is intended for use
|
||||
// by the JIT.
|
||||
static size_t dataOffset();
|
||||
|
||||
static TypedDatum *createUnattachedWithClass(JSContext *cx,
|
||||
|
@ -305,7 +315,7 @@ class TypedDatum : public JSObject
|
|||
size_t offset);
|
||||
|
||||
// If `this` is the owner of the memory, use this.
|
||||
void attach(void *mem);
|
||||
void attach(uint8_t *mem);
|
||||
|
||||
// Otherwise, use this to attach to memory referenced by another datum.
|
||||
void attach(JSObject &datum, uint32_t offset);
|
||||
|
@ -417,12 +427,20 @@ bool Memcpy(ThreadSafeContext *cx, unsigned argc, Value *vp);
|
|||
extern const JSJitInfo MemcpyJitInfo;
|
||||
|
||||
/*
|
||||
* Usage: StoreScalar(targetDatum, targetOffset, value)
|
||||
* Usage: Store_int8(targetDatum, targetOffset, value)
|
||||
* ...
|
||||
* Store_uint8(targetDatum, targetOffset, value)
|
||||
* ...
|
||||
* Store_float32(targetDatum, targetOffset, value)
|
||||
* Store_float64(targetDatum, targetOffset, value)
|
||||
*
|
||||
* Intrinsic function. Stores value (which must be an int32 or uint32)
|
||||
* by `scalarTypeRepr` (which must be a type repr obj) and stores the
|
||||
* value at the memory for `targetDatum` at offset `targetOffset`.
|
||||
* `targetDatum` must be attached.
|
||||
* Intrinsic function. Stores `value` into the memory referenced by
|
||||
* `targetDatum` at the offset `targetOffset`.
|
||||
*
|
||||
* Assumes (and asserts) that:
|
||||
* - `targetDatum` is attached
|
||||
* - `targetOffset` is a valid offset within the bounds of `targetDatum`
|
||||
* - `value` is a number
|
||||
*/
|
||||
#define JS_STORE_SCALAR_CLASS_DEFN(_constant, T, _name) \
|
||||
class StoreScalar##T { \
|
||||
|
@ -431,6 +449,29 @@ class StoreScalar##T { \
|
|||
static const JSJitInfo JitInfo; \
|
||||
};
|
||||
|
||||
/*
|
||||
* Usage: Store_Any(targetDatum, targetOffset, value)
|
||||
* Store_Object(targetDatum, targetOffset, value)
|
||||
* Store_string(targetDatum, targetOffset, value)
|
||||
*
|
||||
* Intrinsic function. Stores `value` into the memory referenced by
|
||||
* `targetDatum` at the offset `targetOffset`.
|
||||
*
|
||||
* Assumes (and asserts) that:
|
||||
* - `targetDatum` is attached
|
||||
* - `targetOffset` is a valid offset within the bounds of `targetDatum`
|
||||
* - `value` is an object (`Store_Object`) or string (`Store_string`).
|
||||
*/
|
||||
#define JS_STORE_REFERENCE_CLASS_DEFN(_constant, T, _name) \
|
||||
class StoreReference##T { \
|
||||
private: \
|
||||
static void store(T* heap, const Value &v); \
|
||||
\
|
||||
public: \
|
||||
static bool Func(ThreadSafeContext *cx, unsigned argc, Value *vp); \
|
||||
static const JSJitInfo JitInfo; \
|
||||
};
|
||||
|
||||
/*
|
||||
* Usage: LoadScalar(targetDatum, targetOffset, value)
|
||||
*
|
||||
|
@ -446,10 +487,30 @@ class LoadScalar##T { \
|
|||
static const JSJitInfo JitInfo; \
|
||||
};
|
||||
|
||||
/*
|
||||
* Usage: LoadReference(targetDatum, targetOffset, value)
|
||||
*
|
||||
* Intrinsic function. Stores value (which must be an int32 or uint32)
|
||||
* by `scalarTypeRepr` (which must be a type repr obj) and stores the
|
||||
* value at the memory for `targetDatum` at offset `targetOffset`.
|
||||
* `targetDatum` must be attached.
|
||||
*/
|
||||
#define JS_LOAD_REFERENCE_CLASS_DEFN(_constant, T, _name) \
|
||||
class LoadReference##T { \
|
||||
private: \
|
||||
static void load(T* heap, MutableHandleValue v); \
|
||||
\
|
||||
public: \
|
||||
static bool Func(ThreadSafeContext *cx, unsigned argc, Value *vp); \
|
||||
static const JSJitInfo JitInfo; \
|
||||
};
|
||||
|
||||
// I was using templates for this stuff instead of macros, but ran
|
||||
// into problems with the Unagi compiler.
|
||||
JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(JS_STORE_SCALAR_CLASS_DEFN)
|
||||
JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(JS_LOAD_SCALAR_CLASS_DEFN)
|
||||
JS_FOR_EACH_REFERENCE_TYPE_REPR(JS_STORE_REFERENCE_CLASS_DEFN)
|
||||
JS_FOR_EACH_REFERENCE_TYPE_REPR(JS_LOAD_REFERENCE_CLASS_DEFN)
|
||||
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -106,6 +106,7 @@ TypedObjectPointer.prototype.kind = function() {
|
|||
TypedObjectPointer.prototype.moveTo = function(propName) {
|
||||
switch (this.kind()) {
|
||||
case JS_TYPEREPR_SCALAR_KIND:
|
||||
case JS_TYPEREPR_REFERENCE_KIND:
|
||||
break;
|
||||
|
||||
case JS_TYPEREPR_ARRAY_KIND:
|
||||
|
@ -179,7 +180,6 @@ TypedObjectPointer.prototype.moveToField = function(propName) {
|
|||
// by `this` and produce JS values. This process is called *reification*
|
||||
// in the spec.
|
||||
|
||||
|
||||
// Reifies the value referenced by the pointer, meaning that it
|
||||
// returns a new object pointing at the value. If the value is
|
||||
// a scalar, it will return a JS number, but otherwise the reified
|
||||
|
@ -191,6 +191,9 @@ TypedObjectPointer.prototype.get = function() {
|
|||
if (REPR_KIND(this.typeRepr) == JS_TYPEREPR_SCALAR_KIND)
|
||||
return this.getScalar();
|
||||
|
||||
if (REPR_KIND(this.typeRepr) == JS_TYPEREPR_REFERENCE_KIND)
|
||||
return this.getReference();
|
||||
|
||||
return NewDerivedTypedDatum(this.typeObj, this.datum, this.offset);
|
||||
}
|
||||
|
||||
|
@ -226,6 +229,22 @@ TypedObjectPointer.prototype.getScalar = function() {
|
|||
assert(false, "Unhandled scalar type: " + type);
|
||||
}
|
||||
|
||||
TypedObjectPointer.prototype.getReference = function() {
|
||||
var type = REPR_TYPE(this.typeRepr);
|
||||
switch (type) {
|
||||
case JS_REFERENCETYPEREPR_ANY:
|
||||
return Load_Any(this.datum, this.offset);
|
||||
|
||||
case JS_REFERENCETYPEREPR_OBJECT:
|
||||
return Load_Object(this.datum, this.offset);
|
||||
|
||||
case JS_REFERENCETYPEREPR_STRING:
|
||||
return Load_string(this.datum, this.offset);
|
||||
}
|
||||
|
||||
assert(false, "Unhandled scalar type: " + type);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Setting values
|
||||
//
|
||||
|
@ -258,6 +277,10 @@ TypedObjectPointer.prototype.set = function(fromValue) {
|
|||
this.setScalar(fromValue);
|
||||
return;
|
||||
|
||||
case JS_TYPEREPR_REFERENCE_KIND:
|
||||
this.setReference(fromValue);
|
||||
return;
|
||||
|
||||
case JS_TYPEREPR_ARRAY_KIND:
|
||||
if (!IsObject(fromValue))
|
||||
break;
|
||||
|
@ -342,6 +365,23 @@ TypedObjectPointer.prototype.setScalar = function(fromValue) {
|
|||
assert(false, "Unhandled scalar type: " + type);
|
||||
}
|
||||
|
||||
TypedObjectPointer.prototype.setReference = function(fromValue) {
|
||||
var type = REPR_TYPE(this.typeRepr);
|
||||
switch (type) {
|
||||
case JS_REFERENCETYPEREPR_ANY:
|
||||
return Store_Any(this.datum, this.offset, fromValue);
|
||||
|
||||
case JS_REFERENCETYPEREPR_OBJECT:
|
||||
var value = (fromValue === null ? fromValue : ToObject(fromValue));
|
||||
return Store_Object(this.datum, this.offset, value);
|
||||
|
||||
case JS_REFERENCETYPEREPR_STRING:
|
||||
return Store_string(this.datum, this.offset, ToString(fromValue));
|
||||
}
|
||||
|
||||
assert(false, "Unhandled scalar type: " + type);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ Wrappers
|
||||
//
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
// Slots for type objects
|
||||
//
|
||||
// Some slots apply to all type objects and some are specific to
|
||||
// particular kinds of type objects. Because all type objects, at
|
||||
// particular kinds of type objects. Because all type objects, at
|
||||
// least for now, have a distinct class, we can assign them distinct
|
||||
// numbers of slots depending on their kind.
|
||||
|
||||
|
@ -23,6 +23,9 @@
|
|||
// Slots on scalars
|
||||
#define JS_TYPEOBJ_SCALAR_SLOTS 1 // Maximum number
|
||||
|
||||
// Slots on references
|
||||
#define JS_TYPEOBJ_REFERENCE_SLOTS 1 // Maximum number
|
||||
|
||||
// Slots on arrays
|
||||
#define JS_TYPEOBJ_SLOT_ARRAY_ELEM_TYPE 1
|
||||
#define JS_TYPEOBJ_ARRAY_SLOTS 2 // Maximum number
|
||||
|
@ -36,7 +39,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
|
||||
// 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.
|
||||
|
@ -49,21 +52,22 @@
|
|||
// Slots on arrays:
|
||||
#define JS_TYPEREPR_SLOT_LENGTH 3 // Length of the array
|
||||
|
||||
// Slots on scalars:
|
||||
// Slots on scalars and references:
|
||||
#define JS_TYPEREPR_SLOT_TYPE 3 // One of the constants below
|
||||
|
||||
// Maximum number of slots for any type representation
|
||||
#define JS_TYPEREPR_SLOTS 4
|
||||
|
||||
// These constants are for use exclusively in JS code. In C++ code,
|
||||
// prefer TypeRepresentation::Scalar etc, since that allows you to
|
||||
// These constants are for use exclusively in JS code. In C++ code,
|
||||
// prefer TypeRepresentation::Scalar etc, which allows you to
|
||||
// write a switch which will receive a warning if you omit a case.
|
||||
#define JS_TYPEREPR_SCALAR_KIND 0
|
||||
#define JS_TYPEREPR_STRUCT_KIND 1
|
||||
#define JS_TYPEREPR_ARRAY_KIND 2
|
||||
#define JS_TYPEREPR_REFERENCE_KIND 1
|
||||
#define JS_TYPEREPR_STRUCT_KIND 2
|
||||
#define JS_TYPEREPR_ARRAY_KIND 3
|
||||
|
||||
// These constants are for use exclusively in JS code. In C++ code,
|
||||
// prefer ScalarTypeRepresentation::TYPE_INT8 etc, since that allows
|
||||
// These constants are for use exclusively in JS code. In C++ code,
|
||||
// prefer ScalarTypeRepresentation::TYPE_INT8 etc, which allows
|
||||
// you to write a switch which will receive a warning if you omit a
|
||||
// case.
|
||||
#define JS_SCALARTYPEREPR_INT8 0
|
||||
|
@ -76,6 +80,14 @@
|
|||
#define JS_SCALARTYPEREPR_FLOAT64 7
|
||||
#define JS_SCALARTYPEREPR_UINT8_CLAMPED 8
|
||||
|
||||
// These constants are for use exclusively in JS code. In C++ code,
|
||||
// prefer ReferenceTypeRepresentation::TYPE_ANY etc, which allows
|
||||
// you to write a switch which will receive a warning if you omit a
|
||||
// case.
|
||||
#define JS_REFERENCETYPEREPR_ANY 0
|
||||
#define JS_REFERENCETYPEREPR_OBJECT 1
|
||||
#define JS_REFERENCETYPEREPR_STRING 2
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Slots for typed objects (actually, any TypedContents objects)
|
||||
|
||||
|
|
|
@ -6521,6 +6521,9 @@ IonBuilder::getElemTryTypedObject(bool *emitted, MDefinition *obj, MDefinition *
|
|||
objTypeReprs,
|
||||
elemTypeReprs,
|
||||
elemSize);
|
||||
|
||||
case TypeRepresentation::Reference:
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSUME_UNREACHABLE("Bad kind");
|
||||
|
@ -8174,6 +8177,9 @@ IonBuilder::getPropTryTypedObject(bool *emitted, PropertyName *name,
|
|||
return true;
|
||||
|
||||
switch (fieldTypeReprs.kind()) {
|
||||
case TypeRepresentation::Reference:
|
||||
return true;
|
||||
|
||||
case TypeRepresentation::Struct:
|
||||
case TypeRepresentation::Array:
|
||||
return getPropTryComplexPropOfTypedObject(emitted,
|
||||
|
@ -8712,6 +8718,7 @@ IonBuilder::setPropTryTypedObject(bool *emitted, MDefinition *obj,
|
|||
return true;
|
||||
|
||||
switch (fieldTypeReprs.kind()) {
|
||||
case TypeRepresentation::Reference:
|
||||
case TypeRepresentation::Struct:
|
||||
case TypeRepresentation::Array:
|
||||
// For now, only optimize storing scalars.
|
||||
|
|
|
@ -14,6 +14,8 @@ var Point = new T.ArrayType(T.float32, 3);
|
|||
var Line = new T.StructType({from: Point, to: Point});
|
||||
var Lines = new T.ArrayType(Line, 3);
|
||||
|
||||
var Objects = new T.ArrayType(T.Object, 3);
|
||||
|
||||
function runTests() {
|
||||
function testHandleGetSetWithScalarType() {
|
||||
var lines = new Lines([
|
||||
|
@ -30,6 +32,23 @@ function runTests() {
|
|||
}
|
||||
testHandleGetSetWithScalarType();
|
||||
|
||||
function testHandleGetSetWithObjectType() {
|
||||
var one = {x: 1};
|
||||
var two = {x: 2};
|
||||
var three = {x: 3};
|
||||
var objects = new Objects([one, two, three]);
|
||||
|
||||
var handle = T.Object.handle(objects, 0);
|
||||
assertEq(T.Handle.get(handle), one);
|
||||
T.Handle.set(handle, three);
|
||||
assertEq(T.Handle.get(handle), three);
|
||||
assertEq(objects[0], three);
|
||||
|
||||
T.Handle.move(handle, objects, 1);
|
||||
assertEq(T.Handle.get(handle), two);
|
||||
}
|
||||
testHandleGetSetWithScalarType();
|
||||
|
||||
function testHandleGetSetWithComplexType() {
|
||||
var lines = new Lines([
|
||||
{from: [1, 2, 3], to: [4, 5, 6]},
|
||||
|
|
|
@ -89,7 +89,7 @@ function runTests()
|
|||
check(function() type(+Infinity) === 0);
|
||||
check(function() type(-Infinity) === 0);
|
||||
check(function() type(NaN) === 0);
|
||||
check(function() type.toString() === strings[i]);
|
||||
check(function() type.toSource() === strings[i]);
|
||||
check(function() type(null) == 0);
|
||||
check(function() type(undefined) == 0);
|
||||
check(function() type([]) == 0);
|
||||
|
@ -110,7 +110,7 @@ function runTests()
|
|||
check(function() type(+Infinity) === Infinity);
|
||||
check(function() type(-Infinity) === -Infinity);
|
||||
check(function() Number.isNaN(type(NaN)));
|
||||
check(function() type.toString() === floatStrings[i]);
|
||||
check(function() type.toSource() === floatStrings[i]);
|
||||
check(function() type(null) == 0);
|
||||
check(function() Number.isNaN(type(undefined)));
|
||||
check(function() type([]) == 0);
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
|
||||
var BUGNUMBER = 898359;
|
||||
var summary = 'TypedObjects reference type aliasing';
|
||||
var actual = '';
|
||||
var expect = '';
|
||||
|
||||
var ArrayType = TypedObject.ArrayType;
|
||||
var StructType = TypedObject.StructType;
|
||||
var Any = TypedObject.Any;
|
||||
var Object = TypedObject.Object;
|
||||
var string = TypedObject.string;
|
||||
|
||||
function runTests()
|
||||
{
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus(summary);
|
||||
|
||||
var MyType = new StructType({f: Object});
|
||||
|
||||
// Test aliasing
|
||||
var myInstance = new MyType({f: {a: 22}});
|
||||
var anotherInstance = new MyType({f: myInstance.f});
|
||||
assertEq(myInstance.f.a, 22);
|
||||
assertEq(myInstance.f.a, anotherInstance.f.a);
|
||||
|
||||
myInstance.f.a += 1;
|
||||
assertEq(myInstance.f.a, 23);
|
||||
assertEq(myInstance.f.a, anotherInstance.f.a);
|
||||
|
||||
reportCompare(true, true, "TypedObjects reference type aliasing tests");
|
||||
}
|
||||
|
||||
runTests();
|
|
@ -0,0 +1,70 @@
|
|||
// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
|
||||
var BUGNUMBER = 898359;
|
||||
var summary = 'TypedObjects reference type coercions';
|
||||
var actual = '';
|
||||
var expect = '';
|
||||
|
||||
var ArrayType = TypedObject.ArrayType;
|
||||
var StructType = TypedObject.StructType;
|
||||
var Any = TypedObject.Any;
|
||||
var Object = TypedObject.Object;
|
||||
var string = TypedObject.string;
|
||||
|
||||
function TestValues(type, values) {
|
||||
for (var i = 0; i < values.length; i++) {
|
||||
compare(type(values[i].input), values[i]);
|
||||
}
|
||||
|
||||
var Struct = new StructType({f: type});
|
||||
for (var i = 0; i < values.length; i++) {
|
||||
var struct = new Struct({f: values[i].input});
|
||||
compare(struct.f, values[i]);
|
||||
}
|
||||
|
||||
for (var i = 0; i < values.length; i++) {
|
||||
var struct = new Struct();
|
||||
struct.f = values[i].input;
|
||||
compare(struct.f, values[i]);
|
||||
}
|
||||
|
||||
var Array = new ArrayType(type, 1);
|
||||
for (var i = 0; i < values.length; i++) {
|
||||
var array = new Array();
|
||||
array[0] = values[i].input;
|
||||
compare(array[0], values[i]);
|
||||
}
|
||||
|
||||
function compare(v, spec) {
|
||||
if (spec.source)
|
||||
v = v.toSource();
|
||||
assertEq(v, spec.output);
|
||||
}
|
||||
}
|
||||
|
||||
function runTests()
|
||||
{
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus(summary);
|
||||
|
||||
var x = {};
|
||||
|
||||
TestValues(Any, [{input: undefined, output: undefined},
|
||||
{input: x, output: x},
|
||||
{input: 22.22, output: 22.22},
|
||||
{input: true, output: true}]);
|
||||
|
||||
TestValues(string, [{input: undefined, output: "undefined"},
|
||||
{input: x, output: x.toString()},
|
||||
{input: 22.22, output: "22.22"},
|
||||
{input: true, output: "true"}]);
|
||||
|
||||
assertThrows(() => Object(undefined));
|
||||
|
||||
TestValues(Object, [{input: x, output: x},
|
||||
{input: 22.22, source: true, output: "(new Number(22.22))"},
|
||||
{input: true, source: true, output: "(new Boolean(true))"}]);
|
||||
|
||||
reportCompare(true, true, "TypedObjects reference type tests");
|
||||
}
|
||||
|
||||
runTests();
|
|
@ -0,0 +1,22 @@
|
|||
// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
|
||||
var BUGNUMBER = 898359;
|
||||
var summary = 'TypedObjects reference type coercions';
|
||||
var actual = '';
|
||||
var expect = '';
|
||||
|
||||
var ArrayType = TypedObject.ArrayType;
|
||||
var StructType = TypedObject.StructType;
|
||||
var Any = TypedObject.Any;
|
||||
var Object = TypedObject.Object;
|
||||
var string = TypedObject.string;
|
||||
|
||||
|
||||
function runTests()
|
||||
{
|
||||
var S = new StructType({f: Any, g: Any});
|
||||
var s = new S({f: "Hello", g: "Hello"});
|
||||
assertEq(s.f, s.g);
|
||||
reportCompare(true, true, "TypedObjects trace tests");
|
||||
}
|
||||
|
||||
runTests();
|
|
@ -0,0 +1,88 @@
|
|||
// |reftest| skip-if(!this.hasOwnProperty("TypedObject")||!this.hasOwnProperty("countHeap"))
|
||||
var BUGNUMBER = 898359;
|
||||
var summary = 'TypedObjects reference type trace';
|
||||
var actual = '';
|
||||
var expect = '';
|
||||
|
||||
var ArrayType = TypedObject.ArrayType;
|
||||
var StructType = TypedObject.StructType;
|
||||
var Any = TypedObject.Any;
|
||||
var Object = TypedObject.Object;
|
||||
var string = TypedObject.string;
|
||||
|
||||
function assertCanReach(from, target, times) {
|
||||
times = times || 1;
|
||||
var count1 = countHeap(from, "specific", target);
|
||||
print("canReach:", count1, times, from.toSource(), target.toSource());
|
||||
assertEq(count1, times);
|
||||
}
|
||||
|
||||
function assertCannotReach(from, target) {
|
||||
var count1 = countHeap(from, "specific", target);
|
||||
print("cannotReach:", count1, from.toSource(), target.toSource());
|
||||
assertEq(count1, 0);
|
||||
}
|
||||
|
||||
function TestStructFields(RefType) {
|
||||
var rabbit = {};
|
||||
var S1 = new StructType({f: RefType});
|
||||
var s1 = new S1({f: rabbit});
|
||||
assertCanReach(s1, rabbit);
|
||||
s1.f = null;
|
||||
assertCannotReach(s1, rabbit);
|
||||
}
|
||||
|
||||
function TestArrayElements(RefType) {
|
||||
var rabbit = {};
|
||||
var S1 = new ArrayType(RefType, 1);
|
||||
var s1 = new S1([rabbit]);
|
||||
assertCanReach(s1, rabbit);
|
||||
s1[0] = null;
|
||||
assertCannotReach(s1, rabbit);
|
||||
}
|
||||
|
||||
function TestStructInArray(RefType) {
|
||||
var rabbit = {};
|
||||
var S2 = new StructType({f: RefType, g: RefType});
|
||||
var S1 = new ArrayType(S2, 1);
|
||||
var s1 = new S1([{f: rabbit, g: {}}]);
|
||||
assertCanReach(s1, rabbit);
|
||||
s1[0].f = null;
|
||||
assertCannotReach(s1, rabbit);
|
||||
}
|
||||
|
||||
function TestStringInStruct() {
|
||||
// Rather subtle hair-pullingly maddening testing phenomena: If you
|
||||
// just use a constant string here, it's always reachable via the
|
||||
// atoms table. Same is true of "Hello" + "1" (an earlier
|
||||
// attempt) due to parser constant folding. So we have to make a
|
||||
// rabbit that's not constant foldable. But don't just use
|
||||
// Math.random(), since small integers are atoms already.
|
||||
var rabbit = "Hello" + Math.random();
|
||||
var S1 = new StructType({f: string});
|
||||
var s1 = new S1({f: rabbit});
|
||||
assertCanReach(s1, rabbit);
|
||||
s1.f = "World";
|
||||
assertCannotReach(s1, rabbit);
|
||||
}
|
||||
|
||||
function runTests()
|
||||
{
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus(summary);
|
||||
|
||||
TestStructFields(Object);
|
||||
TestStructFields(Any);
|
||||
|
||||
TestArrayElements(Object);
|
||||
TestArrayElements(Any);
|
||||
|
||||
TestStructInArray(Object);
|
||||
TestStructInArray(Any);
|
||||
|
||||
TestStringInStruct();
|
||||
|
||||
reportCompare(true, true, "TypedObjects trace tests");
|
||||
}
|
||||
|
||||
runTests();
|
|
@ -0,0 +1,30 @@
|
|||
// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
|
||||
var BUGNUMBER = 898359;
|
||||
var summary = 'TypedObjects reference type default values';
|
||||
var actual = '';
|
||||
var expect = '';
|
||||
|
||||
var ArrayType = TypedObject.ArrayType;
|
||||
var StructType = TypedObject.StructType;
|
||||
var Any = TypedObject.Any;
|
||||
var Object = TypedObject.Object;
|
||||
var string = TypedObject.string;
|
||||
|
||||
function runTests()
|
||||
{
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus(summary);
|
||||
|
||||
var S = new StructType({any: Any,
|
||||
object: Object,
|
||||
string: string});
|
||||
var s = new S();
|
||||
|
||||
assertEq(s.any, undefined);
|
||||
assertEq(s.object, null);
|
||||
assertEq(s.string, "");
|
||||
|
||||
reportCompare(true, true, "TypedObjects ref type uninit");
|
||||
}
|
||||
|
||||
runTests();
|
|
@ -2,30 +2,21 @@
|
|||
var BUGNUMBER = 922216;
|
||||
var summary = 'TypedObjects Equivalent Numeric Types';
|
||||
|
||||
var ArrayType = TypedObject.ArrayType;
|
||||
var StructType = TypedObject.StructType;
|
||||
var uint8 = TypedObject.uint8;
|
||||
var uint16 = TypedObject.uint16;
|
||||
var uint32 = TypedObject.uint32;
|
||||
var uint8Clamped = TypedObject.uint8Clamped;
|
||||
var int8 = TypedObject.int8;
|
||||
var int16 = TypedObject.int16;
|
||||
var int32 = TypedObject.int32;
|
||||
var float32 = TypedObject.float32;
|
||||
var float64 = TypedObject.float64;
|
||||
var T = TypedObject;
|
||||
|
||||
function runTests() {
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
var scalarTypes = [
|
||||
int8, int16, int32,
|
||||
uint8, uint16, uint32,
|
||||
float32, float64
|
||||
var simpleTypes = [
|
||||
T.int8, T.int16, T.int32,
|
||||
T.uint8, T.uint16, T.uint32,
|
||||
T.float32, T.float64,
|
||||
T.Object, T.Any, T.string
|
||||
];
|
||||
|
||||
for (var i = 0; i < scalarTypes.length; i++)
|
||||
for (var j = 0; j < scalarTypes.length; j++)
|
||||
assertEq(i == j, scalarTypes[i].equivalent(scalarTypes[j]));
|
||||
for (var i = 0; i < simpleTypes.length; i++)
|
||||
for (var j = 0; j < simpleTypes.length; j++)
|
||||
assertEq(i == j, simpleTypes[i].equivalent(simpleTypes[j]));
|
||||
|
||||
reportCompare(true, true);
|
||||
print("Tests complete");
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#define FOR_EACH_COMMON_PROPERTYNAME(macro) \
|
||||
macro(anonymous, anonymous, "anonymous") \
|
||||
macro(Any, Any, "Any") \
|
||||
macro(apply, apply, "apply") \
|
||||
macro(arguments, arguments, "arguments") \
|
||||
macro(as, as, "as") \
|
||||
|
|
|
@ -659,14 +659,23 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JSNativeThreadSafeWrapper<js::Memcpy>,
|
||||
&js::MemcpyJitInfo, 5, 0),
|
||||
|
||||
#define LOAD_AND_STORE_FN_DECLS(_constant, _type, _name) \
|
||||
#define LOAD_AND_STORE_SCALAR_FN_DECLS(_constant, _type, _name) \
|
||||
JS_FNINFO("Store_" #_name, \
|
||||
JSNativeThreadSafeWrapper<js::StoreScalar##_type::Func>, \
|
||||
&js::StoreScalar##_type::JitInfo, 3, 0), \
|
||||
JS_FNINFO("Load_" #_name, \
|
||||
JSNativeThreadSafeWrapper<js::LoadScalar##_type::Func>, \
|
||||
&js::LoadScalar##_type::JitInfo, 3, 0),
|
||||
JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(LOAD_AND_STORE_FN_DECLS)
|
||||
JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(LOAD_AND_STORE_SCALAR_FN_DECLS)
|
||||
|
||||
#define LOAD_AND_STORE_REFERENCE_FN_DECLS(_constant, _type, _name) \
|
||||
JS_FNINFO("Store_" #_name, \
|
||||
JSNativeThreadSafeWrapper<js::StoreReference##_type::Func>, \
|
||||
&js::StoreReference##_type::JitInfo, 3, 0), \
|
||||
JS_FNINFO("Load_" #_name, \
|
||||
JSNativeThreadSafeWrapper<js::LoadReference##_type::Func>, \
|
||||
&js::LoadReference##_type::JitInfo, 3, 0),
|
||||
JS_FOR_EACH_REFERENCE_TYPE_REPR(LOAD_AND_STORE_REFERENCE_FN_DECLS)
|
||||
|
||||
// See builtin/Intl.h for descriptions of the intl_* functions.
|
||||
JS_FN("intl_availableCalendars", intl_availableCalendars, 1,0),
|
||||
|
|
Загрузка…
Ссылка в новой задаче