Bug 1232022 - Part 1: Mark self-hosted intrinsics for later checking. (r=till)
authorEric Faust <efaustbmo@gmail.com>
Wed, 16 Dec 2015 08:14:39 -0800
changeset 315832 a91d3c32c0ef17f45e27fd88e0115ce9be40920f
parent 315831 66921f340b4c28695c29a88b29c4fd2c88300dd2
child 315833 cdc3315bff369dfdd6b71bc638cd3e1ed5e6e388
push id8468
push userhurley@todesschaf.org
push dateWed, 16 Dec 2015 19:25:06 +0000
reviewerstill
bugs1232022
milestone46.0a1
Bug 1232022 - Part 1: Mark self-hosted intrinsics for later checking. (r=till)
js/src/builtin/MapObject.cpp
js/src/jsapi.cpp
js/src/jsfun.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/vm/GlobalObject.cpp
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -1406,17 +1406,17 @@ js::InitSetClass(JSContext* cx, HandleOb
 const JSFunctionSpec selfhosting_collection_iterator_methods[] = {
     JS_FN("std_Set_iterator_next", SetIteratorObject::next, 0, 0),
     JS_FS_END
 };
 
 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 *********************************************/
 
 static
 bool
 forEach(const char* funcName, JSContext *cx, HandleObject obj, HandleValue callbackFn, HandleValue thisArg)
 {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3092,17 +3092,17 @@ JS_DefineConstIntegers(JSContext* cx, Ha
 static JS::SymbolCode
 PropertySpecNameToSymbolCode(const char* name)
 {
     MOZ_ASSERT(JS::PropertySpecNameIsSymbol(name));
     uintptr_t u = reinterpret_cast<uintptr_t>(name);
     return JS::SymbolCode(u - 1);
 }
 
-static bool
+bool
 PropertySpecNameToId(JSContext* cx, const char* name, MutableHandleId id,
                      js::PinningBehavior pin = js::DoNotPinAtom)
 {
     if (JS::PropertySpecNameIsSymbol(name)) {
         JS::SymbolCode which = PropertySpecNameToSymbolCode(name);
         id.set(SYMBOL_TO_JSID(cx->wellKnownSymbols().get(which)));
     } else {
         JSAtom* atom = Atomize(cx, name, strlen(name), pin);
@@ -3609,125 +3609,26 @@ JS_IsNativeFunction(JSObject* funobj, JS
 }
 
 extern JS_PUBLIC_API(bool)
 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)
 {
     MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     AssertHeapIsIdle(cx);
     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*)
 JS_DefineFunction(JSContext* cx, HandleObject obj, const char* name, JSNative call,
                   unsigned nargs, unsigned attrs)
 {
     MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
     AssertHeapIsIdle(cx);
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -182,17 +182,16 @@ class JSFunction : public js::NativeObje
     /* Possible attributes of a native function: */
     bool isAsmJSNative()            const { return kind() == AsmJS; }
 
     /* Possible attributes of an interpreted function: */
     bool isFunctionPrototype()      const { return flags() & IS_FUN_PROTO; }
     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; }
     bool isBeingParsed()            const { return flags() & BEING_PARSED; }
 
     // Arrow functions store their lexical new.target in the first extended slot.
     bool isArrow()                  const { return kind() == Arrow; }
     // Every class-constructor is also a method.
@@ -204,16 +203,20 @@ class JSFunction : public js::NativeObje
 
     bool allowSuperProperty() const {
         return isMethod() || isGetter() || isSetter();
     }
 
     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;
 
         return nonLazyScript()->hasBaselineScript() || nonLazyScript()->hasIonScript();
     }
 
     /* Compound attributes: */
@@ -258,21 +261,27 @@ class JSFunction : public js::NativeObje
     }
 
     // Can be called multiple times by the parser.
     void setHasRest() {
         flags_ |= HAS_REST;
     }
 
     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());
         flags_ |= IS_FUN_PROTO;
     }
 
     // Can be called multiple times by the parser.
     void setIsExprBody() {
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2864,16 +2864,128 @@ js::HasDataProperty(JSContext* cx, Nativ
             *vp = obj->getSlot(shape->slot());
             return true;
         }
     }
 
     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 *************************************************************/
 
 /*
  * Gets |obj[id]|.  If that value's not callable, returns true and stores an
  * object value in *vp.  If it's callable, calls it with no arguments and |obj|
  * as |this|, returning the result in *vp.
  *
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -977,16 +977,30 @@ LookupProperty(JSContext* cx, HandleObje
     RootedId id(cx, NameToId(name));
     return LookupProperty(cx, obj, id, objp, propp);
 }
 
 /* Set *result to tell whether obj has an own property with the given id. */
 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.
  *
  * Watchpoints are nonstandard and do not fit in well with the way ES6
  * specifies [[Set]]. They are also insufficient for implementing
  * Object.observe.
  */
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -411,17 +411,17 @@ GlobalObject::initSelfHostingBuiltins(JS
     }
 
     return InitBareBuiltinCtor(cx, global, JSProto_Array) &&
            InitBareBuiltinCtor(cx, global, JSProto_TypedArray) &&
            InitBareBuiltinCtor(cx, global, JSProto_Uint8Array) &&
            InitBareWeakMapCtor(cx, global) &&
            InitStopIterationClass(cx, global) &&
            InitSelfHostingCollectionIteratorFunctions(cx, global) &&
-           JS_DefineFunctions(cx, global, builtins);
+           DefineFunctions(cx, global, builtins, AsIntrinsic);
 }
 
 /* static */ bool
 GlobalObject::isRuntimeCodeGenEnabled(JSContext* cx, Handle<GlobalObject*> global)
 {
     HeapSlot& v = global->getSlotRef(RUNTIME_CODEGEN_ENABLED);
     if (v.isUndefined()) {
         /*