diff options
author | Andy Ayers <andya@microsoft.com> | 2018-12-12 16:56:07 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-12 16:56:07 -0800 |
commit | d279e47a9bc6a9d44484c3143a5f8dd9bc57579c (patch) | |
tree | 45a495d0d1048cb6c154e6c90d62e0809f01977e | |
parent | 962b1737249adcbf6eea9388463a042e4dc19288 (diff) | |
download | coreclr-d279e47a9bc6a9d44484c3143a5f8dd9bc57579c.tar.gz coreclr-d279e47a9bc6a9d44484c3143a5f8dd9bc57579c.tar.bz2 coreclr-d279e47a9bc6a9d44484c3143a5f8dd9bc57579c.zip |
JIT: optimize unbox/unbox.any when type is known (#21501)
Optimize away the unbox type test when the jit knows the type of object
being unboxed and can resolve the type comparison at jit time.
Closes #14473.
-rw-r--r-- | src/jit/importer.cpp | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp index 1b101d0efa..cff3e8d6d9 100644 --- a/src/jit/importer.cpp +++ b/src/jit/importer.cpp @@ -15395,6 +15395,59 @@ void Compiler::impImportBlockCode(BasicBlock* block) if (canExpandInline && shouldExpandInline) { + // See if we know anything about the type of op1, the object being unboxed. + bool isExact = false; + bool isNonNull = false; + CORINFO_CLASS_HANDLE clsHnd = gtGetClassHandle(op1, &isExact, &isNonNull); + + // We can skip the "exact" bit here as we are comparing to a value class. + // compareTypesForEquality should bail on comparisions for shared value classes. + if (clsHnd != NO_CLASS_HANDLE) + { + const TypeCompareState compare = + info.compCompHnd->compareTypesForEquality(resolvedToken.hClass, clsHnd); + + if (compare == TypeCompareState::Must) + { + JITDUMP("\nOptimizing %s (%s) -- type test will succeed\n", + opcode == CEE_UNBOX ? "UNBOX" : "UNBOX.ANY", eeGetClassName(clsHnd)); + + // For UNBOX, null check (if necessary), and then leave the box payload byref on the stack. + if (opcode == CEE_UNBOX) + { + GenTree* cloneOperand; + op1 = impCloneExpr(op1, &cloneOperand, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL, + nullptr DEBUGARG("optimized unbox clone")); + + GenTree* boxPayloadOffset = gtNewIconNode(TARGET_POINTER_SIZE, TYP_I_IMPL); + GenTree* boxPayloadAddress = + gtNewOperNode(GT_ADD, TYP_BYREF, cloneOperand, boxPayloadOffset); + GenTree* nullcheck = gtNewOperNode(GT_NULLCHECK, TYP_I_IMPL, op1); + GenTree* result = gtNewOperNode(GT_COMMA, TYP_BYREF, nullcheck, boxPayloadAddress); + impPushOnStack(result, tiRetVal); + break; + } + + // For UNBOX.ANY load the struct from the box payload byref (the load will nullcheck) + assert(opcode == CEE_UNBOX_ANY); + GenTree* boxPayloadOffset = gtNewIconNode(TARGET_POINTER_SIZE, TYP_I_IMPL); + GenTree* boxPayloadAddress = gtNewOperNode(GT_ADD, TYP_BYREF, op1, boxPayloadOffset); + impPushOnStack(boxPayloadAddress, tiRetVal); + oper = GT_OBJ; + goto OBJ; + } + else + { + JITDUMP("\nUnable to optimize %s -- can't resolve type comparison\n", + opcode == CEE_UNBOX ? "UNBOX" : "UNBOX.ANY"); + } + } + else + { + JITDUMP("\nUnable to optimize %s -- class for [%06u] not known\n", + opcode == CEE_UNBOX ? "UNBOX" : "UNBOX.ANY", dspTreeID(op1)); + } + JITDUMP("\n Importing %s as inline sequence\n", opcode == CEE_UNBOX ? "UNBOX" : "UNBOX.ANY"); // we are doing normal unboxing // inline the common case of the unbox helper |