Reduced memory usage of primitive fields smaller than 4-bytes
Reduced memory used by byte and boolean fields from 4 bytes down to a
single byte and shorts and chars down to two bytes. Fields are now
arranged as Reference followed by decreasing component sizes, with
fields shuffled forward as needed.
Bug: 8135266
Change-Id: I65eaf31ed27e5bd5ba0c7d4606454b720b074752
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index c4dfcb9..3ec37f2 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -18,6 +18,7 @@
#include "dex/dataflow_iterator-inl.h"
#include "dex/quick/dex_file_method_inliner.h"
#include "mir_to_lir-inl.h"
+#include "primitive.h"
#include "thread-inl.h"
namespace art {
@@ -223,9 +224,27 @@
return false;
}
- bool wide = (data.op_variant == InlineMethodAnalyser::IGetVariant(Instruction::IGET_WIDE));
- bool ref = (data.op_variant == InlineMethodAnalyser::IGetVariant(Instruction::IGET_OBJECT));
- OpSize size = LoadStoreOpSize(wide, ref);
+ OpSize size = k32;
+ switch (data.op_variant) {
+ case InlineMethodAnalyser::IGetVariant(Instruction::IGET_OBJECT):
+ size = kReference;
+ break;
+ case InlineMethodAnalyser::IGetVariant(Instruction::IGET_WIDE):
+ size = k64;
+ break;
+ case InlineMethodAnalyser::IGetVariant(Instruction::IGET_SHORT):
+ size = kSignedHalf;
+ break;
+ case InlineMethodAnalyser::IGetVariant(Instruction::IGET_CHAR):
+ size = kUnsignedHalf;
+ break;
+ case InlineMethodAnalyser::IGetVariant(Instruction::IGET_BYTE):
+ size = kSignedByte;
+ break;
+ case InlineMethodAnalyser::IGetVariant(Instruction::IGET_BOOLEAN):
+ size = kUnsignedByte;
+ break;
+ }
// Point of no return - no aborts after this
GenPrintLabel(mir);
@@ -233,20 +252,20 @@
RegStorage reg_obj = LoadArg(data.object_arg, kRefReg);
RegisterClass reg_class = RegClassForFieldLoadStore(size, data.is_volatile);
RegisterClass ret_reg_class = ShortyToRegClass(cu_->shorty[0]);
- RegLocation rl_dest = wide ? GetReturnWide(ret_reg_class) : GetReturn(ret_reg_class);
+ RegLocation rl_dest = IsWide(size) ? GetReturnWide(ret_reg_class) : GetReturn(ret_reg_class);
RegStorage r_result = rl_dest.reg;
if (!RegClassMatches(reg_class, r_result)) {
- r_result = wide ? AllocTypedTempWide(rl_dest.fp, reg_class)
- : AllocTypedTemp(rl_dest.fp, reg_class);
+ r_result = IsWide(size) ? AllocTypedTempWide(rl_dest.fp, reg_class)
+ : AllocTypedTemp(rl_dest.fp, reg_class);
}
- if (ref) {
+ if (IsRef(size)) {
LoadRefDisp(reg_obj, data.field_offset, r_result, data.is_volatile ? kVolatile : kNotVolatile);
} else {
LoadBaseDisp(reg_obj, data.field_offset, r_result, size, data.is_volatile ? kVolatile :
kNotVolatile);
}
if (r_result.NotExactlyEquals(rl_dest.reg)) {
- if (wide) {
+ if (IsWide(size)) {
OpRegCopyWide(rl_dest.reg, r_result);
} else {
OpRegCopy(rl_dest.reg, r_result);
@@ -267,24 +286,42 @@
return false;
}
- bool wide = (data.op_variant == InlineMethodAnalyser::IPutVariant(Instruction::IPUT_WIDE));
- bool ref = (data.op_variant == InlineMethodAnalyser::IGetVariant(Instruction::IGET_OBJECT));
- OpSize size = LoadStoreOpSize(wide, ref);
+ OpSize size = k32;
+ switch (data.op_variant) {
+ case InlineMethodAnalyser::IPutVariant(Instruction::IPUT_OBJECT):
+ size = kReference;
+ break;
+ case InlineMethodAnalyser::IPutVariant(Instruction::IPUT_WIDE):
+ size = k64;
+ break;
+ case InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT):
+ size = kSignedHalf;
+ break;
+ case InlineMethodAnalyser::IPutVariant(Instruction::IPUT_CHAR):
+ size = kUnsignedHalf;
+ break;
+ case InlineMethodAnalyser::IPutVariant(Instruction::IPUT_BYTE):
+ size = kSignedByte;
+ break;
+ case InlineMethodAnalyser::IPutVariant(Instruction::IPUT_BOOLEAN):
+ size = kUnsignedByte;
+ break;
+ }
// Point of no return - no aborts after this
GenPrintLabel(mir);
LockArg(data.object_arg);
- LockArg(data.src_arg, wide);
+ LockArg(data.src_arg, IsWide(size));
RegStorage reg_obj = LoadArg(data.object_arg, kRefReg);
RegisterClass reg_class = RegClassForFieldLoadStore(size, data.is_volatile);
- RegStorage reg_src = LoadArg(data.src_arg, reg_class, wide);
- if (ref) {
+ RegStorage reg_src = LoadArg(data.src_arg, reg_class, IsWide(size));
+ if (IsRef(size)) {
StoreRefDisp(reg_obj, data.field_offset, reg_src, data.is_volatile ? kVolatile : kNotVolatile);
} else {
StoreBaseDisp(reg_obj, data.field_offset, reg_src, size, data.is_volatile ? kVolatile :
kNotVolatile);
}
- if (ref) {
+ if (IsRef(size)) {
MarkGCCard(reg_src, reg_obj);
}
return true;
@@ -720,84 +757,112 @@
break;
case Instruction::IGET_OBJECT:
- GenIGet(mir, opt_flags, kReference, rl_dest, rl_src[0], false, true);
+ GenIGet(mir, opt_flags, kReference, Primitive::kPrimNot, rl_dest, rl_src[0]);
break;
case Instruction::IGET_WIDE:
- GenIGet(mir, opt_flags, k64, rl_dest, rl_src[0], true, false);
+ // kPrimLong and kPrimDouble share the same entrypoints.
+ GenIGet(mir, opt_flags, k64, Primitive::kPrimLong, rl_dest, rl_src[0]);
break;
case Instruction::IGET:
- GenIGet(mir, opt_flags, k32, rl_dest, rl_src[0], false, false);
+ GenIGet(mir, opt_flags, k32, Primitive::kPrimInt, rl_dest, rl_src[0]);
break;
case Instruction::IGET_CHAR:
- GenIGet(mir, opt_flags, kUnsignedHalf, rl_dest, rl_src[0], false, false);
+ GenIGet(mir, opt_flags, kUnsignedHalf, Primitive::kPrimChar, rl_dest, rl_src[0]);
break;
case Instruction::IGET_SHORT:
- GenIGet(mir, opt_flags, kSignedHalf, rl_dest, rl_src[0], false, false);
+ GenIGet(mir, opt_flags, kSignedHalf, Primitive::kPrimShort, rl_dest, rl_src[0]);
break;
case Instruction::IGET_BOOLEAN:
+ GenIGet(mir, opt_flags, kUnsignedByte, Primitive::kPrimBoolean, rl_dest, rl_src[0]);
+ break;
+
case Instruction::IGET_BYTE:
- GenIGet(mir, opt_flags, kUnsignedByte, rl_dest, rl_src[0], false, false);
+ GenIGet(mir, opt_flags, kSignedByte, Primitive::kPrimByte, rl_dest, rl_src[0]);
break;
case Instruction::IPUT_WIDE:
- GenIPut(mir, opt_flags, k64, rl_src[0], rl_src[1], true, false);
+ GenIPut(mir, opt_flags, k64, rl_src[0], rl_src[1]);
break;
case Instruction::IPUT_OBJECT:
- GenIPut(mir, opt_flags, kReference, rl_src[0], rl_src[1], false, true);
+ GenIPut(mir, opt_flags, kReference, rl_src[0], rl_src[1]);
break;
case Instruction::IPUT:
- GenIPut(mir, opt_flags, k32, rl_src[0], rl_src[1], false, false);
+ GenIPut(mir, opt_flags, k32, rl_src[0], rl_src[1]);
break;
- case Instruction::IPUT_BOOLEAN:
case Instruction::IPUT_BYTE:
- GenIPut(mir, opt_flags, kUnsignedByte, rl_src[0], rl_src[1], false, false);
+ case Instruction::IPUT_BOOLEAN:
+ GenIPut(mir, opt_flags, kUnsignedByte, rl_src[0], rl_src[1]);
break;
case Instruction::IPUT_CHAR:
- GenIPut(mir, opt_flags, kUnsignedHalf, rl_src[0], rl_src[1], false, false);
+ GenIPut(mir, opt_flags, kUnsignedHalf, rl_src[0], rl_src[1]);
break;
case Instruction::IPUT_SHORT:
- GenIPut(mir, opt_flags, kSignedHalf, rl_src[0], rl_src[1], false, false);
+ GenIPut(mir, opt_flags, kSignedHalf, rl_src[0], rl_src[1]);
break;
case Instruction::SGET_OBJECT:
- GenSget(mir, rl_dest, false, true);
+ GenSget(mir, rl_dest, kReference, Primitive::kPrimNot);
break;
+
case Instruction::SGET:
- case Instruction::SGET_BOOLEAN:
- case Instruction::SGET_BYTE:
+ GenSget(mir, rl_dest, k32, Primitive::kPrimInt);
+ break;
+
case Instruction::SGET_CHAR:
+ GenSget(mir, rl_dest, kUnsignedHalf, Primitive::kPrimChar);
+ break;
+
case Instruction::SGET_SHORT:
- GenSget(mir, rl_dest, false, false);
+ GenSget(mir, rl_dest, kSignedHalf, Primitive::kPrimShort);
+ break;
+
+ case Instruction::SGET_BOOLEAN:
+ GenSget(mir, rl_dest, kUnsignedByte, Primitive::kPrimBoolean);
+ break;
+
+ case Instruction::SGET_BYTE:
+ GenSget(mir, rl_dest, kSignedByte, Primitive::kPrimByte);
break;
case Instruction::SGET_WIDE:
- GenSget(mir, rl_dest, true, false);
+ // kPrimLong and kPrimDouble share the same entrypoints.
+ GenSget(mir, rl_dest, k64, Primitive::kPrimLong);
break;
case Instruction::SPUT_OBJECT:
- GenSput(mir, rl_src[0], false, true);
+ GenSput(mir, rl_src[0], kReference);
break;
case Instruction::SPUT:
- case Instruction::SPUT_BOOLEAN:
- case Instruction::SPUT_BYTE:
- case Instruction::SPUT_CHAR:
- case Instruction::SPUT_SHORT:
- GenSput(mir, rl_src[0], false, false);
+ GenSput(mir, rl_src[0], k32);
break;
+ case Instruction::SPUT_BYTE:
+ case Instruction::SPUT_BOOLEAN:
+ GenSput(mir, rl_src[0], kUnsignedByte);
+ break;
+
+ case Instruction::SPUT_CHAR:
+ GenSput(mir, rl_src[0], kUnsignedHalf);
+ break;
+
+ case Instruction::SPUT_SHORT:
+ GenSput(mir, rl_src[0], kSignedHalf);
+ break;
+
+
case Instruction::SPUT_WIDE:
- GenSput(mir, rl_src[0], true, false);
+ GenSput(mir, rl_src[0], k64);
break;
case Instruction::INVOKE_STATIC_RANGE: