Merge "Restore end of dex2oat logging"
diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h
index 18122b3..2bc36a5 100644
--- a/compiler/dex/compiler_enums.h
+++ b/compiler/dex/compiler_enums.h
@@ -210,6 +210,22 @@
kOpInvalid,
};
+enum MoveType {
+ kMov8GP, // Move 8-bit general purpose register.
+ kMov16GP, // Move 16-bit general purpose register.
+ kMov32GP, // Move 32-bit general purpose register.
+ kMov64GP, // Move 64-bit general purpose register.
+ kMov32FP, // Move 32-bit FP register.
+ kMov64FP, // Move 64-bit FP register.
+ kMovLo64FP, // Move low 32-bits of 64-bit FP register.
+ kMovHi64FP, // Move high 32-bits of 64-bit FP register.
+ kMovU128FP, // Move 128-bit FP register to/from possibly unaligned region.
+ kMov128FP = kMovU128FP,
+ kMovA128FP, // Move 128-bit FP register to/from region surely aligned to 16-bytes.
+ kMovLo128FP, // Move low 64-bits of 128-bit FP register.
+ kMovHi128FP, // Move high 64-bits of 128-bit FP register.
+};
+
std::ostream& operator<<(std::ostream& os, const OpKind& kind);
enum ConditionCode {
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 32673db..0ed4576 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -154,6 +154,8 @@
LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
+ LIR* OpMovRegMem(int r_dest, int r_base, int offset, MoveType move_type);
+ LIR* OpMovMemReg(int r_base, int offset, int r_src, MoveType move_type);
LIR* OpCondRegReg(OpKind op, ConditionCode cc, int r_dest, int r_src);
LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index 07fc6c7..9d3968b 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -367,6 +367,16 @@
return OpRegRegShift(op, r_dest_src1, r_src2, 0);
}
+LIR* ArmMir2Lir::OpMovRegMem(int r_dest, int r_base, int offset, MoveType move_type) {
+ UNIMPLEMENTED(FATAL);
+ return nullptr;
+}
+
+LIR* ArmMir2Lir::OpMovMemReg(int r_base, int offset, int r_src, MoveType move_type) {
+ UNIMPLEMENTED(FATAL);
+ return nullptr;
+}
+
LIR* ArmMir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, int r_dest, int r_src) {
LOG(FATAL) << "Unexpected use of OpCondRegReg for Arm";
return NULL;
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 3823fb3..6382dd6 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -811,42 +811,145 @@
}
}
+ // Logic below assumes that Method pointer is at offset zero from SP.
+ DCHECK_EQ(VRegOffset(static_cast<int>(kVRegMethodPtrBaseReg)), 0);
+
+ // The first 3 arguments are passed via registers.
+ // TODO: For 64-bit, instead of hardcoding 4 for Method* size, we should either
+ // get size of uintptr_t or size of object reference according to model being used.
+ int outs_offset = 4 /* Method* */ + (3 * sizeof(uint32_t));
int start_offset = SRegOffset(info->args[3].s_reg_low);
- int outs_offset = 4 /* Method* */ + (3 * 4);
- if (cu_->instruction_set != kThumb2) {
+ int regs_left_to_pass_via_stack = info->num_arg_words - 3;
+ DCHECK_GT(regs_left_to_pass_via_stack, 0);
+
+ if (cu_->instruction_set == kThumb2 && regs_left_to_pass_via_stack <= 16) {
+ // Use vldm/vstm pair using kArg3 as a temp
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+ direct_code, direct_method, type);
+ OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
+ LIR* ld = OpVldm(TargetReg(kArg3), regs_left_to_pass_via_stack);
+ // TUNING: loosen barrier
+ ld->u.m.def_mask = ENCODE_ALL;
+ SetMemRefType(ld, true /* is_load */, kDalvikReg);
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+ direct_code, direct_method, type);
+ OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+ direct_code, direct_method, type);
+ LIR* st = OpVstm(TargetReg(kArg3), regs_left_to_pass_via_stack);
+ SetMemRefType(st, false /* is_load */, kDalvikReg);
+ st->u.m.def_mask = ENCODE_ALL;
+ call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
+ direct_code, direct_method, type);
+ } else if (cu_->instruction_set == kX86) {
+ int current_src_offset = start_offset;
+ int current_dest_offset = outs_offset;
+
+ while (regs_left_to_pass_via_stack > 0) {
+ // This is based on the knowledge that the stack itself is 16-byte aligned.
+ bool src_is_16b_aligned = (current_src_offset & 0xF) == 0;
+ bool dest_is_16b_aligned = (current_dest_offset & 0xF) == 0;
+ size_t bytes_to_move;
+
+ /*
+ * The amount to move defaults to 32-bit. If there are 4 registers left to move, then do a
+ * a 128-bit move because we won't get the chance to try to aligned. If there are more than
+ * 4 registers left to move, consider doing a 128-bit only if either src or dest are aligned.
+ * We do this because we could potentially do a smaller move to align.
+ */
+ if (regs_left_to_pass_via_stack == 4 ||
+ (regs_left_to_pass_via_stack > 4 && (src_is_16b_aligned || dest_is_16b_aligned))) {
+ // Moving 128-bits via xmm register.
+ bytes_to_move = sizeof(uint32_t) * 4;
+
+ // Allocate a free xmm temp. Since we are working through the calling sequence,
+ // we expect to have an xmm temporary available.
+ int temp = AllocTempDouble();
+ CHECK_GT(temp, 0);
+
+ LIR* ld1 = nullptr;
+ LIR* ld2 = nullptr;
+ LIR* st1 = nullptr;
+ LIR* st2 = nullptr;
+
+ /*
+ * The logic is similar for both loads and stores. If we have 16-byte alignment,
+ * do an aligned move. If we have 8-byte alignment, then do the move in two
+ * parts. This approach prevents possible cache line splits. Finally, fall back
+ * to doing an unaligned move. In most cases we likely won't split the cache
+ * line but we cannot prove it and thus take a conservative approach.
+ */
+ bool src_is_8b_aligned = (current_src_offset & 0x7) == 0;
+ bool dest_is_8b_aligned = (current_dest_offset & 0x7) == 0;
+
+ if (src_is_16b_aligned) {
+ ld1 = OpMovRegMem(temp, TargetReg(kSp), current_src_offset, kMovA128FP);
+ } else if (src_is_8b_aligned) {
+ ld1 = OpMovRegMem(temp, TargetReg(kSp), current_src_offset, kMovLo128FP);
+ ld2 = OpMovRegMem(temp, TargetReg(kSp), current_src_offset + (bytes_to_move >> 1), kMovHi128FP);
+ } else {
+ ld1 = OpMovRegMem(temp, TargetReg(kSp), current_src_offset, kMovU128FP);
+ }
+
+ if (dest_is_16b_aligned) {
+ st1 = OpMovMemReg(TargetReg(kSp), current_dest_offset, temp, kMovA128FP);
+ } else if (dest_is_8b_aligned) {
+ st1 = OpMovMemReg(TargetReg(kSp), current_dest_offset, temp, kMovLo128FP);
+ st2 = OpMovMemReg(TargetReg(kSp), current_dest_offset + (bytes_to_move >> 1), temp, kMovHi128FP);
+ } else {
+ st1 = OpMovMemReg(TargetReg(kSp), current_dest_offset, temp, kMovU128FP);
+ }
+
+ // TODO If we could keep track of aliasing information for memory accesses that are wider
+ // than 64-bit, we wouldn't need to set up a barrier.
+ if (ld1 != nullptr) {
+ if (ld2 != nullptr) {
+ // For 64-bit load we can actually set up the aliasing information.
+ AnnotateDalvikRegAccess(ld1, current_src_offset >> 2, true, true);
+ AnnotateDalvikRegAccess(ld2, (current_src_offset + (bytes_to_move >> 1)) >> 2, true, true);
+ } else {
+ // Set barrier for 128-bit load.
+ SetMemRefType(ld1, true /* is_load */, kDalvikReg);
+ ld1->u.m.def_mask = ENCODE_ALL;
+ }
+ }
+ if (st1 != nullptr) {
+ if (st2 != nullptr) {
+ // For 64-bit store we can actually set up the aliasing information.
+ AnnotateDalvikRegAccess(st1, current_dest_offset >> 2, false, true);
+ AnnotateDalvikRegAccess(st2, (current_dest_offset + (bytes_to_move >> 1)) >> 2, false, true);
+ } else {
+ // Set barrier for 128-bit store.
+ SetMemRefType(st1, false /* is_load */, kDalvikReg);
+ st1->u.m.def_mask = ENCODE_ALL;
+ }
+ }
+
+ // Free the temporary used for the data movement.
+ FreeTemp(temp);
+ } else {
+ // Moving 32-bits via general purpose register.
+ bytes_to_move = sizeof(uint32_t);
+
+ // Instead of allocating a new temp, simply reuse one of the registers being used
+ // for argument passing.
+ int temp = TargetReg(kArg3);
+
+ // Now load the argument VR and store to the outs.
+ LoadWordDisp(TargetReg(kSp), current_src_offset, temp);
+ StoreWordDisp(TargetReg(kSp), current_dest_offset, temp);
+ }
+
+ current_src_offset += bytes_to_move;
+ current_dest_offset += bytes_to_move;
+ regs_left_to_pass_via_stack -= (bytes_to_move >> 2);
+ }
+ } else {
// Generate memcpy
OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
CallRuntimeHelperRegRegImm(QUICK_ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
- } else {
- if (info->num_arg_words >= 20) {
- // Generate memcpy
- OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
- OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
- CallRuntimeHelperRegRegImm(QUICK_ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
- TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
- } else {
- // Use vldm/vstm pair using kArg3 as a temp
- int regs_left = std::min(info->num_arg_words - 3, 16);
- call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
- direct_code, direct_method, type);
- OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
- LIR* ld = OpVldm(TargetReg(kArg3), regs_left);
- // TUNING: loosen barrier
- ld->u.m.def_mask = ENCODE_ALL;
- SetMemRefType(ld, true /* is_load */, kDalvikReg);
- call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
- direct_code, direct_method, type);
- OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
- call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
- direct_code, direct_method, type);
- LIR* st = OpVstm(TargetReg(kArg3), regs_left);
- SetMemRefType(st, false /* is_load */, kDalvikReg);
- st->u.m.def_mask = ENCODE_ALL;
- call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
- direct_code, direct_method, type);
- }
}
call_state = LoadArgRegs(info, call_state, next_call_insn,
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index aca93f5..11b8f83 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -151,6 +151,8 @@
LIR* OpRegImm(OpKind op, int r_dest_src1, int value);
LIR* OpRegMem(OpKind op, int r_dest, int rBase, int offset);
LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
+ LIR* OpMovRegMem(int r_dest, int r_base, int offset, MoveType move_type);
+ LIR* OpMovMemReg(int r_base, int offset, int r_src, MoveType move_type);
LIR* OpCondRegReg(OpKind op, ConditionCode cc, int r_dest, int r_src);
LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index c5e2b36..21c971c 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -325,6 +325,16 @@
return NewLIR2(opcode, r_dest_src1, r_src2);
}
+LIR* MipsMir2Lir::OpMovRegMem(int r_dest, int r_base, int offset, MoveType move_type) {
+ UNIMPLEMENTED(FATAL);
+ return nullptr;
+}
+
+LIR* MipsMir2Lir::OpMovMemReg(int r_base, int offset, int r_src, MoveType move_type) {
+ UNIMPLEMENTED(FATAL);
+ return nullptr;
+}
+
LIR* MipsMir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, int r_dest, int r_src) {
LOG(FATAL) << "Unexpected use of OpCondRegReg for MIPS";
return NULL;
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 09b501a..3a68044 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -946,6 +946,27 @@
virtual LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2) = 0;
/**
+ * @brief Used to generate an LIR that does a load from mem to reg.
+ * @param r_dest The destination physical register.
+ * @param r_base The base physical register for memory operand.
+ * @param offset The displacement for memory operand.
+ * @param move_type Specification on the move desired (size, alignment, register kind).
+ * @return Returns the generate move LIR.
+ */
+ virtual LIR* OpMovRegMem(int r_dest, int r_base, int offset, MoveType move_type) = 0;
+
+ /**
+ * @brief Used to generate an LIR that does a store from reg to mem.
+ * @param r_base The base physical register for memory operand.
+ * @param offset The displacement for memory operand.
+ * @param r_src The destination physical register.
+ * @param bytes_to_move The number of bytes to move.
+ * @param is_aligned Whether the memory location is known to be aligned.
+ * @return Returns the generate move LIR.
+ */
+ virtual LIR* OpMovMemReg(int r_base, int offset, int r_src, MoveType move_type) = 0;
+
+ /**
* @brief Used for generating a conditional register to register operation.
* @param op The opcode kind.
* @param cc The condition code that when true will perform the opcode.
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index 3058b0c..ae53ddb 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -297,6 +297,24 @@
{ kX86SqrtsdRR, kRegReg, IS_BINARY_OP | REG_DEF0_USE1, { 0xF2, 0, 0x0F, 0x51, 0, 0, 0, 0 }, "SqrtsdRR", "!0r,!1r" },
{ kX86FstpdM, kMem, IS_STORE | IS_BINARY_OP | REG_USE0, { 0x0, 0, 0xDD, 0x00, 0, 3, 0, 0 }, "FstpdM", "[!0r,!1d]" },
+ EXT_0F_ENCODING_MAP(Movups, 0x0, 0x10, REG_DEF0),
+ { kX86MovupsMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02, { 0x0, 0, 0x0F, 0x11, 0, 0, 0, 0 }, "MovupsMR", "[!0r+!1d],!2r" },
+ { kX86MovupsAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014, { 0x0, 0, 0x0F, 0x11, 0, 0, 0, 0 }, "MovupsAR", "[!0r+!1r<<!2d+!3d],!4r" },
+
+ EXT_0F_ENCODING_MAP(Movaps, 0x0, 0x28, REG_DEF0),
+ { kX86MovapsMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02, { 0x0, 0, 0x0F, 0x29, 0, 0, 0, 0 }, "MovapsMR", "[!0r+!1d],!2r" },
+ { kX86MovapsAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014, { 0x0, 0, 0x0F, 0x29, 0, 0, 0, 0 }, "MovapsAR", "[!0r+!1r<<!2d+!3d],!4r" },
+
+ { kX86MovlpsRM, kRegMem, IS_LOAD | IS_TERTIARY_OP | REG_DEF0 | REG_USE01, { 0x0, 0, 0x0F, 0x12, 0, 0, 0, 0 }, "MovlpsRM", "!0r,[!1r+!2d]" },
+ { kX86MovlpsRA, kRegArray, IS_LOAD | IS_QUIN_OP | REG_DEF0 | REG_USE012, { 0x0, 0, 0x0F, 0x12, 0, 0, 0, 0 }, "MovlpsRA", "!0r,[!1r+!2r<<!3d+!4d]" },
+ { kX86MovlpsMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02, { 0x0, 0, 0x0F, 0x13, 0, 0, 0, 0 }, "MovlpsMR", "[!0r+!1d],!2r" },
+ { kX86MovlpsAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014, { 0x0, 0, 0x0F, 0x13, 0, 0, 0, 0 }, "MovlpsAR", "[!0r+!1r<<!2d+!3d],!4r" },
+
+ { kX86MovhpsRM, kRegMem, IS_LOAD | IS_TERTIARY_OP | REG_DEF0 | REG_USE01, { 0x0, 0, 0x0F, 0x16, 0, 0, 0, 0 }, "MovhpsRM", "!0r,[!1r+!2d]" },
+ { kX86MovhpsRA, kRegArray, IS_LOAD | IS_QUIN_OP | REG_DEF0 | REG_USE012, { 0x0, 0, 0x0F, 0x16, 0, 0, 0, 0 }, "MovhpsRA", "!0r,[!1r+!2r<<!3d+!4d]" },
+ { kX86MovhpsMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02, { 0x0, 0, 0x0F, 0x17, 0, 0, 0, 0 }, "MovhpsMR", "[!0r+!1d],!2r" },
+ { kX86MovhpsAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014, { 0x0, 0, 0x0F, 0x17, 0, 0, 0, 0 }, "MovhpsAR", "[!0r+!1r<<!2d+!3d],!4r" },
+
EXT_0F_ENCODING_MAP(Movdxr, 0x66, 0x6E, REG_DEF0),
{ kX86MovdrxRR, kRegRegStore, IS_BINARY_OP | REG_DEF0 | REG_USE01, { 0x66, 0, 0x0F, 0x7E, 0, 0, 0, 0 }, "MovdrxRR", "!0r,!1r" },
{ kX86MovdrxMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02, { 0x66, 0, 0x0F, 0x7E, 0, 0, 0, 0 }, "MovdrxMR", "[!0r+!1d],!2r" },
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 6896504..4c1c171 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -207,6 +207,8 @@
LIR* OpMemReg(OpKind op, RegLocation rl_dest, int value);
LIR* OpRegMem(OpKind op, int r_dest, RegLocation value);
LIR* OpRegReg(OpKind op, int r_dest_src1, int r_src2);
+ LIR* OpMovRegMem(int r_dest, int r_base, int offset, MoveType move_type);
+ LIR* OpMovMemReg(int r_base, int offset, int r_src, MoveType move_type);
LIR* OpCondRegReg(OpKind op, ConditionCode cc, int r_dest, int r_src);
LIR* OpRegRegImm(OpKind op, int r_dest, int r_src1, int value);
LIR* OpRegRegReg(OpKind op, int r_dest, int r_src1, int r_src2);
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index 18c5ca8..e2744d0 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -211,6 +211,110 @@
return NewLIR2(opcode, r_dest_src1, r_src2);
}
+LIR* X86Mir2Lir::OpMovRegMem(int r_dest, int r_base, int offset, MoveType move_type) {
+ DCHECK(!(X86_FPREG(r_base)));
+
+ X86OpCode opcode = kX86Nop;
+ switch (move_type) {
+ case kMov8GP:
+ CHECK(!X86_FPREG(r_dest));
+ opcode = kX86Mov8RM;
+ break;
+ case kMov16GP:
+ CHECK(!X86_FPREG(r_dest));
+ opcode = kX86Mov16RM;
+ break;
+ case kMov32GP:
+ CHECK(!X86_FPREG(r_dest));
+ opcode = kX86Mov32RM;
+ break;
+ case kMov32FP:
+ CHECK(X86_FPREG(r_dest));
+ opcode = kX86MovssRM;
+ break;
+ case kMov64FP:
+ CHECK(X86_FPREG(r_dest));
+ opcode = kX86MovsdRM;
+ break;
+ case kMovU128FP:
+ CHECK(X86_FPREG(r_dest));
+ opcode = kX86MovupsRM;
+ break;
+ case kMovA128FP:
+ CHECK(X86_FPREG(r_dest));
+ opcode = kX86MovapsRM;
+ break;
+ case kMovLo128FP:
+ CHECK(X86_FPREG(r_dest));
+ opcode = kX86MovlpsRM;
+ break;
+ case kMovHi128FP:
+ CHECK(X86_FPREG(r_dest));
+ opcode = kX86MovhpsRM;
+ break;
+ case kMov64GP:
+ case kMovLo64FP:
+ case kMovHi64FP:
+ default:
+ LOG(FATAL) << "Bad case in OpMovRegMem";
+ break;
+ }
+
+ return NewLIR3(opcode, r_dest, r_base, offset);
+}
+
+LIR* X86Mir2Lir::OpMovMemReg(int r_base, int offset, int r_src, MoveType move_type) {
+ DCHECK(!(X86_FPREG(r_base)));
+
+ X86OpCode opcode = kX86Nop;
+ switch (move_type) {
+ case kMov8GP:
+ CHECK(!X86_FPREG(r_src));
+ opcode = kX86Mov8MR;
+ break;
+ case kMov16GP:
+ CHECK(!X86_FPREG(r_src));
+ opcode = kX86Mov16MR;
+ break;
+ case kMov32GP:
+ CHECK(!X86_FPREG(r_src));
+ opcode = kX86Mov32MR;
+ break;
+ case kMov32FP:
+ CHECK(X86_FPREG(r_src));
+ opcode = kX86MovssMR;
+ break;
+ case kMov64FP:
+ CHECK(X86_FPREG(r_src));
+ opcode = kX86MovsdMR;
+ break;
+ case kMovU128FP:
+ CHECK(X86_FPREG(r_src));
+ opcode = kX86MovupsMR;
+ break;
+ case kMovA128FP:
+ CHECK(X86_FPREG(r_src));
+ opcode = kX86MovapsMR;
+ break;
+ case kMovLo128FP:
+ CHECK(X86_FPREG(r_src));
+ opcode = kX86MovlpsMR;
+ break;
+ case kMovHi128FP:
+ CHECK(X86_FPREG(r_src));
+ opcode = kX86MovhpsMR;
+ break;
+ case kMov64GP:
+ case kMovLo64FP:
+ case kMovHi64FP:
+ default:
+ LOG(FATAL) << "Bad case in OpMovMemReg";
+ break;
+ }
+
+ return NewLIR3(opcode, r_base, offset, r_src);
+}
+
LIR* X86Mir2Lir::OpCondRegReg(OpKind op, ConditionCode cc, int r_dest, int r_src) {
// The only conditional reg to reg operation supported is Cmov
DCHECK_EQ(op, kOpCmov);
diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h
index 7f35d06..6962ff7 100644
--- a/compiler/dex/quick/x86/x86_lir.h
+++ b/compiler/dex/quick/x86/x86_lir.h
@@ -357,6 +357,14 @@
kX86PsllqRI, // left shift of floating point registers
kX86SqrtsdRR, // sqrt of floating point register
kX86FstpdM, // Store and pop top x87 fp stack
+ Binary0fOpCode(kX86Movups), // load unaligned packed single FP values from xmm2/m128 to xmm1
+ kX86MovupsMR, kX86MovupsAR, // store unaligned packed single FP values from xmm1 to m128
+ Binary0fOpCode(kX86Movaps), // load aligned packed single FP values from xmm2/m128 to xmm1
+ kX86MovapsMR, kX86MovapsAR, // store aligned packed single FP values from xmm1 to m128
+ kX86MovlpsRM, kX86MovlpsRA, // load packed single FP values from m64 to low quadword of xmm
+ kX86MovlpsMR, kX86MovlpsAR, // store packed single FP values from low quadword of xmm to m64
+ kX86MovhpsRM, kX86MovhpsRA, // load packed single FP values from m64 to high quadword of xmm
+ kX86MovhpsMR, kX86MovhpsAR, // store packed single FP values from high quadword of xmm to m64
Binary0fOpCode(kX86Movdxr), // move into xmm from gpr
kX86MovdrxRR, kX86MovdrxMR, kX86MovdrxAR, // move into reg from xmm
kX86Set8R, kX86Set8M, kX86Set8A, // set byte depending on condition operand
diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc
index 6c25e0a..903d755 100644
--- a/disassembler/disassembler_x86.cc
+++ b/disassembler/disassembler_x86.cc
@@ -246,6 +246,42 @@
load = *instr == 0x10;
store = !load;
break;
+ case 0x12: case 0x13:
+ if (prefix[2] == 0x66) {
+ opcode << "movlpd";
+ prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
+ } else if (prefix[0] == 0) {
+ opcode << "movlps";
+ }
+ has_modrm = true;
+ src_reg_file = dst_reg_file = SSE;
+ load = *instr == 0x12;
+ store = !load;
+ break;
+ case 0x16: case 0x17:
+ if (prefix[2] == 0x66) {
+ opcode << "movhpd";
+ prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
+ } else if (prefix[0] == 0) {
+ opcode << "movhps";
+ }
+ has_modrm = true;
+ src_reg_file = dst_reg_file = SSE;
+ load = *instr == 0x16;
+ store = !load;
+ break;
+ case 0x28: case 0x29:
+ if (prefix[2] == 0x66) {
+ opcode << "movapd";
+ prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
+ } else if (prefix[0] == 0) {
+ opcode << "movaps";
+ }
+ has_modrm = true;
+ src_reg_file = dst_reg_file = SSE;
+ load = *instr == 0x28;
+ store = !load;
+ break;
case 0x2A:
if (prefix[2] == 0x66) {
opcode << "cvtpi2pd";
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 462c328..f1f5905 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -649,15 +649,9 @@
const OatFile* ClassLinker::RegisterOatFile(const OatFile* oat_file) {
WriterMutexLock mu(Thread::Current(), dex_lock_);
- for (size_t i = 0; i < oat_files_.size(); ++i) {
- if (UNLIKELY(oat_file->GetLocation() == oat_files_[i]->GetLocation())) {
- VLOG(class_linker) << "Attempt to register oat file that's already registered: "
- << oat_file->GetLocation();
- for (size_t j = i; j < oat_files_.size(); ++j) {
- CHECK_NE(oat_file, oat_files_[j]) << "Attempt to re-register dex file.";
- }
- delete oat_file;
- return oat_files_[i];
+ if (kIsDebugBuild) {
+ for (size_t i = 0; i < oat_files_.size(); ++i) {
+ CHECK_NE(oat_file, oat_files_[i]) << oat_file->GetLocation();
}
}
VLOG(class_linker) << "Registering " << oat_file->GetLocation();
@@ -826,20 +820,6 @@
<< oat_location << "': " << *error_msg;
error_msg->clear();
- {
- // We might have registered an outdated OatFile in FindDexFileInOatLocation().
- // Get rid of it as its MAP_PRIVATE mapping may not reflect changes we're about to do.
- WriterMutexLock mu(Thread::Current(), dex_lock_);
- for (size_t i = 0; i < oat_files_.size(); ++i) {
- if (oat_location == oat_files_[i]->GetLocation()) {
- VLOG(class_linker) << "De-registering old OatFile: " << oat_location;
- delete oat_files_[i];
- oat_files_.erase(oat_files_.begin() + i);
- break;
- }
- }
- }
-
// Generate the output oat file for the dex file
VLOG(class_linker) << "Generating oat file " << oat_location << " for " << dex_location;
if (!GenerateOatFile(dex_location, scoped_flock.GetFile().Fd(), oat_location, error_msg)) {
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 429c516..d28d986 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -284,6 +284,27 @@
}
}
+DexFile::DexFile(const byte* base, size_t size,
+ const std::string& location,
+ uint32_t location_checksum,
+ MemMap* mem_map)
+ : begin_(base),
+ size_(size),
+ location_(location),
+ location_checksum_(location_checksum),
+ mem_map_(mem_map),
+ modification_lock("DEX modification lock"),
+ header_(reinterpret_cast<const Header*>(base)),
+ string_ids_(reinterpret_cast<const StringId*>(base + header_->string_ids_off_)),
+ type_ids_(reinterpret_cast<const TypeId*>(base + header_->type_ids_off_)),
+ field_ids_(reinterpret_cast<const FieldId*>(base + header_->field_ids_off_)),
+ method_ids_(reinterpret_cast<const MethodId*>(base + header_->method_ids_off_)),
+ proto_ids_(reinterpret_cast<const ProtoId*>(base + header_->proto_ids_off_)),
+ class_defs_(reinterpret_cast<const ClassDef*>(base + header_->class_defs_off_)) {
+ CHECK(begin_ != NULL) << GetLocation();
+ CHECK_GT(size_, 0U) << GetLocation();
+}
+
DexFile::~DexFile() {
// We don't call DeleteGlobalRef on dex_object_ because we're only called by DestroyJavaVM, and
// that's only called after DetachCurrentThread, which means there's no JNIEnv. We could
@@ -292,25 +313,12 @@
}
bool DexFile::Init(std::string* error_msg) {
- InitMembers();
if (!CheckMagicAndVersion(error_msg)) {
return false;
}
return true;
}
-void DexFile::InitMembers() {
- const byte* b = begin_;
- header_ = reinterpret_cast<const Header*>(b);
- const Header* h = header_;
- string_ids_ = reinterpret_cast<const StringId*>(b + h->string_ids_off_);
- type_ids_ = reinterpret_cast<const TypeId*>(b + h->type_ids_off_);
- field_ids_ = reinterpret_cast<const FieldId*>(b + h->field_ids_off_);
- method_ids_ = reinterpret_cast<const MethodId*>(b + h->method_ids_off_);
- proto_ids_ = reinterpret_cast<const ProtoId*>(b + h->proto_ids_off_);
- class_defs_ = reinterpret_cast<const ClassDef*>(b + h->class_defs_off_);
-}
-
bool DexFile::CheckMagicAndVersion(std::string* error_msg) const {
CHECK(header_->magic_ != NULL) << GetLocation();
if (!IsMagicValid(header_->magic_)) {
@@ -856,6 +864,13 @@
}
}
+std::ostream& operator<<(std::ostream& os, const DexFile& dex_file) {
+ os << StringPrintf("[DexFile: %s dex-checksum=%08x location-checksum=%08x %p-%p]",
+ dex_file.GetLocation().c_str(),
+ dex_file.GetHeader().checksum_, dex_file.GetLocationChecksum(),
+ dex_file.Begin(), dex_file.Begin() + dex_file.Size());
+ return os;
+}
std::string Signature::ToString() const {
if (dex_file_ == nullptr) {
CHECK(proto_id_ == nullptr);
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 69593cd..bc2bfde 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -849,30 +849,11 @@
DexFile(const byte* base, size_t size,
const std::string& location,
uint32_t location_checksum,
- MemMap* mem_map)
- : begin_(base),
- size_(size),
- location_(location),
- location_checksum_(location_checksum),
- mem_map_(mem_map),
- modification_lock("DEX modification lock"),
- header_(0),
- string_ids_(0),
- type_ids_(0),
- field_ids_(0),
- method_ids_(0),
- proto_ids_(0),
- class_defs_(0) {
- CHECK(begin_ != NULL) << GetLocation();
- CHECK_GT(size_, 0U) << GetLocation();
- }
+ MemMap* mem_map);
// Top-level initializer that calls other Init methods.
bool Init(std::string* error_msg);
- // Caches pointers into to the various file sections.
- void InitMembers();
-
// Returns true if the header magic and version numbers are of the expected values.
bool CheckMagicAndVersion(std::string* error_msg) const;
@@ -903,26 +884,27 @@
Mutex modification_lock;
// Points to the header section.
- const Header* header_;
+ const Header* const header_;
// Points to the base of the string identifier list.
- const StringId* string_ids_;
+ const StringId* const string_ids_;
// Points to the base of the type identifier list.
- const TypeId* type_ids_;
+ const TypeId* const type_ids_;
// Points to the base of the field identifier list.
- const FieldId* field_ids_;
+ const FieldId* const field_ids_;
// Points to the base of the method identifier list.
- const MethodId* method_ids_;
+ const MethodId* const method_ids_;
// Points to the base of the prototype identifier list.
- const ProtoId* proto_ids_;
+ const ProtoId* const proto_ids_;
// Points to the base of the class definition list.
- const ClassDef* class_defs_;
+ const ClassDef* const class_defs_;
};
+std::ostream& operator<<(std::ostream& os, const DexFile& dex_file);
// Iterate over a dex file's ProtoId's paramters
class DexFileParameterIterator {
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 0a3e1a1..2795e1d 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -120,7 +120,7 @@
CHECK_NE(0, prot);
CHECK_NE(0, flags & (MAP_SHARED | MAP_PRIVATE));
if (byte_count == 0) {
- return new MemMap("file", NULL, 0, NULL, 0, prot);
+ return new MemMap(filename, NULL, 0, NULL, 0, prot);
}
// Adjust 'offset' to be page-aligned as required by mmap.
int page_offset = start % kPageSize;
@@ -153,7 +153,7 @@
maps.c_str());
return NULL;
}
- return new MemMap("file", actual + page_offset, byte_count, actual, page_aligned_byte_count,
+ return new MemMap(filename, actual + page_offset, byte_count, actual, page_aligned_byte_count,
prot);
}
@@ -267,4 +267,11 @@
return false;
}
+std::ostream& operator<<(std::ostream& os, const MemMap& mem_map) {
+ os << StringPrintf("[MemMap: %s prot=%x %p-%p]",
+ mem_map.GetName().c_str(), mem_map.GetProtect(),
+ mem_map.BaseBegin(), mem_map.BaseEnd());
+ return os;
+}
+
} // namespace art
diff --git a/runtime/mem_map.h b/runtime/mem_map.h
index 2c65833..d2059b5 100644
--- a/runtime/mem_map.h
+++ b/runtime/mem_map.h
@@ -62,6 +62,10 @@
// Releases the memory mapping
~MemMap();
+ const std::string& GetName() const {
+ return name_;
+ }
+
bool Protect(int prot);
int GetProtect() const {
@@ -80,6 +84,18 @@
return Begin() + Size();
}
+ void* BaseBegin() const {
+ return base_begin_;
+ }
+
+ size_t BaseSize() const {
+ return base_size_;
+ }
+
+ void* BaseEnd() const {
+ return reinterpret_cast<byte*>(BaseBegin()) + BaseSize();
+ }
+
bool HasAddress(const void* addr) const {
return Begin() <= addr && addr < End();
}
@@ -102,6 +118,7 @@
friend class MemMapTest; // To allow access to base_begin_ and base_size_.
};
+std::ostream& operator<<(std::ostream& os, const MemMap& mem_map);
} // namespace art
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index fa2b485..be882048 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -338,12 +338,17 @@
}
if (warn_if_not_found) {
+ std::string checksum("<unspecified>");
+ if (dex_location_checksum != NULL) {
+ checksum = StringPrintf("0x%08x", *dex_location_checksum);
+ }
LOG(WARNING) << "Failed to find OatDexFile for DexFile " << dex_location
- << " in OatFile " << GetLocation();
+ << " with checksum " << checksum << " in OatFile " << GetLocation();
if (kIsDebugBuild) {
for (Table::const_iterator it = oat_dex_files_.begin(); it != oat_dex_files_.end(); ++it) {
LOG(WARNING) << "OatFile " << GetLocation()
- << " contains OatDexFile " << it->second->GetDexFileLocation();
+ << " contains OatDexFile " << it->second->GetDexFileLocation()
+ << " with checksum 0x" << std::hex << it->second->GetDexFileLocationChecksum();
}
}
}