author | Wes Kocher <wkocher@mozilla.com> |
Tue, 15 Oct 2013 18:51:50 -0700 | |
changeset 150859 | d0fa5c45cabf3653f4587a8b499005705ee62c50 |
parent 150858 | da7c23b2d1c7e3bd07eba75d2c088a9fa9369789 |
child 150860 | 65262f9e75805837dfd57119c8ac8099e8606fcc |
push id | 25469 |
push user | cbook@mozilla.com |
push date | Wed, 16 Oct 2013 10:46:01 +0000 |
treeherder | autoland@afae5911a1e0 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 861925, 900669 |
milestone | 27.0a1 |
backs out | 8febf2f0e35dcc341b8acea6ae882a338144cc72 e646195f32aea58681eb93eef3fe4dcc99579354 015a92e94c0713bdf60dc4b6e0a62699882c3b2f 4546406915c1888356caac095999d46bb4d9e8cf 63321a464309937658f29bbb0be94498f1f8c261 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/public/StructuredClone.h +++ b/js/public/StructuredClone.h @@ -43,19 +43,17 @@ typedef JSObject *(*ReadStructuredCloneO typedef bool (*WriteStructuredCloneOp)(JSContext *cx, JSStructuredCloneWriter *w, JS::Handle<JSObject*> obj, void *closure); // This is called when JS_WriteStructuredClone is given an invalid transferable. // To follow HTML5, the application must throw a DATA_CLONE_ERR DOMException // with error set to one of the JS_SCERR_* values. typedef void (*StructuredCloneErrorOp)(JSContext *cx, uint32_t errorid); -// The maximum supported structured-clone serialization format version. Note -// that this does not need to be bumped for Transferable-only changes, since -// they are never saved to persistent storage. +// The maximum supported structured-clone serialization format version. #define JS_STRUCTURED_CLONE_VERSION 2 struct JSStructuredCloneCallbacks { ReadStructuredCloneOp read; WriteStructuredCloneOp write; StructuredCloneErrorOp reportError; };
--- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -13,33 +13,28 @@ #include "jsobj.h" #ifndef JS_MORE_DETERMINISTIC #include "jsprf.h" #endif #include "jswrapper.h" #include "jit/AsmJS.h" #include "jit/AsmJSLink.h" -#include "js/StructuredClone.h" #include "vm/ForkJoin.h" #include "vm/GlobalObject.h" #include "vm/Interpreter.h" #include "vm/ProxyObject.h" #include "jscntxtinlines.h" using namespace js; using namespace JS; using mozilla::ArrayLength; -// If fuzzingSafe is set, remove functionality that could cause problems with -// fuzzers. Set this via the environment variable MOZ_FUZZING_SAFE. -static bool fuzzingSafe = false; - static bool GetBuildConfiguration(JSContext *cx, unsigned argc, jsval *vp) { RootedObject info(cx, JS_NewObject(cx, nullptr, nullptr, nullptr)); if (!info) return false; RootedValue value(cx); @@ -1091,238 +1086,16 @@ static bool SetIonAssertGraphCoherency(JSContext *cx, unsigned argc, jsval *vp) { CallArgs args = CallArgsFromVp(argc, vp); jit::js_IonOptions.assertGraphConsistency = ToBoolean(args.get(0)); args.rval().setUndefined(); return true; } -class CloneBufferObject : public JSObject { - static const JSPropertySpec props_[2]; - static const size_t DATA_SLOT = 0; - static const size_t LENGTH_SLOT = 1; - static const size_t NUM_SLOTS = 2; - - public: - static const Class class_; - - static CloneBufferObject *Create(JSContext *cx) { - RootedObject obj(cx, JS_NewObject(cx, Jsvalify(&class_), nullptr, nullptr)); - if (!obj) - return nullptr; - obj->setReservedSlot(DATA_SLOT, PrivateValue(nullptr)); - obj->setReservedSlot(LENGTH_SLOT, Int32Value(0)); - - if (!JS_DefineProperties(cx, obj, props_)) - return nullptr; - - return &obj->as<CloneBufferObject>(); - } - - static CloneBufferObject *Create(JSContext *cx, JSAutoStructuredCloneBuffer *buffer) { - Rooted<CloneBufferObject*> obj(cx, Create(cx)); - if (!obj) - return nullptr; - uint64_t *datap; - size_t nbytes; - buffer->steal(&datap, &nbytes); - obj->setData(datap); - obj->setNBytes(nbytes); - return obj; - } - - uint64_t *data() const { - return static_cast<uint64_t*>(getReservedSlot(0).toPrivate()); - } - - void setData(uint64_t *aData) { - JS_ASSERT(!data()); - setReservedSlot(DATA_SLOT, PrivateValue(aData)); - } - - size_t nbytes() const { - return getReservedSlot(LENGTH_SLOT).toInt32(); - } - - void setNBytes(size_t nbytes) { - JS_ASSERT(nbytes <= UINT32_MAX); - setReservedSlot(LENGTH_SLOT, Int32Value(nbytes)); - } - - // Discard an owned clone buffer. - void discard() { - if (data()) - JS_ClearStructuredClone(data(), nbytes()); - setReservedSlot(DATA_SLOT, PrivateValue(nullptr)); - } - - static bool - setCloneBuffer_impl(JSContext* cx, CallArgs args) { - if (args.length() != 1 || !args[0].isString()) { - JS_ReportError(cx, - "the first argument argument must be maxBytes, " - "maxMallocBytes, gcStackpoolLifespan, gcBytes or " - "gcNumber"); - JS_ReportError(cx, "clonebuffer setter requires a single string argument"); - return false; - } - - if (fuzzingSafe) { - // A manually-created clonebuffer could easily trigger a crash - args.rval().setUndefined(); - return true; - } - - Rooted<CloneBufferObject*> obj(cx, &args.thisv().toObject().as<CloneBufferObject>()); - obj->discard(); - - char *str = JS_EncodeString(cx, args[0].toString()); - if (!str) - return false; - obj->setData(reinterpret_cast<uint64_t*>(str)); - obj->setNBytes(JS_GetStringLength(args[0].toString())); - - args.rval().setUndefined(); - return true; - } - - static bool - is(HandleValue v) { - return v.isObject() && v.toObject().is<CloneBufferObject>(); - } - - static bool - setCloneBuffer(JSContext* cx, unsigned int argc, JS::Value* vp) { - CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod<is, setCloneBuffer_impl>(cx, args); - } - - static bool - getCloneBuffer_impl(JSContext* cx, CallArgs args) { - Rooted<CloneBufferObject*> obj(cx, &args.thisv().toObject().as<CloneBufferObject>()); - JS_ASSERT(args.length() == 0); - - if (!obj->data()) { - args.rval().setUndefined(); - return true; - } - - bool hasTransferable; - if (!JS_StructuredCloneHasTransferables(obj->data(), obj->nbytes(), &hasTransferable)) - return false; - - if (hasTransferable) { - JS_ReportError(cx, "cannot retrieve structured clone buffer with transferables"); - return false; - } - - JSString *str = JS_NewStringCopyN(cx, reinterpret_cast<char*>(obj->data()), obj->nbytes()); - if (!str) - return false; - args.rval().setString(str); - return true; - } - - static bool - getCloneBuffer(JSContext* cx, unsigned int argc, JS::Value* vp) { - CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod<is, getCloneBuffer_impl>(cx, args); - } - - static void Finalize(FreeOp *fop, JSObject *obj) { - obj->as<CloneBufferObject>().discard(); - } -}; - -const Class CloneBufferObject::class_ = { - "CloneBuffer", JSCLASS_HAS_RESERVED_SLOTS(CloneBufferObject::NUM_SLOTS), - JS_PropertyStub, /* addProperty */ - JS_DeletePropertyStub, /* delProperty */ - JS_PropertyStub, /* getProperty */ - JS_StrictPropertyStub, /* setProperty */ - JS_EnumerateStub, - JS_ResolveStub, - JS_ConvertStub, - Finalize, - nullptr, /* checkAccess */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr, /* trace */ - JS_NULL_CLASS_EXT, - JS_NULL_OBJECT_OPS -}; - -const JSPropertySpec CloneBufferObject::props_[] = { - JS_PSGS("clonebuffer", getCloneBuffer, setCloneBuffer, 0), - JS_PS_END -}; - -static bool -Serialize(JSContext *cx, unsigned argc, jsval *vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - Value v = args.length() > 0 ? args[0] : UndefinedValue(); - Value transferables = args.length() > 1 ? args[1] : UndefinedValue(); - - JSAutoStructuredCloneBuffer clonebuf; - if (!clonebuf.write(cx, v, transferables)) - return false; - - RootedObject obj(cx, CloneBufferObject::Create(cx, &clonebuf)); - if (!obj) - return false; - - args.rval().setObject(*obj); - return true; -} - -static bool -Deserialize(JSContext *cx, unsigned argc, jsval *vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - if (args.length() != 1 || !args[0].isObject()) { - JS_ReportError(cx, "deserialize requires a single clonebuffer argument"); - return false; - } - - if (!args[0].toObject().is<CloneBufferObject>()) { - JS_ReportError(cx, "deserialize requires a clonebuffer"); - return false; - } - - Rooted<CloneBufferObject*> obj(cx, &args[0].toObject().as<CloneBufferObject>()); - - // Clone buffer was already consumed? - if (!obj->data()) { - JS_ReportError(cx, "deserialize given invalid clone buffer " - "(transferables already consumed?)"); - return false; - } - - bool hasTransferable; - if (!JS_StructuredCloneHasTransferables(obj->data(), obj->nbytes(), &hasTransferable)) - return false; - - RootedValue deserialized(cx); - if (!JS_ReadStructuredClone(cx, obj->data(), obj->nbytes(), - JS_STRUCTURED_CLONE_VERSION, deserialized.address(), NULL, NULL)) { - return false; - } - args.rval().set(deserialized); - - if (hasTransferable) - obj->discard(); - - return true; -} - static const JSFunctionSpecWithHelp TestingFunctions[] = { JS_FN_HELP("gc", ::GC, 0, 0, "gc([obj] | 'compartment')", " Run the garbage collector. When obj is given, GC only its compartment.\n" " If 'compartment' is given, GC any compartments that were scheduled for\n" " GC via schedulegc."), JS_FN_HELP("minorgc", ::MinorGC, 0, 0, @@ -1518,28 +1291,16 @@ static const JSFunctionSpecWithHelp Test " Set a compiler option indexed in JSCompileOption enum to a number.\n"), JS_FN_HELP("setIonAssertGraphCoherency", SetIonAssertGraphCoherency, 1, 0, "setIonAssertGraphCoherency(bool)", " Set whether Ion should perform graph consistency (DEBUG-only) assertions. These assertions\n" " are valuable and should be generally enabled, however they can be very expensive for large\n" " (asm.js) programs."), - JS_FN_HELP("serialize", Serialize, 1, 0, -"serialize(data, [transferables])", -" Serialize 'data' using JS_WriteStructuredClone. Returns a structured\n" -" clone buffer object."), - - JS_FN_HELP("deserialize", Deserialize, 1, 0, -"deserialize(clonebuffer)", -" Deserialize data generated by serialize."), - JS_FS_HELP_END }; bool -js::DefineTestingFunctions(JSContext *cx, HandleObject obj, bool fuzzingSafe_) +js::DefineTestingFunctions(JSContext *cx, HandleObject obj) { - fuzzingSafe = fuzzingSafe_; - if (getenv("MOZ_FUZZING_SAFE") && getenv("MOZ_FUZZING_SAFE")[0] != '0') - fuzzingSafe = true; return JS_DefineFunctionsWithHelp(cx, obj, TestingFunctions); }
--- a/js/src/builtin/TestingFunctions.h +++ b/js/src/builtin/TestingFunctions.h @@ -7,17 +7,17 @@ #ifndef builtin_TestingFunctions_h #define builtin_TestingFunctions_h #include "NamespaceImports.h" namespace js { bool -DefineTestingFunctions(JSContext *cx, HandleObject obj, bool fuzzingSafe); +DefineTestingFunctions(JSContext *cx, HandleObject obj); bool testingFunc_inParallelSection(JSContext *cx, unsigned argc, Value *vp); bool testingFunc_bailout(JSContext *cx, unsigned argc, Value *vp); bool
--- a/js/src/js.msg +++ b/js/src/js.msg @@ -228,18 +228,18 @@ MSG_DEF(JSMSG_UNUSED174, 17 MSG_DEF(JSMSG_NESTING_GENERATOR, 175, 0, JSEXN_TYPEERR, "already executing generator") MSG_DEF(JSMSG_UNUSED176, 176, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED177, 177, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED178, 178, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED179, 179, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED180, 180, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED181, 181, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_BAD_GENERATOR_SEND, 182, 1, JSEXN_TYPEERR, "attempt to send {0} to newborn generator") -MSG_DEF(JSMSG_SC_NOT_TRANSFERABLE, 183, 0, JSEXN_TYPEERR, "invalid transferable array for structured clone") -MSG_DEF(JSMSG_SC_DUP_TRANSFERABLE, 184, 0, JSEXN_TYPEERR, "duplicate transferable for structured clone") +MSG_DEF(JSMSG_UNUSED183, 183, 0, JSEXN_NONE, "") +MSG_DEF(JSMSG_UNUSED184, 184, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE, 185, 0, JSEXN_TYPEERR, "proxy can't report an extensible object as non-extensible") MSG_DEF(JSMSG_UNUSED186, 186, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED187, 187, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 188, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}") MSG_DEF(JSMSG_UNUSED189, 189, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED190, 190, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED191, 191, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_UNUSED192, 192, 0, JSEXN_NONE, "")
--- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -219,39 +219,32 @@ class AutoArrayRooter : private AutoGCRo MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER js::SkipRoot skip; }; template<class T> class AutoVectorRooter : protected AutoGCRooter { - typedef js::Vector<T, 8> VectorImpl; - VectorImpl vector; - - /* Prevent overwriting of inline elements in vector. */ - js::SkipRoot vectorRoot; - public: explicit AutoVectorRooter(JSContext *cx, ptrdiff_t tag MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : AutoGCRooter(cx, tag), vector(cx), vectorRoot(cx, &vector) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } explicit AutoVectorRooter(js::ContextFriendFields *cx, ptrdiff_t tag MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : AutoGCRooter(cx, tag), vector(cx), vectorRoot(cx, &vector) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } typedef T ElementType; - typedef typename VectorImpl::Range Range; size_t length() const { return vector.length(); } bool empty() const { return vector.empty(); } bool append(const T &v) { return vector.append(v); } bool appendAll(const AutoVectorRooter<T> &other) { return vector.appendAll(other.vector); } @@ -301,29 +294,33 @@ class AutoVectorRooter : protected AutoG } const T *begin() const { return vector.begin(); } T *begin() { return vector.begin(); } const T *end() const { return vector.end(); } T *end() { return vector.end(); } - Range all() { return vector.all(); } - const T &back() const { return vector.back(); } friend void AutoGCRooter::trace(JSTracer *trc); private: void makeRangeGCSafe(size_t oldLength) { T *t = vector.begin() + oldLength; for (size_t i = oldLength; i < vector.length(); ++i, ++t) memset(t, 0, sizeof(T)); } + typedef js::Vector<T, 8> VectorImpl; + VectorImpl vector; + + /* Prevent overwriting of inline elements in vector. */ + js::SkipRoot vectorRoot; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; template<class Key, class Value> class AutoHashMapRooter : protected AutoGCRooter { private: typedef js::HashMap<Key, Value> HashMapImpl; @@ -333,17 +330,16 @@ class AutoHashMapRooter : protected Auto MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : AutoGCRooter(cx, tag), map(cx) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; } typedef Key KeyType; typedef Value ValueType; - typedef typename HashMapImpl::Entry Entry; typedef typename HashMapImpl::Lookup Lookup; typedef typename HashMapImpl::Ptr Ptr; typedef typename HashMapImpl::AddPtr AddPtr; bool init(uint32_t len = 16) { return map.init(len); } bool initialized() const {
--- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -1013,17 +1013,17 @@ JS::ObjectPtr::trace(JSTracer *trc, cons JS_FRIEND_API(JSObject *) js::GetTestingFunctions(JSContext *cx) { RootedObject obj(cx, JS_NewObject(cx, nullptr, nullptr, nullptr)); if (!obj) return nullptr; - if (!DefineTestingFunctions(cx, obj, false)) + if (!DefineTestingFunctions(cx, obj)) return nullptr; return obj; } #ifdef DEBUG JS_FRIEND_API(unsigned) js::GetEnterCompartmentDepth(JSContext *cx)
--- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -1236,22 +1236,16 @@ JS_GetArrayBufferViewData(JSObject *obj) * Return the ArrayBuffer underlying an ArrayBufferView. If the buffer has been * neutered, this will still return the neutered buffer. |obj| must be an * object that would return true for JS_IsArrayBufferViewObject(). */ extern JS_FRIEND_API(JSObject *) JS_GetArrayBufferViewBuffer(JSObject *obj); /* - * Set an ArrayBuffer's length to 0 and neuter all of its views. - */ -extern JS_FRIEND_API(void) -JS_NeuterArrayBuffer(JSObject *obj, JSContext *cx); - -/* * Check whether obj supports JS_GetDataView* APIs. */ JS_FRIEND_API(bool) JS_IsDataViewObject(JSObject *obj); /* * Return the byte offset of a data view into its array buffer. |obj| must be a * DataView.
--- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -3828,16 +3828,66 @@ WrapWithProto(JSContext *cx, unsigned ar &Wrapper::singletonWithPrototype); if (!wrapped) return false; JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(wrapped)); return true; } +static bool +Serialize(JSContext *cx, unsigned argc, jsval *vp) +{ + jsval v = argc > 0 ? JS_ARGV(cx, vp)[0] : UndefinedValue(); + uint64_t *datap; + size_t nbytes; + if (!JS_WriteStructuredClone(cx, v, &datap, &nbytes, nullptr, nullptr, UndefinedValue())) + return false; + + JSObject *obj = JS_NewUint8Array(cx, nbytes); + if (!obj) { + JS_free(cx, datap); + return false; + } + TypedArrayObject *tarr = &obj->as<TypedArrayObject>(); + JS_ASSERT((uintptr_t(tarr->viewData()) & 7) == 0); + js_memcpy(tarr->viewData(), datap, nbytes); + + JS_ClearStructuredClone(datap, nbytes); + JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(tarr)); + return true; +} + +static bool +Deserialize(JSContext *cx, unsigned argc, jsval *vp) +{ + Rooted<jsval> v(cx, argc > 0 ? JS_ARGV(cx, vp)[0] : UndefinedValue()); + JSObject *obj; + if (JSVAL_IS_PRIMITIVE(v) || !(obj = JSVAL_TO_OBJECT(v))->is<TypedArrayObject>()) { + JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS, "deserialize"); + return false; + } + TypedArrayObject *tarr = &obj->as<TypedArrayObject>(); + if ((tarr->byteLength() & 7) != 0) { + JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS, "deserialize"); + return false; + } + if ((uintptr_t(tarr->viewData()) & 7) != 0) { + JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_BAD_ALIGNMENT); + return false; + } + + if (!JS_ReadStructuredClone(cx, (uint64_t *) tarr->viewData(), tarr->byteLength(), + JS_STRUCTURED_CLONE_VERSION, v.address(), nullptr, nullptr)) { + return false; + } + JS_SET_RVAL(cx, vp, v); + return true; +} + static JSObject * NewGlobalObject(JSContext *cx, JS::CompartmentOptions &options); static bool NewGlobal(JSContext *cx, unsigned argc, jsval *vp) { JS::CompartmentOptions options; options.setVersion(JSVERSION_LATEST); @@ -4304,16 +4354,24 @@ static const JSFunctionSpecWithHelp shel JS_FN_HELP("wrap", Wrap, 1, 0, "wrap(obj)", " Wrap an object into a noop wrapper."), JS_FN_HELP("wrapWithProto", WrapWithProto, 2, 0, "wrapWithProto(obj)", " Wrap an object into a noop wrapper with prototype semantics."), + JS_FN_HELP("serialize", Serialize, 1, 0, +"serialize(sd)", +" Serialize sd using JS_WriteStructuredClone. Returns a TypedArray."), + + JS_FN_HELP("deserialize", Deserialize, 1, 0, +"deserialize(a)", +" Deserialize data generated by serialize."), + JS_FN_HELP("newGlobal", NewGlobal, 1, 0, "newGlobal([options])", " Return a new global object in a new compartment. If options\n" " is given, it may have any of the following properties:\n" " sameZoneAs: the compartment will be in the same zone as the given object (defaults to a new zone)\n" " invisibleToDebugger: the global will be invisible to the debugger (default false)"), JS_FN_HELP("enableStackWalkingAssertion", EnableStackWalkingAssertion, 1, 0, @@ -5331,17 +5389,17 @@ NewGlobalObject(JSContext *cx, JS::Compa return nullptr; if (!JS::RegisterPerfMeasurement(cx, glob)) return nullptr; if (!JS_DefineFunctionsWithHelp(cx, glob, shell_functions) || !JS_DefineProfilingFunctions(cx, glob)) { return nullptr; } - if (!js::DefineTestingFunctions(cx, glob, fuzzingSafe)) + if (!js::DefineTestingFunctions(cx, glob)) return nullptr; if (!fuzzingSafe && !JS_DefineFunctionsWithHelp(cx, glob, fuzzing_unsafe_functions)) return nullptr; /* Initialize FakeDOMObject. */ static const js::DOMCallbacks DOMcallbacks = { InstanceClassHasProtoAtDepth @@ -5636,18 +5694,16 @@ Shell(JSContext *cx, OptionParser *op, c */ if (op->getBoolOption("no-ti")) { enableTypeInference = false; ContextOptionsRef(cx).toggleTypeInference(); } if (op->getBoolOption("fuzzing-safe")) fuzzingSafe = true; - else - fuzzingSafe = (getenv("MOZ_FUZZING_SAFE") && getenv("MOZ_FUZZING_SAFE")[0] != '0'); RootedObject glob(cx); JS::CompartmentOptions options; options.setVersion(JSVERSION_LATEST); glob = NewGlobalObject(cx, options); if (!glob) return 1;
--- a/js/src/tests/js1_8_5/extensions/clone-forge.js +++ b/js/src/tests/js1_8_5/extensions/clone-forge.js @@ -9,31 +9,24 @@ function assertThrows(f) { f(); } catch (exc) { ok = true; } if (!ok) throw new TypeError("Assertion failed: " + f + " did not throw as expected"); } -function byteArray(str) { - return [ c.charCodeAt(0) for (c of str.split('')) ]; -} - // Don't allow forging bogus Date objects. -var mutated = byteArray(serialize(new Date(NaN)).clonebuffer); - +var buf = serialize(new Date(NaN)); var a = [1/0, -1/0, Number.MIN_VALUE, -Number.MIN_VALUE, Math.PI, 1286523948674.5, Number.MAX_VALUE, -Number.MAX_VALUE, 8.64e15 + 1, -(8.64e15 + 1)]; for (var i = 0; i < a.length; i++) { var n = a[i]; var nbuf = serialize(n); - var data = byteArray(nbuf.clonebuffer); for (var j = 0; j < 8; j++) - mutated[j+8] = data[j]; - nbuf.clonebuffer = String.fromCharCode.apply(null, mutated); - assertThrows(function () { deserialize(nbuf); }); + buf[j + 8] = nbuf[j]; + assertThrows(function () { deserialize(buf); }); } reportCompare(0, 0);
--- a/js/src/tests/js1_8_5/extensions/clone-object.js +++ b/js/src/tests/js1_8_5/extensions/clone-object.js @@ -203,17 +203,17 @@ function test() { // Clone an array with holes. check([0, 1, 2, , 4, 5, 6]); // Array holes should not take up space. b = []; b[255] = 1; check(b); - assertEq(serialize(b).clonebuffer.length < 255, true); + assertEq(serialize(b).length < 255, true); // Self-modifying object. // This should never read through to b's prototype. b = Object.create({y: 2}, {x: {enumerable: true, configurable: true, get: function() { if (this.hasOwnProperty("y")) delete this.y; return 1; }}, y: {enumerable: true,
deleted file mode 100644 --- a/js/src/tests/js1_8_5/extensions/clone-transferables.js +++ /dev/null @@ -1,87 +0,0 @@ -// |reftest| skip-if(!xulRuntime.shell) -// Any copyright is dedicated to the Public Domain. -// http://creativecommons.org/licenses/publicdomain/ - -function test() { - // Note: -8 and -200 will trigger asm.js link failures because 8 and 200 - // bytes are below the minimum allowed size, and the buffer will not - // actually be converted to an asm.js buffer. - for (var size of [0, 8, 16, 200, 1000, 4096, -8, -200, -8192, -65536]) { - var buffer_ctor = (size < 0) ? AsmJSArrayBuffer : ArrayBuffer; - size = Math.abs(size); - - var old = buffer_ctor(size); - var copy = deserialize(serialize(old, [old])); - assertEq(old.byteLength, 0); - assertEq(copy.byteLength, size); - - var constructors = [ Int8Array, - Uint8Array, - Int16Array, - Uint16Array, - Int32Array, - Uint32Array, - Float32Array, - Float64Array, - Uint8ClampedArray ]; - - for (var ctor of constructors) { - var buf = buffer_ctor(size); - var old_arr = ctor(buf); - assertEq(buf.byteLength, size); - assertEq(buf, old_arr.buffer); - assertEq(old_arr.length, size / old_arr.BYTES_PER_ELEMENT); - - var copy_arr = deserialize(serialize(old_arr, [ buf ])); - assertEq(buf.byteLength, 0, "donor array buffer should be neutered"); - assertEq(old_arr.length, 0, "donor typed array should be neutered"); - assertEq(copy_arr.buffer.byteLength == size, true); - assertEq(copy_arr.length, size / old_arr.BYTES_PER_ELEMENT); - - buf = null; - old_arr = null; - gc(); // Tickle the ArrayBuffer -> view management - } - - for (var ctor of constructors) { - var buf = buffer_ctor(size); - var old_arr = ctor(buf); - var dv = DataView(buf); // Second view - var copy_arr = deserialize(serialize(old_arr, [ buf ])); - assertEq(buf.byteLength, 0, "donor array buffer should be neutered"); - assertEq(old_arr.length, 0, "donor typed array should be neutered"); - assertEq(dv.byteLength, 0, "all views of donor array buffer should be neutered"); - - buf = null; - old_arr = null; - gc(); // Tickle the ArrayBuffer -> view management - } - - // Mutate the buffer during the clone operation. The modifications should be visible. - if (size >= 4) { - old = buffer_ctor(size); - var view = Int32Array(old); - view[0] = 1; - var mutator = { get foo() { view[0] = 2; } }; - var copy = deserialize(serialize([ old, mutator ], [old])); - var viewCopy = Int32Array(copy[0]); - assertEq(view.length, 0); // Neutered - assertEq(viewCopy[0], 2); - } - - // Neuter the buffer during the clone operation. Should throw an exception. - if (size >= 4) { - old = buffer_ctor(size); - var mutator = { - get foo() { - deserialize(serialize(old, [old])); - } - }; - // The throw is not yet implemented, bug 919259. - //var copy = deserialize(serialize([ old, mutator ], [old])); - } - } -} - -test(); -reportCompare(0, 0, 'ok');
--- a/js/src/tests/js1_8_5/extensions/clone-v1-typed-array-data.dat +++ b/js/src/tests/js1_8_5/extensions/clone-v1-typed-array-data.dat @@ -1,32 +1,32 @@ var captured = []; -captured[0] = serialize(0); captured[0].clonebuffer = String.fromCharCode(0, 0, 0, 0, 9, 0, 255, 255); -captured[1] = serialize(0); captured[1].clonebuffer = String.fromCharCode(7, 0, 0, 0, 9, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0); +captured[0] = new Uint8Array([0, 0, 0, 0, 9, 0, 255, 255]); +captured[1] = new Uint8Array([7, 0, 0, 0, 9, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0]); captured[2] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19)); -captured[3] = serialize(0); captured[3].clonebuffer = String.fromCharCode(0, 0, 0, 0, 0, 1, 255, 255); -captured[4] = serialize(0); captured[4].clonebuffer = String.fromCharCode(100, 0, 0, 0, 0, 1, 255, 255, 1, 7, 49, 87, 97, 167, 145, 247, 193, 71, 241, 151, 33, 231, 81, 55, 129, 135, 177, 216, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); +captured[3] = new Uint8Array([0, 0, 0, 0, 0, 1, 255, 255]); +captured[4] = new Uint8Array([100, 0, 0, 0, 0, 1, 255, 255, 1, 7, 49, 87, 97, 167, 145, 247, 193, 71, 241, 151, 33, 231, 81, 55, 129, 135, 177, 216, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); captured[5] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19)); -captured[6] = serialize(0); captured[6].clonebuffer = String.fromCharCode(0, 0, 0, 0, 1, 1, 255, 255); -captured[7] = serialize(0); captured[7].clonebuffer = String.fromCharCode(100, 0, 0, 0, 1, 1, 255, 255, 1, 7, 49, 87, 97, 167, 145, 247, 193, 71, 241, 151, 33, 231, 81, 55, 129, 135, 177, 216, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); +captured[6] = new Uint8Array([0, 0, 0, 0, 1, 1, 255, 255]); +captured[7] = new Uint8Array([100, 0, 0, 0, 1, 1, 255, 255, 1, 7, 49, 87, 97, 167, 145, 247, 193, 71, 241, 151, 33, 231, 81, 55, 129, 135, 177, 216, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); captured[8] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19)); -captured[9] = serialize(0); captured[9].clonebuffer = String.fromCharCode(0, 0, 0, 0, 2, 1, 255, 255); -captured[10] = serialize(0); captured[10].clonebuffer = String.fromCharCode(100, 0, 0, 0, 2, 1, 255, 255, 1, 0, 7, 0, 49, 0, 87, 1, 97, 9, 167, 65, 145, 203, 247, 144, 193, 246, 71, 191, 241, 58, 151, 156, 33, 72, 231, 248, 81, 206, 55, 164, 129, 125, 135, 110, 177, 5, 216, 39, 224, 22, 0, 160, 0, 96, 0, 160, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); +captured[9] = new Uint8Array([0, 0, 0, 0, 2, 1, 255, 255]); +captured[10] = new Uint8Array([100, 0, 0, 0, 2, 1, 255, 255, 1, 0, 7, 0, 49, 0, 87, 1, 97, 9, 167, 65, 145, 203, 247, 144, 193, 246, 71, 191, 241, 58, 151, 156, 33, 72, 231, 248, 81, 206, 55, 164, 129, 125, 135, 110, 177, 5, 216, 39, 224, 22, 0, 160, 0, 96, 0, 160, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); captured[11] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19)); -captured[12] = serialize(0); captured[12].clonebuffer = String.fromCharCode(0, 0, 0, 0, 3, 1, 255, 255); -captured[13] = serialize(0); captured[13].clonebuffer = String.fromCharCode(100, 0, 0, 0, 3, 1, 255, 255, 1, 0, 7, 0, 49, 0, 87, 1, 97, 9, 167, 65, 145, 203, 247, 144, 193, 246, 71, 191, 241, 58, 151, 156, 33, 72, 231, 248, 81, 206, 55, 164, 129, 125, 135, 110, 177, 5, 216, 39, 224, 22, 0, 160, 0, 96, 0, 160, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); +captured[12] = new Uint8Array([0, 0, 0, 0, 3, 1, 255, 255]); +captured[13] = new Uint8Array([100, 0, 0, 0, 3, 1, 255, 255, 1, 0, 7, 0, 49, 0, 87, 1, 97, 9, 167, 65, 145, 203, 247, 144, 193, 246, 71, 191, 241, 58, 151, 156, 33, 72, 231, 248, 81, 206, 55, 164, 129, 125, 135, 110, 177, 5, 216, 39, 224, 22, 0, 160, 0, 96, 0, 160, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); captured[14] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19)); -captured[15] = serialize(0); captured[15].clonebuffer = String.fromCharCode(0, 0, 0, 0, 4, 1, 255, 255); -captured[16] = serialize(0); captured[16].clonebuffer = String.fromCharCode(100, 0, 0, 0, 4, 1, 255, 255, 1, 0, 0, 0, 7, 0, 0, 0, 49, 0, 0, 0, 87, 1, 0, 0, 97, 9, 0, 0, 167, 65, 0, 0, 145, 203, 1, 0, 247, 144, 12, 0, 193, 246, 87, 0, 71, 191, 103, 2, 241, 58, 214, 16, 151, 156, 219, 117, 33, 72, 1, 57, 231, 248, 8, 143, 81, 206, 62, 233, 55, 164, 183, 96, 129, 125, 5, 165, 135, 110, 38, 131, 177, 5, 13, 150, 216, 39, 91, 26, 224, 22, 126, 184, 0, 160, 114, 11, 0, 96, 34, 80, 0, 160, 240, 48, 0, 128, 148, 86, 0, 0, 16, 94, 0, 0, 112, 146, 0, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); +captured[15] = new Uint8Array([0, 0, 0, 0, 4, 1, 255, 255]); +captured[16] = new Uint8Array([100, 0, 0, 0, 4, 1, 255, 255, 1, 0, 0, 0, 7, 0, 0, 0, 49, 0, 0, 0, 87, 1, 0, 0, 97, 9, 0, 0, 167, 65, 0, 0, 145, 203, 1, 0, 247, 144, 12, 0, 193, 246, 87, 0, 71, 191, 103, 2, 241, 58, 214, 16, 151, 156, 219, 117, 33, 72, 1, 57, 231, 248, 8, 143, 81, 206, 62, 233, 55, 164, 183, 96, 129, 125, 5, 165, 135, 110, 38, 131, 177, 5, 13, 150, 216, 39, 91, 26, 224, 22, 126, 184, 0, 160, 114, 11, 0, 96, 34, 80, 0, 160, 240, 48, 0, 128, 148, 86, 0, 0, 16, 94, 0, 0, 112, 146, 0, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); captured[17] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19)); -captured[18] = serialize(0); captured[18].clonebuffer = String.fromCharCode(0, 0, 0, 0, 5, 1, 255, 255); -captured[19] = serialize(0); captured[19].clonebuffer = String.fromCharCode(100, 0, 0, 0, 5, 1, 255, 255, 1, 0, 0, 0, 7, 0, 0, 0, 49, 0, 0, 0, 87, 1, 0, 0, 97, 9, 0, 0, 167, 65, 0, 0, 145, 203, 1, 0, 247, 144, 12, 0, 193, 246, 87, 0, 71, 191, 103, 2, 241, 58, 214, 16, 151, 156, 219, 117, 33, 72, 1, 57, 231, 248, 8, 143, 81, 206, 62, 233, 55, 164, 183, 96, 129, 125, 5, 165, 135, 110, 38, 131, 177, 5, 13, 150, 216, 39, 91, 26, 224, 22, 126, 184, 0, 160, 114, 11, 0, 96, 34, 80, 0, 160, 240, 48, 0, 128, 148, 86, 0, 0, 16, 94, 0, 0, 112, 146, 0, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); +captured[18] = new Uint8Array([0, 0, 0, 0, 5, 1, 255, 255]); +captured[19] = new Uint8Array([100, 0, 0, 0, 5, 1, 255, 255, 1, 0, 0, 0, 7, 0, 0, 0, 49, 0, 0, 0, 87, 1, 0, 0, 97, 9, 0, 0, 167, 65, 0, 0, 145, 203, 1, 0, 247, 144, 12, 0, 193, 246, 87, 0, 71, 191, 103, 2, 241, 58, 214, 16, 151, 156, 219, 117, 33, 72, 1, 57, 231, 248, 8, 143, 81, 206, 62, 233, 55, 164, 183, 96, 129, 125, 5, 165, 135, 110, 38, 131, 177, 5, 13, 150, 216, 39, 91, 26, 224, 22, 126, 184, 0, 160, 114, 11, 0, 96, 34, 80, 0, 160, 240, 48, 0, 128, 148, 86, 0, 0, 16, 94, 0, 0, 112, 146, 0, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); captured[20] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19)); -captured[21] = serialize(0); captured[21].clonebuffer = String.fromCharCode(0, 0, 0, 0, 6, 1, 255, 255); -captured[22] = serialize(0); captured[22].clonebuffer = String.fromCharCode(100, 0, 0, 0, 6, 1, 255, 255, 0, 0, 128, 63, 0, 0, 224, 64, 0, 0, 68, 66, 0, 128, 171, 67, 0, 16, 22, 69, 0, 78, 131, 70, 128, 200, 229, 71, 112, 15, 73, 73, 130, 237, 175, 74, 210, 239, 25, 76, 216, 177, 134, 77, 57, 183, 235, 78, 82, 64, 78, 80, 72, 120, 180, 81, 63, 233, 29, 83, 23, 44, 138, 84, 40, 205, 241, 85, 131, 147, 83, 87, 19, 33, 185, 88, 240, 252, 33, 90, 82, 189, 141, 91, 80, 11, 248, 92, 230, 9, 89, 94, 169, 232, 189, 95, 148, 43, 38, 97, 34, 102, 145, 98, 187, 114, 254, 99, 100, 164, 94, 101, 215, 207, 194, 102, 220, 117, 42, 104, 33, 39, 149, 105, 61, 130, 2, 107, 234, 99, 100, 108, 109, 215, 199, 109, 127, 220, 46, 111, 239, 0, 153, 112, 209, 224, 5, 114, 110, 73, 106, 115, 65, 0, 205, 116, 57, 96, 51, 118, 49, 244, 156, 119, 171, 85, 9, 121, 236, 85, 112, 122, 46, 75, 210, 123, 200, 1, 56, 125, 143, 1, 161, 126, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 192, 127); +captured[21] = new Uint8Array([0, 0, 0, 0, 6, 1, 255, 255]); +captured[22] = new Uint8Array([100, 0, 0, 0, 6, 1, 255, 255, 0, 0, 128, 63, 0, 0, 224, 64, 0, 0, 68, 66, 0, 128, 171, 67, 0, 16, 22, 69, 0, 78, 131, 70, 128, 200, 229, 71, 112, 15, 73, 73, 130, 237, 175, 74, 210, 239, 25, 76, 216, 177, 134, 77, 57, 183, 235, 78, 82, 64, 78, 80, 72, 120, 180, 81, 63, 233, 29, 83, 23, 44, 138, 84, 40, 205, 241, 85, 131, 147, 83, 87, 19, 33, 185, 88, 240, 252, 33, 90, 82, 189, 141, 91, 80, 11, 248, 92, 230, 9, 89, 94, 169, 232, 189, 95, 148, 43, 38, 97, 34, 102, 145, 98, 187, 114, 254, 99, 100, 164, 94, 101, 215, 207, 194, 102, 220, 117, 42, 104, 33, 39, 149, 105, 61, 130, 2, 107, 234, 99, 100, 108, 109, 215, 199, 109, 127, 220, 46, 111, 239, 0, 153, 112, 209, 224, 5, 114, 110, 73, 106, 115, 65, 0, 205, 116, 57, 96, 51, 118, 49, 244, 156, 119, 171, 85, 9, 121, 236, 85, 112, 122, 46, 75, 210, 123, 200, 1, 56, 125, 143, 1, 161, 126, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 192, 127]); captured[23] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19)); -captured[24] = serialize(0); captured[24].clonebuffer = String.fromCharCode(0, 0, 0, 0, 7, 1, 255, 255); -captured[25] = serialize(0); captured[25].clonebuffer = String.fromCharCode(100, 0, 0, 0, 7, 1, 255, 255, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 28, 64, 0, 0, 0, 0, 0, 128, 72, 64, 0, 0, 0, 0, 0, 112, 117, 64, 0, 0, 0, 0, 0, 194, 162, 64, 0, 0, 0, 0, 192, 105, 208, 64, 0, 0, 0, 0, 16, 185, 252, 64, 0, 0, 0, 0, 238, 33, 41, 65, 0, 0, 0, 64, 176, 253, 85, 65, 0, 0, 0, 56, 250, 61, 131, 65, 0, 0, 0, 241, 58, 214, 176, 65, 0, 0, 192, 37, 231, 118, 221, 65, 0, 0, 8, 65, 10, 200, 9, 66, 0, 0, 231, 248, 8, 143, 54, 66, 0, 32, 202, 217, 39, 189, 99, 66, 0, 220, 144, 222, 130, 69, 145, 66, 0, 129, 125, 5, 165, 57, 190, 66, 224, 208, 205, 100, 112, 114, 234, 66, 196, 22, 52, 88, 34, 36, 23, 67, 236, 147, 45, 13, 158, 63, 68, 67, 110, 225, 135, 75, 170, 183, 113, 67, 128, 202, 45, 4, 106, 1, 159, 67, 48, 17, 168, 195, 60, 33, 203, 67, 10, 15, 51, 43, 21, 189, 247, 67, 41, 173, 204, 133, 114, 197, 36, 68, 132, 23, 19, 53, 196, 44, 82, 68, 39, 105, 225, 92, 87, 206, 127, 68, 2, 60, 69, 113, 140, 212, 171, 68, 130, 148, 28, 227, 250, 89, 216, 68, 242, 1, 185, 134, 187, 78, 5, 69, 180, 225, 225, 21, 228, 164, 50, 69, 126, 165, 37, 147, 71, 80, 96, 69, 156, 225, 129, 65, 125, 140, 140, 69, 104, 165, 81, 153, 237, 250, 184, 69, 187, 112, 39, 230, 143, 219, 229, 69, 164, 130, 98, 233, 29, 32, 19, 70, 80, 50, 54, 44, 26, 188, 64, 70, 12, 216, 94, 205, 45, 73, 109, 70, 10, 253, 178, 19, 8, 160, 153, 70, 105, 157, 60, 17, 7, 108, 198, 70, 188, 9, 21, 47, 134, 158, 243, 70, 132, 104, 50, 105, 181, 42, 33, 71, 231, 54, 24, 120, 189, 10, 78, 71, 10, 48, 21, 201, 101, 73, 122, 71, 9, 138, 242, 15, 57, 0, 167, 71, 200, 56, 244, 237, 49, 32, 212, 71, 175, 177, 53, 176, 43, 156, 1, 72, 242, 246, 93, 116, 76, 209, 46, 72, 20, 56, 210, 229, 34, 247, 90, 72, 18, 241, 23, 137, 62, 152, 135, 72, 240, 242, 244, 183, 54, 165, 180, 72, 146, 84, 246, 224, 143, 16, 226, 72, 0, 20, 175, 201, 251, 156, 15, 73, 128, 49, 121, 80, 92, 169, 59, 73, 80, 11, 106, 198, 48, 52, 104, 73, 230, 201, 156, 173, 170, 45, 149, 73, 169, 48, 233, 87, 245, 135, 194, 73, 148, 10, 236, 172, 246, 54, 240, 73, 131, 18, 157, 174, 47, 96, 28, 74, 51, 112, 201, 184, 41, 212, 72, 74, 45, 66, 176, 129, 164, 185, 117, 74, 231, 57, 122, 241, 111, 2, 163, 74, 170, 242, 74, 243, 33, 162, 208, 74, 170, 40, 195, 105, 187, 27, 253, 74, 149, 195, 138, 252, 67, 120, 41, 75, 34, 107, 249, 124, 59, 73, 86, 75, 190, 61, 90, 13, 20, 128, 131, 75, 6, 246, 174, 139, 17, 16, 177, 75, 138, 46, 114, 180, 30, 220, 221, 75, 185, 232, 227, 221, 154, 32, 10, 76, 162, 107, 39, 130, 135, 220, 54, 76, 46, 126, 226, 145, 246, 0, 100, 76, 104, 46, 166, 191, 215, 128, 145, 76, 54, 209, 98, 143, 121, 161, 190, 76, 15, 119, 118, 93, 74, 205, 234, 76, 45, 168, 199, 17, 161, 115, 23, 77, 39, 179, 142, 239, 44, 133, 68, 77, 194, 220, 156, 81, 135, 244, 113, 77, 84, 130, 210, 206, 236, 107, 159, 77, 10, 50, 248, 52, 111, 126, 203, 77, 201, 43, 89, 78, 161, 14, 248, 77, 80, 6, 142, 36, 205, 12, 37, 78, 134, 69, 252, 127, 51, 107, 82, 78, 213, 188, 252, 15, 205, 29, 128, 78, 117, 74, 250, 219, 38, 52, 172, 78, 38, 1, 123, 0, 162, 173, 216, 78, 1, 161, 107, 192, 237, 151, 5, 79, 225, 44, 94, 8, 240, 228, 50, 79, 69, 103, 82, 7, 82, 136, 96, 79, 185, 52, 208, 140, 143, 238, 140, 79, 34, 46, 54, 155, 189, 80, 185, 79, 94, 104, 207, 231, 165, 38, 230, 79, 82, 123, 213, 42, 209, 97, 19, 80, 232, 203, 122, 5, 151, 245, 64, 80, 214, 228, 150, 73, 200, 173, 109, 80, 59, 8, 100, 64, 15, 248, 153, 80, 52, 135, 87, 88, 13, 185, 198, 80, 78, 150, 76, 173, 235, 225, 243, 80, 132, 3, 163, 55, 174, 101, 33, 81, 0, 0, 0, 0, 0, 0, 248, 127); +captured[24] = new Uint8Array([0, 0, 0, 0, 7, 1, 255, 255]); +captured[25] = new Uint8Array([100, 0, 0, 0, 7, 1, 255, 255, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 28, 64, 0, 0, 0, 0, 0, 128, 72, 64, 0, 0, 0, 0, 0, 112, 117, 64, 0, 0, 0, 0, 0, 194, 162, 64, 0, 0, 0, 0, 192, 105, 208, 64, 0, 0, 0, 0, 16, 185, 252, 64, 0, 0, 0, 0, 238, 33, 41, 65, 0, 0, 0, 64, 176, 253, 85, 65, 0, 0, 0, 56, 250, 61, 131, 65, 0, 0, 0, 241, 58, 214, 176, 65, 0, 0, 192, 37, 231, 118, 221, 65, 0, 0, 8, 65, 10, 200, 9, 66, 0, 0, 231, 248, 8, 143, 54, 66, 0, 32, 202, 217, 39, 189, 99, 66, 0, 220, 144, 222, 130, 69, 145, 66, 0, 129, 125, 5, 165, 57, 190, 66, 224, 208, 205, 100, 112, 114, 234, 66, 196, 22, 52, 88, 34, 36, 23, 67, 236, 147, 45, 13, 158, 63, 68, 67, 110, 225, 135, 75, 170, 183, 113, 67, 128, 202, 45, 4, 106, 1, 159, 67, 48, 17, 168, 195, 60, 33, 203, 67, 10, 15, 51, 43, 21, 189, 247, 67, 41, 173, 204, 133, 114, 197, 36, 68, 132, 23, 19, 53, 196, 44, 82, 68, 39, 105, 225, 92, 87, 206, 127, 68, 2, 60, 69, 113, 140, 212, 171, 68, 130, 148, 28, 227, 250, 89, 216, 68, 242, 1, 185, 134, 187, 78, 5, 69, 180, 225, 225, 21, 228, 164, 50, 69, 126, 165, 37, 147, 71, 80, 96, 69, 156, 225, 129, 65, 125, 140, 140, 69, 104, 165, 81, 153, 237, 250, 184, 69, 187, 112, 39, 230, 143, 219, 229, 69, 164, 130, 98, 233, 29, 32, 19, 70, 80, 50, 54, 44, 26, 188, 64, 70, 12, 216, 94, 205, 45, 73, 109, 70, 10, 253, 178, 19, 8, 160, 153, 70, 105, 157, 60, 17, 7, 108, 198, 70, 188, 9, 21, 47, 134, 158, 243, 70, 132, 104, 50, 105, 181, 42, 33, 71, 231, 54, 24, 120, 189, 10, 78, 71, 10, 48, 21, 201, 101, 73, 122, 71, 9, 138, 242, 15, 57, 0, 167, 71, 200, 56, 244, 237, 49, 32, 212, 71, 175, 177, 53, 176, 43, 156, 1, 72, 242, 246, 93, 116, 76, 209, 46, 72, 20, 56, 210, 229, 34, 247, 90, 72, 18, 241, 23, 137, 62, 152, 135, 72, 240, 242, 244, 183, 54, 165, 180, 72, 146, 84, 246, 224, 143, 16, 226, 72, 0, 20, 175, 201, 251, 156, 15, 73, 128, 49, 121, 80, 92, 169, 59, 73, 80, 11, 106, 198, 48, 52, 104, 73, 230, 201, 156, 173, 170, 45, 149, 73, 169, 48, 233, 87, 245, 135, 194, 73, 148, 10, 236, 172, 246, 54, 240, 73, 131, 18, 157, 174, 47, 96, 28, 74, 51, 112, 201, 184, 41, 212, 72, 74, 45, 66, 176, 129, 164, 185, 117, 74, 231, 57, 122, 241, 111, 2, 163, 74, 170, 242, 74, 243, 33, 162, 208, 74, 170, 40, 195, 105, 187, 27, 253, 74, 149, 195, 138, 252, 67, 120, 41, 75, 34, 107, 249, 124, 59, 73, 86, 75, 190, 61, 90, 13, 20, 128, 131, 75, 6, 246, 174, 139, 17, 16, 177, 75, 138, 46, 114, 180, 30, 220, 221, 75, 185, 232, 227, 221, 154, 32, 10, 76, 162, 107, 39, 130, 135, 220, 54, 76, 46, 126, 226, 145, 246, 0, 100, 76, 104, 46, 166, 191, 215, 128, 145, 76, 54, 209, 98, 143, 121, 161, 190, 76, 15, 119, 118, 93, 74, 205, 234, 76, 45, 168, 199, 17, 161, 115, 23, 77, 39, 179, 142, 239, 44, 133, 68, 77, 194, 220, 156, 81, 135, 244, 113, 77, 84, 130, 210, 206, 236, 107, 159, 77, 10, 50, 248, 52, 111, 126, 203, 77, 201, 43, 89, 78, 161, 14, 248, 77, 80, 6, 142, 36, 205, 12, 37, 78, 134, 69, 252, 127, 51, 107, 82, 78, 213, 188, 252, 15, 205, 29, 128, 78, 117, 74, 250, 219, 38, 52, 172, 78, 38, 1, 123, 0, 162, 173, 216, 78, 1, 161, 107, 192, 237, 151, 5, 79, 225, 44, 94, 8, 240, 228, 50, 79, 69, 103, 82, 7, 82, 136, 96, 79, 185, 52, 208, 140, 143, 238, 140, 79, 34, 46, 54, 155, 189, 80, 185, 79, 94, 104, 207, 231, 165, 38, 230, 79, 82, 123, 213, 42, 209, 97, 19, 80, 232, 203, 122, 5, 151, 245, 64, 80, 214, 228, 150, 73, 200, 173, 109, 80, 59, 8, 100, 64, 15, 248, 153, 80, 52, 135, 87, 88, 13, 185, 198, 80, 78, 150, 76, 173, 235, 225, 243, 80, 132, 3, 163, 55, 174, 101, 33, 81, 0, 0, 0, 0, 0, 0, 248, 127]); captured[26] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19)); -captured[27] = serialize(0); captured[27].clonebuffer = String.fromCharCode(0, 0, 0, 0, 8, 1, 255, 255); -captured[28] = serialize(0); captured[28].clonebuffer = String.fromCharCode(100, 0, 0, 0, 8, 1, 255, 255, 1, 7, 49, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0); +captured[27] = new Uint8Array([0, 0, 0, 0, 8, 1, 255, 255]); +captured[28] = new Uint8Array([100, 0, 0, 0, 8, 1, 255, 255, 1, 7, 49, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0]); captured[29] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19)); -captured[30] = serialize(0); captured[30].clonebuffer = String.fromCharCode(0, 0, 0, 0, 7, 0, 255, 255, 0, 0, 0, 0, 3, 0, 255, 255, 3, 0, 0, 0, 0, 1, 255, 255, 0, 1, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 255, 255, 3, 0, 0, 0, 0, 1, 255, 255, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255); +captured[30] = new Uint8Array([0, 0, 0, 0, 7, 0, 255, 255, 0, 0, 0, 0, 3, 0, 255, 255, 3, 0, 0, 0, 0, 1, 255, 255, 0, 1, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 255, 255, 3, 0, 0, 0, 0, 1, 255, 255, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255]);
--- a/js/src/tests/js1_8_5/extensions/clone-v1-typed-array.js +++ b/js/src/tests/js1_8_5/extensions/clone-v1-typed-array.js @@ -115,16 +115,14 @@ function test() { test(); reportCompare(0, 0, 'ok'); if ("JS_RECORD_RESULTS" in environment) { print("var captured = [];"); for (var i in captured) { var s = "captured[" + i + "] = "; - if (captured[i] instanceof Error) { + if (captured[i] instanceof Error) print(s + captured[i].toSource() + ";"); - } else { - data = [ c.charCodeAt(0) for (c of captured[i].clonebuffer.split('')) ]; - print(s + "serialize(0); captured[" + i + "].clonebuffer = String.fromCharCode(" + data.join(", ") + ");"); - } + else + print(s + "new Uint8Array(" + [...captured[i]].toSource() + ");"); } }
--- a/js/src/tests/js1_8_5/extensions/shell.js +++ b/js/src/tests/js1_8_5/extensions/shell.js @@ -192,21 +192,8 @@ function referencesVia(from, edge, to) { print("referent is not referenced via: " + uneval(edge)); print("but it is referenced via: " + uneval(alternatives)); } print("all incoming edges, from any object:"); for (var e in edges) print(e); return false; } - -// Note that AsmJS ArrayBuffers have a minimum size, currently 4096 bytes. If a -// smaller size is given, a regular ArrayBuffer will be returned instead. -function AsmJSArrayBuffer(size) { - var ab = new ArrayBuffer(size); - (new Function('global', 'foreign', 'buffer', '' + -' "use asm";' + -' var i32 = new global.Int32Array(buffer);' + -' function g() {};' + -' return g;' + -''))(this,null,ab); - return ab; -}
--- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -27,18 +27,16 @@ * array object. */ #include "js/StructuredClone.h" #include "mozilla/Endian.h" #include "mozilla/FloatingPoint.h" -#include <algorithm> - #include "jsapi.h" #include "jscntxt.h" #include "jsdate.h" #include "jswrapper.h" #include "vm/TypedArrayObject.h" #include "vm/WrapperObject.h" @@ -63,86 +61,59 @@ enum StructuredDataType { SCTAG_REGEXP_OBJECT, SCTAG_ARRAY_OBJECT, SCTAG_OBJECT_OBJECT, SCTAG_ARRAY_BUFFER_OBJECT, SCTAG_BOOLEAN_OBJECT, SCTAG_STRING_OBJECT, SCTAG_NUMBER_OBJECT, SCTAG_BACK_REFERENCE_OBJECT, - SCTAG_DO_NOT_USE_1, - SCTAG_DO_NOT_USE_2, + SCTAG_TRANSFER_MAP_HEADER, + SCTAG_TRANSFER_MAP, SCTAG_TYPED_ARRAY_OBJECT, SCTAG_TYPED_ARRAY_V1_MIN = 0xFFFF0100, SCTAG_TYPED_ARRAY_V1_INT8 = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_INT8, SCTAG_TYPED_ARRAY_V1_UINT8 = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_UINT8, SCTAG_TYPED_ARRAY_V1_INT16 = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_INT16, SCTAG_TYPED_ARRAY_V1_UINT16 = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_UINT16, SCTAG_TYPED_ARRAY_V1_INT32 = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_INT32, SCTAG_TYPED_ARRAY_V1_UINT32 = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_UINT32, SCTAG_TYPED_ARRAY_V1_FLOAT32 = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_FLOAT32, SCTAG_TYPED_ARRAY_V1_FLOAT64 = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_FLOAT64, SCTAG_TYPED_ARRAY_V1_UINT8_CLAMPED = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_UINT8_CLAMPED, SCTAG_TYPED_ARRAY_V1_MAX = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_MAX - 1, - - /* - * Define a separate range of numbers for Transferable-only tags, since - * they are not used for persistent clone buffers and therefore do not - * require bumping JS_STRUCTURED_CLONE_VERSION. - */ - SCTAG_TRANSFER_MAP_HEADER = 0xFFFF0200, - SCTAG_TRANSFER_MAP_ENTRY, - SCTAG_END_OF_BUILTIN_TYPES }; -// Data associated with an SCTAG_TRANSFER_MAP_HEADER that tells whether the -// contents have been read out yet or not. enum TransferableMapHeader { - SCTAG_TM_UNREAD = 0, - SCTAG_TM_TRANSFERRED -}; - -enum TransferableObjectType { - // Transferable data has not been filled in yet - SCTAG_TM_UNFILLED = 0, - - // Structured clone buffer does not yet own the data - SCTAG_TM_UNOWNED = 1, - - // All values at least this large are owned by the clone buffer - SCTAG_TM_FIRST_OWNED = 2, - - // Data is a pointer that can be freed - SCTAG_TM_ALLOC_DATA = 2, + SCTAG_TM_NOT_MARKED = 0, + SCTAG_TM_MARKED }; namespace js { struct SCOutput { public: explicit SCOutput(JSContext *cx); - ~SCOutput(); JSContext *context() const { return cx; } bool write(uint64_t u); bool writePair(uint32_t tag, uint32_t data); bool writeDouble(double d); bool writeBytes(const void *p, size_t nbytes); bool writeChars(const jschar *p, size_t nchars); bool writePtr(const void *); template <class T> bool writeArray(const T *p, size_t nbytes); bool extractBuffer(uint64_t **datap, size_t *sizep); - uint64_t count() const { return buf.length(); } - uint64_t *rawBuffer() { return buf.begin(); } + uint64_t count() { return buf.length(); } private: JSContext *cx; js::Vector<uint64_t> buf; }; struct SCInput { public: @@ -158,22 +129,16 @@ struct SCInput { bool readPtr(void **); bool get(uint64_t *p); bool getPair(uint32_t *tagp, uint32_t *datap); bool replace(uint64_t u); bool replacePair(uint32_t tag, uint32_t data); - uint64_t *tell() const { return point; } - void seek(uint64_t *pos) { - JS_ASSERT(pos <= end); - point = pos; - } - template <class T> bool readArray(T *p, size_t nelems); private: bool eof(); void staticAssertions() { JS_STATIC_ASSERT(sizeof(jschar) == 2); @@ -234,17 +199,18 @@ struct JSStructuredCloneWriter { const JSStructuredCloneCallbacks *cb, void *cbClosure, jsval tVal) : out(out), objs(out.context()), counts(out.context()), ids(out.context()), memory(out.context()), callbacks(cb), closure(cbClosure), transferable(out.context(), tVal), transferableObjects(out.context()) { } - bool init() { return parseTransferable() && memory.init() && writeTransferMap(); } + bool init() { return transferableObjects.init() && parseTransferable() && + memory.init() && writeTransferMap(); } bool write(const js::Value &v); js::SCOutput &output() { return out; } private: JSContext *context() { return out.context(); } @@ -255,17 +221,16 @@ struct JSStructuredCloneWriter { bool writeArrayBuffer(JS::HandleObject obj); bool writeTypedArray(JS::HandleObject obj); bool startObject(JS::HandleObject obj, bool *backref); bool startWrite(const js::Value &v); bool traverseObject(JS::HandleObject obj); bool parseTransferable(); void reportErrorTransferable(); - bool transferOwnership(); inline void checkStack(); js::SCOutput &out; // Vector of objects with properties remaining to be written. // // NB: These can span multiple compartments, so the compartment must be @@ -288,17 +253,17 @@ struct JSStructuredCloneWriter { // The user defined callbacks that will be used for cloning. const JSStructuredCloneCallbacks *callbacks; // Any value passed to JS_WriteStructuredClone. void *closure; // List of transferable objects JS::RootedValue transferable; - JS::AutoObjectVector transferableObjects; + js::AutoObjectHashSet transferableObjects; friend bool JS_WriteTypedArray(JSStructuredCloneWriter *w, JS::Value v); }; JS_FRIEND_API(uint64_t) js_GetSCOffset(JSStructuredCloneWriter* writer) { JS_ASSERT(writer); @@ -325,75 +290,64 @@ bool ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, Value *vp, const JSStructuredCloneCallbacks *cb, void *cbClosure) { SCInput in(cx, data, nbytes); JSStructuredCloneReader r(in, cb, cbClosure); return r.read(vp); } -// This may acquire new ways of discarding transfer map entries as new -// Transferables are implemented. -static void -DiscardEntry(uint32_t mapEntryDescriptor, const uint64_t *ptr) +bool +ClearStructuredClone(const uint64_t *data, size_t nbytes) { - JS_ASSERT(mapEntryDescriptor == SCTAG_TM_ALLOC_DATA); - uint64_t u = LittleEndian::readUint64(ptr); - js_free(reinterpret_cast<void*>(u)); -} - -static void -Discard(const uint64_t *begin, const uint64_t *end) -{ - const uint64_t *point = begin; + const uint64_t *point = data; + const uint64_t *end = data + nbytes / 8; uint64_t u = LittleEndian::readUint64(point++); uint32_t tag = uint32_t(u >> 32); - if (tag != SCTAG_TRANSFER_MAP_HEADER) - return; - - if (TransferableMapHeader(u) == SCTAG_TM_TRANSFERRED) - return; - - uint64_t numTransferables = LittleEndian::readUint64(point++); - while (numTransferables--) { - uint64_t u = LittleEndian::readUint64(point++); - JS_ASSERT(uint32_t(u >> 32) == SCTAG_TRANSFER_MAP_ENTRY); - uint32_t mapEntryDescriptor = uint32_t(u); - if (mapEntryDescriptor >= SCTAG_TM_FIRST_OWNED) { - DiscardEntry(mapEntryDescriptor, point); - point += 2; // Pointer and userdata + if (tag == SCTAG_TRANSFER_MAP_HEADER) { + if ((TransferableMapHeader)uint32_t(u) == SCTAG_TM_NOT_MARKED) { + while (point != end) { + uint64_t u = LittleEndian::readUint64(point++); + uint32_t tag = uint32_t(u >> 32); + if (tag == SCTAG_TRANSFER_MAP) { + u = LittleEndian::readUint64(point++); + js_free(reinterpret_cast<void*>(u)); + } else { + // The only things in the transfer map should be + // SCTAG_TRANSFER_MAP tags paired with pointers. If we find + // any other tag, we've walked off the end of the transfer + // map. + break; + } + } } } -} -static void -ClearStructuredClone(const uint64_t *data, size_t nbytes) -{ - JS_ASSERT(nbytes % 8 == 0); - Discard(data, data + nbytes / 8); - js_free(const_cast<uint64_t*>(data)); + js_free((void *)data); + return true; } bool StructuredCloneHasTransferObjects(const uint64_t *data, size_t nbytes, bool *hasTransferable) { *hasTransferable = false; if (data) { uint64_t u = LittleEndian::readUint64(data); uint32_t tag = uint32_t(u >> 32); - if (tag == SCTAG_TRANSFER_MAP_HEADER) + if (tag == SCTAG_TRANSFER_MAP_HEADER) { *hasTransferable = true; + } } return true; } -} /* namespace js */ +} static inline uint64_t PairToUInt64(uint32_t tag, uint32_t data) { return uint64_t(data) | (uint64_t(tag) << 32); } bool @@ -492,18 +446,17 @@ SCInput::readDouble(double *p) *p = CanonicalizeNan(pun.d); return true; } template <typename T> static void copyAndSwapFromLittleEndian(T *dest, const void *src, size_t nelems) { - if (nelems > 0) - NativeEndian::copyAndSwapFromLittleEndian(dest, src, nelems); + NativeEndian::copyAndSwapFromLittleEndian(dest, src, nelems); } template <> void copyAndSwapFromLittleEndian(uint8_t *dest, const void *src, size_t nelems) { memcpy(dest, src, nelems); } @@ -548,22 +501,16 @@ SCInput::readPtr(void **p) uint64_t tmp; bool ret = read(&tmp); *p = reinterpret_cast<void*>(tmp); return ret; } SCOutput::SCOutput(JSContext *cx) : cx(cx), buf(cx) {} -SCOutput::~SCOutput() -{ - // Free any transferable data left lying around in the buffer - Discard(rawBuffer(), rawBuffer() + count()); -} - bool SCOutput::write(uint64_t u) { return buf.append(NativeEndian::swapToLittleEndian(u)); } bool SCOutput::writePair(uint32_t tag, uint32_t data) @@ -613,18 +560,17 @@ SCOutput::writeDouble(double d) { return write(ReinterpretDoubleAsUInt64(CanonicalizeNan(d))); } template <typename T> static void copyAndSwapToLittleEndian(void *dest, const T *src, size_t nelems) { - if (nelems > 0) - NativeEndian::copyAndSwapToLittleEndian(dest, src, nelems); + NativeEndian::copyAndSwapToLittleEndian(dest, src, nelems); } template <> void copyAndSwapToLittleEndian(void *dest, const uint8_t *src, size_t nelems) { memcpy(dest, src, nelems); } @@ -681,80 +627,77 @@ SCOutput::extractBuffer(uint64_t **datap return (*datap = buf.extractRawBuffer()) != nullptr; } JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX); bool JSStructuredCloneWriter::parseTransferable() { - MOZ_ASSERT(transferableObjects.empty(), "parseTransferable called with stale data"); + transferableObjects.clear(); if (JSVAL_IS_NULL(transferable) || JSVAL_IS_VOID(transferable)) return true; if (!transferable.isObject()) { reportErrorTransferable(); return false; } - JSContext *cx = context(); - RootedObject array(cx, &transferable.toObject()); - if (!JS_IsArrayObject(cx, array)) { + RootedObject array(context(), &transferable.toObject()); + if (!JS_IsArrayObject(context(), array)) { reportErrorTransferable(); return false; } uint32_t length; - if (!JS_GetArrayLength(cx, array, &length)) { + if (!JS_GetArrayLength(context(), array, &length)) { return false; } RootedValue v(context()); for (uint32_t i = 0; i < length; ++i) { - if (!JS_GetElement(cx, array, i, &v)) { + if (!JS_GetElement(context(), array, i, &v)) { return false; } if (!v.isObject()) { reportErrorTransferable(); return false; } JSObject* tObj = CheckedUnwrap(&v.toObject()); if (!tObj) { - JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_UNWRAP_DENIED); + JS_ReportError(context(), "Permission denied to access object"); return false; } if (!tObj->is<ArrayBufferObject>()) { reportErrorTransferable(); return false; } - // No duplicates allowed - if (std::find(transferableObjects.begin(), transferableObjects.end(), tObj) != transferableObjects.end()) { - JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_DUP_TRANSFERABLE); + // No duplicate: + if (transferableObjects.has(tObj)) { + reportErrorTransferable(); return false; } - if (!transferableObjects.append(tObj)) + if (!transferableObjects.putNew(tObj)) return false; } return true; } void JSStructuredCloneWriter::reportErrorTransferable() { if (callbacks && callbacks->reportError) return callbacks->reportError(context(), JS_SCERR_TRANSFERABLE); - else - JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_NOT_TRANSFERABLE); } bool JSStructuredCloneWriter::writeString(uint32_t tag, JSString *str) { size_t length = str->length(); const jschar *chars = str->getChars(context()); if (!chars) @@ -946,84 +889,41 @@ JSStructuredCloneWriter::startWrite(cons JS_ReportErrorNumber(context(), js_GetErrorMessage, nullptr, JSMSG_SC_UNSUPPORTED_TYPE); return false; } bool JSStructuredCloneWriter::writeTransferMap() { - if (transferableObjects.empty()) - return true; - - if (!out.writePair(SCTAG_TRANSFER_MAP_HEADER, (uint32_t)SCTAG_TM_UNREAD)) - return false; - - if (!out.write(transferableObjects.length())) - return false; - - for (JS::AutoObjectVector::Range tr = transferableObjects.all(); - !tr.empty(); tr.popFront()) - { - JSObject *obj = tr.front(); - - if (!memory.put(obj, memory.count())) + if (!transferableObjects.empty()) { + if (!out.writePair(SCTAG_TRANSFER_MAP_HEADER, (uint32_t)SCTAG_TM_NOT_MARKED)) return false; - // Emit a placeholder pointer. We will steal the data and neuter the - // transferable later. - if (!out.writePair(SCTAG_TRANSFER_MAP_ENTRY, SCTAG_TM_UNFILLED) || - !out.writePtr(NULL) || - !out.write(0)) - { - return false; + for (HashSet<JSObject*>::Range r = transferableObjects.all(); + !r.empty(); r.popFront()) { + JSObject *obj = r.front(); + + if (!memory.put(obj, memory.count())) + return false; + + void *content; + uint8_t *data; + if (!JS_StealArrayBufferContents(context(), obj, &content, &data)) + return false; + + if (!out.writePair(SCTAG_TRANSFER_MAP, 0) || !out.writePtr(content)) + return false; } } return true; } bool -JSStructuredCloneWriter::transferOwnership() -{ - if (transferableObjects.empty()) - return true; - - // Walk along the transferables and the transfer map at the same time, - // grabbing out pointers from the transferables and stuffing them into the - // transfer map. - uint64_t *point = out.rawBuffer(); - JS_ASSERT(uint32_t(LittleEndian::readUint64(point) >> 32) == SCTAG_TRANSFER_MAP_HEADER); - point++; - JS_ASSERT(LittleEndian::readUint64(point) == transferableObjects.length()); - point++; - - for (JS::AutoObjectVector::Range tr = transferableObjects.all(); - !tr.empty(); - tr.popFront()) - { - void *content; - uint8_t *data; - if (!JS_StealArrayBufferContents(context(), tr.front(), &content, &data)) - return false; // Destructor will clean up the already-transferred data - - MOZ_ASSERT(uint32_t(LittleEndian::readUint64(point) >> 32) == SCTAG_TRANSFER_MAP_ENTRY); - LittleEndian::writeUint64(point++, PairToUInt64(SCTAG_TRANSFER_MAP_ENTRY, SCTAG_TM_ALLOC_DATA)); - LittleEndian::writeUint64(point++, reinterpret_cast<uint64_t>(content)); - LittleEndian::writeUint64(point++, 0); - } - - JS_ASSERT(point <= out.rawBuffer() + out.count()); - JS_ASSERT_IF(point < out.rawBuffer() + out.count(), - uint32_t(LittleEndian::readUint64(point) >> 32) != SCTAG_TRANSFER_MAP_ENTRY); - - return true; -} - -bool JSStructuredCloneWriter::write(const Value &v) { if (!startWrite(v)) return false; while (!counts.empty()) { RootedObject obj(context(), &objs.back().toObject()); AutoCompartment ac(context(), obj); @@ -1056,17 +956,18 @@ JSStructuredCloneWriter::write(const Val } else { out.writePair(SCTAG_NULL, 0); objs.popBack(); counts.popBack(); } } memory.clear(); - return transferOwnership(); + + return true; } bool JSStructuredCloneReader::checkDouble(double d) { jsval_layout l; l.asDouble = d; if (!JSVAL_IS_DOUBLE_IMPL(l)) { @@ -1382,17 +1283,17 @@ JSStructuredCloneReader::startRead(Value case SCTAG_TRANSFER_MAP_HEADER: // A map header cannot be here but just at the beginning of the buffer. JS_ReportErrorNumber(context(), js_GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA, "invalid input"); return false; - case SCTAG_TRANSFER_MAP_ENTRY: + case SCTAG_TRANSFER_MAP: // A map cannot be here but just at the beginning of the buffer. JS_ReportErrorNumber(context(), js_GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA, "invalid input"); return false; case SCTAG_ARRAY_BUFFER_OBJECT: if (!readArrayBuffer(data, vp)) @@ -1468,67 +1369,47 @@ JSStructuredCloneReader::readId(jsid *id JS_ReportErrorNumber(context(), js_GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA, "id"); return false; } bool JSStructuredCloneReader::readTransferMap() { - uint64_t *headerPos = in.tell(); - uint32_t tag, data; if (!in.getPair(&tag, &data)) return false; - if (tag != SCTAG_TRANSFER_MAP_HEADER || TransferableMapHeader(data) == SCTAG_TM_TRANSFERRED) + if (tag != SCTAG_TRANSFER_MAP_HEADER || + (TransferableMapHeader)data == SCTAG_TM_MARKED) return true; - uint64_t numTransferables; - MOZ_ALWAYS_TRUE(in.readPair(&tag, &data)); - if (!in.read(&numTransferables)) + if (!in.replacePair(SCTAG_TRANSFER_MAP_HEADER, SCTAG_TM_MARKED)) + return false; + + if (!in.readPair(&tag, &data)) return false; - for (uint64_t i = 0; i < numTransferables; i++) { - uint64_t *pos = in.tell(); + while (1) { + if (!in.getPair(&tag, &data)) + return false; - if (!in.readPair(&tag, &data)) - return false; - JS_ASSERT(tag == SCTAG_TRANSFER_MAP_ENTRY); - JS_ASSERT(data == SCTAG_TM_ALLOC_DATA); + if (tag != SCTAG_TRANSFER_MAP) + break; void *content; - if (!in.readPtr(&content)) - return false; - uint64_t userdata; - if (!in.read(&userdata)) + if (!in.readPair(&tag, &data) || !in.readPtr(&content)) return false; JSObject *obj = JS_NewArrayBufferWithContents(context(), content); - if (!obj) - return false; - - // Rewind to the SCTAG_TRANSFER_MAP_ENTRY and mark this entry as unowned by - // the input buffer. - uint64_t *next = in.tell(); - in.seek(pos); - MOZ_ALWAYS_TRUE(in.replacePair(SCTAG_TRANSFER_MAP_ENTRY, SCTAG_TM_UNOWNED)); - in.seek(next); - - if (!allObjs.append(ObjectValue(*obj))) + if (!obj || !allObjs.append(ObjectValue(*obj))) return false; } - // Mark the whole transfer map as consumed - uint64_t *endPos = in.tell(); - in.seek(headerPos); - MOZ_ALWAYS_TRUE(in.replacePair(SCTAG_TRANSFER_MAP_HEADER, SCTAG_TM_TRANSFERRED)); - in.seek(endPos); - return true; } bool JSStructuredCloneReader::read(Value *vp) { if (!readTransferMap()) return false; @@ -1593,18 +1474,17 @@ JS_WriteStructuredClone(JSContext *cx, J optionalCallbacks : cx->runtime()->structuredCloneCallbacks; return WriteStructuredClone(cx, value, bufp, nbytesp, callbacks, closure, transferable); } JS_PUBLIC_API(bool) JS_ClearStructuredClone(const uint64_t *data, size_t nbytes) { - ClearStructuredClone(data, nbytes); - return true; + return ClearStructuredClone(data, nbytes); } JS_PUBLIC_API(bool) JS_StructuredCloneHasTransferables(const uint64_t *data, size_t nbytes, bool *hasTransferable) { bool transferable; if (!StructuredCloneHasTransferObjects(data, nbytes, &transferable))
--- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -239,17 +239,17 @@ AllocateArrayBufferContents(JSContext *m js_ReportOutOfMemory(maybecx); return nullptr; } if (initdata) memcpy(newheader->elements(), initdata, nbytes); // we rely on this being correct - ArrayBufferObject::updateElementsHeader(newheader, nbytes); + ArrayBufferObject::setElementsHeader(newheader, nbytes); return newheader; } bool ArrayBufferObject::allocateSlots(JSContext *maybecx, uint32_t bytes, uint8_t *contents) { /* @@ -269,17 +269,17 @@ ArrayBufferObject::allocateSlots(JSConte } else { elements = fixedElements(); if (contents) memcpy(elements, contents, bytes); else memset(elements, 0, bytes); } - initElementsHeader(getElementsHeader(), bytes); + setElementsHeader(getElementsHeader(), bytes); return true; } static inline void PostBarrierTypedArrayObject(JSObject *obj) { #ifdef JSGC_GENERATIONAL @@ -292,17 +292,17 @@ PostBarrierTypedArrayObject(JSObject *ob // The list of views must be stored somewhere in the ArrayBufferObject, but // the slots are already being used for the element storage and the private // field is used for a delegate object. The ObjectElements header has space // for it, but I don't want to mess around with adding unions to it with // JS_USE_NEW_OBJECT_REPRESENTATION pending, since it will solve this much // more cleanly. struct OldObjectRepresentationHack { - uint32_t flags; + uint32_t capacity; uint32_t initializedLength; EncapsulatedPtr<ArrayBufferViewObject> views; }; static ArrayBufferViewObject * GetViewList(ArrayBufferObject *obj) { return reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views; @@ -325,117 +325,54 @@ InitViewList(ArrayBufferObject *obj, Arr static EncapsulatedPtr<ArrayBufferViewObject> & GetViewListRef(ArrayBufferObject *obj) { JS_ASSERT(obj->runtimeFromMainThread()->isHeapBusy()); return reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views; } void -ArrayBufferObject::neuterViews(JSContext *maybecx) -{ - ArrayBufferViewObject *view; - for (view = GetViewList(this); view; view = view->nextView()) { - view->neuter(); - - // Notify compiled jit code that the base pointer has moved. - if (maybecx) - MarkObjectStateChange(maybecx, view); - } - - // neuterAsmJSArrayBuffer adjusts state specific to the ArrayBuffer data - // itself, but it only affects the behavior of views - if (isAsmJSArrayBuffer()) - ArrayBufferObject::neuterAsmJSArrayBuffer(*this); -} - -void ArrayBufferObject::changeContents(JSContext *maybecx, ObjectElements *newHeader) { - // Grab out data before invalidating it. - uint32_t byteLengthCopy = byteLength(); - uintptr_t oldDataPointer = uintptr_t(dataPointer()); - ArrayBufferViewObject *viewListHead = GetViewList(this); - - // Update all views. - uintptr_t newDataPointer = uintptr_t(newHeader->elements()); - for (ArrayBufferViewObject *view = viewListHead; view; view = view->nextView()) { - uintptr_t newDataPtr = uintptr_t(view->getPrivate()) - oldDataPointer + newDataPointer; - view->setPrivate(reinterpret_cast<uint8_t*>(newDataPtr)); - - // Notify compiled jit code that the base pointer has moved. - if (maybecx) - MarkObjectStateChange(maybecx, view); - } - - // The list of views in the old header is reachable if the contents are - // being transferred, so NULL it out - SetViewList(this, NULL); - - elements = newHeader->elements(); - - initElementsHeader(newHeader, byteLengthCopy); - InitViewList(this, viewListHead); -} - -void -ArrayBufferObject::neuter(JSContext *cx) -{ - JS_ASSERT(cx); - if (hasDynamicElements() && !isAsmJSArrayBuffer()) { - ObjectElements *oldHeader = getElementsHeader(); - changeContents(cx, ObjectElements::fromElements(fixedElements())); - - FreeOp fop(cx->runtime(), false); - fop.free_(oldHeader); - } - - uint32_t byteLen = 0; - updateElementsHeader(getElementsHeader(), byteLen); + // Grab out data before invalidating it. + uint32_t byteLengthCopy = byteLength(); + uintptr_t oldDataPointer = uintptr_t(dataPointer()); + ArrayBufferViewObject *viewListHead = GetViewList(this); + + // Update all views. + uintptr_t newDataPointer = uintptr_t(newHeader->elements()); + for (ArrayBufferViewObject *view = viewListHead; view; view = view->nextView()) { + uintptr_t newDataPtr = uintptr_t(view->getPrivate()) - oldDataPointer + newDataPointer; + view->setPrivate(reinterpret_cast<uint8_t*>(newDataPtr)); + + // Notify compiled jit code that the base pointer has moved. + if (maybecx) + MarkObjectStateChange(maybecx, view); + } + + // Change to the new header (now, so we can use SetViewList). + elements = newHeader->elements(); + + // Initialize 'newHeader'. + ArrayBufferObject::setElementsHeader(newHeader, byteLengthCopy); + SetViewList(this, viewListHead); } bool -ArrayBufferObject::copyData(JSContext *maybecx) -{ - ObjectElements *newHeader = AllocateArrayBufferContents(maybecx, byteLength(), dataPointer()); - if (!newHeader) - return false; - - changeContents(maybecx, newHeader); - return true; -} - -bool -ArrayBufferObject::ensureNonInline(JSContext *maybecx) +ArrayBufferObject::uninlineData(JSContext *maybecx) { - if (hasDynamicElements()) - return true; - return copyData(maybecx); -} - -// If the ArrayBuffer already contains dynamic contents, hand them back. -// Otherwise, allocate some new contents and copy the data over, but in no case -// modify the original ArrayBuffer. (Also, any allocated contents will have no -// views linked to in its header.) -ObjectElements * -ArrayBufferObject::getTransferableContents(JSContext *maybecx, bool *callerOwns) -{ - if (hasDynamicElements() && !isAsmJSArrayBuffer()) { - *callerOwns = false; - return getElementsHeader(); - } - - uint32_t byteLen = byteLength(); - ObjectElements *newheader = AllocateArrayBufferContents(maybecx, byteLen, dataPointer()); - if (!newheader) - return NULL; - - initElementsHeader(newheader, byteLen); - *callerOwns = true; - return newheader; + if (hasDynamicElements()) + return true; + + ObjectElements *newHeader = AllocateArrayBufferContents(maybecx, byteLength(), dataPointer()); + if (!newHeader) + return false; + + changeContents(maybecx, newHeader); + return true; } #if defined(JS_ION) && defined(JS_CPU_X64) // To avoid dynamically checking bounds on each load/store, asm.js code relies // on the SIGSEGV handler in AsmJSSignalHandlers.cpp. However, this only works // if we can guarantee that *any* out-of-bounds access generates a fault. This // isn't generally true since an out-of-bounds access could land on other // Mozilla data. To overcome this on x64, we reserve an entire 4GB space, @@ -537,19 +474,18 @@ ArrayBufferObject::neuterAsmJSArrayBuffe if (mprotect(buffer.dataPointer(), buffer.byteLength(), PROT_NONE)) MOZ_CRASH(); #endif } #else /* defined(JS_ION) && defined(JS_CPU_X64) */ bool ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer) { - if (!buffer->copyData(cx)) + if (!buffer->uninlineData(cx)) return false; - JS_ASSERT(buffer->hasDynamicElements()); buffer->getElementsHeader()->setIsAsmJSArrayBuffer(); return true; } void ArrayBufferObject::releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj) { @@ -656,38 +592,51 @@ ArrayBufferObject::createDataViewForThis bool ArrayBufferObject::createDataViewForThis(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); return CallNonGenericMethod<IsArrayBuffer, createDataViewForThisImpl>(cx, args); } bool -ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, void **contents, uint8_t **data) +ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, void **contents, + uint8_t **data) { ArrayBufferObject &buffer = obj->as<ArrayBufferObject>(); - - // Make the data stealable - bool own; - ObjectElements *header = reinterpret_cast<ObjectElements*>(buffer.getTransferableContents(cx, &own)); - if (!header) - return false; - *contents = header; - *data = reinterpret_cast<uint8_t *>(header + 1); - - // Neuter the views, which may also mprotect(PROT_NONE) the buffer. So do - // it after copying out the data. - buffer.neuterViews(cx); - - if (!own) { - // If header has dynamically allocated elements, revert it back to - // fixed-element storage before neutering it. - buffer.changeContents(cx, ObjectElements::fromElements(buffer.fixedElements())); + ArrayBufferViewObject *views = GetViewList(&buffer); + js::ObjectElements *header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer()); + if (buffer.hasDynamicElements() && !buffer.isAsmJSArrayBuffer()) { + SetViewList(&buffer, nullptr); + *contents = header; + *data = buffer.dataPointer(); + + buffer.setFixedElements(); + header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer()); + } else { + uint32_t length = buffer.byteLength(); + js::ObjectElements *newheader = + AllocateArrayBufferContents(cx, length, buffer.dataPointer()); + if (!newheader) { + js_ReportOutOfMemory(cx); + return false; + } + + ArrayBufferObject::setElementsHeader(newheader, length); + *contents = newheader; + *data = reinterpret_cast<uint8_t *>(newheader + 1); + + if (buffer.isAsmJSArrayBuffer()) + ArrayBufferObject::neuterAsmJSArrayBuffer(buffer); } - buffer.neuter(cx); + + // Neuter the donor ArrayBufferObject and all views of it + ArrayBufferObject::setElementsHeader(header, 0); + InitViewList(&buffer, views); + for (ArrayBufferViewObject *view = views; view; view = view->nextView()) + view->neuter(); return true; } void ArrayBufferObject::obj_trace(JSTracer *trc, JSObject *obj) { /* @@ -4012,29 +3961,21 @@ JS_GetArrayBufferByteLength(JSObject *ob JS_FRIEND_API(uint8_t *) JS_GetArrayBufferData(JSObject *obj) { obj = CheckedUnwrap(obj); if (!obj) return nullptr; ArrayBufferObject &buffer = obj->as<ArrayBufferObject>(); - if (!buffer.ensureNonInline(NULL)) + if (!buffer.uninlineData(nullptr)) return nullptr; return buffer.dataPointer(); } -JS_FRIEND_API(void) -JS_NeuterArrayBuffer(JSObject *obj, JSContext *cx) -{ - ArrayBufferObject &buffer = obj->as<ArrayBufferObject>(); - buffer.neuterViews(cx); - buffer.neuter(cx); -} - JS_FRIEND_API(JSObject *) JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes) { JS_ASSERT(nbytes <= INT32_MAX); return ArrayBufferObject::create(cx, nbytes); } JS_PUBLIC_API(JSObject *) @@ -4051,31 +3992,31 @@ JS_NewArrayBufferWithContents(JSContext JS_PUBLIC_API(bool) JS_AllocateArrayBufferContents(JSContext *cx, uint32_t nbytes, void **contents, uint8_t **data) { js::ObjectElements *header = AllocateArrayBufferContents(cx, nbytes, nullptr); if (!header) return false; - ArrayBufferObject::updateElementsHeader(header, nbytes); + ArrayBufferObject::setElementsHeader(header, nbytes); *contents = header; *data = reinterpret_cast<uint8_t*>(header->elements()); return true; } JS_PUBLIC_API(bool) JS_ReallocateArrayBufferContents(JSContext *cx, uint32_t nbytes, void **contents, uint8_t **data) { js::ObjectElements *header = AllocateArrayBufferContents(cx, nbytes, nullptr, *contents); if (!header) return false; - ArrayBufferObject::initElementsHeader(header, nbytes); + ArrayBufferObject::setElementsHeader(header, nbytes); *contents = header; *data = reinterpret_cast<uint8_t*>(header->elements()); return true; } JS_PUBLIC_API(bool) JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents, @@ -4315,18 +4256,18 @@ JS_GetObjectAsArrayBufferView(JSObject * ? obj->as<DataViewObject>().dataPointer() : obj->as<TypedArrayObject>().viewData()); return obj; } JS_FRIEND_API(JSObject *) JS_GetObjectAsArrayBuffer(JSObject *obj, uint32_t *length, uint8_t **data) { - if (!(obj = CheckedUnwrap(obj))) - return nullptr; + if (!(obj = CheckedUnwrap(obj))) + return nullptr; if (!obj->is<ArrayBufferObject>()) return nullptr; *length = obj->as<ArrayBufferObject>().byteLength(); *data = obj->as<ArrayBufferObject>().dataPointer(); return obj; }
--- a/js/src/vm/TypedArrayObject.h +++ b/js/src/vm/TypedArrayObject.h @@ -141,81 +141,51 @@ class ArrayBufferObject : public JSObjec static void resetArrayBufferList(JSCompartment *rt); static bool saveArrayBufferList(JSCompartment *c, ArrayBufferVector &vector); static void restoreArrayBufferLists(ArrayBufferVector &vector); static bool stealContents(JSContext *cx, JSObject *obj, void **contents, uint8_t **data); - static void updateElementsHeader(js::ObjectElements *header, uint32_t bytes) { + static void setElementsHeader(js::ObjectElements *header, uint32_t bytes) { + header->flags = 0; header->initializedLength = bytes; // NB: one or both of these fields is clobbered by GetViewList to store // the 'views' link. Set them to 0 to effectively initialize 'views' // to nullptr. header->length = 0; header->capacity = 0; } - static void initElementsHeader(js::ObjectElements *header, uint32_t bytes) { - header->flags = 0; - updateElementsHeader(header, bytes); - } - static uint32_t headerInitializedLength(const js::ObjectElements *header) { return header->initializedLength; } void addView(ArrayBufferViewObject *view); bool allocateSlots(JSContext *cx, uint32_t size, uint8_t *contents = nullptr); - void changeContents(JSContext *cx, ObjectElements *newHeader); /* - * Copy the data into freshly-allocated memory. Used when un-inlining or - * when converting an ArrayBuffer to an AsmJS (MMU-assisted) ArrayBuffer. - */ - bool copyData(JSContext *maybecx); - - /* - * Ensure data is not stored inline in the object. Used when handing back a + * Ensure that the data is not stored inline. Used when handing back a * GC-safe pointer. */ - bool ensureNonInline(JSContext *maybecx); + bool uninlineData(JSContext *cx); uint32_t byteLength() const { return getElementsHeader()->initializedLength; } - /* - * Return the contents of an ArrayBuffer without modifying the ArrayBuffer - * itself. Set *callerOwns to true if the caller has the only pointer to - * the returned contents (which is the case for inline or asm.js buffers), - * and false if the ArrayBuffer still owns the pointer. - */ - ObjectElements *getTransferableContents(JSContext *maybecx, bool *callerOwns); - - /* - * Neuter all views of an ArrayBuffer. - */ - void neuterViews(JSContext *maybecx); - inline uint8_t * dataPointer() const { return (uint8_t *) elements; } /* - * Discard the ArrayBuffer contents. For asm.js buffers, at least, should - * be called after neuterViews(). - */ - void neuter(JSContext *maybecx); - - /* * Check if the arrayBuffer contains any data. This will return false for * ArrayBuffer.prototype and neutered ArrayBuffers. */ bool hasData() const { return getClass() == &class_; } bool isAsmJSArrayBuffer() const { @@ -546,17 +516,16 @@ class DataViewObject : public ArrayBuffe static bool setFloat32Impl(JSContext *cx, CallArgs args); static bool fun_setFloat32(JSContext *cx, unsigned argc, Value *vp); static bool setFloat64Impl(JSContext *cx, CallArgs args); static bool fun_setFloat64(JSContext *cx, unsigned argc, Value *vp); static JSObject *initClass(JSContext *cx); - static void neuter(JSObject *view); static bool getDataPointer(JSContext *cx, Handle<DataViewObject*> obj, CallArgs args, size_t typeSize, uint8_t **data); template<typename NativeType> static bool read(JSContext *cx, Handle<DataViewObject*> obj, CallArgs &args, NativeType *val, const char *method); template<typename NativeType> static bool write(JSContext *cx, Handle<DataViewObject*> obj, CallArgs &args, const char *method);