Bug 1232022 - Part 1: Mark self-hosted intrinsics for later checking. (r=till)

This commit is contained in:
Eric Faust 2015-12-16 08:14:39 -08:00
parent 64c257e2ac
commit c26c287169
6 changed files with 140 additions and 104 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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