Bug 952777 - part 5 - move JSJitInfo::argTypes to a separate JSTypedMethodJitInfo subclass; r=efaust,bz
authorNathan Froyd <froydnj@mozilla.com>
Tue, 07 Jan 2014 16:52:40 -0500
changeset 163878 e7aa4248135dbc203eb7e0cfffa5d63559f31c12
parent 163877 d17caf3f9294d0e4de59a7b07bfca14028137370
child 163879 1e77fda6a5e092faebae0b72e2d0c94defa2ee60
push id38579
push usernfroyd@mozilla.com
push dateFri, 17 Jan 2014 02:06:03 +0000
treeherdermozilla-inbound@4b7079694645 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust, bz
bugs952777
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 952777 - part 5 - move JSJitInfo::argTypes to a separate JSTypedMethodJitInfo subclass; r=efaust,bz
dom/bindings/Codegen.py
js/src/jit/MIR.cpp
js/src/jsfriendapi.h
js/src/shell/js.cpp
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1582,17 +1582,19 @@ class MethodDefiner(PropertyDefiner):
                 selfHostedName = '"%s"' % m["selfHostedName"]
                 assert not m.get("methodInfo", True)
                 accessor = "nullptr"
                 jitinfo = "nullptr"
             else:
                 selfHostedName = "nullptr";
                 accessor = m.get("nativeName", m["name"])
                 if m.get("methodInfo", True):
-                    jitinfo = ("&%s_methodinfo" % accessor)
+                    # Cast this in case the methodInfo is a
+                    # JSTypedMethodJitInfo.
+                    jitinfo = ("reinterpret_cast<const JSJitInfo*>(&%s_methodinfo)" % accessor)
                     if m.get("allowCrossOriginThis", False):
                         accessor = "genericCrossOriginMethod"
                     else:
                         accessor = "genericMethod"
                 else:
                     jitinfo = "nullptr"
 
             return (m["name"], accessor, jitinfo, m["length"], m["flags"], selfHostedName)
@@ -6343,43 +6345,51 @@ class CGMemberJITInfo(CGThing):
         assert(not hasSlot or movable) # Things with slots had better be movable
         protoID = "prototypes::id::%s" % self.descriptor.name
         depth = "PrototypeTraits<%s>::Depth" % protoID
         failstr = toStringBool(infallible)
         movablestr = toStringBool(movable)
         slotStr = toStringBool(hasSlot)
         returnType = reduce(CGMemberJITInfo.getSingleReturnType, returnTypes,
                             "")
+        def jitInfoInitializer(isTypedMethod):
+            typedMethodStr = toStringBool(isTypedMethod)
+            return ("{\n"
+                    " { %s },\n"
+                    "  %s,\n"
+                    "  %s,\n"
+                    "  JSJitInfo::%s,\n"
+                    "  %s,  /* returnType.  Not relevant for setters. */\n"
+                    "  %s,  /* isInfallible. False in setters. */\n"
+                    "  %s,  /* isMovable.  Not relevant for setters. */\n"
+                    "  %s,  /* isInSlot.  Only relevant for getters. */\n"
+                    "  %s,  /* isTypedMethod.  Only relevant for methods. */\n"
+                    "  %s,  /* Reserved slot index, if we're stored in a slot, else 0. */\n"
+                    "  JSJitInfo::%s  /* aliasSet.  Not relevant for setters. */\n"
+                    "}" % (opName, protoID, depth, opType,
+                           returnType, failstr, movablestr, slotStr,
+                           typedMethodStr, slotIndex, aliasSet))
         if args is not None:
             argTypes = "%s_argTypes" % infoName
             args = [CGMemberJITInfo.getJSArgType(arg.type) for arg in args]
             args.append("JSJitInfo::ArgTypeListEnd")
             argTypesDecl = (
                 "static const JSJitInfo::ArgType %s[] = { %s };\n" %
                 (argTypes, ", ".join(args)))
-        else:
-            argTypes = "nullptr"
-            argTypesDecl = ""
+            return ("\n"
+                    "%s"
+                    "static const JSTypedMethodJitInfo %s = {\n"
+                    "  %s,\n"
+                    "  %s\n"
+                    "};\n" % (argTypesDecl, infoName,
+                              jitInfoInitializer(True), argTypes))
+
         return ("\n"
-                "%s"
-                "static const JSJitInfo %s = {\n"
-                "  { %s },\n"
-                "  %s,\n"
-                "  %s,\n"
-                "  JSJitInfo::%s,\n"
-                "  %s,  /* returnType.  Not relevant for setters. */\n"
-                "  %s,  /* isInfallible. False in setters. */\n"
-                "  %s,  /* isMovable.  Not relevant for setters. */\n"
-                "  %s,  /* isInSlot.  Only relevant for getters. */\n"
-                "  %s,  /* Reserved slot index, if we're stored in a slot, else 0. */\n"
-                "  JSJitInfo::%s,  /* aliasSet.  Not relevant for setters. */\n"
-                "  %s   /* argTypes.  Only relevant for methods */\n"
-                "};\n" % (argTypesDecl, infoName, opName, protoID, depth,
-                          opType, returnType, failstr, movablestr, slotStr,
-                          slotIndex, aliasSet, argTypes))
+                "static const JSJitInfo %s = %s;\n"
+                % (infoName, jitInfoInitializer(False)))
 
     def define(self):
         if self.member.isAttr():
             getterinfo = ("%s_getterinfo" % self.member.identifier.name)
             # We need the cast here because JSJitGetterOp has a "void* self"
             # while we have the right type.
             getter = ("(JSJitGetterOp)get_%s" % self.member.identifier.name)
             getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True)
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -670,21 +670,23 @@ MCallDOMNative::getAliasSet() const
 
     const JSJitInfo *jitInfo = getSingleTarget()->jitInfo();
     JS_ASSERT(jitInfo);
 
     JS_ASSERT(jitInfo->aliasSet != JSJitInfo::AliasNone);
     // If we don't know anything about the types of our arguments, we have to
     // assume that type-coercions can have side-effects, so we need to alias
     // everything.
-    if (jitInfo->aliasSet != JSJitInfo::AliasDOMSets || !jitInfo->argTypes)
+    if (jitInfo->aliasSet != JSJitInfo::AliasDOMSets || !jitInfo->isTypedMethodJitInfo())
         return AliasSet::Store(AliasSet::Any);
 
     uint32_t argIndex = 0;
-    for (const JSJitInfo::ArgType *argType = jitInfo->argTypes;
+    const JSTypedMethodJitInfo *methodInfo =
+        reinterpret_cast<const JSTypedMethodJitInfo*>(jitInfo);
+    for (const JSJitInfo::ArgType *argType = methodInfo->argTypes;
          *argType != JSJitInfo::ArgTypeListEnd;
          ++argType, ++argIndex)
     {
         if (argIndex >= numActualArgs()) {
             // Passing through undefined can't have side-effects
             continue;
         }
         // getArg(0) is "this", so skip it
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1499,16 +1499,21 @@ struct JSJitInfo {
         return type == ParallelNative;
     }
 
     bool isDOMJitInfo() const
     {
         return type != ParallelNative;
     }
 
+    bool isTypedMethodJitInfo() const
+    {
+        return isTypedMethod;
+    }
+
     union {
         JSJitGetterOp getter;
         JSJitSetterOp setter;
         JSJitMethodOp method;
         /* An alternative native that's safe to call in parallel mode. */
         JSParallelNative parallelNative;
     };
 
@@ -1521,45 +1526,61 @@ struct JSJitInfo {
     JSValueType returnType; /* The return type tag.  Might be JSVAL_TYPE_UNKNOWN */
     uint16_t isInfallible : 1; /* Is op fallible? False in setters. */
     uint16_t isMovable : 1;    /* Is op movable?  To be movable the op must
                                   not AliasEverything, but even that might
                                   not be enough (e.g. in cases when it can
                                   throw). */
     uint16_t isInSlot : 1;     /* True if this is a getter that can get a member
                                   from a slot of the "this" object directly. */
-    uint16_t slotIndex : 13;   /* If isInSlot is true, the index of the slot to
+    uint16_t isTypedMethod : 1; /* True if this is an instance of
+                                   JSTypedMethodJitInfo. */
+    uint16_t slotIndex : 12;   /* If isInSlot is true, the index of the slot to
                                   get the value from.  Otherwise 0. */
 
     AliasSet aliasSet;      /* The alias set for this op.  This is a _minimal_
                                alias set; in particular for a method it does not
                                include whatever argument conversions might do.
                                That's covered by argTypes and runtime analysis
                                of the actual argument types being passed in. */
     // XXXbz should we have a JSGetterJitInfo subclass or something?
     // XXXbz should we have a JSValueType for the type of the member?
-    const ArgType* const argTypes; /* For a method, a list of sets of types that
-                                      the function expects.  This can be used,
-                                      for example, to figure out when argument
-                                      coercions can have side-effects. nullptr
-                                      if we have no type information for
-                                      arguments. */
 
 private:
     static void staticAsserts()
     {
         JS_STATIC_ASSERT(Any & String);
         JS_STATIC_ASSERT(Any & Integer);
         JS_STATIC_ASSERT(Any & Double);
         JS_STATIC_ASSERT(Any & Boolean);
         JS_STATIC_ASSERT(Any & Object);
         JS_STATIC_ASSERT(Any & Null);
     }
 };
 
+struct JSTypedMethodJitInfo
+{
+    // We use C-style inheritance here, rather than C++ style inheritance
+    // because not all compilers support brace-initialization for non-aggregate
+    // classes. Using C++ style inheritance and constructors instead of
+    // brace-initialization would also force the creation of static
+    // constructors (on some compilers) when JSJitInfo and JSTypedMethodJitInfo
+    // structures are declared. Since there can be several thousand of these
+    // structures present and we want to have roughly equivalent performance
+    // across a range of compilers, we do things manually.
+    JSJitInfo base;
+
+    const JSJitInfo::ArgType* const argTypes; /* For a method, a list of sets of
+                                                 types that the function
+                                                 expects.  This can be used,
+                                                 for example, to figure out
+                                                 when argument coercions can
+                                                 have side-effects. */
+};
+
 namespace JS {
 namespace detail {
 
 /* NEVER DEFINED, DON'T USE.  For use by JS_CAST_PARALLEL_NATIVE_TO only. */
 inline int CheckIsParallelNative(JSParallelNative parallelNative);
 
 } // namespace detail
 } // namespace JS
@@ -1579,17 +1600,17 @@ inline int CheckIsParallelNative(JSParal
  * a datum of the type of the union's first member.)
  *
  * Presumably this has something to do with template instantiation.
  * Initializing with a normal function pointer seems to work fine. Hence
  * the ugliness that you see before you.
  */
 #define JS_JITINFO_NATIVE_PARALLEL(infoName, parallelOp)                \
     const JSJitInfo infoName =                                          \
-        {{JS_CAST_PARALLEL_NATIVE_TO(parallelOp, JSJitGetterOp)},0,0,JSJitInfo::ParallelNative,JSVAL_TYPE_MISSING,false,false,false,0,JSJitInfo::AliasEverything,nullptr}
+        {{JS_CAST_PARALLEL_NATIVE_TO(parallelOp, JSJitGetterOp)},0,0,JSJitInfo::ParallelNative,JSVAL_TYPE_MISSING,false,false,false,false,0,JSJitInfo::AliasEverything}
 
 #define JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(infoName, wrapperName, serialOp) \
     bool wrapperName##_ParallelNativeThreadSafeWrapper(js::ForkJoinSlice *slice, unsigned argc, \
                                                        JS::Value *vp)   \
     {                                                                   \
         return JSParallelNativeThreadSafeWrapper<serialOp>(slice, argc, vp); \
     }                                                                   \
     JS_JITINFO_NATIVE_PARALLEL(infoName, wrapperName##_ParallelNativeThreadSafeWrapper)
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -4833,47 +4833,47 @@ static const JSJitInfo dom_x_getterinfo 
     { (JSJitGetterOp)dom_get_x },
     0,        /* protoID */
     0,        /* depth */
     JSJitInfo::Getter,
     JSVAL_TYPE_UNKNOWN, /* returnType */
     true,     /* isInfallible. False in setters. */
     true,     /* isMovable */
     false,    /* isInSlot */
+    false,    /* isTypedMethod */
     0,        /* slotIndex */
-    JSJitInfo::AliasNone, /* aliasSet */
-    nullptr   /* argTypes */
+    JSJitInfo::AliasNone /* aliasSet */
 };
 
 static const JSJitInfo dom_x_setterinfo = {
     { (JSJitGetterOp)dom_set_x },
     0,        /* protoID */
     0,        /* depth */
     JSJitInfo::Setter,
     JSVAL_TYPE_UNKNOWN, /* returnType */
     false,    /* isInfallible. False in setters. */
     false,    /* isMovable. */
     false,    /* isInSlot */
+    false,    /* isTypedMethod */
     0,        /* slotIndex */
-    JSJitInfo::AliasEverything, /* aliasSet */
-    nullptr   /* argTypes */
+    JSJitInfo::AliasEverything /* aliasSet */
 };
 
 static const JSJitInfo doFoo_methodinfo = {
     { (JSJitGetterOp)dom_doFoo },
     0,        /* protoID */
     0,        /* depth */
     JSJitInfo::Method,
     JSVAL_TYPE_UNKNOWN, /* returnType */
     false,    /* isInfallible. False in setters. */
     false,    /* isMovable */
     false,    /* isInSlot */
+    false,    /* isTypedMethod */
     0,        /* slotIndex */
-    JSJitInfo::AliasEverything, /* aliasSet */
-    nullptr   /* argTypes */
+    JSJitInfo::AliasEverything /* aliasSet */
 };
 
 static const JSPropertySpec dom_props[] = {
     {"x", 0,
      JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS,
      { (JSPropertyOp)dom_genericGetter, &dom_x_getterinfo },
      { (JSStrictPropertyOp)dom_genericSetter, &dom_x_setterinfo }
     },