From 27a028256c384984b63738b30309a15c5ebc07ad Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Fri, 13 Nov 2015 20:49:49 -0800 Subject: [PATCH] Back out 19 changesets (bug 1055472) for hazards and jstest failures CLOSED TREE Backed out changeset 738e23a218c8 (bug 1055472) Backed out changeset 2c454e1ac50c (bug 1055472) Backed out changeset 40919fcffecd (bug 1055472) Backed out changeset f42360dbd545 (bug 1055472) Backed out changeset ce74f9a7b479 (bug 1055472) Backed out changeset 8b8fa139568b (bug 1055472) Backed out changeset 42d1ecbce781 (bug 1055472) Backed out changeset ccb9403a345c (bug 1055472) Backed out changeset fdd35ea9ef38 (bug 1055472) Backed out changeset 2f77faf418ce (bug 1055472) Backed out changeset 1e968e8a279a (bug 1055472) Backed out changeset d3975d948208 (bug 1055472) Backed out changeset 03d708347ebb (bug 1055472) Backed out changeset 5ec1640cdfd2 (bug 1055472) Backed out changeset 5e2b91587001 (bug 1055472) Backed out changeset fd09d5077094 (bug 1055472) Backed out changeset 2e58e0e479b7 (bug 1055472) Backed out changeset 67f0802a5c13 (bug 1055472) Backed out changeset 69d9fb855787 (bug 1055472) --- js/src/builtin/MapObject.cpp | 49 ++-- js/src/builtin/MapObject.h | 4 +- js/src/builtin/Object.cpp | 7 +- js/src/builtin/RegExp.cpp | 52 ++-- js/src/builtin/WeakMapObject.cpp | 3 +- js/src/builtin/WeakSetObject.cpp | 23 +- js/src/builtin/WeakSetObject.h | 2 +- .../jit-test/tests/TypedObject/bug976697.js | 15 ++ js/src/jit/BaselineIC.cpp | 2 +- js/src/jsarray.cpp | 32 +-- js/src/jsarray.h | 5 +- js/src/jsbool.cpp | 8 +- js/src/jsdate.cpp | 13 +- js/src/jsdate.h | 2 +- js/src/jsexn.cpp | 7 +- js/src/jsfun.cpp | 42 +-- js/src/jsfun.h | 12 +- js/src/jsnum.cpp | 6 +- js/src/jsobj.cpp | 35 +-- js/src/jsobj.h | 7 - js/src/jsobjinlines.h | 18 -- js/src/jsstr.cpp | 7 +- .../ecma_6/Class/boundFunctionSubclassing.js | 24 -- .../ecma_6/Class/extendBuiltinConstructors.js | 86 ------- .../ecma_6/Class/subclassedArrayUnboxed.js | 29 --- .../ecma_6/Class/superCallBaseInvoked.js | 2 + .../DataView/detach-after-construction.js | 11 - js/src/tests/ecma_6/Reflect/construct.js | 4 +- .../ecma_6/RegExp/constructor-ordering-2.js | 21 -- .../ecma_6/RegExp/constructor-ordering.js | 16 -- .../TypedArray/constructor-non-detached.js | 27 -- .../tests/js1_5/Error/constructor-ordering.js | 17 -- js/src/vm/ArrayBufferObject.cpp | 41 +-- js/src/vm/ArrayBufferObject.h | 2 - js/src/vm/BooleanObject-inl.h | 9 +- js/src/vm/BooleanObject.h | 7 +- js/src/vm/ErrorObject.cpp | 12 +- js/src/vm/ErrorObject.h | 2 +- js/src/vm/Interpreter.cpp | 15 +- js/src/vm/NumberObject-inl.h | 9 +- js/src/vm/NumberObject.h | 7 +- js/src/vm/ObjectGroup.cpp | 55 ++-- js/src/vm/ObjectGroup.h | 5 +- js/src/vm/RegExpObject.cpp | 31 +-- js/src/vm/RegExpObject.h | 13 +- js/src/vm/StringObject-inl.h | 4 +- js/src/vm/StringObject.h | 1 - js/src/vm/TypedArrayCommon.h | 11 - js/src/vm/TypedArrayObject.cpp | 243 ++++-------------- js/src/vm/TypedArrayObject.h | 17 +- 50 files changed, 266 insertions(+), 806 deletions(-) create mode 100644 js/src/jit-test/tests/TypedObject/bug976697.js delete mode 100644 js/src/tests/ecma_6/Class/boundFunctionSubclassing.js delete mode 100644 js/src/tests/ecma_6/Class/extendBuiltinConstructors.js delete mode 100644 js/src/tests/ecma_6/Class/subclassedArrayUnboxed.js delete mode 100644 js/src/tests/ecma_6/DataView/detach-after-construction.js delete mode 100644 js/src/tests/ecma_6/RegExp/constructor-ordering-2.js delete mode 100644 js/src/tests/ecma_6/RegExp/constructor-ordering.js delete mode 100644 js/src/tests/ecma_6/TypedArray/constructor-non-detached.js delete mode 100644 js/src/tests/js1_5/Error/constructor-ordering.js diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index 5e82aeea2528c..1aaa9f4a57d5c 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -221,7 +221,7 @@ MapIteratorObject::next(JSContext* cx, Handle mapIterator, const Class MapObject::class_ = { "Map", - JSCLASS_HAS_PRIVATE | + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Map), nullptr, // addProperty nullptr, // delProperty @@ -412,20 +412,21 @@ MapObject::set(JSContext* cx, HandleObject obj, HandleValue k, HandleValue v) } MapObject* -MapObject::create(JSContext* cx, HandleObject proto /* = nullptr */) +MapObject::create(JSContext* cx) { - auto map = cx->make_unique(cx->runtime()); + Rooted obj(cx, NewBuiltinClassInstance(cx)); + if (!obj) + return nullptr; + + ValueMap* map = cx->new_(cx->runtime()); if (!map || !map->init()) { + js_delete(map); ReportOutOfMemory(cx); return nullptr; } - MapObject* mapObj = NewObjectWithClassProto(cx, proto); - if (!mapObj) - return nullptr; - - mapObj->setPrivate(map.release()); - return mapObj; + obj->setPrivate(map); + return obj; } void @@ -443,12 +444,7 @@ MapObject::construct(JSContext* cx, unsigned argc, Value* vp) if (!ThrowIfNotConstructing(cx, args, "Map")) return false; - RootedObject proto(cx); - RootedObject newTarget(cx, &args.newTarget().toObject()); - if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) - return false; - - Rooted obj(cx, MapObject::create(cx, proto)); + Rooted obj(cx, MapObject::create(cx)); if (!obj) return false; @@ -1068,19 +1064,19 @@ SetObject::add(JSContext* cx, HandleObject obj, HandleValue k) } SetObject* -SetObject::create(JSContext* cx, HandleObject proto /* = nullptr */) +SetObject::create(JSContext* cx) { - auto set = cx->make_unique(cx->runtime()); + SetObject* obj = NewBuiltinClassInstance(cx); + if (!obj) + return nullptr; + + ValueSet* set = cx->new_(cx->runtime()); if (!set || !set->init()) { + js_delete(set); ReportOutOfMemory(cx); return nullptr; } - - SetObject* obj = NewObjectWithClassProto(cx, proto); - if (!obj) - return nullptr; - - obj->setPrivate(set.release()); + obj->setPrivate(set); return obj; } @@ -1110,12 +1106,7 @@ SetObject::construct(JSContext* cx, unsigned argc, Value* vp) if (!ThrowIfNotConstructing(cx, args, "Set")) return false; - RootedObject proto(cx); - RootedObject newTarget(cx, &args.newTarget().toObject()); - if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) - return false; - - Rooted obj(cx, SetObject::create(cx, proto)); + Rooted obj(cx, SetObject::create(cx)); if (!obj) return false; diff --git a/js/src/builtin/MapObject.h b/js/src/builtin/MapObject.h index 1118675f8736f..835905594d8c7 100644 --- a/js/src/builtin/MapObject.h +++ b/js/src/builtin/MapObject.h @@ -92,7 +92,7 @@ class MapObject : public NativeObject { JS::AutoValueVector* entries); static bool entries(JSContext* cx, unsigned argc, Value* vp); static bool has(JSContext* cx, unsigned argc, Value* vp); - static MapObject* create(JSContext* cx, HandleObject proto = nullptr); + static MapObject* create(JSContext* cx); // Publicly exposed Map calls for JSAPI access (webidl maplike/setlike // interfaces, etc.) @@ -181,7 +181,7 @@ class SetObject : public NativeObject { // Publicly exposed Set calls for JSAPI access (webidl maplike/setlike // interfaces, etc.) - static SetObject* create(JSContext *cx, HandleObject proto = nullptr); + static SetObject* create(JSContext *cx); static uint32_t size(JSContext *cx, HandleObject obj); static bool has(JSContext *cx, HandleObject obj, HandleValue key, bool* rval); static bool clear(JSContext *cx, HandleObject obj); diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index cfdc652c7a8de..372c39ea4f6a5 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -33,12 +33,7 @@ js::obj_construct(JSContext* cx, unsigned argc, Value* vp) CallArgs args = CallArgsFromVp(argc, vp); RootedObject obj(cx, nullptr); - if (args.isConstructing() && (&args.newTarget().toObject() != &args.callee())) { - RootedObject newTarget(cx, &args.newTarget().toObject()); - obj = CreateThis(cx, &PlainObject::class_, newTarget); - if (!obj) - return false; - } else if (args.length() > 0 && !args[0].isNullOrUndefined()) { + if (args.length() > 0 && !args[0].isNullOrUndefined()) { obj = ToObject(cx, args[0]); if (!obj) return false; diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 2ddd1b1d43922..7df68daff9b5d 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -185,7 +185,7 @@ RegExpInitialize(JSContext* cx, Handle obj, HandleValue patternVa } /* Steps 11-15. */ - if (!RegExpObject::initFromAtom(cx, obj, pattern, flags)) + if (!InitializeRegExp(cx, obj, pattern, flags)) return false; /* Step 16. */ @@ -268,7 +268,7 @@ regexp_compile_impl(JSContext* cx, const CallArgs& args) } // Step 5. - if (!RegExpObject::initFromAtom(cx, regexp, sourceAtom, flags)) + if (!InitializeRegExp(cx, regexp, sourceAtom, flags)) return false; args.rval().setObject(*regexp); @@ -307,11 +307,11 @@ js::regexp_construct(JSContext* cx, unsigned argc, Value* vp) if (!IsRegExp(cx, args.get(0), &patternIsRegExp)) return false; + if (args.isConstructing()) { + // XXX Step 3! + } else { + // XXX Step 4a - // We can delay step 3 and step 4a until later, during - // GetPrototypeFromCallableConstructor calls. Accessing the new.target - // and the callee from the stack is unobservable. - if (!args.isConstructing()) { // Step 4b. if (patternIsRegExp && !args.hasDefined(1)) { RootedObject patternObj(cx, &args[0].toObject()); @@ -341,7 +341,6 @@ js::regexp_construct(JSContext* cx, unsigned argc, Value* vp) // don't reuse the RegExpShared below. RootedObject patternObj(cx, &patternValue.toObject()); - // Step 5 RootedAtom sourceAtom(cx); RegExpFlag flags; { @@ -354,30 +353,27 @@ js::regexp_construct(JSContext* cx, unsigned argc, Value* vp) if (!args.hasDefined(1)) { // Step 5b. flags = g->getFlags(); + } else { + // Step 5c. + // XXX We shouldn't be converting to string yet! This must + // come *after* the .constructor access in step 8. + flags = RegExpFlag(0); + RootedString flagStr(cx, ToString(cx, args[1])); + if (!flagStr) + return false; + if (!ParseRegExpFlags(cx, flagStr, &flags)) + return false; } } // Steps 8-9. - RootedObject proto(cx); - if (!GetPrototypeFromCallableConstructor(cx, args, &proto)) - return false; - - Rooted regexp(cx, RegExpAlloc(cx, proto)); + // XXX Note bug in step 5c, with respect to step 8. + Rooted regexp(cx, RegExpAlloc(cx)); if (!regexp) return false; // Step 10. - if (args.hasDefined(1)) { - // Step 5c / 21.2.3.2.2 RegExpInitialize step 5. - flags = RegExpFlag(0); - RootedString flagStr(cx, ToString(cx, args[1])); - if (!flagStr) - return false; - if (!ParseRegExpFlags(cx, flagStr, &flags)) - return false; - } - - if (!RegExpObject::initFromAtom(cx, regexp, sourceAtom, flags)) + if (!InitializeRegExp(cx, regexp, sourceAtom, flags)) return false; args.rval().setObject(*regexp); @@ -408,11 +404,7 @@ js::regexp_construct(JSContext* cx, unsigned argc, Value* vp) } // Steps 8-9. - RootedObject proto(cx); - if (!GetPrototypeFromCallableConstructor(cx, args, &proto)) - return false; - - Rooted regexp(cx, RegExpAlloc(cx, proto)); + Rooted regexp(cx, RegExpAlloc(cx)); if (!regexp) return false; @@ -709,9 +701,7 @@ js::CreateRegExpPrototype(JSContext* cx, JSProtoKey key) proto->NativeObject::setPrivate(nullptr); RootedAtom source(cx, cx->names().empty); - if (!RegExpObject::initFromAtom(cx, proto, source, RegExpFlag(0))) - return nullptr; - return proto; + return InitializeRegExp(cx, proto, source, RegExpFlag(0)); } static bool diff --git a/js/src/builtin/WeakMapObject.cpp b/js/src/builtin/WeakMapObject.cpp index f948728538831..240398b71be52 100644 --- a/js/src/builtin/WeakMapObject.cpp +++ b/js/src/builtin/WeakMapObject.cpp @@ -316,8 +316,7 @@ WeakMap_construct(JSContext* cx, unsigned argc, Value* vp) if (!ThrowIfNotConstructing(cx, args, "WeakMap")) return false; - RootedObject newTarget(cx, &args.newTarget().toObject()); - RootedObject obj(cx, CreateThis(cx, &WeakMapObject::class_, newTarget)); + RootedObject obj(cx, NewBuiltinClassInstance(cx, &WeakMapObject::class_)); if (!obj) return false; diff --git a/js/src/builtin/WeakSetObject.cpp b/js/src/builtin/WeakSetObject.cpp index 4f748d78eb8a2..0642bef03e674 100644 --- a/js/src/builtin/WeakSetObject.cpp +++ b/js/src/builtin/WeakSetObject.cpp @@ -61,14 +61,14 @@ WeakSetObject::initClass(JSContext* cx, JSObject* obj) } WeakSetObject* -WeakSetObject::create(JSContext* cx, HandleObject proto /* = nullptr */) +WeakSetObject::create(JSContext* cx) { - RootedObject map(cx, NewBuiltinClassInstance(cx)); - if (!map) + Rooted obj(cx, NewBuiltinClassInstance(cx)); + if (!obj) return nullptr; - WeakSetObject* obj = NewObjectWithClassProto(cx, proto); - if (!obj) + RootedObject map(cx, JS::NewWeakMapObject(cx)); + if (!map) return nullptr; obj->setReservedSlot(WEAKSET_MAP_SLOT, ObjectValue(*map)); @@ -78,21 +78,16 @@ WeakSetObject::create(JSContext* cx, HandleObject proto /* = nullptr */) bool WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp) { + Rooted obj(cx, WeakSetObject::create(cx)); + if (!obj) + return false; + // Based on our "Set" implementation instead of the more general ES6 steps. CallArgs args = CallArgsFromVp(argc, vp); if (!ThrowIfNotConstructing(cx, args, "WeakSet")) return false; - RootedObject proto(cx); - RootedObject newTarget(cx, &args.newTarget().toObject()); - if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) - return false; - - Rooted obj(cx, WeakSetObject::create(cx, proto)); - if (!obj) - return false; - if (!args.get(0).isNullOrUndefined()) { RootedObject map(cx, &obj->getReservedSlot(WEAKSET_MAP_SLOT).toObject()); diff --git a/js/src/builtin/WeakSetObject.h b/js/src/builtin/WeakSetObject.h index 9aa4fc51d63d3..308b67e67fc4f 100644 --- a/js/src/builtin/WeakSetObject.h +++ b/js/src/builtin/WeakSetObject.h @@ -23,7 +23,7 @@ class WeakSetObject : public NativeObject static const JSPropertySpec properties[]; static const JSFunctionSpec methods[]; - static WeakSetObject* create(JSContext* cx, HandleObject proto = nullptr); + static WeakSetObject* create(JSContext* cx); static bool construct(JSContext* cx, unsigned argc, Value* vp); }; diff --git a/js/src/jit-test/tests/TypedObject/bug976697.js b/js/src/jit-test/tests/TypedObject/bug976697.js new file mode 100644 index 0000000000000..fa1a5de55172c --- /dev/null +++ b/js/src/jit-test/tests/TypedObject/bug976697.js @@ -0,0 +1,15 @@ +// Test that instantiating a typed array on top of a neutered buffer +// doesn't trip any asserts. +// +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +x = new ArrayBuffer(); +neuter(x, "same-data"); +new Uint32Array(x); +gc(); + +x = new ArrayBuffer(); +neuter(x, "change-data"); +new Uint32Array(x); +gc(); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index e5247b49d374b..247faac70f27f 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -8278,7 +8278,7 @@ GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args, if (native == StringConstructor) { RootedString emptyString(cx, cx->runtime()->emptyString); - res.set(StringObject::create(cx, emptyString, /* proto = */ nullptr, TenuredObject)); + res.set(StringObject::create(cx, emptyString, TenuredObject)); return !!res; } diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 56f193b809ed9..fa2b8233c70a3 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -3060,9 +3060,9 @@ IsArrayConstructor(const Value& v) } static bool -ArrayFromCallArgs(JSContext* cx, CallArgs& args, HandleObject proto = nullptr) +ArrayFromCallArgs(JSContext* cx, CallArgs& args) { - JSObject* obj = NewCopiedArrayForCallingAllocationSite(cx, args.array(), args.length(), proto); + JSObject* obj = NewCopiedArrayForCallingAllocationSite(cx, args.array(), args.length()); if (!obj) return false; @@ -3183,12 +3183,8 @@ js::ArrayConstructor(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - RootedObject proto(cx); - if (!GetPrototypeFromCallableConstructor(cx, args, &proto)) - return false; - if (args.length() != 1 || !args[0].isNumber()) - return ArrayFromCallArgs(cx, args, proto); + return ArrayFromCallArgs(cx, args); uint32_t length; if (args[0].isInt32()) { @@ -3207,7 +3203,7 @@ js::ArrayConstructor(JSContext* cx, unsigned argc, Value* vp) } } - JSObject* obj = NewPartlyAllocatedArrayForCallingAllocationSite(cx, length, proto); + JSObject* obj = NewPartlyAllocatedArrayForCallingAllocationSite(cx, length); if (!obj) return false; @@ -3494,9 +3490,7 @@ js::NewDenseCopyOnWriteArray(JSContext* cx, HandleArrayObject templateObject, gc } // Return a new boxed or unboxed array with the specified length and allocated -// capacity (up to maxLength), using the specified group if possible. If the -// specified group cannot be used, ensure that the created array at least has -// the given [[Prototype]]. +// capacity (up to maxLength), using the specified group if possible. template static inline JSObject* NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length, @@ -3511,10 +3505,9 @@ NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length newKind = TenuredObject; if (group->maybeUnboxedLayout()) { - if (length > UnboxedArrayObject::MaximumCapacity) { - RootedObject proto(cx, group->proto().toObject()); - return NewArray(cx, length, proto, newKind); - } + if (length > UnboxedArrayObject::MaximumCapacity) + return NewArray(cx, length, nullptr, newKind); + return UnboxedArrayObject::create(cx, group, length, newKind, maxLength); } @@ -3597,9 +3590,9 @@ js::NewFullyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, } JSObject* -js::NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, HandleObject proto) +js::NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length) { - RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array, proto)); + RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array)); if (!group) return nullptr; return NewArrayTryUseGroup(cx, group, length); @@ -3659,10 +3652,9 @@ js::NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, } JSObject* -js::NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length, - HandleObject proto /* = nullptr */) +js::NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length) { - RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array, proto)); + RootedObjectGroup group(cx, ObjectGroup::callingAllocationSiteGroup(cx, JSProto_Array)); if (!group) return nullptr; return NewCopiedArrayTryUseGroup(cx, group, vp, length); diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 160be920b6a3a..957c32ffaaeeb 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -101,7 +101,7 @@ NewFullyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, bool forceAnalyze = false); extern JSObject* -NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length, HandleObject proto); +NewPartlyAllocatedArrayForCallingAllocationSite(JSContext* cx, size_t length); enum class ShouldUpdateTypes { @@ -116,8 +116,7 @@ NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update); extern JSObject* -NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length, - HandleObject proto = nullptr); +NewCopiedArrayForCallingAllocationSite(JSContext* cx, const Value* vp, size_t length); /* * Determines whether a write to the given element on |obj| should fail because diff --git a/js/src/jsbool.cpp b/js/src/jsbool.cpp index c8109b02c288a..b5cd8ad404ccf 100644 --- a/js/src/jsbool.cpp +++ b/js/src/jsbool.cpp @@ -116,13 +116,7 @@ Boolean(JSContext* cx, unsigned argc, Value* vp) bool b = args.length() != 0 ? JS::ToBoolean(args[0]) : false; if (args.isConstructing()) { - RootedObject newTarget (cx, &args.newTarget().toObject()); - RootedObject proto(cx); - - if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) - return false; - - JSObject* obj = BooleanObject::create(cx, b, proto); + JSObject* obj = BooleanObject::create(cx, b); if (!obj) return false; args.rval().setObject(*obj); diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 6c7859b426d83..963f211593df6 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -3016,14 +3016,7 @@ static const JSFunctionSpec date_methods[] = { static bool NewDateObject(JSContext* cx, const CallArgs& args, ClippedTime t) { - MOZ_ASSERT(args.isConstructing()); - - RootedObject proto(cx); - RootedObject newTarget(cx, &args.newTarget().toObject()); - if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) - return false; - - JSObject* obj = NewDateObjectMsec(cx, t, proto); + JSObject* obj = NewDateObjectMsec(cx, t); if (!obj) return false; @@ -3267,9 +3260,9 @@ const Class DateObject::protoClass_ = { }; JSObject* -js::NewDateObjectMsec(JSContext* cx, ClippedTime t, HandleObject proto /* = nullptr */) +js::NewDateObjectMsec(JSContext* cx, ClippedTime t) { - JSObject* obj = NewObjectWithClassProto(cx, &DateObject::class_, proto); + JSObject* obj = NewBuiltinClassInstance(cx, &DateObject::class_); if (!obj) return nullptr; obj->as().setUTCTime(t); diff --git a/js/src/jsdate.h b/js/src/jsdate.h index 7dc62b4711368..29bde83bb237b 100644 --- a/js/src/jsdate.h +++ b/js/src/jsdate.h @@ -30,7 +30,7 @@ namespace js { * since the epoch. */ extern JSObject* -NewDateObjectMsec(JSContext* cx, JS::ClippedTime t, JS::HandleObject proto = nullptr); +NewDateObjectMsec(JSContext* cx, JS::ClippedTime t); /* * Construct a new Date Object from an exploded local time value. diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index ee1e16b86e9c9..8af3d0a0585d9 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -338,11 +338,6 @@ Error(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - // ES6 19.5.1.1 mandates the .prototype lookup happens before the toString - RootedObject proto(cx); - if (!GetPrototypeFromCallableConstructor(cx, args, &proto)) - return false; - /* Compute the error message, if any. */ RootedString message(cx, nullptr); if (args.hasDefined(0)) { @@ -394,7 +389,7 @@ Error(JSContext* cx, unsigned argc, Value* vp) JSExnType exnType = JSExnType(args.callee().as().getExtendedSlot(0).toInt32()); RootedObject obj(cx, ErrorObject::create(cx, exnType, stack, fileName, - lineNumber, columnNumber, nullptr, message, proto)); + lineNumber, columnNumber, nullptr, message)); if (!obj) return false; diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index b6d2f468ea892..4c0132b3edac5 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1592,22 +1592,6 @@ fun_isGenerator(JSContext* cx, unsigned argc, Value* vp) return true; } -static JSFunction* -NewNativeFunctionWithGivenProto(JSContext* cx, Native native, unsigned nargs, - HandleAtom atom, HandleObject proto) -{ - return NewFunctionWithProto(cx, native, nargs, JSFunction::NATIVE_FUN, nullptr, atom, proto, - AllocKind::FUNCTION, GenericObject, NewFunctionGivenProto); -} - -static JSFunction* -NewNativeConstructorWithGivenProto(JSContext* cx, Native native, unsigned nargs, - HandleAtom atom, HandleObject proto) -{ - return NewFunctionWithProto(cx, native, nargs, JSFunction::NATIVE_CTOR, nullptr, atom, proto, - AllocKind::FUNCTION, GenericObject, NewFunctionGivenProto); -} - // ES6 draft rev32 19.2.3.2 bool js::fun_bind(JSContext* cx, unsigned argc, Value* vp) @@ -1634,11 +1618,6 @@ js::fun_bind(JSContext* cx, unsigned argc, Value* vp) RootedValue thisArg(cx, args.length() >= 1 ? args[0] : UndefinedValue()); RootedObject target(cx, &thisv.toObject()); - // This is part of step 4, but we're delaying allocating the function object. - RootedObject proto(cx); - if (!GetPrototype(cx, target, &proto)) - return false; - double length = 0.0; // Try to avoid invoking the resolve hook. if (target->is() && !target->as().hasResolvedLength()) { @@ -1694,8 +1673,8 @@ js::fun_bind(JSContext* cx, unsigned argc, Value* vp) // Step 4. RootedFunction fun(cx, target->isConstructor() ? - NewNativeConstructorWithGivenProto(cx, CallOrConstructBoundFunction, length, nameAtom, proto) : - NewNativeFunctionWithGivenProto(cx, CallOrConstructBoundFunction, length, nameAtom, proto)); + NewNativeConstructor(cx, CallOrConstructBoundFunction, length, nameAtom) : + NewNativeFunction(cx, CallOrConstructBoundFunction, length, nameAtom)); if (!fun) return false; @@ -1862,11 +1841,7 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global); if (!proto) return false; - } else { - if (!GetPrototypeFromCallableConstructor(cx, args, &proto)) - return false; } - RootedObject globalLexical(cx, &global->lexicalScope()); RootedFunction fun(cx, NewFunctionWithProto(cx, nullptr, 0, JSFunction::INTERPRETED_LAMBDA, globalLexical, @@ -2038,8 +2013,7 @@ js::NewFunctionWithProto(ExclusiveContext* cx, Native native, unsigned nargs, JSFunction::Flags flags, HandleObject enclosingDynamicScope, HandleAtom atom, HandleObject proto, gc::AllocKind allocKind /* = AllocKind::FUNCTION */, - NewObjectKind newKind /* = GenericObject */, - NewFunctionProtoHandling protoHandling /* = NewFunctionClassProto */) + NewObjectKind newKind /* = GenericObject */) { MOZ_ASSERT(allocKind == AllocKind::FUNCTION || allocKind == AllocKind::FUNCTION_EXTENDED); MOZ_ASSERT_IF(native, !enclosingDynamicScope); @@ -2051,14 +2025,8 @@ js::NewFunctionWithProto(ExclusiveContext* cx, Native native, // isSingleton implies isInterpreted. if (native && !IsAsmJSModuleNative(native)) newKind = SingletonObject; - - if (protoHandling == NewFunctionClassProto) { - funobj = NewObjectWithClassProto(cx, &JSFunction::class_, proto, allocKind, - newKind); - } else { - funobj = NewObjectWithGivenTaggedProto(cx, &JSFunction::class_, AsTaggedProto(proto), - allocKind, newKind); - } + funobj = NewObjectWithClassProto(cx, &JSFunction::class_, proto, allocKind, + newKind); if (!funobj) return nullptr; diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 3cae99e53c555..26586bd1eea06 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -632,23 +632,15 @@ NewScriptedFunction(ExclusiveContext* cx, unsigned nargs, JSFunction::Flags flag NewObjectKind newKind = GenericObject, HandleObject enclosingDynamicScope = nullptr); -// By default, if proto is nullptr, Function.prototype is used instead.i -// If protoHandling is NewFunctionExactProto, and proto is nullptr, the created -// function will use nullptr as its [[Prototype]] instead. If +// If proto is nullptr, Function.prototype is used instead. If // enclosingDynamicScope is null, the function will have a null environment() // (yes, null, not the global). In all cases, the global will be used as the // parent. - -enum NewFunctionProtoHandling { - NewFunctionClassProto, - NewFunctionGivenProto -}; extern JSFunction* NewFunctionWithProto(ExclusiveContext* cx, JSNative native, unsigned nargs, JSFunction::Flags flags, HandleObject enclosingDynamicScope, HandleAtom atom, HandleObject proto, gc::AllocKind allocKind = gc::AllocKind::FUNCTION, - NewObjectKind newKind = GenericObject, - NewFunctionProtoHandling protoHandling = NewFunctionClassProto); + NewObjectKind newKind = GenericObject); extern JSAtom* IdToFunctionName(JSContext* cx, HandleId id); diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 68c70a028a536..1b90adb581fc7 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -488,11 +488,7 @@ Number(JSContext* cx, unsigned argc, Value* vp) if (!isConstructing) return true; - RootedObject newTarget(cx, &args.newTarget().toObject()); - RootedObject proto(cx); - if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) - return false; - JSObject* obj = NumberObject::create(cx, args.rval().toNumber(), proto); + JSObject* obj = NumberObject::create(cx, args.rval().toNumber()); if (!obj) return false; args.rval().setObject(*obj); diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 5d8482c30865e..b435c94d376cf 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -883,9 +883,11 @@ js::NewObjectScriptedCall(JSContext* cx, MutableHandleObject pobj) JSObject* js::CreateThis(JSContext* cx, const Class* newclasp, HandleObject callee) { - RootedObject proto(cx); - if (!GetPrototypeFromConstructor(cx, callee, &proto)) + RootedValue protov(cx); + if (!GetProperty(cx, callee, callee, cx->names().prototype, &protov)) return nullptr; + + RootedObject proto(cx, protov.isObjectOrNull() ? protov.toObjectOrNull() : nullptr); gc::AllocKind kind = NewObjectGCKind(newclasp); return NewObjectWithClassProto(cx, newclasp, proto, kind); } @@ -987,35 +989,16 @@ js::CreateThisForFunctionWithProto(JSContext* cx, HandleObject callee, HandleObj return res; } -bool -js::GetPrototypeFromConstructor(JSContext* cx, HandleObject newTarget, MutableHandleObject proto) -{ - RootedValue protov(cx); - if (!GetProperty(cx, newTarget, newTarget, cx->names().prototype, &protov)) - return false; - proto.set(protov.isObject() ? &protov.toObject() : nullptr); - return true; -} - -bool -js::GetPrototypeFromCallableConstructor(JSContext* cx, const CallArgs& args, MutableHandleObject proto) -{ - RootedObject newTarget(cx); - if (args.isConstructing()) - newTarget = &args.newTarget().toObject(); - else - newTarget = &args.callee(); - return GetPrototypeFromConstructor(cx, newTarget, proto); -} - JSObject* js::CreateThisForFunction(JSContext* cx, HandleObject callee, HandleObject newTarget, NewObjectKind newKind) { - RootedObject proto(cx); - if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) + RootedValue protov(cx); + if (!GetProperty(cx, newTarget, newTarget, cx->names().prototype, &protov)) return nullptr; - + RootedObject proto(cx); + if (protov.isObject()) + proto = &protov.toObject(); JSObject* obj = CreateThisForFunctionWithProto(cx, callee, newTarget, proto, newKind); if (obj && newKind == SingletonObject) { diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 6e0727f29c321..705efbc4bbf78 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -1100,13 +1100,6 @@ GetInitialHeap(NewObjectKind newKind, const Class* clasp) return gc::DefaultHeap; } -// ES6 9.1.15 GetPrototypeFromConstructor. -extern bool -GetPrototypeFromConstructor(JSContext* cx, js::HandleObject newTarget, js::MutableHandleObject proto); - -extern bool -GetPrototypeFromCallableConstructor(JSContext* cx, const CallArgs& args, js::MutableHandleObject proto); - // Specialized call for constructing |this| with a known function callee, // and a known prototype. extern JSObject* diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 0b352e6b3cc00..9067a2bca0191 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -687,24 +687,6 @@ NewObjectWithClassProto(ExclusiveContext* cx, const Class* clasp, HandleObject p return NewObjectWithClassProto(cx, clasp, proto, allocKind, newKind); } -template -inline T* -NewObjectWithClassProto(ExclusiveContext* cx, HandleObject proto, - NewObjectKind newKind = GenericObject) -{ - JSObject* obj = NewObjectWithClassProto(cx, &T::class_, proto, newKind); - return obj ? &obj->as() : nullptr; -} - -template -inline T* -NewObjectWithClassProto(ExclusiveContext* cx, HandleObject proto, gc::AllocKind allocKind, - NewObjectKind newKind = GenericObject) -{ - JSObject* obj = NewObjectWithClassProto(cx, &T::class_, proto, allocKind, newKind); - return obj ? &obj->as() : nullptr; -} - /* * Create a native instance of the given class with parent and proto set * according to the context's active global. diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index fb22c7cf643d3..b531f928b0a17 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -4081,12 +4081,7 @@ js::StringConstructor(JSContext* cx, unsigned argc, Value* vp) } if (args.isConstructing()) { - RootedObject proto(cx); - RootedObject newTarget(cx, &args.newTarget().toObject()); - if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) - return false; - - StringObject* strobj = StringObject::create(cx, str, proto); + StringObject* strobj = StringObject::create(cx, str); if (!strobj) return false; args.rval().setObject(*strobj); diff --git a/js/src/tests/ecma_6/Class/boundFunctionSubclassing.js b/js/src/tests/ecma_6/Class/boundFunctionSubclassing.js deleted file mode 100644 index fa5544f8d3e79..0000000000000 --- a/js/src/tests/ecma_6/Class/boundFunctionSubclassing.js +++ /dev/null @@ -1,24 +0,0 @@ -var test = ` - -class func extends Function { } -let inst = new func("x", "return this.bar + x"); - -// First, ensure that we get sane prototype chains for the bound instance -let bound = inst.bind({bar: 3}, 4); -assertEq(bound instanceof func, true); -assertEq(bound(), 7); - -// Check the corner case for Function.prototype.bind where the function has -// a null [[Prototype]] -Object.setPrototypeOf(inst, null); -bound = Function.prototype.bind.call(inst, {bar:1}, 3); -assertEq(Object.getPrototypeOf(bound), null); -assertEq(bound(), 4); - -`; - -if (classesEnabled()) - eval(test); - -if (typeof reportCompare === 'function') - reportCompare(0,0,"OK"); diff --git a/js/src/tests/ecma_6/Class/extendBuiltinConstructors.js b/js/src/tests/ecma_6/Class/extendBuiltinConstructors.js deleted file mode 100644 index 22c548c3703be..0000000000000 --- a/js/src/tests/ecma_6/Class/extendBuiltinConstructors.js +++ /dev/null @@ -1,86 +0,0 @@ -var test = ` - -function testBuiltin(builtin, ...args) { - class inst extends builtin { - constructor(...args) { - super(...args); - this.called = true; - } - } - - let instance = new inst(...args); - assertEq(instance instanceof inst, true); - assertEq(instance instanceof builtin, true); - assertEq(instance.called, true); - return instance; -} - -function testBuiltinTypedArrays() { - let typedArrays = [Int8Array, - Uint8Array, - Uint8ClampedArray, - Int16Array, - Uint16Array, - Int32Array, - Uint32Array, - Float32Array, - Float64Array]; - - for (let array of typedArrays) { - testBuiltin(array); - testBuiltin(array, 5); - testBuiltin(array, new array()); - testBuiltin(array, new ArrayBuffer()); - } -} - -function testBuiltinArray() { - let argsLists = [ - [], - [15], - [3.0], - ["non-length one-arg"], - [5, 10, 15, "these are elements"] - ]; - - for (let args of argsLists) { - let instance = testBuiltin(Array, ...args); - assertEq(Array.isArray(instance), true); - } -} - -testBuiltin(Function); -testBuiltin(Object); -testBuiltin(Boolean); -testBuiltin(Error); -testBuiltin(EvalError); -testBuiltin(RangeError); -testBuiltin(ReferenceError); -testBuiltin(SyntaxError); -testBuiltin(TypeError); -testBuiltin(URIError); -testBuiltin(Number); -testBuiltin(Date); -testBuiltin(Date, 5); -testBuiltin(Date, 5, 10); -testBuiltin(RegExp); -testBuiltin(RegExp, /Regexp Argument/); -testBuiltin(RegExp, "String Argument"); -testBuiltin(Map); -testBuiltin(Set); -testBuiltin(WeakMap); -testBuiltin(WeakSet); -testBuiltin(ArrayBuffer); -testBuiltinTypedArrays(); -testBuiltin(DataView, new ArrayBuffer()); -testBuiltin(DataView, new (newGlobal().ArrayBuffer)()); -testBuiltin(String); -testBuiltinArray(); - -`; - -if (classesEnabled()) - eval(test); - -if (typeof reportCompare === 'function') - reportCompare(0,0,"OK"); diff --git a/js/src/tests/ecma_6/Class/subclassedArrayUnboxed.js b/js/src/tests/ecma_6/Class/subclassedArrayUnboxed.js deleted file mode 100644 index 00e812e94595a..0000000000000 --- a/js/src/tests/ecma_6/Class/subclassedArrayUnboxed.js +++ /dev/null @@ -1,29 +0,0 @@ -var test = ` - -class foo extends Array { } - -function testArrs(arrs) { - for (let arr of arrs) { - assertEq(Object.getPrototypeOf(arr), foo.prototype); - } -} - -var arrs = []; -for (var i = 0; i < 25; i++) - arrs.push(new foo(1)); - -testArrs(arrs); - -arrs[0].nonIndexedProp = "uhoh"; - -arrs.push(new foo(1)); - -testArrs(arrs); - -`; - -if (classesEnabled()) - eval(test); - -if (typeof reportCompare === 'function') - reportCompare(0,0,"OK"); diff --git a/js/src/tests/ecma_6/Class/superCallBaseInvoked.js b/js/src/tests/ecma_6/Class/superCallBaseInvoked.js index 59ef23650dc35..807b132000be5 100644 --- a/js/src/tests/ecma_6/Class/superCallBaseInvoked.js +++ b/js/src/tests/ecma_6/Class/superCallBaseInvoked.js @@ -53,6 +53,8 @@ testBase(p); handler.construct = (target, args, nt) => Reflect.construct(target, args, nt); testBase(p); +// Object will have to wait for fixed builtins. + `; if (classesEnabled()) diff --git a/js/src/tests/ecma_6/DataView/detach-after-construction.js b/js/src/tests/ecma_6/DataView/detach-after-construction.js deleted file mode 100644 index 32a272579a629..0000000000000 --- a/js/src/tests/ecma_6/DataView/detach-after-construction.js +++ /dev/null @@ -1,11 +0,0 @@ -for (var neuterArg of ['change-data', 'same-data']) { - var buf = new ArrayBuffer([1,2]); - var bufView = new DataView(buf); - - neuter(buf, neuterArg); - - assertThrowsInstanceOf(()=>bufView.getInt8(0), TypeError); -} - -if (typeof reportCompare === 'function') - reportCompare(0,0,"OK"); diff --git a/js/src/tests/ecma_6/Reflect/construct.js b/js/src/tests/ecma_6/Reflect/construct.js index 32a8b712301ea..00473d591f67a 100644 --- a/js/src/tests/ecma_6/Reflect/construct.js +++ b/js/src/tests/ecma_6/Reflect/construct.js @@ -101,7 +101,9 @@ for (var v of SOME_PRIMITIVE_VALUES.concat(nonConstructors)) { // creates a real array object. function someConstructor() {} var result = Reflect.construct(Array, [], someConstructor); -assertEq(Reflect.getPrototypeOf(result), someConstructor.prototype); +assertEq(Reflect.getPrototypeOf(result), + Array.prototype, // should be someConstructor.prototype, per ES6 22.1.1.1 Array() + "Congratulations on implementing Array subclassing! Fix this test for +1 karma point."); assertEq(result.length, 0); assertEq(Array.isArray(result), true); diff --git a/js/src/tests/ecma_6/RegExp/constructor-ordering-2.js b/js/src/tests/ecma_6/RegExp/constructor-ordering-2.js deleted file mode 100644 index 21a6bbeca745a..0000000000000 --- a/js/src/tests/ecma_6/RegExp/constructor-ordering-2.js +++ /dev/null @@ -1,21 +0,0 @@ -// Make sure that we don't ToString the second argument until /after/ doing -// the appropriate subclassing lookups - -var didLookup = false; - -var re = /a/; -var flags = { toString() { assertEq(didLookup, true); return "g"; } }; -var newRe = Reflect.construct(RegExp, [re, flags], - Object.defineProperty(function(){}.bind(null), "prototype", { - get() { - didLookup = true; - return RegExp.prototype; - } -})); - -assertEq(Object.getPrototypeOf(newRe), RegExp.prototype); -assertEq(didLookup, true); - - -if (typeof reportCompare === 'function') - reportCompare(0,0,"OK"); diff --git a/js/src/tests/ecma_6/RegExp/constructor-ordering.js b/js/src/tests/ecma_6/RegExp/constructor-ordering.js deleted file mode 100644 index 3e3a9b695b319..0000000000000 --- a/js/src/tests/ecma_6/RegExp/constructor-ordering.js +++ /dev/null @@ -1,16 +0,0 @@ -// Make sure that we don't misorder subclassing accesses with respect to -// accessing regex arg internal slots -// -// Test credit André Bargull. - -var re = /a/; -var newRe = Reflect.construct(RegExp, [re], Object.defineProperty(function(){}.bind(null), "prototype", { - get() { - re.compile("b"); - return RegExp.prototype; - } -})); -assertEq(newRe.source, "a"); - -if (typeof reportCompare === 'function') - reportCompare(0,0,"OK"); diff --git a/js/src/tests/ecma_6/TypedArray/constructor-non-detached.js b/js/src/tests/ecma_6/TypedArray/constructor-non-detached.js deleted file mode 100644 index 73c9ffb6a7238..0000000000000 --- a/js/src/tests/ecma_6/TypedArray/constructor-non-detached.js +++ /dev/null @@ -1,27 +0,0 @@ -const constructors = [ - Int8Array, - Uint8Array, - Uint8ClampedArray, - Int16Array, - Uint16Array, - Int32Array, - Uint32Array, - Float32Array, - Float64Array -]; - -for (var constructor of constructors) { - for (var neuterType of ["change-data", "same-data"]) { - var buf = new constructor(); - neuter(buf.buffer, neuterType); - assertThrowsInstanceOf(()=> new constructor(buf), TypeError); - - var buffer = new ArrayBuffer(); - neuter(buffer, neuterType); - assertThrowsInstanceOf(()=> new constructor(buffer), TypeError); - } -} - - -if (typeof reportCompare === "function") - reportCompare(true, true); diff --git a/js/src/tests/js1_5/Error/constructor-ordering.js b/js/src/tests/js1_5/Error/constructor-ordering.js deleted file mode 100644 index dbcc2e6048acc..0000000000000 --- a/js/src/tests/js1_5/Error/constructor-ordering.js +++ /dev/null @@ -1,17 +0,0 @@ -var order = 0; -function assertOrdering(ordering) { - assertEq(order, ordering); - order++; -} - -// Spec mandates that the prototype is looked up /before/ we toString the -// argument. -var handler = { get() { assertOrdering(0); return Error.prototype } }; -var errorProxy = new Proxy(Error, handler); - -var toStringable = { toString() { assertOrdering(1); return "Argument"; } }; - -new errorProxy(toStringable); - -if (typeof reportCompare === 'function') - reportCompare(0,0,"OK"); diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index 40144a99bec32..d68ddae867a99 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -476,12 +476,7 @@ ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp) return false; } - RootedObject proto(cx); - RootedObject newTarget(cx, &args.newTarget().toObject()); - if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) - return false; - - JSObject* bufobj = create(cx, uint32_t(nbytes), proto); + JSObject* bufobj = create(cx, uint32_t(nbytes)); if (!bufobj) return false; args.rval().setObject(*bufobj); @@ -790,7 +785,6 @@ ArrayBufferObject::setFlags(uint32_t flags) ArrayBufferObject* ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents contents, OwnsState ownsState /* = OwnsData */, - HandleObject proto /* = nullptr */, NewObjectKind newKind /* = GenericObject */) { MOZ_ASSERT_IF(contents.kind() == MAPPED, contents); @@ -831,8 +825,7 @@ ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents content gc::AllocKind allocKind = GetGCObjectKind(nslots); AutoSetNewObjectMetadata metadata(cx); - Rooted obj(cx, - NewObjectWithClassProto(cx, proto, allocKind, newKind)); + Rooted obj(cx, NewBuiltinClassInstance(cx, allocKind, newKind)); if (!obj) { if (allocated) js_free(contents.data()); @@ -855,11 +848,9 @@ ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents content ArrayBufferObject* ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, - HandleObject proto /* = nullptr */, NewObjectKind newKind /* = GenericObject */) { - return create(cx, nbytes, BufferContents::createPlain(nullptr), - OwnsState::OwnsData, proto); + return create(cx, nbytes, BufferContents::createPlain(nullptr)); } JSObject* @@ -891,25 +882,21 @@ ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args /* * This method is only called for |DataView(alienBuf, ...)| which calls - * this as |createDataViewForThis.call(alienBuf, byteOffset, byteLength, - * DataView.prototype)|, - * ergo there must be exactly 3 arguments. + * this as |createDataViewForThis.call(alienBuf, ..., DataView.prototype)|, + * ergo there must be at least two arguments. */ - MOZ_ASSERT(args.length() == 3); + MOZ_ASSERT(args.length() >= 2); + + Rooted proto(cx, &args[args.length() - 1].toObject()); - uint32_t byteOffset = args[0].toPrivateUint32(); - uint32_t byteLength = args[1].toPrivateUint32(); - Rooted buffer(cx, &args.thisv().toObject().as()); + Rooted buffer(cx, &args.thisv().toObject()); /* * Pop off the passed-along prototype and delegate to normal DataViewObject * construction. */ - JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, &args[2].toObject()); - if (!obj) - return false; - args.rval().setObject(*obj); - return true; + CallArgs frobbedArgs = CallArgsFromVp(args.length() - 1, args.base()); + return DataViewObject::construct(cx, buffer, frobbedArgs, proto); } bool @@ -1401,8 +1388,7 @@ JS_NewArrayBufferWithContents(JSContext* cx, size_t nbytes, void* data) MOZ_ASSERT_IF(!data, nbytes == 0); ArrayBufferObject::BufferContents contents = ArrayBufferObject::BufferContents::create(data); - return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::OwnsData, - /* proto = */ nullptr, TenuredObject); + return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::OwnsData, TenuredObject); } JS_FRIEND_API(bool) @@ -1467,8 +1453,7 @@ JS_NewMappedArrayBufferWithContents(JSContext* cx, size_t nbytes, void* data) MOZ_ASSERT(data); ArrayBufferObject::BufferContents contents = ArrayBufferObject::BufferContents::create(data); - return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::OwnsData, - /* proto = */ nullptr, TenuredObject); + return ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::OwnsData, TenuredObject); } JS_PUBLIC_API(void*) diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h index 23f4754e15c05..998ed35bda3a8 100644 --- a/js/src/vm/ArrayBufferObject.h +++ b/js/src/vm/ArrayBufferObject.h @@ -218,10 +218,8 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared static ArrayBufferObject* create(JSContext* cx, uint32_t nbytes, BufferContents contents, OwnsState ownsState = OwnsData, - HandleObject proto = nullptr, NewObjectKind newKind = GenericObject); static ArrayBufferObject* create(JSContext* cx, uint32_t nbytes, - HandleObject proto = nullptr, NewObjectKind newKind = GenericObject); static JSObject* createSlice(JSContext* cx, Handle arrayBuffer, diff --git a/js/src/vm/BooleanObject-inl.h b/js/src/vm/BooleanObject-inl.h index c5e0f75381fa4..c8be7646e430b 100644 --- a/js/src/vm/BooleanObject-inl.h +++ b/js/src/vm/BooleanObject-inl.h @@ -14,13 +14,14 @@ namespace js { inline BooleanObject* -BooleanObject::create(JSContext* cx, bool b, HandleObject proto /* = nullptr */) +BooleanObject::create(JSContext* cx, bool b) { - BooleanObject* obj = NewObjectWithClassProto(cx, proto); + JSObject* obj = NewBuiltinClassInstance(cx, &class_); if (!obj) return nullptr; - obj->setPrimitiveValue(b); - return obj; + BooleanObject& boolobj = obj->as(); + boolobj.setPrimitiveValue(b); + return &boolobj; } } // namespace js diff --git a/js/src/vm/BooleanObject.h b/js/src/vm/BooleanObject.h index c3c74fb198379..5472c50303d39 100644 --- a/js/src/vm/BooleanObject.h +++ b/js/src/vm/BooleanObject.h @@ -24,11 +24,10 @@ class BooleanObject : public NativeObject static const Class class_; /* - * Creates a new Boolean object boxing the given primitive bool. - * If proto is nullptr, the [[Prototype]] will default to Boolean.prototype. + * Creates a new Boolean object boxing the given primitive bool. The + * object's [[Prototype]] is determined from context. */ - static inline BooleanObject* create(JSContext* cx, bool b, - HandleObject proto = nullptr); + static inline BooleanObject* create(JSContext* cx, bool b); bool unbox() const { return getFixedSlot(PRIMITIVE_VALUE_SLOT).toBoolean(); diff --git a/js/src/vm/ErrorObject.cpp b/js/src/vm/ErrorObject.cpp index cdf07f3a04a42..0b141f2689d6c 100644 --- a/js/src/vm/ErrorObject.cpp +++ b/js/src/vm/ErrorObject.cpp @@ -84,17 +84,13 @@ js::ErrorObject::init(JSContext* cx, Handle obj, JSExnType type, /* static */ ErrorObject* js::ErrorObject::create(JSContext* cx, JSExnType errorType, HandleObject stack, HandleString fileName, uint32_t lineNumber, uint32_t columnNumber, - ScopedJSFreePtr* report, HandleString message, - HandleObject protoArg /* = nullptr */) + ScopedJSFreePtr* report, HandleString message) { AssertObjectIsSavedFrameOrWrapper(cx, stack); - RootedObject proto(cx, protoArg); - if (!proto) { - proto = GlobalObject::getOrCreateCustomErrorPrototype(cx, cx->global(), errorType); - if (!proto) - return nullptr; - } + Rooted proto(cx, GlobalObject::getOrCreateCustomErrorPrototype(cx, cx->global(), errorType)); + if (!proto) + return nullptr; Rooted errObject(cx); { diff --git a/js/src/vm/ErrorObject.h b/js/src/vm/ErrorObject.h index 39e2c37f5dd65..c4edd40389831 100644 --- a/js/src/vm/ErrorObject.h +++ b/js/src/vm/ErrorObject.h @@ -72,7 +72,7 @@ class ErrorObject : public NativeObject static ErrorObject* create(JSContext* cx, JSExnType type, HandleObject stack, HandleString fileName, uint32_t lineNumber, uint32_t columnNumber, ScopedJSFreePtr* report, - HandleString message, HandleObject proto = nullptr); + HandleString message); /* * Assign the initial error shape to the empty object. (This shape does diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index daa9610b747a6..257b0121ae6c8 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -4676,7 +4676,20 @@ js::DefaultClassConstructor(JSContext* cx, unsigned argc, Value* vp) } RootedObject newTarget(cx, &args.newTarget().toObject()); - JSObject* obj = CreateThis(cx, &PlainObject::class_, newTarget); + RootedValue protoVal(cx); + + if (!GetProperty(cx, newTarget, newTarget, cx->names().prototype, &protoVal)) + return false; + + RootedObject proto(cx); + if (!protoVal.isObject()) { + if (!GetBuiltinPrototype(cx, JSProto_Object, &proto)) + return false; + } else { + proto = &protoVal.toObject(); + } + + JSObject* obj = NewObjectWithGivenProto(cx, &PlainObject::class_, proto); if (!obj) return false; diff --git a/js/src/vm/NumberObject-inl.h b/js/src/vm/NumberObject-inl.h index 7e0237b1c864d..5d4ff02143275 100644 --- a/js/src/vm/NumberObject-inl.h +++ b/js/src/vm/NumberObject-inl.h @@ -14,13 +14,14 @@ namespace js { inline NumberObject* -NumberObject::create(JSContext* cx, double d, HandleObject proto /* = nullptr */) +NumberObject::create(JSContext* cx, double d) { - NumberObject* obj = NewObjectWithClassProto(cx, proto); + JSObject* obj = NewBuiltinClassInstance(cx, &class_); if (!obj) return nullptr; - obj->setPrimitiveValue(d); - return obj; + NumberObject& numobj = obj->as(); + numobj.setPrimitiveValue(d); + return &numobj; } } // namespace js diff --git a/js/src/vm/NumberObject.h b/js/src/vm/NumberObject.h index dd808309c782b..c3523b8465ab0 100644 --- a/js/src/vm/NumberObject.h +++ b/js/src/vm/NumberObject.h @@ -22,11 +22,10 @@ class NumberObject : public NativeObject static const Class class_; /* - * Creates a new Number object boxing the given number. - * If proto is nullptr, then Number.prototype will be used instead. + * Creates a new Number object boxing the given number. The object's + * [[Prototype]] is determined from context. */ - static inline NumberObject* create(JSContext* cx, double d, - HandleObject proto = nullptr); + static inline NumberObject* create(JSContext* cx, double d); double unbox() const { return getFixedSlot(PRIMITIVE_VALUE_SLOT).toNumber(); diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 1290ec1d0f057..36de84d365f39 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -1363,38 +1363,34 @@ struct ObjectGroupCompartment::AllocationSiteKey : public DefaultHasheroffsetToPC(key.offset)) ^ key.kind ^ size_t(key.proto)); + return uint32_t(size_t(key.script->offsetToPC(key.offset)) ^ key.kind); } static inline bool match(const AllocationSiteKey& a, const AllocationSiteKey& b) { - return a.script == b.script && a.offset == b.offset && a.kind == b.kind && a.proto == b.proto; + return a.script == b.script && a.offset == b.offset && a.kind == b.kind; } }; /* static */ ObjectGroup* ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* script, jsbytecode* pc, - JSProtoKey kind, HandleObject protoArg /* = nullptr */) + JSProtoKey kind) { MOZ_ASSERT(!useSingletonForAllocationSite(script, pc, kind)); - MOZ_ASSERT_IF(protoArg, kind == JSProto_Array); uint32_t offset = script->pcToOffset(pc); - if (offset >= ObjectGroupCompartment::AllocationSiteKey::OFFSET_LIMIT) { - if (protoArg) - return defaultNewGroup(cx, GetClassForProtoKey(kind), TaggedProto(protoArg)); + if (offset >= ObjectGroupCompartment::AllocationSiteKey::OFFSET_LIMIT) return defaultNewGroup(cx, kind); - } - if (protoArg && gc::IsInsideNursery(protoArg)) - return defaultNewGroup(cx, GetClassForProtoKey(kind), TaggedProto(protoArg)); + ObjectGroupCompartment::AllocationSiteKey key; + key.script = script; + key.offset = offset; + key.kind = kind; ObjectGroupCompartment::AllocationSiteTable*& table = cx->compartment()->objectGroups.allocationSiteTable; @@ -1409,24 +1405,16 @@ ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* script, jsbytecode* pc } } - RootedObject proto(cx, protoArg); - if (!proto && kind != JSProto_Null && !GetBuiltinPrototype(cx, kind, &proto)) - return nullptr; - - MOZ_ASSERT(!gc::IsInsideNursery(proto)); - - ObjectGroupCompartment::AllocationSiteKey key; - key.script = script; - key.offset = offset; - key.kind = kind; - key.proto = proto; - ObjectGroupCompartment::AllocationSiteTable::AddPtr p = table->lookupForAdd(key); if (p) return p->value(); AutoEnterAnalysis enter(cx); + RootedObject proto(cx); + if (kind != JSProto_Null && !GetBuiltinPrototype(cx, kind, &proto)) + return nullptr; + Rooted tagged(cx, TaggedProto(proto)); ObjectGroup* res = ObjectGroupCompartment::makeGroup(cx, GetClassForProtoKey(kind), tagged, OBJECT_FLAG_FROM_ALLOCATION_SITE); @@ -1475,7 +1463,6 @@ ObjectGroupCompartment::replaceAllocationSiteGroup(JSScript* script, jsbytecode* key.script = script; key.offset = script->pcToOffset(pc); key.kind = kind; - key.proto = group->proto().toObjectOrNull(); AllocationSiteTable::Ptr p = allocationSiteTable->lookup(key); MOZ_RELEASE_ASSERT(p); @@ -1488,16 +1475,12 @@ ObjectGroupCompartment::replaceAllocationSiteGroup(JSScript* script, jsbytecode* } /* static */ ObjectGroup* -ObjectGroup::callingAllocationSiteGroup(JSContext* cx, JSProtoKey key, HandleObject proto) +ObjectGroup::callingAllocationSiteGroup(JSContext* cx, JSProtoKey key) { - MOZ_ASSERT_IF(proto, key == JSProto_Array); - jsbytecode* pc; RootedScript script(cx, cx->currentScript(&pc)); if (script) - return allocationSiteGroup(cx, script, pc, key, proto); - if (proto) - return defaultNewGroup(cx, GetClassForProtoKey(key), TaggedProto(proto)); + return allocationSiteGroup(cx, script, pc, key); return defaultNewGroup(cx, key); } @@ -1783,16 +1766,12 @@ ObjectGroupCompartment::sweep(FreeOp* fop) if (allocationSiteTable) { for (AllocationSiteTable::Enum e(*allocationSiteTable); !e.empty(); e.popFront()) { AllocationSiteKey key = e.front().key(); - bool keyDying = IsAboutToBeFinalizedUnbarriered(&key.script) || - (key.proto && IsAboutToBeFinalizedUnbarriered(&key.proto)); + bool keyDying = IsAboutToBeFinalizedUnbarriered(&key.script); bool valDying = IsAboutToBeFinalized(&e.front().value()); - if (keyDying || valDying) { + if (keyDying || valDying) e.removeFront(); - } else if (key.script != e.front().key().script || - key.proto != e.front().key().proto) - { + else if (key.script != e.front().key().script) e.rekeyFront(key); - } } } diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h index a1b09dc356d8d..a83fe0071ed0e 100644 --- a/js/src/vm/ObjectGroup.h +++ b/js/src/vm/ObjectGroup.h @@ -510,11 +510,10 @@ class ObjectGroup : public gc::TenuredCell // Get a non-singleton group to use for objects created at the specified // allocation site. static ObjectGroup* allocationSiteGroup(JSContext* cx, JSScript* script, jsbytecode* pc, - JSProtoKey key, HandleObject proto = nullptr); + JSProtoKey key); // Get a non-singleton group to use for objects created in a JSNative call. - static ObjectGroup* callingAllocationSiteGroup(JSContext* cx, JSProtoKey key, - HandleObject proto = nullptr); + static ObjectGroup* callingAllocationSiteGroup(JSContext* cx, JSProtoKey key); // Set the group or singleton-ness of an object created for an allocation site. static bool diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 89b3bf6ac345f..88b8b3143daeb 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -41,17 +41,25 @@ JS_STATIC_ASSERT(MultilineFlag == JSREG_MULTILINE); JS_STATIC_ASSERT(StickyFlag == JSREG_STICKY); RegExpObject* -js::RegExpAlloc(ExclusiveContext* cx, HandleObject proto /* = nullptr */) +js::RegExpAlloc(ExclusiveContext* cx) { // Note: RegExp objects are always allocated in the tenured heap. This is // not strictly required, but simplifies embedding them in jitcode. - RegExpObject* regexp = NewObjectWithClassProto(cx, proto, TenuredObject); + RegExpObject* regexp = NewBuiltinClassInstance(cx, TenuredObject); if (!regexp) return nullptr; + regexp->initPrivate(nullptr); return regexp; } +RegExpObject* +js::InitializeRegExp(ExclusiveContext* cx, Handle regexp, HandleAtom source, + RegExpFlag flags) +{ + return regexp->init(cx, source, flags) ? regexp : nullptr; +} + /* MatchPairs */ bool @@ -147,13 +155,6 @@ RegExpObject::trace(JSTracer* trc, JSObject* obj) } } -/* static */ bool -RegExpObject::initFromAtom(ExclusiveContext* cx, Handle regexp, HandleAtom source, - RegExpFlag flags) -{ - return regexp->init(cx, source, flags); -} - const Class RegExpObject::class_ = { js_RegExp_str, JSCLASS_HAS_PRIVATE | @@ -223,10 +224,7 @@ RegExpObject::createNoStatics(ExclusiveContext* cx, HandleAtom source, RegExpFla if (!regexp) return nullptr; - if (!RegExpObject::initFromAtom(cx, regexp, source, flags)) - return nullptr; - - return regexp; + return InitializeRegExp(cx, regexp, source, flags); } bool @@ -896,10 +894,7 @@ js::CloneRegExpObject(JSContext* cx, JSObject* obj_) if (!clone) return nullptr; - if (!RegExpObject::initFromAtom(cx, clone, source, RegExpFlag(origFlags | staticsFlags))) - return nullptr; - - return clone; + return InitializeRegExp(cx, clone, source, RegExpFlag(origFlags | staticsFlags)); } // Otherwise, the clone can use |regexp|'s RegExpShared. @@ -916,7 +911,7 @@ js::CloneRegExpObject(JSContext* cx, JSObject* obj_) if (!regex->getShared(cx, &g)) return nullptr; - if (!RegExpObject::initFromAtom(cx, clone, source, g->getFlags())) + if (!InitializeRegExp(cx, clone, source, g->getFlags())) return nullptr; clone->setShared(*g.re()); diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index ad118914d9d00..02972e314315a 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -64,7 +64,11 @@ enum RegExpRunStatus }; extern RegExpObject* -RegExpAlloc(ExclusiveContext* cx, HandleObject proto = nullptr); +RegExpAlloc(ExclusiveContext* cx); + +extern RegExpObject* +InitializeRegExp(ExclusiveContext* cx, Handle regexp, HandleAtom source, + RegExpFlag flags); // |regexp| is under-typed because this function's used in the JIT. extern JSObject* @@ -443,10 +447,11 @@ class RegExpObject : public NativeObject static void trace(JSTracer* trc, JSObject* obj); - static bool initFromAtom(ExclusiveContext* cx, Handle regexp, HandleAtom source, - RegExpFlag flags); - private: + friend RegExpObject* + InitializeRegExp(ExclusiveContext* cx, Handle regexp, HandleAtom source, + RegExpFlag flags); + bool init(ExclusiveContext* cx, HandleAtom source, RegExpFlag flags); /* diff --git a/js/src/vm/StringObject-inl.h b/js/src/vm/StringObject-inl.h index 5fc1656f691e3..de3a9714f7592 100644 --- a/js/src/vm/StringObject-inl.h +++ b/js/src/vm/StringObject-inl.h @@ -33,9 +33,9 @@ StringObject::init(JSContext* cx, HandleString str) } inline StringObject* -StringObject::create(JSContext* cx, HandleString str, HandleObject proto, NewObjectKind newKind) +StringObject::create(JSContext* cx, HandleString str, NewObjectKind newKind) { - JSObject* obj = NewObjectWithClassProto(cx, &class_, proto, newKind); + JSObject* obj = NewBuiltinClassInstance(cx, &class_, newKind); if (!obj) return nullptr; Rooted strobj(cx, &obj->as()); diff --git a/js/src/vm/StringObject.h b/js/src/vm/StringObject.h index 119e3d9fa6d00..57adbc80a50f0 100644 --- a/js/src/vm/StringObject.h +++ b/js/src/vm/StringObject.h @@ -29,7 +29,6 @@ class StringObject : public NativeObject * [[Prototype]] is determined from context. */ static inline StringObject* create(JSContext* cx, HandleString str, - HandleObject proto = nullptr, NewObjectKind newKind = GenericObject); /* diff --git a/js/src/vm/TypedArrayCommon.h b/js/src/vm/TypedArrayCommon.h index 92b821c58b10f..1434233025657 100644 --- a/js/src/vm/TypedArrayCommon.h +++ b/js/src/vm/TypedArrayCommon.h @@ -141,17 +141,6 @@ IsAnyTypedArrayClass(const Class* clasp) return IsTypedArrayClass(clasp) || IsSharedTypedArrayClass(clasp); } -inline bool -AnyTypedArrayIsDetached(const JSObject* obj) -{ - if (obj->is()) { - ArrayBufferObject* buffer = obj->as().buffer(); - return buffer && buffer->isNeutered(); - } - // You cannoy detatch a shared array buffer - return false; -} - class SharedOps { public: diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 7d3493e7144ce..de81ea4379f9e 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -182,20 +182,6 @@ NewArray(JSContext* cx, uint32_t nelements); namespace { -// We allow nullptr for newTarget for all the creation methods, to allow for -// JSFriendAPI functions that don't care about subclassing -static bool -GetPrototypeForInstance(JSContext* cx, HandleObject newTarget, MutableHandleObject proto) -{ - if (newTarget) { - if (!GetPrototypeFromConstructor(cx, newTarget, proto)) - return false; - } else { - proto.set(nullptr); - } - return true; -} - // Note, this template can probably be merged in part with the one in // SharedTypedArrayObject.cpp once our implementation of // TypedArrayObject is closer to ES6: at the moment, our @@ -439,13 +425,10 @@ class TypedArrayObjectTemplate : public TypedArrayObject static JSObject* create(JSContext* cx, const CallArgs& args) { - MOZ_ASSERT(args.isConstructing()); - RootedObject newTarget(cx, &args.newTarget().toObject()); - /* () or (number) */ uint32_t len = 0; if (args.length() == 0 || ValueIsLength(args[0], &len)) - return fromLength(cx, len, newTarget); + return fromLength(cx, len); /* (not an object) */ if (!args[0].isObject()) { @@ -466,13 +449,9 @@ class TypedArrayObjectTemplate : public TypedArrayObject * shared array's values are copied here. */ if (!UncheckedUnwrap(dataObj)->is()) - return fromArray(cx, dataObj, newTarget); + return fromArray(cx, dataObj); /* (ArrayBuffer, [byteOffset, [length]]) */ - RootedObject proto(cx); - if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) - return nullptr; - int32_t byteOffset = 0; int32_t length = -1; @@ -496,7 +475,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject } } - return fromBufferWithProto(cx, dataObj, byteOffset, length, proto); + return fromBuffer(cx, dataObj, byteOffset, length); } public: @@ -550,11 +529,9 @@ class TypedArrayObjectTemplate : public TypedArrayObject * don't have to do anything *uniquely* crazy here. */ - RootedObject protoRoot(cx, proto); - if (!protoRoot) { - if (!GetBuiltinPrototype(cx, JSCLASS_CACHED_PROTO_KEY(instanceClass()), &protoRoot)) - return nullptr; - } + Rooted proto(cx); + if (!GetBuiltinPrototype(cx, JSCLASS_CACHED_PROTO_KEY(instanceClass()), &proto)) + return nullptr; InvokeArgs args(cx); if (!args.init(3)) @@ -564,7 +541,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject args.setThis(ObjectValue(*bufobj)); args[0].setNumber(byteOffset); args[1].setInt32(lengthInt); - args[2].setObject(*protoRoot); + args[2].setObject(*proto); if (!Invoke(cx, args)) return nullptr; @@ -579,11 +556,6 @@ class TypedArrayObjectTemplate : public TypedArrayObject Rooted buffer(cx, &AsArrayBuffer(bufobj)); - if (buffer->isNeutered()) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); - return nullptr; - } - if (byteOffset > buffer->byteLength() || byteOffset % sizeof(NativeType) != 0) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS); return nullptr; // invalid byteOffset @@ -642,21 +614,16 @@ class TypedArrayObjectTemplate : public TypedArrayObject } static JSObject* - fromLength(JSContext* cx, uint32_t nelements, HandleObject newTarget = nullptr) + fromLength(JSContext* cx, uint32_t nelements) { - RootedObject proto(cx); - if (!GetPrototypeForInstance(cx, newTarget, &proto)) - return nullptr; - Rooted buffer(cx); if (!maybeCreateArrayBuffer(cx, nelements, &buffer)) return nullptr; - - return makeInstance(cx, buffer, 0, nelements, proto); + return makeInstance(cx, buffer, 0, nelements); } static JSObject* - fromArray(JSContext* cx, HandleObject other, HandleObject newTarget = nullptr); + fromArray(JSContext* cx, HandleObject other); static const NativeType getIndex(JSObject* obj, uint32_t index) @@ -696,35 +663,20 @@ struct TypedArrayObject::OfType template /* static */ JSObject* -TypedArrayObjectTemplate::fromArray(JSContext* cx, HandleObject other, - HandleObject newTarget /* = nullptr */) +TypedArrayObjectTemplate::fromArray(JSContext* cx, HandleObject other) { - // Allow nullptr newTarget for FriendAPI methods, which don't care about - // subclassing. - RootedObject proto(cx); - uint32_t len; if (IsAnyTypedArray(other)) { - if (!GetPrototypeForInstance(cx, newTarget, &proto)) - return nullptr; - - if (AnyTypedArrayIsDetached(other)) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); - return nullptr; - } len = AnyTypedArrayLength(other); - } else { - if (!GetLengthProperty(cx, other, &len)) - return nullptr; - if (!GetPrototypeForInstance(cx, newTarget, &proto)) - return nullptr; + } else if (!GetLengthProperty(cx, other, &len)) { + return nullptr; } Rooted buffer(cx); if (!maybeCreateArrayBuffer(cx, len, &buffer)) return nullptr; - Rooted obj(cx, makeInstance(cx, buffer, 0, len, proto)); + Rooted obj(cx, makeInstance(cx, buffer, 0, len)); if (!obj || !TypedArrayMethods::setFromArrayLike(cx, obj, other, len)) return nullptr; return obj; @@ -1010,7 +962,7 @@ DataViewNewObjectKind(JSContext* cx, uint32_t byteLength, JSObject* proto) return GenericObject; } -DataViewObject* +inline DataViewObject* DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength, Handle arrayBuffer, JSObject* protoArg) { @@ -1070,8 +1022,7 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength, } bool -DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, const CallArgs& args, - uint32_t* byteOffsetPtr, uint32_t* byteLengthPtr) +DataViewObject::construct(JSContext* cx, JSObject* bufobj, const CallArgs& args, HandleObject proto) { if (!IsArrayBuffer(bufobj)) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE, @@ -1087,40 +1038,29 @@ DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, cons if (!ToUint32(cx, args[1], &byteOffset)) return false; if (byteOffset > INT32_MAX) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1"); - return false; - } - } - - if (buffer->isNeutered()) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); - return false; - } - - if (args.length() > 1) { - if (byteOffset > byteLength) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1"); + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, + JSMSG_ARG_INDEX_OUT_OF_RANGE, "1"); return false; } - if (args.get(2).isUndefined()) { - byteLength -= byteOffset; - } else { + if (!args.get(2).isUndefined()) { if (!ToUint32(cx, args[2], &byteLength)) return false; if (byteLength > INT32_MAX) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, - JSMSG_ARG_INDEX_OUT_OF_RANGE, "2"); + JSMSG_ARG_INDEX_OUT_OF_RANGE, "2"); return false; } + } else { + uint32_t bufferLength = buffer->byteLength(); - MOZ_ASSERT(byteOffset + byteLength > byteOffset, - "can't overflow: both numbers are less than INT32_MAX"); - if (byteOffset + byteLength > buffer->byteLength()) { + if (byteOffset > bufferLength) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1"); return false; } + + byteLength = bufferLength - byteOffset; } } @@ -1128,29 +1068,11 @@ DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, cons MOZ_ASSERT(byteOffset <= INT32_MAX); MOZ_ASSERT(byteLength <= INT32_MAX); - - *byteOffsetPtr = byteOffset; - *byteLengthPtr = byteLength; - - return true; -} - -bool -DataViewObject::constructSameCompartment(JSContext* cx, JSObject* bufobj, const CallArgs& args) -{ - MOZ_ASSERT(args.isConstructing()); - assertSameCompartment(cx, bufobj); - - uint32_t byteOffset, byteLength; - if (!getAndCheckConstructorArgs(cx, bufobj, args, &byteOffset, &byteLength)) - return false; - - RootedObject proto(cx); - RootedObject newTarget(cx, &args.newTarget().toObject()); - if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) + if (byteOffset + byteLength > buffer->byteLength()) { + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1"); return false; + } - Rooted buffer(cx, &AsArrayBuffer(bufobj)); JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, proto); if (!obj) return false; @@ -1158,70 +1080,6 @@ DataViewObject::constructSameCompartment(JSContext* cx, JSObject* bufobj, const return true; } -// Create a DataView object in another compartment. -// -// ES6 supports creating a DataView in global A (using global A's DataView -// constructor) backed by an ArrayBuffer created in global B. -// -// Our DataViewObject implementation doesn't support a DataView in -// compartment A backed by an ArrayBuffer in compartment B. So in this case, -// we create the DataView in B (!) and return a cross-compartment wrapper. -// -// Extra twist: the spec says the new DataView's [[Prototype]] must be -// A's DataView.prototype. So even though we're creating the DataView in B, -// its [[Prototype]] must be (a cross-compartment wrapper for) the -// DataView.prototype in A. -// -// As if this were not confusing enough, the way we actually do this is also -// tricky. We call compartment A's createDataViewForThis method, passing it -// bufobj as `this`. That calls ArrayBufferObject::createDataViewForThis(), -// which uses CallNonGenericMethod to switch to compartment B so that -// the new DataView is created there. -bool -DataViewObject::constructWrapped(JSContext* cx, JSObject* bufobj, const CallArgs& args) -{ - MOZ_ASSERT(args.isConstructing()); - MOZ_ASSERT(bufobj->is()); - - JSObject* unwrapped = CheckedUnwrap(bufobj); - if (!unwrapped) { - JS_ReportError(cx, "Permission denied to access object"); - return false; - } - - // NB: This entails the IsArrayBuffer check - uint32_t byteOffset, byteLength; - if (!getAndCheckConstructorArgs(cx, unwrapped, args, &byteOffset, &byteLength)) - return false; - - // Make sure to get the [[Prototype]] for the created view from this - // compartment. - RootedObject proto(cx); - RootedObject newTarget(cx, &args.newTarget().toObject()); - if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) - return false; - - Rooted global(cx, cx->compartment()->maybeGlobal()); - if (!proto) { - proto = global->getOrCreateDataViewPrototype(cx); - if (!proto) - return false; - } - - InvokeArgs args2(cx); - if (!args2.init(3)) - return false; - args2.setCallee(global->createDataViewForThis()); - args2.setThis(ObjectValue(*bufobj)); - args2[0].set(PrivateUint32Value(byteOffset)); - args2[1].set(PrivateUint32Value(byteLength)); - args2[2].setObject(*proto); - if (!Invoke(cx, args2)) - return false; - args.rval().set(args2.rval()); - return true; -} - bool DataViewObject::class_constructor(JSContext* cx, unsigned argc, Value* vp) { @@ -1234,9 +1092,26 @@ DataViewObject::class_constructor(JSContext* cx, unsigned argc, Value* vp) if (!GetFirstArgumentAsObject(cx, args, "DataView constructor", &bufobj)) return false; - if (bufobj->is()) - return constructWrapped(cx, bufobj, args); - return constructSameCompartment(cx, bufobj, args); + if (bufobj->is() && IsArrayBuffer(UncheckedUnwrap(bufobj))) { + Rooted global(cx, cx->compartment()->maybeGlobal()); + Rooted proto(cx, global->getOrCreateDataViewPrototype(cx)); + if (!proto) + return false; + + InvokeArgs args2(cx); + if (!args2.init(args.length() + 1)) + return false; + args2.setCallee(global->createDataViewForThis()); + args2.setThis(ObjectValue(*bufobj)); + PodCopy(args2.array(), args.array(), args.length()); + args2[args.length()].setObject(*proto); + if (!Invoke(cx, args2)) + return false; + args.rval().set(args2.rval()); + return true; + } + + return construct(cx, bufobj, args, nullptr); } template @@ -1343,11 +1218,6 @@ DataViewObject::read(JSContext* cx, Handle obj, bool fromLittleEndian = args.length() >= 2 && ToBoolean(args[1]); - if (obj->arrayBuffer().isNeutered()) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); - return false; - } - uint8_t* data = DataViewObject::getDataPointer(cx, obj, offset); if (!data) return false; @@ -1409,11 +1279,6 @@ DataViewObject::write(JSContext* cx, Handle obj, bool toLittleEndian = args.length() >= 3 && ToBoolean(args[2]); - if (obj->arrayBuffer().isNeutered()) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); - return false; - } - uint8_t* data = DataViewObject::getDataPointer(cx, obj, offset); if (!data) return false; @@ -1834,15 +1699,15 @@ TypedArrayObject::setElement(TypedArrayObject& obj, uint32_t index, double d) */ #define IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Name,NativeType) \ - JS_FRIEND_API(JSObject*) JS_New ## Name ## Array(JSContext* cx, uint32_t nelements) \ + JS_FRIEND_API(JSObject*) JS_New ## Name ## Array(JSContext* cx, uint32_t nelements) \ { \ return TypedArrayObjectTemplate::fromLength(cx, nelements); \ } \ - JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayFromArray(JSContext* cx, HandleObject other) \ + JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayFromArray(JSContext* cx, HandleObject other) \ { \ return TypedArrayObjectTemplate::fromArray(cx, other); \ } \ - JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayWithBuffer(JSContext* cx, \ + JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayWithBuffer(JSContext* cx, \ HandleObject arrayBuffer, uint32_t byteOffset, int32_t length) \ { \ return TypedArrayObjectTemplate::fromBuffer(cx, arrayBuffer, byteOffset, \ @@ -1854,8 +1719,8 @@ TypedArrayObject::setElement(TypedArrayObject& obj, uint32_t index, double d) return false; \ const Class* clasp = obj->getClass(); \ return clasp == TypedArrayObjectTemplate::instanceClass(); \ - } \ - JS_FRIEND_API(JSObject*) js::Unwrap ## Name ## Array(JSObject* obj) \ + } \ + JS_FRIEND_API(JSObject*) js::Unwrap ## Name ## Array(JSObject* obj) \ { \ obj = CheckedUnwrap(obj); \ if (!obj) \ @@ -1864,7 +1729,7 @@ TypedArrayObject::setElement(TypedArrayObject& obj, uint32_t index, double d) if (clasp == TypedArrayObjectTemplate::instanceClass()) \ return obj; \ return nullptr; \ - } \ + } \ const js::Class* const js::detail::Name ## ArrayClassPtr = \ &js::TypedArrayObject::classes[TypedArrayObjectTemplate::ArrayTypeID()]; diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h index 1a4cc684f1f1f..15b8a01c1afd5 100644 --- a/js/src/vm/TypedArrayObject.h +++ b/js/src/vm/TypedArrayObject.h @@ -377,16 +377,6 @@ class DataViewObject : public NativeObject static bool defineGetter(JSContext* cx, PropertyName* name, HandleNativeObject proto); - static bool getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, const CallArgs& args, - uint32_t *byteOffset, uint32_t* byteLength); - static bool constructSameCompartment(JSContext* cx, JSObject* bufobj, const CallArgs& args); - static bool constructWrapped(JSContext* cx, JSObject* bufobj, const CallArgs& args); - - friend bool ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args); - static DataViewObject* - create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength, - Handle arrayBuffer, JSObject* proto); - public: static const Class class_; @@ -423,6 +413,13 @@ class DataViewObject : public NativeObject } static bool class_constructor(JSContext* cx, unsigned argc, Value* vp); + static bool constructWithProto(JSContext* cx, unsigned argc, Value* vp); + static bool construct(JSContext* cx, JSObject* bufobj, const CallArgs& args, + HandleObject proto); + + static inline DataViewObject* + create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength, + Handle arrayBuffer, JSObject* proto); static bool getInt8Impl(JSContext* cx, const CallArgs& args); static bool fun_getInt8(JSContext* cx, unsigned argc, Value* vp);