summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Ayers <andya@microsoft.com>2018-12-12 16:56:07 -0800
committerGitHub <noreply@github.com>2018-12-12 16:56:07 -0800
commitd279e47a9bc6a9d44484c3143a5f8dd9bc57579c (patch)
tree45a495d0d1048cb6c154e6c90d62e0809f01977e
parent962b1737249adcbf6eea9388463a042e4dc19288 (diff)
downloadcoreclr-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.cpp53
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