Import `new` multi-dimmensional array using the non-vararg helper (dotnet/coreclr...
authorJan Kotas <jkotas@microsoft.com>
Thu, 2 Jun 2016 00:09:15 +0000 (17:09 -0700)
committerJan Kotas <jkotas@microsoft.com>
Thu, 2 Jun 2016 00:09:15 +0000 (17:09 -0700)
* Factor out import of `new` multi-dimmensional array
* Implement import of `new` multi-dimmensional array using the non-vararg helper
* Delete RETURN_TYPE_IS_COMPOSITE inlining observation because of it is never hit.
* Add R2R id for non-vararg helper
* Reformat affected code to follow coding conventions

Commit migrated from https://github.com/dotnet/coreclr/commit/5b97541ab67310b7831c4f5c13be7978c0b024cd

src/coreclr/src/inc/readytorun.h
src/coreclr/src/inc/readytorunhelpers.h
src/coreclr/src/jit/compiler.h
src/coreclr/src/jit/importer.cpp
src/coreclr/src/jit/inline.def
src/coreclr/src/jit/lclvars.cpp

index 71879cd..0fa1a14 100644 (file)
@@ -229,6 +229,7 @@ enum ReadyToRunHelper
     READYTORUN_HELPER_Unbox                     = 0x5A,
     READYTORUN_HELPER_Unbox_Nullable            = 0x5B,
     READYTORUN_HELPER_NewMultiDimArr            = 0x5C,
+    READYTORUN_HELPER_NewMultiDimArr_NonVarArg  = 0x5D,
 
     // Helpers used with generic handle lookup cases
     READYTORUN_HELPER_NewObject                 = 0x60,
index c9c4292..4524e1a 100644 (file)
@@ -41,6 +41,7 @@ HELPER(READYTORUN_HELPER_Box_Nullable,              CORINFO_HELP_BOX_NULLABLE,
 HELPER(READYTORUN_HELPER_Unbox,                     CORINFO_HELP_UNBOX,                             )
 HELPER(READYTORUN_HELPER_Unbox_Nullable,            CORINFO_HELP_UNBOX_NULLABLE,                    )
 HELPER(READYTORUN_HELPER_NewMultiDimArr,            CORINFO_HELP_NEW_MDARR,                         )
+HELPER(READYTORUN_HELPER_NewMultiDimArr_NonVarArg,  CORINFO_HELP_NEW_MDARR_NONVARARG,               )
 
 HELPER(READYTORUN_HELPER_NewObject,                 CORINFO_HELP_NEWFAST,                           )
 HELPER(READYTORUN_HELPER_NewArray,                  CORINFO_HELP_NEWARR_1_DIRECT,                   )
index 28bde5f..c8eccbc 100644 (file)
@@ -2303,6 +2303,8 @@ public :
     
     unsigned            lvaLocAllocSPvar;               // variable which has the result of the last alloca/localloc
 
+    unsigned            lvaNewObjArrayArgs;             // variable with arguments for new MD array helper
+
     // TODO-Review: Prior to reg predict we reserve 24 bytes for Spill temps.
     //              after the reg predict we will use a computed maxTmpSize 
     //              which is based upon the number of spill temps predicted by reg predict
@@ -2678,6 +2680,8 @@ protected :
 
     void                impImportAndPushBox (CORINFO_RESOLVED_TOKEN * pResolvedToken);
 
+    void                impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken,
+                                             CORINFO_CALL_INFO* pCallInfo);
 
     bool                impCanPInvokeInline(var_types callRetTyp);
     bool                impCanPInvokeInlineCallSite(var_types callRetTyp);
index 3573584..862a33e 100755 (executable)
@@ -4545,7 +4545,7 @@ GenTreePtr Compiler::impImportLdvirtftn (GenTreePtr thisPtr,
     return gtNewHelperCallNode( CORINFO_HELP_VIRTUAL_FUNC_PTR, TYP_I_IMPL, GTF_EXCEPT, helpArgs);
 }
 
-                    
+
 /*****************************************************************************
  *
  *  Build and import a box node
@@ -4693,6 +4693,148 @@ void           Compiler::impImportAndPushBox (CORINFO_RESOLVED_TOKEN * pResolved
     impPushOnStack(op1, tiRetVal);
 }
 
+//------------------------------------------------------------------------
+// impImportNewObjArray: Build and import `new` of multi-dimmensional array
+//
+// Arguments:
+//    pResolvedToken - The CORINFO_RESOLVED_TOKEN that has been initialized
+//                     by a call to CEEInfo::resolveToken().
+//    pCallInfo - The CORINFO_CALL_INFO that has been initialized
+//                by a call to CEEInfo::getCallInfo().
+//
+// Assumptions:
+//    The multi-dimensional array constructor arguments (array dimensions) are
+//    pushed on the IL stack on entry to this method.
+//
+// Notes:
+//    Multi-dimensional array constructors are imported as calls to a JIT 
+//    helper, not as regular calls.
+
+void Compiler::impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken,
+                                    CORINFO_CALL_INFO* pCallInfo)
+{
+    GenTreePtr classHandle = impParentClassTokenToHandle(pResolvedToken);
+    if (classHandle == nullptr) // compDonotInline()
+        return;
+
+    assert(pCallInfo->sig.numArgs);
+
+    GenTreePtr node;
+    GenTreeArgList* args;
+
+    //
+    // There are two different JIT helpers that can be used to allocate 
+    // multi-dimensional arrays:
+    //
+    // - CORINFO_HELP_NEW_MDARR - takes the array dimensions as varargs.
+    //      This variant is deprecated. It should be eventually removed.
+    //
+    // - CORINFO_HELP_NEW_MDARR_NONVARARG - takes the array dimensions as
+    //      pointer to block of int32s. This variant is more portable.
+    //
+    // The non-varargs helper is enabled for CoreRT only for now. Enabling this 
+    // unconditionally would require ReadyToRun version bump.
+    //
+
+#if COR_JIT_EE_VERSION > 460
+    if (!opts.IsReadyToRun() || (eeGetEEInfo()->targetAbi == CORINFO_CORERT_ABI))
+    {
+        LclVarDsc* newObjArrayArgsVar;
+
+        // Reuse the temp used to pass the array dimensions to avoid bloating
+        // the stack frame in case there are multiple calls to multi-dim array 
+        // constructors within a single method.
+        if (lvaNewObjArrayArgs == BAD_VAR_NUM)
+        {
+            lvaNewObjArrayArgs = lvaGrabTemp(false DEBUGARG("NewObjArrayArgs"));
+            lvaTable[lvaNewObjArrayArgs].lvType = TYP_BLK;
+            lvaTable[lvaNewObjArrayArgs].lvExactSize = 0;
+        }
+
+        // Increase size of lvaNewObjArrayArgs to be the largest size needed to hold 'numArgs' integers
+        // for our call to CORINFO_HELP_NEW_MDARR_NONVARARG.
+        lvaTable[lvaNewObjArrayArgs].lvExactSize = 
+            max(lvaTable[lvaNewObjArrayArgs].lvExactSize, pCallInfo->sig.numArgs * sizeof(INT32));
+
+        // The side-effects may include allocation of more multi-dimensional arrays. Spill all side-effects
+        // to ensure that the shared lvaNewObjArrayArgs local variable is only ever used to pass arguments
+        // to one allocation at a time.
+        impSpillSideEffects(true, (unsigned)CHECK_SPILL_ALL DEBUGARG("impImportNewObjArray"));
+
+        //
+        // The arguments of the CORINFO_HELP_NEW_MDARR_NONVARARG helper are:
+        //  - Array class handle
+        //  - Number of dimension arguments
+        //  - Pointer to block of int32 dimensions - address  of lvaNewObjArrayArgs temp.
+        //
+
+        node = gtNewLclvNode(lvaNewObjArrayArgs, TYP_BLK);
+        node = gtNewOperNode(GT_ADDR, TYP_I_IMPL, node);
+
+        // Pop dimension arguments from the stack one at a time and store it 
+        // into lvaNewObjArrayArgs temp.
+        for (int i = pCallInfo->sig.numArgs - 1; i >= 0; i--)
+        {
+            GenTreePtr arg = impImplicitIorI4Cast(impPopStack().val, TYP_INT);
+
+            GenTreePtr dest = gtNewLclvNode(lvaNewObjArrayArgs, TYP_BLK);
+            dest = gtNewOperNode(GT_ADDR, TYP_I_IMPL, dest);
+            dest = gtNewOperNode(GT_ADD, TYP_I_IMPL, dest, 
+                new (this, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, sizeof(INT32) * i));
+            dest = gtNewOperNode(GT_IND, TYP_INT, dest);
+
+            node = gtNewOperNode(GT_COMMA, node->TypeGet(), gtNewAssignNode(dest, arg), node);
+        }
+
+        args = gtNewArgList(node);
+
+        // pass number of arguments to the helper
+        args = gtNewListNode(gtNewIconNode(pCallInfo->sig.numArgs), args);
+
+        args = gtNewListNode(classHandle, args);
+
+        node = gtNewHelperCallNode(CORINFO_HELP_NEW_MDARR_NONVARARG, TYP_REF, 0, args);
+    }
+    else
+#endif
+    {
+        //
+        // The varargs helper needs the type and method handles as last
+        // and  last-1 param (this is a cdecl call, so args will be
+        // pushed in reverse order on the CPU stack)
+        //
+
+        args = gtNewArgList(classHandle);
+
+        // pass number of arguments to the helper
+        args = gtNewListNode(gtNewIconNode(pCallInfo->sig.numArgs), args);
+
+        unsigned argFlags = 0;
+        args = impPopList(pCallInfo->sig.numArgs, &argFlags, &pCallInfo->sig, args);
+
+        node = gtNewHelperCallNode(CORINFO_HELP_NEW_MDARR, TYP_REF, 0, args);
+
+        // varargs, so we pop the arguments
+        node->gtFlags |= GTF_CALL_POP_ARGS;
+
+#ifdef DEBUG
+        // At the present time we don't track Caller pop arguments
+        // that have GC references in them
+        for (GenTreeArgList* temp = args; temp; temp = temp->Rest())
+        {
+            assert(temp->Current()->gtType != TYP_REF);
+        }
+#endif
+    }
+
+    node->gtFlags |= args->gtFlags & GTF_GLOB_EFFECT;
+
+    // Remember that this basic block contains 'new' of a md array
+    compCurBB->bbFlags |= BBF_HAS_NEWARRAY;
+
+    impPushOnStack(node, typeInfo(TI_REF, pResolvedToken->hClass));
+}
+
 GenTreePtr Compiler::impTransformThis (GenTreePtr thisPtr,
                                        CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
                                        CORINFO_THIS_TRANSFORM transform)
@@ -11367,56 +11509,10 @@ DO_LDFTN:
                 // Arrays need to call the NEWOBJ helper.
                 assertImp(clsFlags & CORINFO_FLG_VAROBJSIZE);
 
-                /* The varargs helper needs the type and method handles as last
-                   and  last-1 param (this is a cdecl call, so args will be
-                   pushed in reverse order on the CPU stack) */
-
-                op1 = impParentClassTokenToHandle(&resolvedToken);
-                if (op1 == NULL) // compDonotInline()
+                impImportNewObjArray(&resolvedToken, &callInfo);
+                if (compDonotInline())
                     return;
 
-                args = gtNewArgList(op1);
-
-                // pass number of arguments to the helper
-                op2 = gtNewIconNode(callInfo.sig.numArgs);
-
-                args = gtNewListNode(op2, args);
-
-                assertImp(callInfo.sig.numArgs);
-                if (compIsForInlining())
-                {
-                    if (varTypeIsComposite(JITtype2varType(callInfo.sig.retType)) && callInfo.sig.retTypeClass == NULL)
-                    {
-                        compInlineResult->NoteFatal(InlineObservation::CALLEE_RETURN_TYPE_IS_COMPOSITE);
-                        return;
-                    }
-                }
-             
-                flags = 0;
-                args = impPopList(callInfo.sig.numArgs, &flags, &callInfo.sig, args);
-
-                op1 = gtNewHelperCallNode(  CORINFO_HELP_NEW_MDARR,
-                                            TYP_REF, 0,
-                                            args );
-
-                /* Remember that this basic block contains 'new' of a md array */
-                block->bbFlags |= BBF_HAS_NEWARRAY;
-
-                // varargs, so we pop the arguments
-                op1->gtFlags |= GTF_CALL_POP_ARGS;
-
-#ifdef DEBUG
-                // At the present time we don't track Caller pop arguments
-                // that have GC references in them
-                for (GenTreeArgList* temp = args; temp; temp = temp->Rest())
-                {
-                    assertImp(temp->Current()->gtType != TYP_REF);
-                }
-#endif
-                op1->gtFlags |= args->gtFlags & GTF_GLOB_EFFECT;
-
-                impPushOnStack(op1, typeInfo(TI_REF, resolvedToken.hClass));
-
                 callTyp = TYP_REF;
                 break;
             }
index 4ee03bb..b8a227a 100644 (file)
@@ -56,7 +56,6 @@ INLINE_OBSERVATION(NEEDS_SECURITY_CHECK,      bool,   "needs security check",
 INLINE_OBSERVATION(NO_METHOD_INFO,            bool,   "cannot get method info",        FATAL,       CALLEE)
 INLINE_OBSERVATION(NOT_PROFITABLE_INLINE,     bool,   "unprofitable inline",           FATAL,       CALLEE)
 INLINE_OBSERVATION(RANDOM_REJECT,             bool,   "random reject",                 FATAL,       CALLEE)
-INLINE_OBSERVATION(RETURN_TYPE_IS_COMPOSITE,  bool,   "has composite return type",     FATAL,       CALLEE)
 INLINE_OBSERVATION(STACK_CRAWL_MARK,          bool,   "uses stack crawl mark",         FATAL,       CALLEE)
 INLINE_OBSERVATION(STFLD_NEEDS_HELPER,        bool,   "stfld needs helper",            FATAL,       CALLEE)
 INLINE_OBSERVATION(THROW_WITH_INVALID_STACK,  bool,   "throw with invalid stack",      FATAL,       CALLEE)
index 55a7b83..74ba79d 100644 (file)
@@ -55,6 +55,7 @@ void                Compiler::lvaInit()
     lvaPromotedStructAssemblyScratchVar = BAD_VAR_NUM;
 #endif // _TARGET_ARM_
     lvaLocAllocSPvar = BAD_VAR_NUM;
+    lvaNewObjArrayArgs = BAD_VAR_NUM;
     lvaGSSecurityCookie  = BAD_VAR_NUM;
 #ifdef _TARGET_X86_
     lvaVarargsBaseOfStkArgs = BAD_VAR_NUM;