mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1082672, part 1 - Add JSAPI macros JS_SYM_FN etc. to support defining functions with well-known symbol keys. r=Waldo.
--HG-- extra : rebase_source : 9791c940599844802c9a262fe8b1610a0de3ef40
This commit is contained in:
parent
2f541b83f6
commit
f07de76ea5
@ -1685,7 +1685,7 @@ InitIds(JSContext* cx, const Prefable<Spec>* prefableSpecs, jsid* ids)
|
||||
// because this is only done once per application runtime.
|
||||
Spec* spec = prefableSpecs->specs;
|
||||
do {
|
||||
if (!InternJSString(cx, *ids, spec->name)) {
|
||||
if (!JS::PropertySpecNameToPermanentId(cx, spec->name, ids)) {
|
||||
return false;
|
||||
}
|
||||
} while (++ids, (++spec)->name);
|
||||
|
133
js/src/jsapi.cpp
133
js/src/jsapi.cpp
@ -2781,7 +2781,8 @@ JS_AlreadyHasOwnUCProperty(JSContext *cx, HandleObject obj, const char16_t *name
|
||||
return JS_AlreadyHasOwnPropertyById(cx, obj, id, foundp);
|
||||
}
|
||||
|
||||
/* Wrapper functions to create wrappers with no corresponding JSJitInfo from API
|
||||
/*
|
||||
* Wrapper functions to create wrappers with no corresponding JSJitInfo from API
|
||||
* function arguments.
|
||||
*/
|
||||
static JSPropertyOpWrapper
|
||||
@ -2825,8 +2826,6 @@ DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue val
|
||||
MOZ_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
|
||||
JSFunction::Flags zeroFlags = JSAPIToJSFunctionFlags(0);
|
||||
|
||||
// We can't just use JS_NewFunctionById here because it assumes a
|
||||
// string id.
|
||||
RootedAtom atom(cx, JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : nullptr);
|
||||
attrs &= ~JSPROP_NATIVE_ACCESSORS;
|
||||
if (getter) {
|
||||
@ -2863,12 +2862,12 @@ DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue val
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, id, value,
|
||||
(attrs & JSPROP_GETTER)
|
||||
? JS_FUNC_TO_DATA_PTR(JSObject *, getter)
|
||||
: nullptr,
|
||||
(attrs & JSPROP_SETTER)
|
||||
? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
|
||||
: nullptr);
|
||||
(attrs & JSPROP_GETTER)
|
||||
? JS_FUNC_TO_DATA_PTR(JSObject *, getter)
|
||||
: nullptr,
|
||||
(attrs & JSPROP_SETTER)
|
||||
? JS_FUNC_TO_DATA_PTR(JSObject *, setter)
|
||||
: nullptr);
|
||||
|
||||
return JSObject::defineGeneric(cx, obj, id, value, getter, setter, attrs);
|
||||
}
|
||||
@ -3012,30 +3011,22 @@ DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue va
|
||||
return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags);
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
DefineSelfHostedProperty(JSContext *cx,
|
||||
HandleObject obj,
|
||||
const char *name,
|
||||
const char *getterName,
|
||||
const char *setterName,
|
||||
unsigned attrs,
|
||||
unsigned flags)
|
||||
DefineSelfHostedProperty(JSContext *cx, HandleObject obj, HandleId id,
|
||||
const char *getterName, const char *setterName,
|
||||
unsigned attrs, unsigned flags)
|
||||
{
|
||||
RootedAtom nameAtom(cx, Atomize(cx, name, strlen(name)));
|
||||
if (!nameAtom)
|
||||
return false;
|
||||
|
||||
RootedAtom getterNameAtom(cx, Atomize(cx, getterName, strlen(getterName)));
|
||||
if (!getterNameAtom)
|
||||
return false;
|
||||
|
||||
RootedValue getterValue(cx);
|
||||
if (!cx->global()->getSelfHostedFunction(cx, getterNameAtom, nameAtom,
|
||||
0, &getterValue))
|
||||
{
|
||||
RootedAtom name(cx, IdToFunctionName(cx, id));
|
||||
if (!name)
|
||||
return false;
|
||||
|
||||
RootedValue getterValue(cx);
|
||||
if (!cx->global()->getSelfHostedFunction(cx, getterNameAtom, name, 0, &getterValue))
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(getterValue.isObject() && getterValue.toObject().is<JSFunction>());
|
||||
RootedFunction getterFunc(cx, &getterValue.toObject().as<JSFunction>());
|
||||
JSPropertyOp getterOp = JS_DATA_TO_FUNC_PTR(PropertyOp, getterFunc.get());
|
||||
@ -3047,19 +3038,16 @@ DefineSelfHostedProperty(JSContext *cx,
|
||||
return false;
|
||||
|
||||
RootedValue setterValue(cx);
|
||||
if (!cx->global()->getSelfHostedFunction(cx, setterNameAtom, nameAtom,
|
||||
0, &setterValue))
|
||||
{
|
||||
if (!cx->global()->getSelfHostedFunction(cx, setterNameAtom, name, 0, &setterValue))
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(setterValue.isObject() && setterValue.toObject().is<JSFunction>());
|
||||
setterFunc = &getterValue.toObject().as<JSFunction>();
|
||||
}
|
||||
JSStrictPropertyOp setterOp = JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setterFunc.get());
|
||||
|
||||
return DefineProperty(cx, obj, name, JS::UndefinedHandleValue,
|
||||
GetterWrapper(getterOp), SetterWrapper(setterOp),
|
||||
attrs, flags);
|
||||
return DefinePropertyById(cx, obj, id, JS::UndefinedHandleValue,
|
||||
GetterWrapper(getterOp), SetterWrapper(setterOp),
|
||||
attrs, flags);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
@ -3256,37 +3244,73 @@ JS_DefineConstIntegers(JSContext *cx, HandleObject obj, const JSConstIntegerSpec
|
||||
return DefineConstScalar(cx, obj, cis);
|
||||
}
|
||||
|
||||
static bool
|
||||
PropertySpecNameToId(JSContext *cx, const char *name, MutableHandleId id,
|
||||
js::InternBehavior ib = js::DoNotInternAtom)
|
||||
{
|
||||
if (JS::PropertySpecNameIsSymbol(name)) {
|
||||
uintptr_t u = reinterpret_cast<uintptr_t>(name);
|
||||
id.set(SYMBOL_TO_JSID(cx->wellKnownSymbols().get(u - 1)));
|
||||
} else {
|
||||
JSAtom *atom = Atomize(cx, name, strlen(name), ib);
|
||||
if (!atom)
|
||||
return false;
|
||||
id.set(AtomToId(atom));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::PropertySpecNameToPermanentId(JSContext *cx, const char *name, jsid *idp)
|
||||
{
|
||||
// We are calling fromMarkedLocation(idp) even though idp points to a
|
||||
// location that will never be marked. This is OK because the whole point
|
||||
// of this API is to populate *idp with a jsid that does not need to be
|
||||
// marked.
|
||||
return PropertySpecNameToId(cx, name, MutableHandleId::fromMarkedLocation(idp),
|
||||
js::InternAtom);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_DefineProperties(JSContext *cx, HandleObject obj, const JSPropertySpec *ps)
|
||||
{
|
||||
bool ok;
|
||||
for (ok = true; ps->name; ps++) {
|
||||
RootedId id(cx);
|
||||
|
||||
for (; ps->name; ps++) {
|
||||
if (!PropertySpecNameToId(cx, ps->name, &id))
|
||||
return false;
|
||||
|
||||
if (ps->flags & JSPROP_NATIVE_ACCESSORS) {
|
||||
// If you declare native accessors, then you should have a native
|
||||
// getter.
|
||||
MOZ_ASSERT(ps->getter.propertyOp.op);
|
||||
|
||||
// If you do not have a self-hosted getter, you should not have a
|
||||
// self-hosted setter. This is the closest approximation to that
|
||||
// assertion we can have with our setup.
|
||||
MOZ_ASSERT_IF(ps->setter.propertyOp.info, ps->setter.propertyOp.op);
|
||||
|
||||
ok = DefineProperty(cx, obj, ps->name, JS::UndefinedHandleValue,
|
||||
ps->getter.propertyOp, ps->setter.propertyOp, ps->flags, 0);
|
||||
if (!DefinePropertyById(cx, obj, id, JS::UndefinedHandleValue,
|
||||
ps->getter.propertyOp, ps->setter.propertyOp, ps->flags, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// If you have self-hosted getter/setter, you can't have a
|
||||
// native one.
|
||||
MOZ_ASSERT(!ps->getter.propertyOp.op && !ps->setter.propertyOp.op);
|
||||
MOZ_ASSERT(ps->flags & JSPROP_GETTER);
|
||||
|
||||
ok = DefineSelfHostedProperty(cx, obj, ps->name,
|
||||
if (!DefineSelfHostedProperty(cx, obj, id,
|
||||
ps->getter.selfHosted.funname,
|
||||
ps->setter.selfHosted.funname,
|
||||
ps->flags, 0);
|
||||
ps->flags, 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!ok)
|
||||
break;
|
||||
}
|
||||
return ok;
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
@ -3768,12 +3792,14 @@ JS_NewFunctionById(JSContext *cx, JSNative native, unsigned nargs, unsigned flag
|
||||
JS_PUBLIC_API(JSFunction *)
|
||||
JS::GetSelfHostedFunction(JSContext *cx, const char *selfHostedName, HandleId id, unsigned nargs)
|
||||
{
|
||||
MOZ_ASSERT(JSID_IS_STRING(id));
|
||||
MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
|
||||
AssertHeapIsIdle(cx);
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
RootedAtom name(cx, JSID_TO_ATOM(id));
|
||||
RootedAtom name(cx, IdToFunctionName(cx, id));
|
||||
if (!name)
|
||||
return nullptr;
|
||||
|
||||
RootedAtom shName(cx, Atomize(cx, selfHostedName, strlen(selfHostedName)));
|
||||
if (!shName)
|
||||
return nullptr;
|
||||
@ -3937,21 +3963,11 @@ JS_DefineFunctions(JSContext *cx, HandleObject obj, const JSFunctionSpec *fs)
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj);
|
||||
|
||||
RootedId id(cx);
|
||||
for (; fs->name; fs++) {
|
||||
RootedAtom atom(cx);
|
||||
// If the name starts with "@@", it must be a well-known symbol.
|
||||
if (fs->name[0] != '@' || fs->name[1] != '@')
|
||||
atom = Atomize(cx, fs->name, strlen(fs->name));
|
||||
else if (strcmp(fs->name, "@@iterator") == 0)
|
||||
// FIXME: This atom should be a symbol: bug 918828.
|
||||
atom = cx->names().std_iterator;
|
||||
else
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_SYMBOL, fs->name);
|
||||
if (!atom)
|
||||
if (!PropertySpecNameToId(cx, fs->name, &id))
|
||||
return false;
|
||||
|
||||
Rooted<jsid> id(cx, AtomToId(atom));
|
||||
|
||||
/*
|
||||
* Define a generic arity N+1 static method for the arity N prototype
|
||||
* method if flags contains JSFUN_GENERIC_NATIVE.
|
||||
@ -3993,8 +4009,11 @@ JS_DefineFunctions(JSContext *cx, HandleObject obj, const JSFunctionSpec *fs)
|
||||
RootedAtom shName(cx, Atomize(cx, fs->selfHostedName, strlen(fs->selfHostedName)));
|
||||
if (!shName)
|
||||
return false;
|
||||
RootedAtom name(cx, IdToFunctionName(cx, id));
|
||||
if (!name)
|
||||
return false;
|
||||
RootedValue funVal(cx);
|
||||
if (!cx->global()->getSelfHostedFunction(cx, shName, atom, fs->nargs, &funVal))
|
||||
if (!cx->global()->getSelfHostedFunction(cx, shName, name, fs->nargs, &funVal))
|
||||
return false;
|
||||
if (!JSObject::defineGeneric(cx, obj, id, funVal, nullptr, nullptr, flags))
|
||||
return false;
|
||||
|
@ -2475,15 +2475,27 @@ struct JSFunctionSpec {
|
||||
* JSFUN_STUB_GSOPS. JS_FNINFO allows the simple adding of
|
||||
* JSJitInfos. JS_SELF_HOSTED_FN declares a self-hosted function. Finally
|
||||
* JS_FNSPEC has slots for all the fields.
|
||||
*
|
||||
* The _SYM variants allow defining a function with a symbol key rather than a
|
||||
* string key. For example, use JS_SYM_FN(iterator, ...) to define an
|
||||
* @@iterator method.
|
||||
*/
|
||||
#define JS_FS(name,call,nargs,flags) \
|
||||
JS_FNSPEC(name, call, nullptr, nargs, flags, nullptr)
|
||||
#define JS_FN(name,call,nargs,flags) \
|
||||
JS_FNSPEC(name, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr)
|
||||
#define JS_SYM_FN(name,call,nargs,flags) \
|
||||
JS_SYM_FNSPEC(symbol, call, nullptr, nargs, (flags) | JSFUN_STUB_GSOPS, nullptr)
|
||||
#define JS_FNINFO(name,call,info,nargs,flags) \
|
||||
JS_FNSPEC(name, call, info, nargs, flags, nullptr)
|
||||
#define JS_SELF_HOSTED_FN(name,selfHostedName,nargs,flags) \
|
||||
JS_FNSPEC(name, nullptr, nullptr, nargs, flags, selfHostedName)
|
||||
#define JS_SELF_HOSTED_SYM_FN(symbol, selfHostedName, nargs, flags) \
|
||||
JS_SYM_FNSPEC(symbol, nullptr, nullptr, nargs, flags, selfHostedName)
|
||||
#define JS_SYM_FNSPEC(symbol, call, info, nargs, flags, selfHostedName) \
|
||||
JS_FNSPEC(reinterpret_cast<const char *>( \
|
||||
uint32_t(::JS::SymbolCode::symbol) + 1), \
|
||||
call, info, nargs, flags, selfHostedName)
|
||||
#define JS_FNSPEC(name,call,info,nargs,flags,selfHostedName) \
|
||||
{name, {call, info}, nargs, flags, selfHostedName}
|
||||
|
||||
@ -4494,6 +4506,28 @@ GetSymbolCode(Handle<Symbol*> symbol);
|
||||
JS_PUBLIC_API(Symbol *)
|
||||
GetWellKnownSymbol(JSContext *cx, SymbolCode which);
|
||||
|
||||
/*
|
||||
* Return true if the given JSPropertySpec::name or JSFunctionSpec::name value
|
||||
* is actually a symbol code and not a string. See JS_SYM_FN.
|
||||
*/
|
||||
inline bool
|
||||
PropertySpecNameIsSymbol(const char *name)
|
||||
{
|
||||
uintptr_t u = reinterpret_cast<uintptr_t>(name);
|
||||
return u != 0 && u - 1 < WellKnownSymbolLimit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a jsid that does not need to be marked for GC.
|
||||
*
|
||||
* 'name' is a JSPropertySpec::name or JSFunctionSpec::name value. The
|
||||
* resulting jsid, on success, is either an interned string or a well-known
|
||||
* symbol; either way it is immune to GC so there is no need to visit *idp
|
||||
* during GC marking.
|
||||
*/
|
||||
JS_PUBLIC_API(bool)
|
||||
PropertySpecNameToPermanentId(JSContext *cx, const char *name, jsid *idp);
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
/************************************************************************/
|
||||
|
@ -284,6 +284,7 @@ struct ThreadSafeContext : ContextFriendFields,
|
||||
JSAtomState &names() { return *runtime_->commonNames; }
|
||||
StaticStrings &staticStrings() { return *runtime_->staticStrings; }
|
||||
AtomSet &permanentAtoms() { return *runtime_->permanentAtoms; }
|
||||
WellKnownSymbols &wellKnownSymbols() { return *runtime_->wellKnownSymbols; }
|
||||
const JS::AsmJSCacheOps &asmJSCacheOps() { return runtime_->asmJSCacheOps; }
|
||||
PropertyName *emptyString() { return runtime_->emptyString; }
|
||||
FreeOp *defaultFreeOp() { return runtime_->defaultFreeOp(); }
|
||||
|
@ -2063,6 +2063,33 @@ js::CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent,
|
||||
return cloneRoot;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return an atom for use as the name of a builtin method with the given
|
||||
* property id.
|
||||
*
|
||||
* Function names are always strings. If id is the well-known @@iterator
|
||||
* symbol, this returns "[Symbol.iterator]".
|
||||
*
|
||||
* Implements step 4 of SetFunctionName in ES6 draft rev 27 (24 Aug 2014).
|
||||
*/
|
||||
JSAtom *
|
||||
js::IdToFunctionName(JSContext *cx, HandleId id)
|
||||
{
|
||||
if (JSID_IS_ATOM(id))
|
||||
return JSID_TO_ATOM(id);
|
||||
|
||||
if (JSID_IS_SYMBOL(id)) {
|
||||
RootedAtom desc(cx, JSID_TO_SYMBOL(id)->description());
|
||||
StringBuffer sb(cx);
|
||||
if (!sb.append('[') || !sb.append(desc) || !sb.append(']'))
|
||||
return nullptr;
|
||||
return sb.finishAtom();
|
||||
}
|
||||
|
||||
RootedValue idv(cx, IdToValue(id));
|
||||
return ToAtom<CanGC>(cx, idv);
|
||||
}
|
||||
|
||||
JSFunction *
|
||||
js::DefineFunction(JSContext *cx, HandleObject obj, HandleId id, Native native,
|
||||
unsigned nargs, unsigned flags, AllocKind allocKind /* = FinalizeKind */,
|
||||
@ -2070,9 +2097,6 @@ js::DefineFunction(JSContext *cx, HandleObject obj, HandleId id, Native native,
|
||||
{
|
||||
PropertyOp gop;
|
||||
StrictPropertyOp sop;
|
||||
|
||||
RootedFunction fun(cx);
|
||||
|
||||
if (flags & JSFUN_STUB_GSOPS) {
|
||||
/*
|
||||
* JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
|
||||
@ -2093,8 +2117,13 @@ js::DefineFunction(JSContext *cx, HandleObject obj, HandleId id, Native native,
|
||||
funFlags = JSFunction::INTERPRETED_LAZY;
|
||||
else
|
||||
funFlags = JSAPIToJSFunctionFlags(flags);
|
||||
RootedAtom atom(cx, JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : nullptr);
|
||||
fun = NewFunction(cx, NullPtr(), native, nargs, funFlags, obj, atom, allocKind, newKind);
|
||||
|
||||
RootedAtom atom(cx, IdToFunctionName(cx, id));
|
||||
if (!atom)
|
||||
return nullptr;
|
||||
|
||||
RootedFunction fun(cx, NewFunction(cx, NullPtr(), native, nargs, funFlags, obj, atom,
|
||||
allocKind, newKind));
|
||||
if (!fun)
|
||||
return nullptr;
|
||||
|
||||
|
@ -521,6 +521,9 @@ NewFunctionWithProto(ExclusiveContext *cx, HandleObject funobj, JSNative native,
|
||||
JSObject *proto, gc::AllocKind allocKind = JSFunction::FinalizeKind,
|
||||
NewObjectKind newKind = GenericObject);
|
||||
|
||||
extern JSAtom *
|
||||
IdToFunctionName(JSContext *cx, HandleId id);
|
||||
|
||||
extern JSFunction *
|
||||
DefineFunction(JSContext *cx, HandleObject obj, HandleId id, JSNative native,
|
||||
unsigned nargs, unsigned flags,
|
||||
@ -572,7 +575,6 @@ CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent,
|
||||
gc::AllocKind kind = JSFunction::FinalizeKind,
|
||||
NewObjectKind newKindArg = GenericObject);
|
||||
|
||||
|
||||
extern bool
|
||||
FindBody(JSContext *cx, HandleFunction fun, HandleLinearString src, size_t *bodyStart,
|
||||
size_t *bodyEnd);
|
||||
@ -664,7 +666,7 @@ js_fun_apply(JSContext *cx, unsigned argc, js::Value *vp);
|
||||
extern bool
|
||||
js_fun_call(JSContext *cx, unsigned argc, js::Value *vp);
|
||||
|
||||
extern JSObject*
|
||||
extern JSObject *
|
||||
js_fun_bind(JSContext *cx, js::HandleObject target, js::HandleValue thisArg,
|
||||
js::Value *boundArgs, unsigned argslen);
|
||||
|
||||
|
@ -414,7 +414,7 @@ namespace js {
|
||||
* Storage for well-known symbols. It's a separate struct from the Runtime so
|
||||
* that it can be shared across multiple runtimes. As in JSAtomState, each
|
||||
* field is a smart pointer that's immutable once initialized.
|
||||
* `rt->wellKnownSymbols.iterator` is convertible to Handle<Symbol*>.
|
||||
* `rt->wellKnownSymbols->iterator` is convertible to Handle<Symbol*>.
|
||||
*
|
||||
* Well-known symbols are never GC'd. The description() of each well-known
|
||||
* symbol is a permanent atom.
|
||||
|
Loading…
Reference in New Issue
Block a user