Backed out 20 changesets (bug 1055472) for Linux64 cgc failures and an apparent crash in the cpp test test_audio on OS X 10.6 debug

CLOSED TREE

Backed out changeset edd1c18b5a5b (bug 1055472)
Backed out changeset 41be086be0e8 (bug 1055472)
Backed out changeset 6ed32cadfc31 (bug 1055472)
Backed out changeset 2f0b0b246e25 (bug 1055472)
Backed out changeset 33d5c8ef947c (bug 1055472)
Backed out changeset 74dca890ec34 (bug 1055472)
Backed out changeset b4a4144b96fa (bug 1055472)
Backed out changeset 9dd0b1fff545 (bug 1055472)
Backed out changeset 31c41d6a16ab (bug 1055472)
Backed out changeset bf8f9604c34f (bug 1055472)
Backed out changeset 69bf1faa9d85 (bug 1055472)
Backed out changeset 284934443cd3 (bug 1055472)
Backed out changeset 65d962413c98 (bug 1055472)
Backed out changeset 94135702e1b5 (bug 1055472)
Backed out changeset 1509efcfa629 (bug 1055472)
Backed out changeset c7180ea9dfa4 (bug 1055472)
Backed out changeset a47a3ce6f35e (bug 1055472)
Backed out changeset 9b4f7a838a66 (bug 1055472)
Backed out changeset e5f593ea362c (bug 1055472)
Backed out changeset 8ec3005245c1 (bug 1055472)
This commit is contained in:
Phil Ringnalda 2015-11-19 20:01:07 -08:00
parent 233df95182
commit 3d1087acb2
54 changed files with 326 additions and 946 deletions

View File

@ -221,7 +221,7 @@ MapIteratorObject::next(JSContext* cx, Handle<MapIteratorObject*> 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<ValueMap>(cx->runtime());
Rooted<MapObject*> obj(cx, NewBuiltinClassInstance<MapObject>(cx));
if (!obj)
return nullptr;
ValueMap* map = cx->new_<ValueMap>(cx->runtime());
if (!map || !map->init()) {
js_delete(map);
ReportOutOfMemory(cx);
return nullptr;
}
MapObject* mapObj = NewObjectWithClassProto<MapObject>(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<MapObject*> obj(cx, MapObject::create(cx, proto));
Rooted<MapObject*> 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<ValueSet>(cx->runtime());
if (!set || !set->init()) {
ReportOutOfMemory(cx);
return nullptr;
}
SetObject* obj = NewObjectWithClassProto<SetObject>(cx, proto);
SetObject* obj = NewBuiltinClassInstance<SetObject>(cx);
if (!obj)
return nullptr;
obj->setPrivate(set.release());
ValueSet* set = cx->new_<ValueSet>(cx->runtime());
if (!set || !set->init()) {
js_delete(set);
ReportOutOfMemory(cx);
return nullptr;
}
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<SetObject*> obj(cx, SetObject::create(cx, proto));
Rooted<SetObject*> obj(cx, SetObject::create(cx));
if (!obj)
return false;

View File

@ -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);

View File

@ -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;

View File

@ -185,7 +185,7 @@ RegExpInitialize(JSContext* cx, Handle<RegExpObject*> 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<CanGC>(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<RegExpObject*> regexp(cx, RegExpAlloc(cx, proto));
// XXX Note bug in step 5c, with respect to step 8.
Rooted<RegExpObject*> 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<CanGC>(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<RegExpObject*> regexp(cx, RegExpAlloc(cx, proto));
Rooted<RegExpObject*> 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

View File

@ -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;

View File

@ -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<WeakMapObject>(cx));
if (!map)
Rooted<WeakSetObject*> obj(cx, NewBuiltinClassInstance<WeakSetObject>(cx));
if (!obj)
return nullptr;
WeakSetObject* obj = NewObjectWithClassProto<WeakSetObject>(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<WeakSetObject*> 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<WeakSetObject*> obj(cx, WeakSetObject::create(cx, proto));
if (!obj)
return false;
if (!args.get(0).isNullOrUndefined()) {
RootedObject map(cx, &obj->getReservedSlot(WEAKSET_MAP_SLOT).toObject());

View File

@ -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);
};

View File

@ -425,13 +425,6 @@ js::TraceRoot(JSTracer* trc, T* thingp, const char* name)
DispatchToTracer(trc, ConvertToBase(thingp), name);
}
template <typename T>
void
js::TraceRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
{
TraceRoot(trc, thingp->unsafeGet(), name);
}
template <typename T>
void
js::TraceNullableRoot(JSTracer* trc, T* thingp, const char* name)
@ -441,13 +434,6 @@ js::TraceNullableRoot(JSTracer* trc, T* thingp, const char* name)
DispatchToTracer(trc, ConvertToBase(thingp), name);
}
template <typename T>
void
js::TraceNullableRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
{
TraceNullableRoot(trc, thingp->unsafeGet(), name);
}
template <typename T>
void
js::TraceRange(JSTracer* trc, size_t len, WriteBarrieredBase<T>* vec, const char* name)
@ -479,9 +465,7 @@ js::TraceRootRange(JSTracer* trc, size_t len, T* vec, const char* name)
template void js::TraceManuallyBarrieredEdge<type>(JSTracer*, type*, const char*); \
template void js::TraceWeakEdge<type>(JSTracer*, WeakRef<type>*, const char*); \
template void js::TraceRoot<type>(JSTracer*, type*, const char*); \
template void js::TraceRoot<type>(JSTracer*, ReadBarriered<type>*, const char*); \
template void js::TraceNullableRoot<type>(JSTracer*, type*, const char*); \
template void js::TraceNullableRoot<type>(JSTracer*, ReadBarriered<type>*, const char*); \
template void js::TraceRange<type>(JSTracer*, size_t, WriteBarrieredBase<type>*, const char*); \
template void js::TraceRootRange<type>(JSTracer*, size_t, type*, const char*);
FOR_EACH_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS)

View File

@ -63,20 +63,12 @@ template <typename T>
void
TraceRoot(JSTracer* trc, T* thingp, const char* name);
template <typename T>
void
TraceRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name);
// Idential to TraceRoot, except that this variant will not crash if |*thingp|
// is null.
template <typename T>
void
TraceNullableRoot(JSTracer* trc, T* thingp, const char* name);
template <typename T>
void
TraceNullableRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name);
// Like TraceEdge, but for edges that do not use one of the automatic barrier
// classes and, thus, must be treated specially for moving GC. This method is
// separate from TraceEdge to make accidental use of such edges more obvious.

View File

@ -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();

View File

@ -1,17 +0,0 @@
function f(v, expected) {
assertEq(v.prop, expected);
};
class SubArrayA extends Array {
}
class SubArrayB extends Array {
}
SubArrayA.prototype.prop = "A";
SubArrayB.prototype.prop = "B";
var a = new SubArrayA();
var b = new SubArrayB();
for (let i = 0; i < 10; i++) {
f(a, "A");
f(b, "B");
}

View File

@ -5708,7 +5708,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;
}

View File

@ -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;
@ -3314,6 +3310,12 @@ EnsureNewArrayElements(ExclusiveContext* cx, ArrayObject* obj, uint32_t length)
return true;
}
static bool
NewArrayIsCachable(ExclusiveContext* cxArg, NewObjectKind newKind)
{
return cxArg->isJSContext() && newKind == GenericObject;
}
template <uint32_t maxLength>
static MOZ_ALWAYS_INLINE ArrayObject*
NewArray(ExclusiveContext* cxArg, uint32_t length,
@ -3323,18 +3325,13 @@ NewArray(ExclusiveContext* cxArg, uint32_t length,
MOZ_ASSERT(CanBeFinalizedInBackground(allocKind, &ArrayObject::class_));
allocKind = GetBackgroundAllocKind(allocKind);
RootedObject proto(cxArg, protoArg);
if (!proto && !GetBuiltinPrototype(cxArg, JSProto_Array, &proto))
return nullptr;
Rooted<TaggedProto> taggedProto(cxArg, TaggedProto(proto));
bool isCachable = NewObjectWithTaggedProtoIsCachable(cxArg, taggedProto, newKind, &ArrayObject::class_);
bool isCachable = NewArrayIsCachable(cxArg, newKind);
if (isCachable) {
JSContext* cx = cxArg->asJSContext();
JSRuntime* rt = cx->runtime();
NewObjectCache& cache = rt->newObjectCache;
NewObjectCache::EntryIndex entry = -1;
if (cache.lookupProto(&ArrayObject::class_, proto, allocKind, &entry)) {
if (cache.lookupGlobal(&ArrayObject::class_, cx->global(), allocKind, &entry)) {
gc::InitialHeap heap = GetInitialHeap(newKind, &ArrayObject::class_);
AutoSetNewObjectMetadata metadata(cx);
JSObject* obj = cache.newObjectFromHit(cx, entry, heap);
@ -3353,6 +3350,10 @@ NewArray(ExclusiveContext* cxArg, uint32_t length,
}
}
RootedObject proto(cxArg, protoArg);
if (!proto && !GetBuiltinPrototype(cxArg, JSProto_Array, &proto))
return nullptr;
RootedObjectGroup group(cxArg, ObjectGroup::defaultNewGroup(cxArg, &ArrayObject::class_,
TaggedProto(proto)));
if (!group)
@ -3388,8 +3389,8 @@ NewArray(ExclusiveContext* cxArg, uint32_t length,
if (isCachable) {
NewObjectCache& cache = cxArg->asJSContext()->runtime()->newObjectCache;
NewObjectCache::EntryIndex entry = -1;
cache.lookupProto(&ArrayObject::class_, proto, allocKind, &entry);
cache.fillProto(entry, &ArrayObject::class_, taggedProto, allocKind, arr);
cache.lookupGlobal(&ArrayObject::class_, cxArg->global(), allocKind, &entry);
cache.fillGlobal(entry, &ArrayObject::class_, cxArg->global(), allocKind, arr);
}
if (maxLength > 0 && !EnsureNewArrayElements(cxArg, arr, std::min(maxLength, length)))
@ -3489,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 <uint32_t maxLength>
static inline JSObject*
NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length,
@ -3505,15 +3504,14 @@ NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length
if (group->shouldPreTenure() || group->maybePreliminaryObjects())
newKind = TenuredObject;
RootedObject proto(cx, group->proto().toObject());
if (group->maybeUnboxedLayout()) {
if (length > UnboxedArrayObject::MaximumCapacity) {
return NewArray<maxLength>(cx, length, proto, newKind);
}
if (length > UnboxedArrayObject::MaximumCapacity)
return NewArray<maxLength>(cx, length, nullptr, newKind);
return UnboxedArrayObject::create(cx, group, length, newKind, maxLength);
}
ArrayObject* res = NewArray<maxLength>(cx, length, proto, newKind);
ArrayObject* res = NewArray<maxLength>(cx, length, nullptr, newKind);
if (!res)
return nullptr;
@ -3592,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<ArrayObject::EagerAllocationMaxLength>(cx, group, length);
@ -3654,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);

View File

@ -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

View File

@ -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);

View File

@ -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<DateObject>().setUTCTime(t);

View File

@ -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.

View File

@ -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<JSFunction>().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;

View File

@ -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<JSFunction>() && !target->as<JSFunction>().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;

View File

@ -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);

View File

@ -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);

View File

@ -689,9 +689,9 @@ NewObjectCache::fillProto(EntryIndex entry, const Class* clasp, js::TaggedProto
return fill(entry, clasp, proto.raw(), kind, obj);
}
bool
js::NewObjectWithTaggedProtoIsCachable(ExclusiveContext* cxArg, Handle<TaggedProto> proto,
NewObjectKind newKind, const Class* clasp)
static bool
NewObjectWithTaggedProtoIsCachable(ExclusiveContext* cxArg, Handle<TaggedProto> proto,
NewObjectKind newKind, const Class* clasp)
{
return cxArg->isJSContext() &&
proto.isObject() &&
@ -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) {

View File

@ -1089,17 +1089,6 @@ GetInitialHeap(NewObjectKind newKind, const Class* clasp)
return gc::DefaultHeap;
}
bool
NewObjectWithTaggedProtoIsCachable(ExclusiveContext* cxArg, Handle<TaggedProto> proto,
NewObjectKind newKind, const Class* clasp);
// 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*

View File

@ -687,24 +687,6 @@ NewObjectWithClassProto(ExclusiveContext* cx, const Class* clasp, HandleObject p
return NewObjectWithClassProto(cx, clasp, proto, allocKind, newKind);
}
template<class T>
inline T*
NewObjectWithClassProto(ExclusiveContext* cx, HandleObject proto,
NewObjectKind newKind = GenericObject)
{
JSObject* obj = NewObjectWithClassProto(cx, &T::class_, proto, newKind);
return obj ? &obj->as<T>() : nullptr;
}
template <class T>
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<T>() : nullptr;
}
/*
* Create a native instance of the given class with parent and proto set
* according to the context's active global.

View File

@ -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);

View File

@ -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");

View File

@ -1,112 +0,0 @@
var test = `
function testBuiltinInstanceIsInstanceOf(instance, builtin, class_) {
assertEq(instance instanceof class_, true);
assertEq(instance instanceof builtin, true);
if (builtin === Array)
assertEq(Array.isArray(instance), true);
}
function testBuiltinInstance(builtin, ...args) {
class sub extends builtin {
constructor(...args) {
super(...args);
this.called = true;
}
}
let instance = new sub(...args);
assertEq(instance.called, true);
testBuiltinInstanceIsInstanceOf(instance, builtin, sub);
}
function testBuiltinMultipleSubclasses(builtin, ...args) {
function f(obj, prop) {
assertEq(obj.prop, prop);
}
class sub1 extends builtin { };
class sub2 extends builtin { };
const prop1 = "A";
const prop2 = "B";
sub1.prototype.prop = prop1;
sub2.prototype.prop = prop2;
let instance1 = new sub1(...args);
let instance2 = new sub2(...args);
// Also make sure we get the properties we want with a default constructor
testBuiltinInstanceIsInstanceOf(instance1, builtin, sub1);
for (let i = 0; i < 10; i++) {
f(instance1, prop1);
f(instance2, prop2);
}
}
function testBuiltin(builtin, ...args) {
testBuiltinInstance(builtin, ...args);
testBuiltinMultipleSubclasses(builtin, ...args);
}
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());
}
}
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);
testBuiltin(Array);
testBuiltin(Array, 15);
testBuiltin(Array, 3.0);
testBuiltin(Array, "non-length one-arg");
testBuiltin(Array, 5, 10, 15, "these are elements");
`;
if (classesEnabled())
eval(test);
if (typeof reportCompare === 'function')
reportCompare(0,0,"OK");

View File

@ -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");

View File

@ -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())

View File

@ -1,13 +0,0 @@
// |reftest| skip-if(!xulRuntime.shell)
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");

View File

@ -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);

View File

@ -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");

View File

@ -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");

View File

@ -1,29 +0,0 @@
// |reftest| skip-if(!xulRuntime.shell)
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);

View File

@ -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");

View File

@ -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<ArrayBufferObject*> obj(cx,
NewObjectWithClassProto<ArrayBufferObject>(cx, proto, allocKind, newKind));
Rooted<ArrayBufferObject*> obj(cx, NewBuiltinClassInstance<ArrayBufferObject>(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);
uint32_t byteOffset = args[0].toPrivateUint32();
uint32_t byteLength = args[1].toPrivateUint32();
Rooted<ArrayBufferObject*> buffer(cx, &args.thisv().toObject().as<ArrayBufferObject>());
Rooted<JSObject*> proto(cx, &args[args.length() - 1].toObject());
Rooted<JSObject*> 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<ArrayBufferObject::PLAIN>(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<ArrayBufferObject::MAPPED>(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*)

View File

@ -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<ArrayBufferObject*> arrayBuffer,

View File

@ -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<BooleanObject>(cx, proto);
JSObject* obj = NewBuiltinClassInstance(cx, &class_);
if (!obj)
return nullptr;
obj->setPrimitiveValue(b);
return obj;
BooleanObject& boolobj = obj->as<BooleanObject>();
boolobj.setPrimitiveValue(b);
return &boolobj;
}
} // namespace js

View File

@ -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();

View File

@ -84,17 +84,13 @@ js::ErrorObject::init(JSContext* cx, Handle<ErrorObject*> obj, JSExnType type,
/* static */ ErrorObject*
js::ErrorObject::create(JSContext* cx, JSExnType errorType, HandleObject stack,
HandleString fileName, uint32_t lineNumber, uint32_t columnNumber,
ScopedJSFreePtr<JSErrorReport>* report, HandleString message,
HandleObject protoArg /* = nullptr */)
ScopedJSFreePtr<JSErrorReport>* report, HandleString message)
{
AssertObjectIsSavedFrameOrWrapper(cx, stack);
RootedObject proto(cx, protoArg);
if (!proto) {
proto = GlobalObject::getOrCreateCustomErrorPrototype(cx, cx->global(), errorType);
if (!proto)
return nullptr;
}
Rooted<JSObject*> proto(cx, GlobalObject::getOrCreateCustomErrorPrototype(cx, cx->global(), errorType));
if (!proto)
return nullptr;
Rooted<ErrorObject*> errObject(cx);
{

View File

@ -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<JSErrorReport>* report,
HandleString message, HandleObject proto = nullptr);
HandleString message);
/*
* Assign the initial error shape to the empty object. (This shape does

View File

@ -4704,7 +4704,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;

View File

@ -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<NumberObject>(cx, proto);
JSObject* obj = NewBuiltinClassInstance(cx, &class_);
if (!obj)
return nullptr;
obj->setPrimitiveValue(d);
return obj;
NumberObject& numobj = obj->as<NumberObject>();
numobj.setPrimitiveValue(d);
return &numobj;
}
} // namespace js

View File

@ -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();

View File

@ -1357,69 +1357,40 @@ ObjectGroup::newPlainObject(ExclusiveContext* cx, IdValuePair* properties, size_
// ObjectGroupCompartment AllocationSiteTable
/////////////////////////////////////////////////////////////////////
struct ObjectGroupCompartment::AllocationSiteKey : public DefaultHasher<AllocationSiteKey>,
public JS::Traceable {
ReadBarrieredScript script;
struct ObjectGroupCompartment::AllocationSiteKey : public DefaultHasher<AllocationSiteKey> {
JSScript* script;
uint32_t offset : 24;
JSProtoKey kind : 8;
ReadBarrieredObject proto;
static const uint32_t OFFSET_LIMIT = (1 << 23);
AllocationSiteKey(JSScript* script_, uint32_t offset_, JSProtoKey kind_, JSObject* proto_)
: script(script_), offset(offset_), kind(kind_), proto(proto_)
{
MOZ_ASSERT(offset_ < OFFSET_LIMIT);
}
AllocationSiteKey(AllocationSiteKey&& key)
: script(mozilla::Move(key.script)),
offset(key.offset),
kind(key.kind),
proto(mozilla::Move(key.proto))
{ }
AllocationSiteKey(const AllocationSiteKey& key)
: script(key.script),
offset(key.offset),
kind(key.kind),
proto(key.proto)
{ }
AllocationSiteKey() { mozilla::PodZero(this); }
static inline uint32_t hash(AllocationSiteKey key) {
return uint32_t(size_t(key.script->offsetToPC(key.offset)) ^ key.kind ^
MovableCellHasher<JSObject*>::hash(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 DefaultHasher<JSScript*>::match(a.script, b.script) &&
a.offset == b.offset &&
a.kind == b.kind &&
MovableCellHasher<JSObject*>::match(a.proto, b.proto);
}
static void trace(AllocationSiteKey* key, JSTracer* trc) {
TraceRoot(trc, &key->script, "AllocationSiteKey script");
TraceNullableRoot(trc, &key->proto, "AllocationSiteKey proto");
return a.script == b.script && a.offset == b.offset && a.kind == b.kind;
}
};
/* static */ ObjectGroup*
ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* scriptArg, jsbytecode* pc,
JSProtoKey kind, HandleObject protoArg /* = nullptr */)
ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* script, jsbytecode* pc,
JSProtoKey kind)
{
MOZ_ASSERT(!useSingletonForAllocationSite(scriptArg, pc, kind));
MOZ_ASSERT_IF(protoArg, kind == JSProto_Array);
MOZ_ASSERT(!useSingletonForAllocationSite(script, pc, kind));
uint32_t offset = scriptArg->pcToOffset(pc);
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);
}
ObjectGroupCompartment::AllocationSiteKey key;
key.script = script;
key.offset = offset;
key.kind = kind;
ObjectGroupCompartment::AllocationSiteTable*& table =
cx->compartment()->objectGroups.allocationSiteTable;
@ -1434,20 +1405,16 @@ ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* scriptArg, jsbytecode*
}
}
RootedScript script(cx, scriptArg);
RootedObject proto(cx, protoArg);
if (!proto && kind != JSProto_Null && !GetBuiltinPrototype(cx, kind, &proto))
return nullptr;
Rooted<ObjectGroupCompartment::AllocationSiteKey> key(cx,
ObjectGroupCompartment::AllocationSiteKey(script, offset, kind, 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<TaggedProto> tagged(cx, TaggedProto(proto));
ObjectGroup* res = ObjectGroupCompartment::makeGroup(cx, GetClassForProtoKey(kind), tagged,
OBJECT_FLAG_FROM_ALLOCATION_SITE);
@ -1492,7 +1459,10 @@ void
ObjectGroupCompartment::replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
JSProtoKey kind, ObjectGroup* group)
{
AllocationSiteKey key(script, script->pcToOffset(pc), kind, group->proto().toObjectOrNull());
AllocationSiteKey key;
key.script = script;
key.offset = script->pcToOffset(pc);
key.kind = kind;
AllocationSiteTable::Ptr p = allocationSiteTable->lookup(key);
MOZ_RELEASE_ASSERT(p);
@ -1505,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);
}
@ -1799,11 +1765,13 @@ ObjectGroupCompartment::sweep(FreeOp* fop)
if (allocationSiteTable) {
for (AllocationSiteTable::Enum e(*allocationSiteTable); !e.empty(); e.popFront()) {
bool keyDying = IsAboutToBeFinalized(&e.front().mutableKey().script) ||
(e.front().key().proto && IsAboutToBeFinalized(&e.front().mutableKey().proto));
AllocationSiteKey key = e.front().key();
bool keyDying = IsAboutToBeFinalizedUnbarriered(&key.script);
bool valDying = IsAboutToBeFinalized(&e.front().value());
if (keyDying || valDying)
e.removeFront();
else if (key.script != e.front().key().script)
e.rekeyFront(key);
}
}

View File

@ -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

View File

@ -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<RegExpObject>(cx, proto, TenuredObject);
RegExpObject* regexp = NewBuiltinClassInstance<RegExpObject>(cx, TenuredObject);
if (!regexp)
return nullptr;
regexp->initPrivate(nullptr);
return regexp;
}
RegExpObject*
js::InitializeRegExp(ExclusiveContext* cx, Handle<RegExpObject*> 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<RegExpObject*> 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());

View File

@ -64,7 +64,11 @@ enum RegExpRunStatus
};
extern RegExpObject*
RegExpAlloc(ExclusiveContext* cx, HandleObject proto = nullptr);
RegExpAlloc(ExclusiveContext* cx);
extern RegExpObject*
InitializeRegExp(ExclusiveContext* cx, Handle<RegExpObject*> 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<RegExpObject*> regexp, HandleAtom source,
RegExpFlag flags);
private:
friend RegExpObject*
InitializeRegExp(ExclusiveContext* cx, Handle<RegExpObject*> regexp, HandleAtom source,
RegExpFlag flags);
bool init(ExclusiveContext* cx, HandleAtom source, RegExpFlag flags);
/*

View File

@ -1290,21 +1290,10 @@ intrinsic_ConstructorForTypedArray(JSContext* cx, unsigned argc, Value* vp)
RootedObject object(cx, &args[0].toObject());
JSProtoKey protoKey = StandardProtoKeyOrNull(object);
MOZ_ASSERT(protoKey);
RootedValue ctor(cx, cx->global()->getConstructor(protoKey));
MOZ_ASSERT(ctor.isObject());
// While it may seem like an invariant that in any compartment,
// seeing a typed array object implies that the TypedArray constructor
// for that type is initialized on the compartment's global, this is not
// the case. When we construct a typed array given a cross-compartment
// ArrayBuffer, we put the constructed TypedArray in the same compartment
// as the ArrayBuffer. Since we use the prototype from the initial
// compartment, and never call the constructor in the ArrayBuffer's
// compartment from script, we are not guaranteed to have initialized
// the constructor.
RootedObject ctor(cx);
if (!GetBuiltinConstructor(cx, protoKey, &ctor))
return false;
args.rval().setObject(*ctor);
args.rval().set(ctor);
return true;
}

View File

@ -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<StringObject*> strobj(cx, &obj->as<StringObject>());

View File

@ -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);
/*

View File

@ -141,17 +141,6 @@ IsAnyTypedArrayClass(const Class* clasp)
return IsTypedArrayClass(clasp) || IsSharedTypedArrayClass(clasp);
}
inline bool
AnyTypedArrayIsDetached(const JSObject* obj)
{
if (obj->is<TypedArrayObject>()) {
ArrayBufferObject* buffer = obj->as<TypedArrayObject>().buffer();
return buffer && buffer->isNeutered();
}
// You cannot detatch a shared array buffer
return false;
}
class SharedOps
{
public:

View File

@ -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
@ -305,8 +291,17 @@ class TypedArrayObjectTemplate : public TypedArrayObject
{
MOZ_ASSERT(proto);
JSObject* obj = NewObjectWithClassProto(cx, instanceClass(), proto, allocKind);
return obj ? &obj->as<TypedArrayObject>() : nullptr;
RootedObject obj(cx, NewBuiltinClassInstance(cx, instanceClass(), allocKind));
if (!obj)
return nullptr;
ObjectGroup* group = ObjectGroup::defaultNewGroup(cx, obj->getClass(),
TaggedProto(proto.get()));
if (!group)
return nullptr;
obj->setGroup(group);
return &obj->as<TypedArrayObject>();
}
static TypedArrayObject*
@ -430,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()) {
@ -457,13 +449,9 @@ class TypedArrayObjectTemplate : public TypedArrayObject
* shared array's values are copied here.
*/
if (!UncheckedUnwrap(dataObj)->is<ArrayBufferObject>())
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;
@ -487,7 +475,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
}
}
return fromBufferWithProto(cx, dataObj, byteOffset, length, proto);
return fromBuffer(cx, dataObj, byteOffset, length);
}
public:
@ -541,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<JSObject*> proto(cx);
if (!GetBuiltinPrototype(cx, JSCLASS_CACHED_PROTO_KEY(instanceClass()), &proto))
return nullptr;
InvokeArgs args(cx);
if (!args.init(3))
@ -555,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;
@ -570,11 +556,6 @@ class TypedArrayObjectTemplate : public TypedArrayObject
Rooted<ArrayBufferObject*> 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
@ -633,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<ArrayBufferObject*> 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)
@ -687,35 +663,20 @@ struct TypedArrayObject::OfType
template<typename T>
/* static */ JSObject*
TypedArrayObjectTemplate<T>::fromArray(JSContext* cx, HandleObject other,
HandleObject newTarget /* = nullptr */)
TypedArrayObjectTemplate<T>::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<ArrayBufferObject*> buffer(cx);
if (!maybeCreateArrayBuffer(cx, len, &buffer))
return nullptr;
Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, len, proto));
Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, len));
if (!obj || !TypedArrayMethods<TypedArrayObject>::setFromArrayLike(cx, obj, other, len))
return nullptr;
return obj;
@ -1001,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<ArrayBufferObject*> arrayBuffer, JSObject* protoArg)
{
@ -1013,21 +974,24 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
RootedObject obj(cx);
NewObjectKind newKind = DataViewNewObjectKind(cx, byteLength, proto);
obj = NewObjectWithClassProto(cx, &class_, proto, newKind);
obj = NewBuiltinClassInstance(cx, &class_, newKind);
if (!obj)
return nullptr;
if (!proto) {
if (byteLength >= TypedArrayObject::SINGLETON_BYTE_LENGTH) {
MOZ_ASSERT(obj->isSingleton());
} else {
jsbytecode* pc;
RootedScript script(cx, cx->currentScript(&pc));
if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, obj,
newKind == SingletonObject))
{
return nullptr;
}
if (proto) {
ObjectGroup* group = ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(proto));
if (!group)
return nullptr;
obj->setGroup(group);
} else if (byteLength >= TypedArrayObject::SINGLETON_BYTE_LENGTH) {
MOZ_ASSERT(obj->isSingleton());
} else {
jsbytecode* pc;
RootedScript script(cx, cx->currentScript(&pc));
if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, obj,
newKind == SingletonObject))
{
return nullptr;
}
}
@ -1058,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,
@ -1075,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;
}
}
@ -1116,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, HandleObject bufobj, const CallArgs& args)
{
MOZ_ASSERT(args.isConstructing());
assertSameCompartment(cx, bufobj);
uint32_t byteOffset, byteLength;
if (!getAndCheckConstructorArgs(cx, bufobj, args, &byteOffset, &byteLength))
if (byteOffset + byteLength > buffer->byteLength()) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
return false;
}
RootedObject proto(cx);
RootedObject newTarget(cx, &args.newTarget().toObject());
if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
return false;
Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(bufobj));
JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, proto);
if (!obj)
return false;
@ -1146,70 +1080,6 @@ DataViewObject::constructSameCompartment(JSContext* cx, HandleObject bufobj, con
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, HandleObject bufobj, const CallArgs& args)
{
MOZ_ASSERT(args.isConstructing());
MOZ_ASSERT(bufobj->is<WrapperObject>());
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<GlobalObject*> 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)
{
@ -1222,9 +1092,26 @@ DataViewObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
if (!GetFirstArgumentAsObject(cx, args, "DataView constructor", &bufobj))
return false;
if (bufobj->is<WrapperObject>())
return constructWrapped(cx, bufobj, args);
return constructSameCompartment(cx, bufobj, args);
if (bufobj->is<WrapperObject>() && IsArrayBuffer(UncheckedUnwrap(bufobj))) {
Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
Rooted<JSObject*> 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 <typename NativeType>
@ -1331,11 +1218,6 @@ DataViewObject::read(JSContext* cx, Handle<DataViewObject*> 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<NativeType>(cx, obj, offset);
if (!data)
return false;
@ -1397,11 +1279,6 @@ DataViewObject::write(JSContext* cx, Handle<DataViewObject*> 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<NativeType>(cx, obj, offset);
if (!data)
return false;
@ -1822,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<NativeType>::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<NativeType>::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<NativeType>::fromBuffer(cx, arrayBuffer, byteOffset, \
@ -1842,8 +1719,8 @@ TypedArrayObject::setElement(TypedArrayObject& obj, uint32_t index, double d)
return false; \
const Class* clasp = obj->getClass(); \
return clasp == TypedArrayObjectTemplate<NativeType>::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) \
@ -1852,7 +1729,7 @@ TypedArrayObject::setElement(TypedArrayObject& obj, uint32_t index, double d)
if (clasp == TypedArrayObjectTemplate<NativeType>::instanceClass()) \
return obj; \
return nullptr; \
} \
} \
const js::Class* const js::detail::Name ## ArrayClassPtr = \
&js::TypedArrayObject::classes[TypedArrayObjectTemplate<NativeType>::ArrayTypeID()];

View File

@ -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, HandleObject bufobj, const CallArgs& args);
static bool constructWrapped(JSContext* cx, HandleObject 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<ArrayBufferObject*> 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<ArrayBufferObject*> arrayBuffer, JSObject* proto);
static bool getInt8Impl(JSContext* cx, const CallArgs& args);
static bool fun_getInt8(JSContext* cx, unsigned argc, Value* vp);