# HG changeset patch # Parent 187a63dc45b74870e3b025cf337b07f7eb2f5f1a # User Nikhil Marathe Bug 578700 - Memory management diff --git a/js/src/jsbinarydata.cpp b/js/src/jsbinarydata.cpp --- a/js/src/jsbinarydata.cpp +++ b/js/src/jsbinarydata.cpp @@ -14,18 +14,18 @@ #include "vm/GlobalObject.h" #include "vm/String.h" #include "vm/StringBuffer.h" #include "jsobjinlines.h" using namespace js; -static bool Reify(JSContext *cx, JSObject *type, void *mem, MutableHandleValue vp); -static bool ConvertAndCopyTo(JSContext *cx, JSObject *type, HandleValue from, void *mem); +static bool Reify(JSContext *cx, JSObject *type, RawObject obj, size_t offset, MutableHandleValue vp); +static bool ConvertAndCopyTo(JSContext *cx, JSObject *type, HandleValue from, uint8_t *mem); static void ReportTypeError(JSContext *cx, jsval fromValue, const char *toType) { char *valueStr = JS_EncodeString(cx, JS_ValueToString(cx, fromValue)); JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO, valueStr, toType); JS_free(cx, (void *) valueStr); } @@ -363,22 +363,22 @@ Class BinaryArray::class_ = { JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayType), JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, - NULL, /* finalize */ + BinaryArray::finalize, NULL, /* checkAccess */ NULL, /* call */ NULL, /* construct */ NULL, /* hasInstance */ - NULL, + BinaryArray::obj_trace, JS_NULL_CLASS_EXT, { BinaryArray::obj_lookupGeneric, BinaryArray::obj_lookupProperty, BinaryArray::obj_lookupElement, BinaryArray::obj_lookupSpecial, BinaryArray::obj_defineGeneric, BinaryArray::obj_defineProperty, @@ -443,17 +443,17 @@ ArrayType::convert(JSContext *cx, JSObje ReportTypeError(cx, from, "binary array"); // TODO better type reporting once toString is implemented return false; } JSObject *val = from.toObjectOrNull(); if (IsBlock(val)) { if (IsSame(cx, exemplar, GetType(val))) { uint8_t *priv = (uint8_t*) val->getPrivate(); - *blockref = priv; // we can be sure this is properly aligned + memcpy(*blockref, priv, GetMemSize(cx, exemplar)); // we can be sure this is properly aligned return true; } ReportTypeError(cx, from, "incompatible types"); return false; } RootedObject valRooted(cx, val); // TODO fix this conversion scourge once and for all RootedValue fromLenVal(cx); @@ -466,37 +466,34 @@ ArrayType::convert(JSContext *cx, JSObje if (ArrayType::length(cx, exemplar) != fromLen) { ReportTypeError(cx, from, "length mismatch"); return false; } JSObject *elementType = ArrayType::elementType(cx, exemplar); - uint32_t memsize = GetMemSize(cx, exemplar); - uint8_t *block = (uint8_t*) JS_malloc(cx, memsize); uint32_t offsetMult = GetMemSize(cx, elementType); for (uint32_t i = 0; i < fromLen; i++) { RootedValue fromElem(cx); if (!JSObject::getElement(cx, valRooted, valRooted, i, &fromElem)) continue; // TODO should we abort here? a JS array can have holes - if (!ConvertAndCopyTo(cx, elementType, fromElem, (uint8_t *) block + offsetMult * i)) + if (!ConvertAndCopyTo(cx, elementType, fromElem, (*blockref) + offsetMult * i)) return false; } - *blockref = block; // TODO this is a memory leak return true; } inline bool -ArrayType::reify(JSContext *cx, JSObject *type, void *mem, MutableHandleValue to) +ArrayType::reify(JSContext *cx, JSObject *type, RawObject owner, size_t offset, MutableHandleValue to) { - JSObject *obj = BinaryArray::create(cx, type, (uint8_t*) mem); + JSObject *obj = BinaryArray::create(cx, type, owner, offset); if (!obj) return false; to.setObject(*obj); return true; } JSObject * ArrayType::create(JSContext *cx, JSObject *elementType, int32_t length) @@ -677,16 +674,17 @@ BinaryArray::createEmpty(JSContext *cx, RootedObject typeRooted(cx, type); RootedValue protoVal(cx); if (!JSObject::getProperty(cx, typeRooted, typeRooted, cx->names().classPrototype, &protoVal)) return NULL; RootedObject obj(cx, NewObjectWithClassProto(cx, &BinaryArray::class_, protoVal.toObjectOrNull(), NULL)); obj->setFixedSlot(SLOT_DATATYPE, ObjectValue(*type)); + obj->setFixedSlot(SLOT_BLOCKREFOWNER, NullValue()); return obj; } JSObject * BinaryArray::create(JSContext *cx, JSObject *type) { JSObject *obj = createEmpty(cx, type); if (!obj) @@ -711,23 +709,25 @@ BinaryArray::create(JSContext *cx, JSObj uint8_t *memory = (uint8_t*) obj->getPrivate(); if (!ConvertAndCopyTo(cx, type, initial, memory)) return NULL; return obj; } JSObject * -BinaryArray::create(JSContext *cx, JSObject *type, uint8_t *block) +BinaryArray::create(JSContext *cx, JSObject *type, JSObject *owner, size_t offset) { + JS_ASSERT(IsBlock(owner)); JSObject *obj = createEmpty(cx, type); if (!obj) return NULL; - obj->setPrivate(block); + obj->setPrivate(((uint8_t*) owner->getPrivate()) + offset); + obj->setFixedSlot(SLOT_BLOCKREFOWNER, ObjectValue(*owner)); return obj; } JSBool BinaryArray::construct(JSContext *cx, unsigned int argc, jsval *vp) { CallArgs args = CallArgsFromVp(argc, vp); @@ -747,16 +747,33 @@ BinaryArray::construct(JSContext *cx, un } if (obj) args.rval().setObject(*obj); return obj != NULL; } +void +BinaryArray::finalize(js::FreeOp *op, JSObject *obj) +{ + if (obj->getFixedSlot(SLOT_BLOCKREFOWNER).isNull()) + op->free_(obj->getPrivate()); +} + +void +BinaryArray::obj_trace(JSTracer *tracer, RawObject obj) +{ + RawValue val = obj->getFixedSlot(SLOT_BLOCKREFOWNER); + if (val.isObject()) { + HeapPtrObject owner(val.toObjectOrNull()); + MarkObject(tracer, &owner, "binaryarray.blockRefOwner"); + } +} + JSBool BinaryArray::lengthGetter(JSContext *cx, unsigned int argc, jsval *vp) { CallArgs args = CallArgsFromVp(argc, vp); JS_ASSERT(IsBinaryArray(args.thisv().toObjectOrNull())); vp->setInt32(ArrayType::length(cx, GetType(args.thisv().toObjectOrNull()))); return true; @@ -865,17 +882,17 @@ BinaryArray::fill(JSContext *cx, unsigne ReportTypeError(cx, ObjectValue(*thisObj), "XXX"); // TODO use toString return false; } RootedValue val(cx, args[0]); JSObject *elementType = ArrayType::elementType(cx, type); for (uint32_t i = 0; i < ArrayType::length(cx, type); i++) { uint32_t offset = GetMemSize(cx, elementType) * i; - if (!ConvertAndCopyTo(cx, elementType, val, (void *) (((uint8_t*) thisObj->getPrivate()) + offset))) { + if (!ConvertAndCopyTo(cx, elementType, val, ((uint8_t*) thisObj->getPrivate()) + offset)) { ReportTypeError(cx, args[0], "Binary data"); // TODO use toString and point out exact elementType return false; } } args.rval().setUndefined(); return true; } @@ -1008,18 +1025,18 @@ BinaryArray::obj_getProperty(JSContext * JSBool BinaryArray::obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index, MutableHandleValue vp) { RootedObject type(cx, GetType(obj)); if (index < ArrayType::length(cx, type)) { RootedObject elementType(cx, ArrayType::elementType(cx, type)); - uint32_t offset = GetMemSize(cx, elementType) * index; - return Reify(cx, elementType, (void *)( ((uint8_t*) obj->getPrivate()) + offset ), vp); + size_t offset = GetMemSize(cx, elementType) * index; + return Reify(cx, elementType, obj, offset, vp); } RootedObject proto(cx, obj->getProto()); if (!proto) { vp.setUndefined(); return true; } @@ -1082,17 +1099,17 @@ BinaryArray::obj_setElement(JSContext *c RootedObject type(cx, GetType(obj)); RootedValue elementTypeVal(cx); if (!JSObject::getProperty(cx, type, type, cx->names().elementType, &elementTypeVal)) return false; RootedObject elementType(cx, elementTypeVal.toObjectOrNull()); uint32_t offset = GetMemSize(cx, elementType) * index; - bool result = ConvertAndCopyTo(cx, elementType, vp, (void *)( ((uint8_t*) obj->getPrivate()) + offset )); + bool result = ConvertAndCopyTo(cx, elementType, vp, ((uint8_t*) obj->getPrivate()) + offset ); if (!result) { ReportTypeError(cx, vp, elementType->getClass()->name); return false; } return true; } @@ -1250,17 +1267,17 @@ Class StructType::class_ = { JSCLASS_HAS_CACHED_PROTO(JSProto_StructType), JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, - NULL, + StructType::finalize, NULL, NULL, NULL, BinaryStruct::construct, NULL }; Class BinaryStruct::class_ = { @@ -1271,22 +1288,22 @@ Class BinaryStruct::class_ = { JSCLASS_HAS_CACHED_PROTO(JSProto_StructType), JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, - NULL, /* finalize */ + BinaryStruct::finalize, NULL, /* checkAccess */ NULL, /* call */ NULL, /* construct */ NULL, /* hasInstance */ - NULL, + BinaryStruct::obj_trace, JS_NULL_CLASS_EXT, { NULL, //BinaryStruct::obj_lookupGeneric, BinaryStruct::obj_lookupProperty, BinaryStruct::obj_lookupElement, NULL, // BinaryStruct::obj_lookupSpecial, NULL, // BinaryStruct::obj_defineGeneric, NULL, // BinaryStruct::obj_defineProperty, @@ -1404,17 +1421,17 @@ StructType::convert(JSContext *cx, JSObj ReportTypeError(cx, from, "binary struct"); // TODO better type reporting once toString is implemented return false; } JSObject *val = from.toObjectOrNull(); if (IsBlock(val)) { if (IsSame(cx, exemplar, GetType(val))) { uint8_t *priv = (uint8_t*) val->getPrivate(); - *blockref = priv; // we can be sure this is properly aligned + memcpy(*blockref, priv, GetMemSize(cx, exemplar)); // we can be sure this is properly aligned return true; } ReportTypeError(cx, from, "incompatible types"); return false; } RootedObject valRooted(cx, val); AutoIdVector ownProps(cx); @@ -1426,37 +1443,33 @@ StructType::convert(JSContext *cx, JSObj if (ownProps.length() != fieldMap->count()) return false; for (uint32_t i = 0; i < ownProps.length(); i++) { if (!fieldMap->lookup(IdToString(cx, ownProps[i]))) return false; } - int32_t memsize = GetMemSize(cx, exemplar); - uint8_t *block = (uint8_t*) JS_malloc(cx, memsize); - for (FieldMap::Range r = fieldMap->all(); !r.empty(); r.popFront()) { FieldInfo fieldInfo = r.front().value; RootedValue fromProp(cx); if (!JSObject::getProperty(cx, valRooted, valRooted, AtomizeString(cx, r.front().key)->asPropertyName(), &fromProp)) continue; // TODO should we abort here? - if (ConvertAndCopyTo(cx, fieldInfo.type, fromProp, (uint8_t *) block + fieldInfo.offset)) + if (ConvertAndCopyTo(cx, fieldInfo.type, fromProp, (*blockref) + fieldInfo.offset)) continue; // TODO what to do? } - - *blockref = block; // TODO this is a memory leak return true; } bool -StructType::reify(JSContext *cx, JSObject *type, void *mem, MutableHandleValue to) { - JSObject *obj = BinaryStruct::create(cx, type, (uint8_t*) mem); +StructType::reify(JSContext *cx, JSObject *type, RawObject owner, size_t offset, MutableHandleValue to) +{ + JSObject *obj = BinaryStruct::create(cx, type, owner, offset); if (!obj) return false; to.setObject(*obj); return true; } JSObject * StructType::create(JSContext *cx, HandleObject fields) @@ -1502,16 +1515,22 @@ StructType::construct(JSContext *cx, uns args.rval().setObject(*obj); return true; } //TODO error message return false; } +void +StructType::finalize(js::FreeOp *op, JSObject *obj) +{ + op->delete_(static_cast(obj->getPrivate())); +} + JSBool StructType::toString(JSContext *cx, unsigned int argc, jsval *vp) { CallArgs args = CallArgsFromVp(argc, vp); JSObject *thisObj = args.thisv().toObjectOrNull(); if (!IsStructType(thisObj)) @@ -1557,16 +1576,17 @@ BinaryStruct::createEmpty(JSContext *cx, RootedObject typeRooted(cx, type); RootedValue protoVal(cx); if (!JSObject::getProperty(cx, typeRooted, typeRooted, cx->names().classPrototype, &protoVal)) return NULL; RootedObject obj(cx, NewObjectWithClassProto(cx, &BinaryStruct::class_, protoVal.toObjectOrNull(), NULL)); obj->setFixedSlot(SLOT_DATATYPE, ObjectValue(*type)); + obj->setFixedSlot(SLOT_BLOCKREFOWNER, NullValue()); return obj; } JSObject * BinaryStruct::create(JSContext *cx, JSObject *type) { JSObject *obj = createEmpty(cx, type); if (!obj) @@ -1577,23 +1597,25 @@ BinaryStruct::create(JSContext *cx, JSOb if (!memory) return NULL; memset(memory, 0, memsize); obj->setPrivate(memory); return obj; } JSObject * -BinaryStruct::create(JSContext *cx, JSObject *type, uint8_t *block) +BinaryStruct::create(JSContext *cx, JSObject *type, RawObject owner, size_t offset) { + JS_ASSERT(IsBlock(owner)); JSObject *obj = createEmpty(cx, type); if (!obj) return NULL; - obj->setPrivate(block); + obj->setPrivate(((uint8_t*) owner->getPrivate()) + offset); + obj->setFixedSlot(SLOT_BLOCKREFOWNER, ObjectValue(*owner)); return obj; } JSBool BinaryStruct::construct(JSContext *cx, unsigned int argc, jsval *vp) { CallArgs args = CallArgsFromVp(argc, vp); @@ -1608,16 +1630,33 @@ BinaryStruct::construct(JSContext *cx, u JSObject *obj = create(cx, callee); if (obj) args.rval().setObject(*obj); return obj != NULL; } +void +BinaryStruct::finalize(js::FreeOp *op, JSObject *obj) +{ + if (obj->getFixedSlot(SLOT_BLOCKREFOWNER).isNull()) + op->free_(obj->getPrivate()); +} + +void +BinaryStruct::obj_trace(JSTracer *tracer, RawObject obj) +{ + RawValue val = obj->getFixedSlot(SLOT_BLOCKREFOWNER); + if (val.isObject()) { + HeapPtrObject owner(val.toObjectOrNull()); + MarkObject(tracer, &owner, "binarystruct.blockRefOwner"); + } +} + JSBool BinaryStruct::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp, MutableHandleShape propp) { JS_ASSERT(0); return false; } JSBool @@ -1697,17 +1736,17 @@ BinaryStruct::obj_getGeneric(JSContext * return true; } return JSObject::getGeneric(cx, proto, receiver, id, vp); } uint8_t *loc = ((uint8_t *) obj->getPrivate()) + fieldInfo->value.offset; - return Reify(cx, fieldInfo->value.type, (void *) loc, vp); + return Reify(cx, fieldInfo->value.type, obj, fieldInfo->value.offset, vp); } JSBool BinaryStruct::obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name, MutableHandleValue vp) { RootedId id(cx, NON_INTEGER_ATOM_TO_JSID(&(*name))); return obj_getGeneric(cx, obj, receiver, id, vp); @@ -1875,56 +1914,57 @@ JSBool BinaryStruct::obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op, MutableHandleValue statep, MutableHandleId idp) { JS_ASSERT(0); return false; } static bool -Reify(JSContext *cx, JSObject *type, void *mem, MutableHandleValue to) +Reify(JSContext *cx, JSObject *type, RawObject owner, size_t offset, MutableHandleValue to) { if (IsArrayType(type)) { - return ArrayType::reify(cx, type, mem, to); + return ArrayType::reify(cx, type, owner, offset, to); } if (IsStructType(type)) { - return StructType::reify(cx, type, mem, to); + return StructType::reify(cx, type, owner, offset, to); } JS_ASSERT(&NumericTypeClasses[NUMERICTYPE_UINT8] <= type->getClass() && type->getClass() <= &NumericTypeClasses[NUMERICTYPE_FLOAT64]); #define REIFY_CASES(constant_, type_)\ case constant_:\ - return NumericType::reify(cx, mem, to); + return NumericType::reify(cx, ((uint8_t*) owner->getPrivate()) + offset, to); switch(type->getFixedSlot(0).toInt32()) { BINARYDATA_FOR_EACH_NUMERIC_TYPES(REIFY_CASES); default: abort(); } #undef REIFY_CASES return false; } +/** + * `mem` must be pre-allocated + */ static bool -ConvertAndCopyTo(JSContext *cx, JSObject *type, HandleValue from, void *mem) +ConvertAndCopyTo(JSContext *cx, JSObject *type, HandleValue from, uint8_t *mem) { if (IsComplexType(type)) { - uint8_t *block = NULL; if (IsArrayType(type)) { - if (!ArrayType::convert(cx, type, from, &block)) + if (!ArrayType::convert(cx, type, from, &mem)) return false; } else if (IsStructType(type)) { - if (!StructType::convert(cx, type, from, &block)) + if (!StructType::convert(cx, type, from, &mem)) return false; } else { JS_ASSERT(0); } - memcpy(mem, block, GetMemSize(cx, type)); return true; } JS_ASSERT(&NumericTypeClasses[NUMERICTYPE_UINT8] <= type->getClass() && type->getClass() <= &NumericTypeClasses[NUMERICTYPE_FLOAT64]); #define CONVERT_CASES(constant_, type_)\ case constant_:\ {\ diff --git a/js/src/jsbinarydata.h b/js/src/jsbinarydata.h --- a/js/src/jsbinarydata.h +++ b/js/src/jsbinarydata.h @@ -8,19 +8,16 @@ #define jsbinarydata_h #include "jsapi.h" #include "jsobj.h" #include "jsfriendapi.h" #include "gc/Heap.h" namespace js { -class Block : public gc::Cell -{ -}; typedef float float32_t; typedef double float64_t; enum { NUMERICTYPE_UINT8 = 0, NUMERICTYPE_UINT16, NUMERICTYPE_UINT32, @@ -72,16 +69,17 @@ bool NumericType::reify(JSCon enum TypeCommonSlots { SLOT_MEMSIZE = 0, SLOT_ALIGN, TYPE_RESERVED_SLOTS }; enum BlockCommonSlots { SLOT_DATATYPE = 0, + SLOT_BLOCKREFOWNER, BLOCK_RESERVED_SLOTS }; /* This represents the 'A' and it's [[Prototype]] chain * in: * A = new ArrayType(Type, N); * a = new A(); */ @@ -95,35 +93,37 @@ class ArrayType : public JSObject static JSBool construct(JSContext *cx, unsigned int argc, jsval *vp); static JSBool repeat(JSContext *cx, unsigned int argc, jsval *vp); static JSBool toString(JSContext *cx, unsigned int argc, jsval *vp); static uint32_t length(JSContext *cx, JSObject *obj); static JSObject *elementType(JSContext *cx, JSObject *obj); static bool convert(JSContext *cx, JSObject *exemplar, HandleValue from, uint8_t **blockref); - static bool reify(JSContext *cx, JSObject *type, void *mem, MutableHandleValue to); + static bool reify(JSContext *cx, JSObject *type, RawObject owner, size_t offset, MutableHandleValue to); }; /* This represents the 'a' and it's [[Prototype]] chain */ class BinaryArray { private: static JSObject *createEmpty(JSContext *cx, JSObject *type); // attempts to [[Convert]] static JSObject *create(JSContext *cx, JSObject *type, HandleValue initial); public: static Class class_; + // creates initialized memory of size of type static JSObject *create(JSContext *cx, JSObject *type); - // uses passed block as memory - static JSObject *create(JSContext *cx, JSObject *type, uint8_t *block); + static JSObject *create(JSContext *cx, JSObject *type, JSObject *owner, size_t offset); static JSBool construct(JSContext *cx, unsigned int argc, jsval *vp); + static void finalize(js::FreeOp *op, JSObject *obj); + static void obj_trace(JSTracer *tracer, RawObject obj); static JSBool subarray(JSContext *cx, unsigned int argc, jsval *vp); static JSBool fill(JSContext *cx, unsigned int argc, jsval *vp); static JSBool obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp, MutableHandleShape propp); static JSBool obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleObject objp, MutableHandleShape propp); @@ -212,30 +212,33 @@ class StructType : public JSObject static bool layout(JSContext *cx, JSObject *structType, HandleObject fields); public: static Class class_; static JSBool construct(JSContext *cx, unsigned int argc, jsval *vp); static JSBool toString(JSContext *cx, unsigned int argc, jsval *vp); static bool convert(JSContext *cx, JSObject *exemplar, HandleValue from, uint8_t **blockref); - static bool reify(JSContext *cx, JSObject *type, void *mem, MutableHandleValue to); + static void finalize(js::FreeOp *op, JSObject *obj); + static bool reify(JSContext *cx, JSObject *type, RawObject owner, size_t offset, MutableHandleValue to); }; class BinaryStruct : public JSObject { private: static JSObject *createEmpty(JSContext *cx, JSObject *type); - static JSObject *create(JSContext *cx, JSObject *type); public: static Class class_; - static JSObject *create(JSContext *cx, JSObject *type, uint8_t *block); + static JSObject *create(JSContext *cx, JSObject *type); + static JSObject *create(JSContext *cx, JSObject *type, RawObject owner, size_t offset); static JSBool construct(JSContext *cx, unsigned int argc, jsval *vp); + static void finalize(js::FreeOp *op, JSObject *obj); + static void obj_trace(JSTracer *tracer, RawObject obj); static JSBool obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp, MutableHandleShape propp); static JSBool obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleObject objp, MutableHandleShape propp); static JSBool obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleObject objp, MutableHandleShape propp); static JSBool obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, diff --git a/js/src/tests/ecma_6/BinaryData/arraytype.js b/js/src/tests/ecma_6/BinaryData/arraytype.js --- a/js/src/tests/ecma_6/BinaryData/arraytype.js +++ b/js/src/tests/ecma_6/BinaryData/arraytype.js @@ -191,11 +191,19 @@ assertEq(indexPropDesc.writable, true); var lengthPropDesc = Object.getOwnPropertyDescriptor(as, 'length'); assertEq(typeof lengthPropDesc == "undefined", false); assertEq(lengthPropDesc.configurable, false); assertEq(lengthPropDesc.enumerable, false); assertEq(lengthPropDesc.writable, false); assertThrows(function() Object.defineProperty(o, "foo", { value: "bar" })); +// check if a reference acts the way it should +var AA = new ArrayType(new ArrayType(uint8, 5), 5); +var aa = new AA(); +var aa0 = aa[0]; +aa[0] = [0,1,2,3,4]; +for (var i = 0; i < aa0.length; i++) + assertEq(aa0[i], i); + if (typeof reportCompare === "function") reportCompare(true, true); print("Tests complete"); diff --git a/js/src/tests/ecma_6/BinaryData/memory.js b/js/src/tests/ecma_6/BinaryData/memory.js new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_6/BinaryData/memory.js @@ -0,0 +1,55 @@ +var BUGNUMBER = 578700; +var summary = 'ArrayType implementation'; + +var spin = function() { + for (var i = 0; i < 10000; i++) + ; +} + +print(BUGNUMBER + ": " + summary); + +var AA = new ArrayType(new ArrayType(uint8, 5), 5); +var aa = new AA(); +var aa0 = aa[0]; +aa[0] = [0,1,2,3,4]; + +aa = null; + +gc(); +spin(); + +for (var i = 0; i < aa0.length; i++) + assertEq(aa0[i], i); + +var AAA = new ArrayType(AA, 5); +var aaa = new AAA(); +var a0 = aaa[0][0]; + +for (var i = 0; i < a0.length; i++) + assertEq(a0[i], 0); + +aaa[0] = [[0,1,2,3,4], [0,1,2,3,4], [0,1,2,3,4], [0,1,2,3,4], [0,1,2,3,4]]; + +aaa = null; +gc(); +spin(); +for (var i = 0; i < a0.length; i++) + assertEq(a0[i], i); + + +var Color = new StructType({'r': uint8, 'g': uint8, 'b': uint8}); +var Rainbow = new ArrayType(Color, 7); +var theOneISawWasJustBlack = Rainbow.repeat({'r': 0, 'g': 0, 'b': 0}); + +var middleBand = theOneISawWasJustBlack[3]; + +theOneISawWasJustBlack = null; +gc(); +spin(); +assertEq(middleBand['r'] == 0 && middleBand['g'] == 0 && middleBand['b'] == 0, true); +middleBand.update({'r': 255, 'g': 207, 'b': 142}); +assertEq(middleBand['r'] == 255 && middleBand['g'] == 207 && middleBand['b'] == 142, true); + +if (typeof reportCompare === "function") + reportCompare(true, true); +print("Tests complete");