mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-18 15:55:36 +00:00
Bug 1232022 - Part 1: Mark self-hosted intrinsics for later checking. (r=till)
This commit is contained in:
parent
64c257e2ac
commit
c26c287169
@ -1411,7 +1411,7 @@ const JSFunctionSpec selfhosting_collection_iterator_methods[] = {
|
||||
bool
|
||||
js::InitSelfHostingCollectionIteratorFunctions(JSContext* cx, HandleObject obj)
|
||||
{
|
||||
return JS_DefineFunctions(cx, obj, selfhosting_collection_iterator_methods);
|
||||
return DefineFunctions(cx, obj, selfhosting_collection_iterator_methods, AsIntrinsic);
|
||||
}
|
||||
|
||||
/*** JS static utility functions *********************************************/
|
||||
|
103
js/src/jsapi.cpp
103
js/src/jsapi.cpp
@ -3097,7 +3097,7 @@ PropertySpecNameToSymbolCode(const char* name)
|
||||
return JS::SymbolCode(u - 1);
|
||||
}
|
||||
|
||||
static bool
|
||||
bool
|
||||
PropertySpecNameToId(JSContext* cx, const char* name, MutableHandleId id,
|
||||
js::PinningBehavior pin = js::DoNotPinAtom)
|
||||
{
|
||||
@ -3614,87 +3614,6 @@ JS_IsConstructor(JSFunction* fun)
|
||||
return fun->isConstructor();
|
||||
}
|
||||
|
||||
static bool
|
||||
GenericNativeMethodDispatcher(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
const JSFunctionSpec* fs = (JSFunctionSpec*)
|
||||
args.callee().as<JSFunction>().getExtendedSlot(0).toPrivate();
|
||||
MOZ_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
|
||||
|
||||
if (argc < 1) {
|
||||
ReportMissingArg(cx, args.calleev(), 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy all actual (argc) arguments down over our |this| parameter, vp[1],
|
||||
* which is almost always the class constructor object, e.g. Array. Then
|
||||
* call the corresponding prototype native method with our first argument
|
||||
* passed as |this|.
|
||||
*/
|
||||
memmove(vp + 1, vp + 2, argc * sizeof(Value));
|
||||
|
||||
/* Clear the last parameter in case too few arguments were passed. */
|
||||
vp[2 + --argc].setUndefined();
|
||||
|
||||
return fs->call.op(cx, argc, vp);
|
||||
}
|
||||
|
||||
static bool
|
||||
DefineFunctionFromSpec(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs, unsigned flags)
|
||||
{
|
||||
GetterOp gop;
|
||||
SetterOp sop;
|
||||
if (flags & JSFUN_STUB_GSOPS) {
|
||||
// JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
|
||||
// the defined property's attributes.
|
||||
flags &= ~JSFUN_STUB_GSOPS;
|
||||
gop = nullptr;
|
||||
sop = nullptr;
|
||||
} else {
|
||||
gop = obj->getClass()->getProperty;
|
||||
sop = obj->getClass()->setProperty;
|
||||
MOZ_ASSERT(gop != JS_PropertyStub);
|
||||
MOZ_ASSERT(sop != JS_StrictPropertyStub);
|
||||
}
|
||||
|
||||
RootedId id(cx);
|
||||
if (!PropertySpecNameToId(cx, fs->name, &id))
|
||||
return false;
|
||||
|
||||
// Define a generic arity N+1 static method for the arity N prototype
|
||||
// method if flags contains JSFUN_GENERIC_NATIVE.
|
||||
if (flags & JSFUN_GENERIC_NATIVE) {
|
||||
// We require that any consumers using JSFUN_GENERIC_NATIVE stash
|
||||
// the prototype and constructor in the global slots before invoking
|
||||
// JS_DefineFunctions on the proto.
|
||||
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
|
||||
MOZ_ASSERT(obj == &obj->global().getPrototype(key).toObject());
|
||||
RootedObject ctor(cx, &obj->global().getConstructor(key).toObject());
|
||||
|
||||
flags &= ~JSFUN_GENERIC_NATIVE;
|
||||
JSFunction* fun = DefineFunction(cx, ctor, id,
|
||||
GenericNativeMethodDispatcher,
|
||||
fs->nargs + 1, flags,
|
||||
gc::AllocKind::FUNCTION_EXTENDED);
|
||||
if (!fun)
|
||||
return false;
|
||||
|
||||
// As jsapi.h notes, fs must point to storage that lives as long
|
||||
// as fun->object lives.
|
||||
fun->setExtendedSlot(0, PrivateValue(const_cast<JSFunctionSpec*>(fs)));
|
||||
}
|
||||
|
||||
JSFunction* fun = NewFunctionFromSpec(cx, fs, id);
|
||||
if (!fun)
|
||||
return false;
|
||||
|
||||
RootedValue funVal(cx, ObjectValue(*fun));
|
||||
return DefineProperty(cx, obj, id, funVal, gop, sop, flags & ~JSFUN_FLAGS_MASK);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
|
||||
PropertyDefinitionBehavior behavior)
|
||||
@ -3704,25 +3623,7 @@ JS_DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj);
|
||||
|
||||
for (; fs->name; fs++) {
|
||||
unsigned flags = fs->flags;
|
||||
switch (behavior) {
|
||||
case DefineAllProperties:
|
||||
break;
|
||||
case OnlyDefineLateProperties:
|
||||
if (!(flags & JSPROP_DEFINE_LATE))
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(behavior == DontDefineLateProperties);
|
||||
if (flags & JSPROP_DEFINE_LATE)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!DefineFunctionFromSpec(cx, obj, fs, flags & ~JSPROP_DEFINE_LATE))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return DefineFunctions(cx, obj, fs, NotIntrinsic, behavior);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSFunction*)
|
||||
|
@ -187,7 +187,6 @@ class JSFunction : public js::NativeObject
|
||||
bool isExprBody() const { return flags() & EXPR_BODY; }
|
||||
bool hasGuessedAtom() const { return flags() & HAS_GUESSED_ATOM; }
|
||||
bool isLambda() const { return flags() & LAMBDA; }
|
||||
bool isSelfHostedBuiltin() const { return flags() & SELF_HOSTED; }
|
||||
bool hasRest() const { return flags() & HAS_REST; }
|
||||
bool isInterpretedLazy() const { return flags() & INTERPRETED_LAZY; }
|
||||
bool hasScript() const { return flags() & INTERPRETED; }
|
||||
@ -209,6 +208,10 @@ class JSFunction : public js::NativeObject
|
||||
bool hasResolvedLength() const { return flags() & RESOLVED_LENGTH; }
|
||||
bool hasResolvedName() const { return flags() & RESOLVED_NAME; }
|
||||
|
||||
bool isSelfHostedOrIntrinsic() const { return flags() & SELF_HOSTED; }
|
||||
bool isSelfHostedBuiltin() const { return isSelfHostedOrIntrinsic() && !isNative(); }
|
||||
bool isIntrinsic() const { return isSelfHostedOrIntrinsic() && isNative(); }
|
||||
|
||||
bool hasJITCode() const {
|
||||
if (!hasScript())
|
||||
return false;
|
||||
@ -263,11 +266,17 @@ class JSFunction : public js::NativeObject
|
||||
}
|
||||
|
||||
void setIsSelfHostedBuiltin() {
|
||||
MOZ_ASSERT(isInterpreted());
|
||||
MOZ_ASSERT(!isSelfHostedBuiltin());
|
||||
flags_ |= SELF_HOSTED;
|
||||
// Self-hosted functions should not be constructable.
|
||||
flags_ &= ~CONSTRUCTOR;
|
||||
}
|
||||
void setIsIntrinsic() {
|
||||
MOZ_ASSERT(isNative());
|
||||
MOZ_ASSERT(!isIntrinsic());
|
||||
flags_ |= SELF_HOSTED;
|
||||
}
|
||||
|
||||
void setIsFunctionPrototype() {
|
||||
MOZ_ASSERT(!isFunctionPrototype());
|
||||
|
112
js/src/jsobj.cpp
112
js/src/jsobj.cpp
@ -2869,6 +2869,118 @@ js::HasDataProperty(JSContext* cx, NativeObject* obj, jsid id, Value* vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
GenericNativeMethodDispatcher(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
const JSFunctionSpec* fs = (JSFunctionSpec*)
|
||||
args.callee().as<JSFunction>().getExtendedSlot(0).toPrivate();
|
||||
MOZ_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
|
||||
|
||||
if (argc < 1) {
|
||||
ReportMissingArg(cx, args.calleev(), 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy all actual (argc) arguments down over our |this| parameter, vp[1],
|
||||
* which is almost always the class constructor object, e.g. Array. Then
|
||||
* call the corresponding prototype native method with our first argument
|
||||
* passed as |this|.
|
||||
*/
|
||||
memmove(vp + 1, vp + 2, argc * sizeof(Value));
|
||||
|
||||
/* Clear the last parameter in case too few arguments were passed. */
|
||||
vp[2 + --argc].setUndefined();
|
||||
|
||||
return fs->call.op(cx, argc, vp);
|
||||
}
|
||||
|
||||
extern bool
|
||||
PropertySpecNameToId(JSContext* cx, const char* name, MutableHandleId id,
|
||||
js::PinningBehavior pin = js::DoNotPinAtom);
|
||||
|
||||
static bool
|
||||
DefineFunctionFromSpec(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs, unsigned flags,
|
||||
DefineAsIntrinsic intrinsic)
|
||||
{
|
||||
GetterOp gop;
|
||||
SetterOp sop;
|
||||
if (flags & JSFUN_STUB_GSOPS) {
|
||||
// JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or
|
||||
// the defined property's attributes.
|
||||
flags &= ~JSFUN_STUB_GSOPS;
|
||||
gop = nullptr;
|
||||
sop = nullptr;
|
||||
} else {
|
||||
gop = obj->getClass()->getProperty;
|
||||
sop = obj->getClass()->setProperty;
|
||||
MOZ_ASSERT(gop != JS_PropertyStub);
|
||||
MOZ_ASSERT(sop != JS_StrictPropertyStub);
|
||||
}
|
||||
|
||||
RootedId id(cx);
|
||||
if (!PropertySpecNameToId(cx, fs->name, &id))
|
||||
return false;
|
||||
|
||||
// Define a generic arity N+1 static method for the arity N prototype
|
||||
// method if flags contains JSFUN_GENERIC_NATIVE.
|
||||
if (flags & JSFUN_GENERIC_NATIVE) {
|
||||
// We require that any consumers using JSFUN_GENERIC_NATIVE stash
|
||||
// the prototype and constructor in the global slots before invoking
|
||||
// JS_DefineFunctions on the proto.
|
||||
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
|
||||
MOZ_ASSERT(obj == &obj->global().getPrototype(key).toObject());
|
||||
RootedObject ctor(cx, &obj->global().getConstructor(key).toObject());
|
||||
|
||||
flags &= ~JSFUN_GENERIC_NATIVE;
|
||||
JSFunction* fun = DefineFunction(cx, ctor, id,
|
||||
GenericNativeMethodDispatcher,
|
||||
fs->nargs + 1, flags,
|
||||
gc::AllocKind::FUNCTION_EXTENDED);
|
||||
if (!fun)
|
||||
return false;
|
||||
|
||||
fun->setExtendedSlot(0, PrivateValue(const_cast<JSFunctionSpec*>(fs)));
|
||||
}
|
||||
|
||||
JSFunction* fun = NewFunctionFromSpec(cx, fs, id);
|
||||
if (!fun)
|
||||
return false;
|
||||
|
||||
if (intrinsic == AsIntrinsic)
|
||||
fun->setIsIntrinsic();
|
||||
|
||||
RootedValue funVal(cx, ObjectValue(*fun));
|
||||
return DefineProperty(cx, obj, id, funVal, gop, sop, flags & ~JSFUN_FLAGS_MASK);
|
||||
}
|
||||
|
||||
bool
|
||||
js::DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
|
||||
DefineAsIntrinsic intrinsic, PropertyDefinitionBehavior behavior)
|
||||
{
|
||||
for (; fs->name; fs++) {
|
||||
unsigned flags = fs->flags;
|
||||
switch (behavior) {
|
||||
case DefineAllProperties:
|
||||
break;
|
||||
case OnlyDefineLateProperties:
|
||||
if (!(flags & JSPROP_DEFINE_LATE))
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(behavior == DontDefineLateProperties);
|
||||
if (flags & JSPROP_DEFINE_LATE)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!DefineFunctionFromSpec(cx, obj, fs, flags & ~JSPROP_DEFINE_LATE, intrinsic))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*** ToPrimitive *************************************************************/
|
||||
|
||||
|
@ -982,6 +982,20 @@ LookupProperty(JSContext* cx, HandleObject obj, PropertyName* name,
|
||||
extern bool
|
||||
HasOwnProperty(JSContext* cx, HandleObject obj, HandleId id, bool* result);
|
||||
|
||||
/**
|
||||
* This enum is used to select whether the defined functions should be marked as
|
||||
* builtin native instrinsics for self-hosted code.
|
||||
*/
|
||||
enum DefineAsIntrinsic {
|
||||
NotIntrinsic,
|
||||
AsIntrinsic
|
||||
};
|
||||
|
||||
extern bool
|
||||
DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
|
||||
DefineAsIntrinsic intrinsic,
|
||||
PropertyDefinitionBehavior behavior = DefineAllProperties);
|
||||
|
||||
/*
|
||||
* Set a watchpoint: a synchronous callback when the given property of the
|
||||
* given object is set.
|
||||
|
@ -416,7 +416,7 @@ GlobalObject::initSelfHostingBuiltins(JSContext* cx, Handle<GlobalObject*> globa
|
||||
InitBareWeakMapCtor(cx, global) &&
|
||||
InitStopIterationClass(cx, global) &&
|
||||
InitSelfHostingCollectionIteratorFunctions(cx, global) &&
|
||||
JS_DefineFunctions(cx, global, builtins);
|
||||
DefineFunctions(cx, global, builtins, AsIntrinsic);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
Loading…
Reference in New Issue
Block a user