Bug 1386534 - Use a C++ version of SpeciesConstructor when calling from C++. r=anba,rs=jonco

MozReview-Commit-ID: qyU0pqt0tV
This commit is contained in:
Till Schneidereit 2017-08-01 16:14:05 +02:00
Родитель f979e78b8c
Коммит 718ce2a817
6 изменённых файлов: 111 добавлений и 95 удалений

Просмотреть файл

@ -2177,7 +2177,18 @@ PromiseObject::unforgeableResolve(JSContext* cx, HandleValue value)
return CommonStaticResolveRejectImpl(cx, cVal, value, ResolveMode);
}
// ES2016, 25.4.4.6, implemented in Promise.js.
/**
* ES2016, 25.4.4.6 get Promise [ @@species ]
*/
static bool
Promise_static_species(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1: Return the this value.
args.rval().set(args.thisv());
return true;
}
// ES2016, 25.4.5.1, implemented in Promise.js.
@ -2209,6 +2220,12 @@ NewReactionRecord(JSContext* cx, HandleObject resultPromise, HandleValue onFulfi
return reaction;
}
static bool
IsPromiseSpecies(JSContext* cx, JSFunction* species)
{
return species->maybeNative() == Promise_static_species;
}
// ES2016, 25.4.5.3., steps 3-5.
MOZ_MUST_USE bool
js::OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
@ -2227,10 +2244,9 @@ js::OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
if (createDependent) {
// Step 3.
RootedValue ctorVal(cx);
if (!SpeciesConstructor(cx, promiseObj, JSProto_Promise, &ctorVal))
RootedObject C(cx, SpeciesConstructor(cx, promiseObj, JSProto_Promise, IsPromiseSpecies));
if (!C)
return false;
RootedObject C(cx, &ctorVal.toObject());
// Step 4.
if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, true))
@ -2875,11 +2891,10 @@ BlockOnPromise(JSContext* cx, HandleValue promiseVal, HandleObject blockedPromis
RootedObject PromiseCtor(cx);
if (!GetBuiltinConstructor(cx, JSProto_Promise, &PromiseCtor))
return false;
RootedValue PromiseCtorVal(cx, ObjectValue(*PromiseCtor));
RootedValue CVal(cx);
if (!SpeciesConstructor(cx, promiseObj, PromiseCtorVal, &CVal))
RootedObject C(cx, SpeciesConstructor(cx, PromiseCtor, JSProto_Promise, IsPromiseSpecies));
if (!C)
return false;
RootedObject C(cx, &CVal.toObject());
RootedObject resultPromise(cx, blockedPromise_);
RootedObject resolveFun(cx);
@ -3471,7 +3486,7 @@ static const JSFunctionSpec promise_static_methods[] = {
};
static const JSPropertySpec promise_static_properties[] = {
JS_SELF_HOSTED_SYM_GET(species, "Promise_static_get_species", 0),
JS_SYM_GET(species, Promise_static_species, 0),
JS_PS_END
};

Просмотреть файл

@ -2,13 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// ES6, 25.4.4.6.
function Promise_static_get_species() {
// Step 1.
return this;
}
_SetCanonicalName(Promise_static_get_species, "get [Symbol.species]");
// ES6, 25.4.5.1.
function Promise_catch(onRejected) {
// Steps 1-2.

Просмотреть файл

@ -2294,6 +2294,9 @@ inline int CheckIsSetterOp(JSSetterOp op);
#define JS_PSGS(name, getter, setter, flags) \
JS_PS_ACCESSOR_SPEC(name, JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(setter), flags, \
JSPROP_SHARED)
#define JS_SYM_GET(symbol, getter, flags) \
JS_PS_ACCESSOR_SPEC(reinterpret_cast<const char*>(uint32_t(::JS::SymbolCode::symbol) + 1), \
JSNATIVE_WRAPPER(getter), JSNATIVE_WRAPPER(nullptr), flags, JSPROP_SHARED)
#define JS_SELF_HOSTED_GET(name, getterName, flags) \
JS_PS_ACCESSOR_SPEC(name, SELFHOSTED_WRAPPER(getterName), JSNATIVE_WRAPPER(nullptr), flags, \
JSPROP_SHARED | JSPROP_GETTER)

Просмотреть файл

@ -3998,34 +3998,77 @@ JSObject::maybeConstructorDisplayAtom() const
return displayAtomFromObjectGroup(*group());
}
bool
js::SpeciesConstructor(JSContext* cx, HandleObject obj, HandleValue defaultCtor, MutableHandleValue pctor)
// ES 2016 7.3.20.
MOZ_MUST_USE JSObject*
js::SpeciesConstructor(JSContext* cx, HandleObject obj, HandleObject defaultCtor,
bool (*isDefaultSpecies)(JSContext*, JSFunction*))
{
HandlePropertyName shName = cx->names().SpeciesConstructor;
RootedValue func(cx);
if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, shName, 2, &func))
return false;
// Step 1 (implicit).
FixedInvokeArgs<2> args(cx);
// Fast-path for steps 2 - 8. Applies if all of the following conditions
// are met:
// - obj.constructor can be retrieved without side-effects.
// - obj.constructor[[@@species]] can be retrieved without side-effects.
// - obj.constructor[[@@species]] is the builtin's original @@species
// getter.
RootedValue ctor(cx);
bool ctorGetSucceeded = GetPropertyPure(cx, obj, NameToId(cx->names().constructor),
ctor.address());
if (ctorGetSucceeded && ctor.isObject() && &ctor.toObject() == defaultCtor) {
RootedObject ctorObj(cx, &ctor.toObject());
RootedId speciesId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().species));
JSFunction* getter;
if (GetGetterPure(cx, ctorObj, speciesId, &getter) && getter &&
isDefaultSpecies(cx, getter))
{
return defaultCtor;
}
}
args[0].setObject(*obj);
args[1].set(defaultCtor);
// Step 2.
if (!ctorGetSucceeded && !GetProperty(cx, obj, obj, cx->names().constructor, &ctor))
return nullptr;
if (!Call(cx, func, UndefinedHandleValue, args, pctor))
return false;
// Step 3.
if (ctor.isUndefined())
return defaultCtor;
pctor.set(args.rval());
return true;
// Step 4.
if (!ctor.isObject()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
"object's 'constructor' property");
return nullptr;
}
// Step 5.
RootedObject ctorObj(cx, &ctor.toObject());
RootedValue s(cx);
RootedId speciesId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().species));
if (!GetProperty(cx, ctorObj, ctor, speciesId, &s))
return nullptr;
// Step 6.
if (s.isNullOrUndefined())
return defaultCtor;
// Step 7.
if (IsConstructor(s))
return &s.toObject();
// Step 8.
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_CONSTRUCTOR,
"[Symbol.species] property of object's constructor");
return nullptr;
}
bool
MOZ_MUST_USE JSObject*
js::SpeciesConstructor(JSContext* cx, HandleObject obj, JSProtoKey ctorKey,
MutableHandleValue pctor)
bool (*isDefaultSpecies)(JSContext*, JSFunction*))
{
if (!GlobalObject::ensureConstructor(cx, cx->global(), ctorKey))
return false;
RootedValue defaultCtor(cx, cx->global()->getConstructor(ctorKey));
return SpeciesConstructor(cx, obj, defaultCtor, pctor);
return nullptr;
RootedObject defaultCtor(cx, &cx->global()->getConstructor(ctorKey).toObject());
return SpeciesConstructor(cx, obj, defaultCtor, isDefaultSpecies);
}
bool

Просмотреть файл

@ -1418,11 +1418,13 @@ FreezeObject(JSContext* cx, HandleObject obj)
extern bool
TestIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level, bool* resultp);
extern bool
SpeciesConstructor(JSContext* cx, HandleObject obj, HandleValue defaultCtor, MutableHandleValue pctor);
extern MOZ_MUST_USE JSObject*
SpeciesConstructor(JSContext* cx, HandleObject obj, HandleObject defaultCtor,
bool (*isDefaultSpecies)(JSContext*, JSFunction*));
extern bool
SpeciesConstructor(JSContext* cx, HandleObject obj, JSProtoKey ctorKey, MutableHandleValue pctor);
extern MOZ_MUST_USE JSObject*
SpeciesConstructor(JSContext* cx, HandleObject obj, JSProtoKey ctorKey,
bool (*isDefaultSpecies)(JSContext*, JSFunction*));
extern bool
GetObjectFromIncumbentGlobal(JSContext* cx, MutableHandleObject obj);

Просмотреть файл

@ -1067,70 +1067,28 @@ TypedArrayObjectTemplate<T>::AllocateArrayBuffer(JSContext* cx, HandleValue ctor
}
static bool
IsArrayBufferConstructor(const Value& v)
IsArrayBufferSpecies(JSContext* cx, JSFunction* species)
{
return v.isObject() &&
v.toObject().is<JSFunction>() &&
v.toObject().as<JSFunction>().isNative() &&
v.toObject().as<JSFunction>().native() == ArrayBufferObject::class_constructor;
return IsSelfHostedFunctionWithName(species, cx->names().ArrayBufferSpecies);
}
static bool
IsArrayBufferSpecies(JSContext* cx, HandleObject origBuffer)
{
RootedValue ctor(cx);
if (!GetPropertyPure(cx, origBuffer, NameToId(cx->names().constructor), ctor.address()))
return false;
if (!IsArrayBufferConstructor(ctor))
return false;
RootedObject ctorObj(cx, &ctor.toObject());
RootedId speciesId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().species));
JSFunction* getter;
if (!GetGetterPure(cx, ctorObj, speciesId, &getter))
return false;
if (!getter)
return false;
return IsSelfHostedFunctionWithName(getter, cx->names().ArrayBufferSpecies);
}
static bool
static JSObject*
GetSpeciesConstructor(JSContext* cx, HandleObject obj, bool isWrapped,
SpeciesConstructorOverride override, MutableHandleValue ctor)
SpeciesConstructorOverride override)
{
if (!GlobalObject::ensureConstructor(cx, cx->global(), JSProto_ArrayBuffer))
return false;
RootedValue defaultCtor(cx, cx->global()->getConstructor(JSProto_ArrayBuffer));
return nullptr;
RootedObject defaultCtor(cx, &cx->global()->getConstructor(JSProto_ArrayBuffer).toObject());
// Use the current global's ArrayBuffer if the override is set.
if (override == SpeciesConstructorOverride::ArrayBuffer) {
ctor.set(defaultCtor);
return true;
}
if (!isWrapped) {
// As an optimization, avoid calling into self-hosted code if |obj|'s
// constructor is the built-in ArrayBuffer and the constructor's
// species property is the original ArrayBuffer[@@species] function.
if (IsArrayBufferSpecies(cx, obj))
ctor.set(defaultCtor);
else if (!SpeciesConstructor(cx, obj, defaultCtor, ctor))
return false;
return true;
}
if (override == SpeciesConstructorOverride::ArrayBuffer)
return defaultCtor;
RootedObject wrappedObj(cx, obj);
if (!cx->compartment()->wrap(cx, &wrappedObj))
return false;
if (isWrapped && !cx->compartment()->wrap(cx, &wrappedObj))
return nullptr;
if (!SpeciesConstructor(cx, wrappedObj, defaultCtor, ctor))
return false;
return true;
return SpeciesConstructor(cx, wrappedObj, defaultCtor, IsArrayBufferSpecies);
}
// ES 2017 draft rev 8633ffd9394b203b8876bb23cb79aff13eb07310 24.1.1.4.
@ -1146,9 +1104,10 @@ TypedArrayObjectTemplate<T>::CloneArrayBufferNoCopy(JSContext* cx,
// Step 1 (skipped).
// Step 2.a.
RootedValue cloneCtor(cx);
if (!GetSpeciesConstructor(cx, srcBuffer, isWrapped, override, &cloneCtor))
JSObject* ctorObj = GetSpeciesConstructor(cx, srcBuffer, isWrapped, override);
if (!ctorObj)
return false;
RootedValue cloneCtor(cx, ObjectValue(*ctorObj));
// Step 2.b.
if (srcBuffer->isDetached()) {
@ -1266,9 +1225,10 @@ TypedArrayObjectTemplate<T>::fromTypedArray(JSContext* cx, HandleObject other, b
}
} else {
// Steps 17.a-b.
RootedValue bufferCtor(cx);
if (!GetSpeciesConstructor(cx, srcData, isWrapped, override, &bufferCtor))
JSObject* ctorObj = GetSpeciesConstructor(cx, srcData, isWrapped, override);
if (!ctorObj)
return nullptr;
RootedValue bufferCtor(cx, ObjectValue(*ctorObj));
// Steps 14-15, 17.c.
if (!AllocateArrayBuffer(cx, bufferCtor, elementLength, BYTES_PER_ELEMENT, &buffer))