Merge "ART: Ensure order of field gaps"
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 69b4295..beb34dc 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -119,7 +119,6 @@
optimizing/primitive_type_propagation.cc \
optimizing/reference_type_propagation.cc \
trampolines/trampoline_compiler.cc \
- utils/arena_allocator.cc \
utils/arena_bit_vector.cc \
utils/arm/assembler_arm.cc \
utils/arm/assembler_arm32.cc \
@@ -137,7 +136,6 @@
utils/x86/managed_register_x86.cc \
utils/x86_64/assembler_x86_64.cc \
utils/x86_64/managed_register_x86_64.cc \
- utils/scoped_arena_allocator.cc \
utils/swap_space.cc \
buffered_output_stream.cc \
compiler.cc \
diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h
index 0c46d43..dceea24 100644
--- a/compiler/dex/compiler_ir.h
+++ b/compiler/dex/compiler_ir.h
@@ -21,11 +21,11 @@
#include <string>
#include <vector>
+#include "base/arena_allocator.h"
+#include "base/scoped_arena_allocator.h"
#include "base/timing_logger.h"
#include "invoke_type.h"
#include "safe_map.h"
-#include "utils/arena_allocator.h"
-#include "utils/scoped_arena_allocator.h"
namespace art {
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index f7968c2..7e916be 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -238,7 +238,7 @@
bool is_volatile;
bool fast_path = driver_.ComputeInstanceFieldInfo(field_idx, &unit_, is_put,
&field_offset, &is_volatile);
- if (fast_path && !is_volatile && IsUint(16, field_offset.Int32Value())) {
+ if (fast_path && !is_volatile && IsUint<16>(field_offset.Int32Value())) {
VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode())
<< " to " << Instruction::Name(new_opcode)
<< " by replacing field index " << field_idx
@@ -274,7 +274,7 @@
&target_method, &vtable_idx,
&direct_code, &direct_method);
if (fast_path && original_invoke_type == invoke_type) {
- if (vtable_idx >= 0 && IsUint(16, vtable_idx)) {
+ if (vtable_idx >= 0 && IsUint<16>(vtable_idx)) {
VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode())
<< "(" << PrettyMethod(method_idx, GetDexFile(), true) << ")"
<< " to " << Instruction::Name(new_opcode)
diff --git a/compiler/dex/global_value_numbering.h b/compiler/dex/global_value_numbering.h
index c7bca85..6fa658c 100644
--- a/compiler/dex/global_value_numbering.h
+++ b/compiler/dex/global_value_numbering.h
@@ -17,12 +17,12 @@
#ifndef ART_COMPILER_DEX_GLOBAL_VALUE_NUMBERING_H_
#define ART_COMPILER_DEX_GLOBAL_VALUE_NUMBERING_H_
+#include "base/arena_object.h"
#include "base/logging.h"
#include "base/macros.h"
#include "mir_graph.h"
#include "compiler_ir.h"
#include "dex_flags.h"
-#include "utils/arena_object.h"
namespace art {
diff --git a/compiler/dex/gvn_dead_code_elimination.h b/compiler/dex/gvn_dead_code_elimination.h
index ea28039..9a19f29 100644
--- a/compiler/dex/gvn_dead_code_elimination.h
+++ b/compiler/dex/gvn_dead_code_elimination.h
@@ -17,9 +17,9 @@
#ifndef ART_COMPILER_DEX_GVN_DEAD_CODE_ELIMINATION_H_
#define ART_COMPILER_DEX_GVN_DEAD_CODE_ELIMINATION_H_
+#include "base/arena_object.h"
+#include "base/scoped_arena_containers.h"
#include "global_value_numbering.h"
-#include "utils/arena_object.h"
-#include "utils/scoped_arena_containers.h"
namespace art {
diff --git a/compiler/dex/local_value_numbering.h b/compiler/dex/local_value_numbering.h
index bfacf8e..97ea05a 100644
--- a/compiler/dex/local_value_numbering.h
+++ b/compiler/dex/local_value_numbering.h
@@ -19,9 +19,9 @@
#include <memory>
+#include "base/arena_object.h"
#include "base/logging.h"
#include "global_value_numbering.h"
-#include "utils/arena_object.h"
#include "utils/dex_instruction_utils.h"
namespace art {
diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc
index cc16dc4..31dbc60 100644
--- a/compiler/dex/mir_analysis.cc
+++ b/compiler/dex/mir_analysis.cc
@@ -18,6 +18,7 @@
#include <memory>
#include "base/logging.h"
+#include "base/scoped_arena_containers.h"
#include "dataflow_iterator-inl.h"
#include "compiler_ir.h"
#include "dex_flags.h"
@@ -29,7 +30,6 @@
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
#include "driver/dex_compilation_unit.h"
-#include "utils/scoped_arena_containers.h"
namespace art {
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index 08ca1b2..76b5e44 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -24,6 +24,7 @@
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/stringprintf.h"
+#include "base/scoped_arena_containers.h"
#include "compiler_ir.h"
#include "dex_file-inl.h"
#include "dex_flags.h"
@@ -34,7 +35,6 @@
#include "leb128.h"
#include "pass_driver_me_post_opt.h"
#include "stack.h"
-#include "utils/scoped_arena_containers.h"
namespace art {
@@ -1738,7 +1738,7 @@
info->num_arg_words = mir->ssa_rep->num_uses;
info->args = (info->num_arg_words == 0) ? nullptr :
arena_->AllocArray<RegLocation>(info->num_arg_words, kArenaAllocMisc);
- for (int i = 0; i < info->num_arg_words; i++) {
+ for (size_t i = 0; i < info->num_arg_words; i++) {
info->args[i] = GetRawSrc(mir, i);
}
info->opt_flags = mir->optimization_flags;
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index 020136c..e5abd3b 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -19,17 +19,17 @@
#include <stdint.h>
+#include "base/arena_containers.h"
+#include "base/scoped_arena_containers.h"
#include "dex_file.h"
#include "dex_instruction.h"
#include "dex_types.h"
#include "invoke_type.h"
#include "mir_field_info.h"
#include "mir_method_info.h"
-#include "utils/arena_bit_vector.h"
-#include "utils/arena_containers.h"
-#include "utils/scoped_arena_containers.h"
#include "reg_location.h"
#include "reg_storage.h"
+#include "utils/arena_bit_vector.h"
namespace art {
@@ -498,19 +498,19 @@
* more efficient invoke code generation.
*/
struct CallInfo {
- int num_arg_words; // Note: word count, not arg count.
- RegLocation* args; // One for each word of arguments.
- RegLocation result; // Eventual target of MOVE_RESULT.
+ size_t num_arg_words; // Note: word count, not arg count.
+ RegLocation* args; // One for each word of arguments.
+ RegLocation result; // Eventual target of MOVE_RESULT.
int opt_flags;
InvokeType type;
uint32_t dex_idx;
- uint32_t index; // Method idx for invokes, type idx for FilledNewArray.
+ uint32_t index; // Method idx for invokes, type idx for FilledNewArray.
uintptr_t direct_code;
uintptr_t direct_method;
- RegLocation target; // Target of following move_result.
+ RegLocation target; // Target of following move_result.
bool skip_this;
bool is_range;
- DexOffset offset; // Offset in code units.
+ DexOffset offset; // Offset in code units.
MIR* mir;
};
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index 2f547ea..fd67d4e 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -16,6 +16,7 @@
#include "base/bit_vector-inl.h"
#include "base/logging.h"
+#include "base/scoped_arena_containers.h"
#include "dataflow_iterator-inl.h"
#include "dex_flags.h"
#include "driver/compiler_driver.h"
@@ -27,7 +28,6 @@
#include "quick/dex_file_method_inliner.h"
#include "quick/dex_file_to_method_inliner_map.h"
#include "stack.h"
-#include "utils/scoped_arena_containers.h"
namespace art {
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 1b5dde2..9cf005b 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -484,6 +484,28 @@
NewLIR1(kThumbBx, rs_rARM_LR.GetReg());
}
+void ArmMir2Lir::GenSpecialEntryForSuspend() {
+ // Keep 16-byte stack alignment - push r0, i.e. ArtMethod*, r5, r6, lr.
+ DCHECK(!IsTemp(rs_r5));
+ DCHECK(!IsTemp(rs_r6));
+ core_spill_mask_ =
+ (1u << rs_r5.GetRegNum()) | (1u << rs_r6.GetRegNum()) | (1u << rs_rARM_LR.GetRegNum());
+ num_core_spills_ = 3u;
+ fp_spill_mask_ = 0u;
+ num_fp_spills_ = 0u;
+ frame_size_ = 16u;
+ core_vmap_table_.clear();
+ fp_vmap_table_.clear();
+ NewLIR1(kThumbPush, (1u << rs_r0.GetRegNum()) | // ArtMethod*
+ (core_spill_mask_ & ~(1u << rs_rARM_LR.GetRegNum())) | // Spills other than LR.
+ (1u << 8)); // LR encoded for 16-bit push.
+}
+
+void ArmMir2Lir::GenSpecialExitForSuspend() {
+ // Pop the frame. (ArtMethod* no longer needed but restore it anyway.)
+ NewLIR1(kThumb2Pop, (1u << rs_r0.GetRegNum()) | core_spill_mask_); // 32-bit because of LR.
+}
+
static bool ArmUseRelativeCall(CompilationUnit* cu, const MethodReference& target_method) {
// Emit relative calls only within a dex file due to the limited range of the BL insn.
return cu->dex_file == target_method.dex_file;
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 025e69f..67fabbd 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -18,9 +18,9 @@
#define ART_COMPILER_DEX_QUICK_ARM_CODEGEN_ARM_H_
#include "arm_lir.h"
+#include "base/arena_containers.h"
#include "base/logging.h"
#include "dex/quick/mir_to_lir.h"
-#include "utils/arena_containers.h"
namespace art {
@@ -167,7 +167,9 @@
void GenDivZeroCheckWide(RegStorage reg);
void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
void GenExitSequence();
- void GenSpecialExitSequence();
+ void GenSpecialExitSequence() OVERRIDE;
+ void GenSpecialEntryForSuspend() OVERRIDE;
+ void GenSpecialExitForSuspend() OVERRIDE;
void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
void GenSelect(BasicBlock* bb, MIR* mir);
diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc
index d1e4b7e..24e8fdf 100644
--- a/compiler/dex/quick/arm64/call_arm64.cc
+++ b/compiler/dex/quick/arm64/call_arm64.cc
@@ -392,6 +392,23 @@
NewLIR0(kA64Ret);
}
+void Arm64Mir2Lir::GenSpecialEntryForSuspend() {
+ // Keep 16-byte stack alignment - push x0, i.e. ArtMethod*, lr.
+ core_spill_mask_ = (1u << rs_xLR.GetRegNum());
+ num_core_spills_ = 1u;
+ fp_spill_mask_ = 0u;
+ num_fp_spills_ = 0u;
+ frame_size_ = 16u;
+ core_vmap_table_.clear();
+ fp_vmap_table_.clear();
+ NewLIR4(WIDE(kA64StpPre4rrXD), rs_x0.GetReg(), rs_xLR.GetReg(), rs_sp.GetReg(), -frame_size_ / 8);
+}
+
+void Arm64Mir2Lir::GenSpecialExitForSuspend() {
+ // Pop the frame. (ArtMethod* no longer needed but restore it anyway.)
+ NewLIR4(WIDE(kA64LdpPost4rrXD), rs_x0.GetReg(), rs_xLR.GetReg(), rs_sp.GetReg(), frame_size_ / 8);
+}
+
static bool Arm64UseRelativeCall(CompilationUnit* cu, const MethodReference& target_method) {
// Emit relative calls anywhere in the image or within a dex file otherwise.
return cu->compiler_driver->IsImage() || cu->dex_file == target_method.dex_file;
diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h
index 49ca625..d5f0536 100644
--- a/compiler/dex/quick/arm64/codegen_arm64.h
+++ b/compiler/dex/quick/arm64/codegen_arm64.h
@@ -169,6 +169,8 @@
void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) OVERRIDE;
void GenExitSequence() OVERRIDE;
void GenSpecialExitSequence() OVERRIDE;
+ void GenSpecialEntryForSuspend() OVERRIDE;
+ void GenSpecialExitForSuspend() OVERRIDE;
void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double) OVERRIDE;
void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) OVERRIDE;
void GenSelect(BasicBlock* bb, MIR* mir) OVERRIDE;
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 9f53b89..3c9b7a3 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -413,7 +413,7 @@
* Current code also throws internal unimp if not 'L', '[' or 'I'.
*/
void Mir2Lir::GenFilledNewArray(CallInfo* info) {
- int elems = info->num_arg_words;
+ size_t elems = info->num_arg_words;
int type_idx = info->index;
FlushAllRegs(); /* Everything to home location */
QuickEntrypointEnum target;
@@ -450,7 +450,7 @@
* of any regs in the source range that have been promoted to
* home location.
*/
- for (int i = 0; i < elems; i++) {
+ for (size_t i = 0; i < elems; i++) {
RegLocation loc = UpdateLoc(info->args[i]);
if (loc.location == kLocPhysReg) {
ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
@@ -493,7 +493,7 @@
OpRegRegImm(kOpAdd, r_dst, ref_reg,
mirror::Array::DataOffset(component_size).Int32Value());
// Set up the loop counter (known to be > 0)
- LoadConstant(r_idx, elems - 1);
+ LoadConstant(r_idx, static_cast<int>(elems - 1));
// Generate the copy loop. Going backwards for convenience
LIR* loop_head_target = NewLIR0(kPseudoTargetLabel);
// Copy next element
@@ -515,9 +515,9 @@
FreeTemp(r_dst);
FreeTemp(r_src);
} else {
- DCHECK_LE(elems, 5); // Usually but not necessarily non-range.
+ DCHECK_LE(elems, 5u); // Usually but not necessarily non-range.
// TUNING: interleave
- for (int i = 0; i < elems; i++) {
+ for (size_t i = 0; i < elems; i++) {
RegLocation rl_arg;
if (info->args[i].ref) {
rl_arg = LoadValue(info->args[i], kRefReg);
@@ -537,7 +537,7 @@
}
if (elems != 0 && info->args[0].ref) {
// If there is at least one potentially non-null value, unconditionally mark the GC card.
- for (int i = 0; i < elems; i++) {
+ for (size_t i = 0; i < elems; i++) {
if (!mir_graph_->IsConstantNullRef(info->args[i])) {
UnconditionallyMarkGCCard(ref_reg);
break;
@@ -2158,7 +2158,7 @@
}
}
-class SuspendCheckSlowPath : public Mir2Lir::LIRSlowPath {
+class Mir2Lir::SuspendCheckSlowPath : public Mir2Lir::LIRSlowPath {
public:
SuspendCheckSlowPath(Mir2Lir* m2l, LIR* branch, LIR* cont)
: LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch, cont) {
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index bb5b0cd..8e3df7c 100755
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -405,9 +405,10 @@
*/
ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
RegLocation* t_loc = nullptr;
+ EnsureInitializedArgMappingToPhysicalReg();
for (uint32_t i = 0; i < mir_graph_->GetNumOfInVRs(); i += t_loc->wide ? 2 : 1) {
// get reg corresponding to input
- RegStorage reg = GetArgMappingToPhysicalReg(i);
+ RegStorage reg = in_to_reg_storage_mapping_.GetReg(i);
t_loc = &ArgLocs[i];
// If the wide input appeared as single, flush it and go
@@ -661,7 +662,7 @@
}
ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
// Scan the rest of the args - if in phys_reg flush to memory
- for (int next_arg = start; next_arg < info->num_arg_words;) {
+ for (size_t next_arg = start; next_arg < info->num_arg_words;) {
RegLocation loc = info->args[next_arg];
if (loc.wide) {
loc = UpdateLocWide(loc);
@@ -719,10 +720,10 @@
uint32_t vtable_idx, uintptr_t direct_code, uintptr_t direct_method,
InvokeType type, bool skip_this) {
// If no arguments, just return.
- if (info->num_arg_words == 0)
+ if (info->num_arg_words == 0u)
return call_state;
- const int start_index = skip_this ? 1 : 0;
+ const size_t start_index = skip_this ? 1 : 0;
// Get architecture dependent mapping between output VRs and physical registers
// basing on shorty of method to call.
@@ -733,13 +734,13 @@
in_to_reg_storage_mapping.Initialize(&shorty_iterator, GetResetedInToRegStorageMapper());
}
- int stack_map_start = std::max(in_to_reg_storage_mapping.GetMaxMappedIn() + 1, start_index);
+ size_t stack_map_start = std::max(in_to_reg_storage_mapping.GetEndMappedIn(), start_index);
if ((stack_map_start < info->num_arg_words) && info->args[stack_map_start].high_word) {
// It is possible that the last mapped reg is 32 bit while arg is 64-bit.
// It will be handled together with low part mapped to register.
stack_map_start++;
}
- int regs_left_to_pass_via_stack = info->num_arg_words - stack_map_start;
+ size_t regs_left_to_pass_via_stack = info->num_arg_words - stack_map_start;
// If it is a range case we can try to copy remaining VRs (not mapped to physical registers)
// using more optimal algorithm.
@@ -755,11 +756,10 @@
RegStorage regRef = TargetReg(kArg3, kRef);
RegStorage regSingle = TargetReg(kArg3, kNotWide);
RegStorage regWide = TargetReg(kArg2, kWide);
- for (int i = start_index;
- i < stack_map_start + regs_left_to_pass_via_stack; i++) {
+ for (size_t i = start_index; i < stack_map_start + regs_left_to_pass_via_stack; i++) {
RegLocation rl_arg = info->args[i];
rl_arg = UpdateRawLoc(rl_arg);
- RegStorage reg = in_to_reg_storage_mapping.Get(i);
+ RegStorage reg = in_to_reg_storage_mapping.GetReg(i);
if (!reg.Valid()) {
int out_offset = StackVisitor::GetOutVROffset(i, cu_->instruction_set);
{
@@ -799,10 +799,10 @@
}
// Finish with VRs mapped to physical registers.
- for (int i = start_index; i < stack_map_start; i++) {
+ for (size_t i = start_index; i < stack_map_start; i++) {
RegLocation rl_arg = info->args[i];
rl_arg = UpdateRawLoc(rl_arg);
- RegStorage reg = in_to_reg_storage_mapping.Get(i);
+ RegStorage reg = in_to_reg_storage_mapping.GetReg(i);
if (reg.Valid()) {
if (rl_arg.wide) {
// if reg is not 64-bit (it is half of 64-bit) then handle it separately.
@@ -852,12 +852,11 @@
return call_state;
}
-RegStorage Mir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
+void Mir2Lir::EnsureInitializedArgMappingToPhysicalReg() {
if (!in_to_reg_storage_mapping_.IsInitialized()) {
ShortyIterator shorty_iterator(cu_->shorty, cu_->invoke_type == kStatic);
in_to_reg_storage_mapping_.Initialize(&shorty_iterator, GetResetedInToRegStorageMapper());
}
- return in_to_reg_storage_mapping_.Get(arg_num);
}
RegLocation Mir2Lir::InlineTarget(CallInfo* info) {
diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc
index 0719b52..d9471f6 100644
--- a/compiler/dex/quick/mips/call_mips.cc
+++ b/compiler/dex/quick/mips/call_mips.cc
@@ -315,6 +315,26 @@
OpReg(kOpBx, rs_rRA);
}
+void MipsMir2Lir::GenSpecialEntryForSuspend() {
+ // Keep 16-byte stack alignment - push A0, i.e. ArtMethod*, 2 filler words and RA.
+ core_spill_mask_ = (1u << rs_rRA.GetRegNum());
+ num_core_spills_ = 1u;
+ fp_spill_mask_ = 0u;
+ num_fp_spills_ = 0u;
+ frame_size_ = 16u;
+ core_vmap_table_.clear();
+ fp_vmap_table_.clear();
+ OpRegImm(kOpSub, rs_rMIPS_SP, frame_size_);
+ Store32Disp(rs_rMIPS_SP, frame_size_ - 4, rs_rRA);
+ Store32Disp(rs_rMIPS_SP, 0, rs_rA0);
+}
+
+void MipsMir2Lir::GenSpecialExitForSuspend() {
+ // Pop the frame. Don't pop ArtMethod*, it's no longer needed.
+ Load32Disp(rs_rMIPS_SP, frame_size_ - 4, rs_rRA);
+ OpRegImm(kOpAdd, rs_rMIPS_SP, frame_size_);
+}
+
/*
* Bit of a hack here - in the absence of a real scheduling pass,
* emit the next instruction in static & direct invoke sequences.
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index a37fe40..e1b43ca 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -141,7 +141,9 @@
void GenDivZeroCheckWide(RegStorage reg);
void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
void GenExitSequence();
- void GenSpecialExitSequence();
+ void GenSpecialExitSequence() OVERRIDE;
+ void GenSpecialEntryForSuspend() OVERRIDE;
+ void GenSpecialExitForSuspend() OVERRIDE;
void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
void GenSelect(BasicBlock* bb, MIR* mir);
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index 6f6bf68..ec6edab 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -56,7 +56,8 @@
}
bool MipsMir2Lir::InexpensiveConstantInt(int32_t value) {
- return ((value == 0) || IsUint(16, value) || ((value < 0) && (value >= -32768)));
+ // For encodings, see LoadConstantNoClobber below.
+ return ((value == 0) || IsUint<16>(value) || IsInt<16>(value));
}
bool MipsMir2Lir::InexpensiveConstantFloat(int32_t value) {
@@ -96,9 +97,11 @@
/* See if the value can be constructed cheaply */
if (value == 0) {
res = NewLIR2(kMipsMove, r_dest.GetReg(), rZERO);
- } else if ((value > 0) && (value <= 65535)) {
+ } else if (IsUint<16>(value)) {
+ // Use OR with (unsigned) immediate to encode 16b unsigned int.
res = NewLIR3(kMipsOri, r_dest.GetReg(), rZERO, value);
- } else if ((value < 0) && (value >= -32768)) {
+ } else if (IsInt<16>(value)) {
+ // Use ADD with (signed) immediate to encode 16b signed int.
res = NewLIR3(kMipsAddiu, r_dest.GetReg(), rZERO, value);
} else {
res = NewLIR2(kMipsLui, r_dest.GetReg(), value >> 16);
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 9f6d8af..34e5e25 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -24,6 +24,69 @@
namespace art {
+class Mir2Lir::SpecialSuspendCheckSlowPath : public Mir2Lir::LIRSlowPath {
+ public:
+ SpecialSuspendCheckSlowPath(Mir2Lir* m2l, LIR* branch, LIR* cont)
+ : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch, cont),
+ num_used_args_(0u) {
+ }
+
+ void PreserveArg(int in_position) {
+ // Avoid duplicates.
+ for (size_t i = 0; i != num_used_args_; ++i) {
+ if (used_args_[i] == in_position) {
+ return;
+ }
+ }
+ DCHECK_LT(num_used_args_, kMaxArgsToPreserve);
+ used_args_[num_used_args_] = in_position;
+ ++num_used_args_;
+ }
+
+ void Compile() OVERRIDE {
+ m2l_->ResetRegPool();
+ m2l_->ResetDefTracking();
+ GenerateTargetLabel(kPseudoSuspendTarget);
+
+ m2l_->LockCallTemps();
+
+ // Generate frame.
+ m2l_->GenSpecialEntryForSuspend();
+
+ // Spill all args.
+ for (size_t i = 0, end = m2l_->in_to_reg_storage_mapping_.GetEndMappedIn(); i < end;
+ i += m2l_->in_to_reg_storage_mapping_.GetShorty(i).IsWide() ? 2u : 1u) {
+ m2l_->SpillArg(i);
+ }
+
+ m2l_->FreeCallTemps();
+
+ // Do the actual suspend call to runtime.
+ m2l_->CallRuntimeHelper(kQuickTestSuspend, true);
+
+ m2l_->LockCallTemps();
+
+ // Unspill used regs. (Don't unspill unused args.)
+ for (size_t i = 0; i != num_used_args_; ++i) {
+ m2l_->UnspillArg(used_args_[i]);
+ }
+
+ // Pop the frame.
+ m2l_->GenSpecialExitForSuspend();
+
+ // Branch to the continue label.
+ DCHECK(cont_ != nullptr);
+ m2l_->OpUnconditionalBranch(cont_);
+
+ m2l_->FreeCallTemps();
+ }
+
+ private:
+ static constexpr size_t kMaxArgsToPreserve = 2u;
+ size_t num_used_args_;
+ int used_args_[kMaxArgsToPreserve];
+};
+
RegisterClass Mir2Lir::ShortyToRegClass(char shorty_type) {
RegisterClass res;
switch (shorty_type) {
@@ -54,15 +117,15 @@
return res;
}
-void Mir2Lir::LockArg(int in_position, bool) {
- RegStorage reg_arg = GetArgMappingToPhysicalReg(in_position);
+void Mir2Lir::LockArg(size_t in_position) {
+ RegStorage reg_arg = in_to_reg_storage_mapping_.GetReg(in_position);
if (reg_arg.Valid()) {
LockTemp(reg_arg);
}
}
-RegStorage Mir2Lir::LoadArg(int in_position, RegisterClass reg_class, bool wide) {
+RegStorage Mir2Lir::LoadArg(size_t in_position, RegisterClass reg_class, bool wide) {
ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
int offset = StackVisitor::GetOutVROffset(in_position, cu_->instruction_set);
@@ -82,7 +145,7 @@
offset += sizeof(uint64_t);
}
- RegStorage reg_arg = GetArgMappingToPhysicalReg(in_position);
+ RegStorage reg_arg = in_to_reg_storage_mapping_.GetReg(in_position);
// TODO: REVISIT: This adds a spill of low part while we could just copy it.
if (reg_arg.Valid() && wide && (reg_arg.GetWideKind() == kNotWide)) {
@@ -112,7 +175,7 @@
return reg_arg;
}
-void Mir2Lir::LoadArgDirect(int in_position, RegLocation rl_dest) {
+void Mir2Lir::LoadArgDirect(size_t in_position, RegLocation rl_dest) {
DCHECK_EQ(rl_dest.location, kLocPhysReg);
ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
int offset = StackVisitor::GetOutVROffset(in_position, cu_->instruction_set);
@@ -132,7 +195,7 @@
offset += sizeof(uint64_t);
}
- RegStorage reg_arg = GetArgMappingToPhysicalReg(in_position);
+ RegStorage reg_arg = in_to_reg_storage_mapping_.GetReg(in_position);
// TODO: REVISIT: This adds a spill of low part while we could just copy it.
if (reg_arg.Valid() && rl_dest.wide && (reg_arg.GetWideKind() == kNotWide)) {
@@ -153,6 +216,41 @@
}
}
+void Mir2Lir::SpillArg(size_t in_position) {
+ RegStorage reg_arg = in_to_reg_storage_mapping_.GetReg(in_position);
+
+ if (reg_arg.Valid()) {
+ int offset = frame_size_ + StackVisitor::GetOutVROffset(in_position, cu_->instruction_set);
+ ShortyArg arg = in_to_reg_storage_mapping_.GetShorty(in_position);
+ OpSize size = arg.IsRef() ? kReference :
+ (arg.IsWide() && reg_arg.GetWideKind() == kWide) ? k64 : k32;
+ StoreBaseDisp(TargetPtrReg(kSp), offset, reg_arg, size, kNotVolatile);
+ }
+}
+
+void Mir2Lir::UnspillArg(size_t in_position) {
+ RegStorage reg_arg = in_to_reg_storage_mapping_.GetReg(in_position);
+
+ if (reg_arg.Valid()) {
+ int offset = frame_size_ + StackVisitor::GetOutVROffset(in_position, cu_->instruction_set);
+ ShortyArg arg = in_to_reg_storage_mapping_.GetShorty(in_position);
+ OpSize size = arg.IsRef() ? kReference :
+ (arg.IsWide() && reg_arg.GetWideKind() == kWide) ? k64 : k32;
+ LoadBaseDisp(TargetPtrReg(kSp), offset, reg_arg, size, kNotVolatile);
+ }
+}
+
+Mir2Lir::SpecialSuspendCheckSlowPath* Mir2Lir::GenSpecialSuspendTest() {
+ LockCallTemps();
+ LIR* branch = OpTestSuspend(nullptr);
+ FreeCallTemps();
+ LIR* cont = NewLIR0(kPseudoTargetLabel);
+ SpecialSuspendCheckSlowPath* slow_path =
+ new (arena_) SpecialSuspendCheckSlowPath(this, branch, cont);
+ AddSlowPath(slow_path);
+ return slow_path;
+}
+
bool Mir2Lir::GenSpecialIGet(MIR* mir, const InlineMethod& special) {
// FastInstance() already checked by DexFileMethodInliner.
const InlineIGetIPutData& data = special.d.ifield_data;
@@ -161,13 +259,16 @@
return false;
}
- OpSize size = k32;
+ OpSize size;
switch (data.op_variant) {
- case InlineMethodAnalyser::IGetVariant(Instruction::IGET_OBJECT):
- size = kReference;
+ case InlineMethodAnalyser::IGetVariant(Instruction::IGET):
+ size = in_to_reg_storage_mapping_.GetShorty(data.src_arg).IsFP() ? kSingle : k32;
break;
case InlineMethodAnalyser::IGetVariant(Instruction::IGET_WIDE):
- size = k64;
+ size = in_to_reg_storage_mapping_.GetShorty(data.src_arg).IsFP() ? kDouble : k64;
+ break;
+ case InlineMethodAnalyser::IGetVariant(Instruction::IGET_OBJECT):
+ size = kReference;
break;
case InlineMethodAnalyser::IGetVariant(Instruction::IGET_SHORT):
size = kSignedHalf;
@@ -181,11 +282,18 @@
case InlineMethodAnalyser::IGetVariant(Instruction::IGET_BOOLEAN):
size = kUnsignedByte;
break;
+ default:
+ LOG(FATAL) << "Unknown variant: " << data.op_variant;
+ UNREACHABLE();
}
// Point of no return - no aborts after this
- GenPrintLabel(mir);
+ if (!kLeafOptimization) {
+ auto* slow_path = GenSpecialSuspendTest();
+ slow_path->PreserveArg(data.object_arg);
+ }
LockArg(data.object_arg);
+ GenPrintLabel(mir);
RegStorage reg_obj = LoadArg(data.object_arg, kRefReg);
RegisterClass reg_class = RegClassForFieldLoadStore(size, data.is_volatile);
RegisterClass ret_reg_class = ShortyToRegClass(cu_->shorty[0]);
@@ -223,13 +331,16 @@
return false;
}
- OpSize size = k32;
+ OpSize size;
switch (data.op_variant) {
- case InlineMethodAnalyser::IPutVariant(Instruction::IPUT_OBJECT):
- size = kReference;
+ case InlineMethodAnalyser::IPutVariant(Instruction::IPUT):
+ size = in_to_reg_storage_mapping_.GetShorty(data.src_arg).IsFP() ? kSingle : k32;
break;
case InlineMethodAnalyser::IPutVariant(Instruction::IPUT_WIDE):
- size = k64;
+ size = in_to_reg_storage_mapping_.GetShorty(data.src_arg).IsFP() ? kDouble : k64;
+ break;
+ case InlineMethodAnalyser::IPutVariant(Instruction::IPUT_OBJECT):
+ size = kReference;
break;
case InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT):
size = kSignedHalf;
@@ -243,12 +354,20 @@
case InlineMethodAnalyser::IPutVariant(Instruction::IPUT_BOOLEAN):
size = kUnsignedByte;
break;
+ default:
+ LOG(FATAL) << "Unknown variant: " << data.op_variant;
+ UNREACHABLE();
}
// Point of no return - no aborts after this
- GenPrintLabel(mir);
+ if (!kLeafOptimization) {
+ auto* slow_path = GenSpecialSuspendTest();
+ slow_path->PreserveArg(data.object_arg);
+ slow_path->PreserveArg(data.src_arg);
+ }
LockArg(data.object_arg);
- LockArg(data.src_arg, IsWide(size));
+ LockArg(data.src_arg);
+ GenPrintLabel(mir);
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, IsWide(size));
@@ -269,8 +388,12 @@
bool wide = (data.is_wide != 0u);
// Point of no return - no aborts after this
+ if (!kLeafOptimization) {
+ auto* slow_path = GenSpecialSuspendTest();
+ slow_path->PreserveArg(data.arg);
+ }
+ LockArg(data.arg);
GenPrintLabel(mir);
- LockArg(data.arg, wide);
RegisterClass reg_class = ShortyToRegClass(cu_->shorty[0]);
RegLocation rl_dest = wide ? GetReturnWide(reg_class) : GetReturn(reg_class);
LoadArgDirect(data.arg, rl_dest);
@@ -285,15 +408,22 @@
current_dalvik_offset_ = mir->offset;
MIR* return_mir = nullptr;
bool successful = false;
+ EnsureInitializedArgMappingToPhysicalReg();
switch (special.opcode) {
case kInlineOpNop:
successful = true;
DCHECK_EQ(mir->dalvikInsn.opcode, Instruction::RETURN_VOID);
+ if (!kLeafOptimization) {
+ GenSpecialSuspendTest();
+ }
return_mir = mir;
break;
case kInlineOpNonWideConst: {
successful = true;
+ if (!kLeafOptimization) {
+ GenSpecialSuspendTest();
+ }
RegLocation rl_dest = GetReturn(ShortyToRegClass(cu_->shorty[0]));
GenPrintLabel(mir);
LoadConstant(rl_dest.reg, static_cast<int>(special.d.data));
@@ -333,13 +463,17 @@
}
GenSpecialExitSequence();
- core_spill_mask_ = 0;
- num_core_spills_ = 0;
- fp_spill_mask_ = 0;
- num_fp_spills_ = 0;
- frame_size_ = 0;
- core_vmap_table_.clear();
- fp_vmap_table_.clear();
+ if (!kLeafOptimization) {
+ HandleSlowPaths();
+ } else {
+ core_spill_mask_ = 0;
+ num_core_spills_ = 0;
+ fp_spill_mask_ = 0;
+ num_fp_spills_ = 0;
+ frame_size_ = 0;
+ core_vmap_table_.clear();
+ fp_vmap_table_.clear();
+ }
}
return successful;
@@ -1287,31 +1421,41 @@
InToRegStorageMapper* mapper) {
DCHECK(mapper != nullptr);
DCHECK(shorty != nullptr);
- max_mapped_in_ = -1;
- has_arguments_on_stack_ = false;
+ DCHECK(!IsInitialized());
+ DCHECK_EQ(end_mapped_in_, 0u);
+ DCHECK(!has_arguments_on_stack_);
while (shorty->Next()) {
ShortyArg arg = shorty->GetArg();
RegStorage reg = mapper->GetNextReg(arg);
+ mapping_.emplace_back(arg, reg);
+ if (arg.IsWide()) {
+ mapping_.emplace_back(ShortyArg(kInvalidShorty), RegStorage::InvalidReg());
+ }
if (reg.Valid()) {
- mapping_.Put(count_, reg);
- max_mapped_in_ = count_;
- // If the VR is wide and was mapped as wide then account for it.
- if (arg.IsWide() && reg.Is64Bit()) {
- max_mapped_in_++;
+ end_mapped_in_ = mapping_.size();
+ // If the VR is wide but wasn't mapped as wide then account for it.
+ if (arg.IsWide() && !reg.Is64Bit()) {
+ --end_mapped_in_;
}
} else {
has_arguments_on_stack_ = true;
}
- count_ += arg.IsWide() ? 2 : 1;
}
initialized_ = true;
}
-RegStorage Mir2Lir::InToRegStorageMapping::Get(int in_position) {
+RegStorage Mir2Lir::InToRegStorageMapping::GetReg(size_t in_position) {
DCHECK(IsInitialized());
- DCHECK_LT(in_position, count_);
- auto res = mapping_.find(in_position);
- return res != mapping_.end() ? res->second : RegStorage::InvalidReg();
+ DCHECK_LT(in_position, mapping_.size());
+ DCHECK_NE(mapping_[in_position].first.GetType(), kInvalidShorty);
+ return mapping_[in_position].second;
+}
+
+Mir2Lir::ShortyArg Mir2Lir::InToRegStorageMapping::GetShorty(size_t in_position) {
+ DCHECK(IsInitialized());
+ DCHECK_LT(static_cast<size_t>(in_position), mapping_.size());
+ DCHECK_NE(mapping_[in_position].first.GetType(), kInvalidShorty);
+ return mapping_[in_position].first;
}
} // namespace art
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 88ca911..ff1f7de 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -17,6 +17,9 @@
#ifndef ART_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
#define ART_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
+#include "base/arena_allocator.h"
+#include "base/arena_containers.h"
+#include "base/arena_object.h"
#include "compiled_method.h"
#include "dex/compiler_enums.h"
#include "dex/dex_flags.h"
@@ -29,9 +32,6 @@
#include "leb128.h"
#include "safe_map.h"
#include "utils/array_ref.h"
-#include "utils/arena_allocator.h"
-#include "utils/arena_containers.h"
-#include "utils/arena_object.h"
#include "utils/stack_checks.h"
namespace art {
@@ -515,6 +515,9 @@
LIR* const cont_;
};
+ class SuspendCheckSlowPath;
+ class SpecialSuspendCheckSlowPath;
+
// Helper class for changing mem_ref_type_ until the end of current scope. See mem_ref_type_.
class ScopedMemRefType {
public:
@@ -1203,7 +1206,7 @@
}
}
- RegStorage GetArgMappingToPhysicalReg(int arg_num);
+ void EnsureInitializedArgMappingToPhysicalReg();
virtual RegLocation GetReturnAlt() = 0;
virtual RegLocation GetReturnWideAlt() = 0;
virtual RegLocation LocCReturn() = 0;
@@ -1570,6 +1573,16 @@
virtual void GenSpecialExitSequence() = 0;
/**
+ * @brief Used to generate stack frame for suspend path of special methods.
+ */
+ virtual void GenSpecialEntryForSuspend() = 0;
+
+ /**
+ * @brief Used to pop the stack frame for suspend path of special methods.
+ */
+ virtual void GenSpecialExitForSuspend() = 0;
+
+ /**
* @brief Used to generate code for special methods that are known to be
* small enough to work in frameless mode.
* @param bb The basic block of the first MIR.
@@ -1590,9 +1603,8 @@
* @brief Used to lock register if argument at in_position was passed that way.
* @details Does nothing if the argument is passed via stack.
* @param in_position The argument number whose register to lock.
- * @param wide Whether the argument is wide.
*/
- void LockArg(int in_position, bool wide = false);
+ void LockArg(size_t in_position);
/**
* @brief Used to load VR argument to a physical register.
@@ -1602,14 +1614,33 @@
* @param wide Whether the argument is 64-bit or not.
* @return Returns the register (or register pair) for the loaded argument.
*/
- RegStorage LoadArg(int in_position, RegisterClass reg_class, bool wide = false);
+ RegStorage LoadArg(size_t in_position, RegisterClass reg_class, bool wide = false);
/**
* @brief Used to load a VR argument directly to a specified register location.
* @param in_position The argument number to place in register.
* @param rl_dest The register location where to place argument.
*/
- void LoadArgDirect(int in_position, RegLocation rl_dest);
+ void LoadArgDirect(size_t in_position, RegLocation rl_dest);
+
+ /**
+ * @brief Used to spill register if argument at in_position was passed that way.
+ * @details Does nothing if the argument is passed via stack.
+ * @param in_position The argument number whose register to spill.
+ */
+ void SpillArg(size_t in_position);
+
+ /**
+ * @brief Used to unspill register if argument at in_position was passed that way.
+ * @details Does nothing if the argument is passed via stack.
+ * @param in_position The argument number whose register to spill.
+ */
+ void UnspillArg(size_t in_position);
+
+ /**
+ * @brief Generate suspend test in a special method.
+ */
+ SpecialSuspendCheckSlowPath* GenSpecialSuspendTest();
/**
* @brief Used to generate LIR for special getter method.
@@ -1802,21 +1833,22 @@
class InToRegStorageMapping {
public:
explicit InToRegStorageMapping(ArenaAllocator* arena)
- : mapping_(std::less<int>(), arena->Adapter()), count_(0),
- max_mapped_in_(0), has_arguments_on_stack_(false), initialized_(false) {}
+ : mapping_(arena->Adapter()),
+ end_mapped_in_(0u), has_arguments_on_stack_(false), initialized_(false) {}
void Initialize(ShortyIterator* shorty, InToRegStorageMapper* mapper);
/**
- * @return the index of last VR mapped to physical register. In other words
- * any VR starting from (return value + 1) index is mapped to memory.
+ * @return the past-the-end index of VRs mapped to physical registers.
+ * In other words any VR starting from this index is mapped to memory.
*/
- int GetMaxMappedIn() { return max_mapped_in_; }
+ size_t GetEndMappedIn() { return end_mapped_in_; }
bool HasArgumentsOnStack() { return has_arguments_on_stack_; }
- RegStorage Get(int in_position);
+ RegStorage GetReg(size_t in_position);
+ ShortyArg GetShorty(size_t in_position);
bool IsInitialized() { return initialized_; }
private:
- ArenaSafeMap<int, RegStorage> mapping_;
- int count_;
- int max_mapped_in_;
+ static constexpr char kInvalidShorty = '-';
+ ArenaVector<std::pair<ShortyArg, RegStorage>> mapping_;
+ size_t end_mapped_in_;
bool has_arguments_on_stack_;
bool initialized_;
};
diff --git a/compiler/dex/quick/resource_mask.cc b/compiler/dex/quick/resource_mask.cc
index 8a27ecb..57e8af3 100644
--- a/compiler/dex/quick/resource_mask.cc
+++ b/compiler/dex/quick/resource_mask.cc
@@ -18,8 +18,8 @@
#include "resource_mask.h"
+#include "base/arena_allocator.h"
#include "base/logging.h"
-#include "utils/arena_allocator.h"
#include "utils.h"
namespace art {
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 284e8f6..f964691 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -272,6 +272,41 @@
NewLIR0(kX86Ret);
}
+void X86Mir2Lir::GenSpecialEntryForSuspend() {
+ // Keep 16-byte stack alignment, there's already the return address, so
+ // - for 32-bit push EAX, i.e. ArtMethod*, ESI, EDI,
+ // - for 64-bit push RAX, i.e. ArtMethod*.
+ if (!cu_->target64) {
+ DCHECK(!IsTemp(rs_rSI));
+ DCHECK(!IsTemp(rs_rDI));
+ core_spill_mask_ =
+ (1u << rs_rSI.GetRegNum()) | (1u << rs_rSI.GetRegNum()) | (1u << rs_rRET.GetRegNum());
+ num_core_spills_ = 3u;
+ } else {
+ core_spill_mask_ = (1u << rs_rRET.GetRegNum());
+ num_core_spills_ = 1u;
+ }
+ fp_spill_mask_ = 0u;
+ num_fp_spills_ = 0u;
+ frame_size_ = 16u;
+ core_vmap_table_.clear();
+ fp_vmap_table_.clear();
+ if (!cu_->target64) {
+ NewLIR1(kX86Push32R, rs_rDI.GetReg());
+ NewLIR1(kX86Push32R, rs_rSI.GetReg());
+ }
+ NewLIR1(kX86Push32R, TargetReg(kArg0, kRef).GetReg()); // ArtMethod*
+}
+
+void X86Mir2Lir::GenSpecialExitForSuspend() {
+ // Pop the frame. (ArtMethod* no longer needed but restore it anyway.)
+ NewLIR1(kX86Pop32R, TargetReg(kArg0, kRef).GetReg()); // ArtMethod*
+ if (!cu_->target64) {
+ NewLIR1(kX86Pop32R, rs_rSI.GetReg());
+ NewLIR1(kX86Pop32R, rs_rDI.GetReg());
+ }
+}
+
void X86Mir2Lir::GenImplicitNullCheck(RegStorage reg, int opt_flags) {
if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
return;
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index ca60400..20163b4 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -259,6 +259,8 @@
void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) OVERRIDE;
void GenExitSequence() OVERRIDE;
void GenSpecialExitSequence() OVERRIDE;
+ void GenSpecialEntryForSuspend() OVERRIDE;
+ void GenSpecialExitForSuspend() OVERRIDE;
void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double) OVERRIDE;
void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) OVERRIDE;
void GenSelect(BasicBlock* bb, MIR* mir) OVERRIDE;
diff --git a/compiler/dex/ssa_transformation.cc b/compiler/dex/ssa_transformation.cc
index fcea77c..197f66d 100644
--- a/compiler/dex/ssa_transformation.cc
+++ b/compiler/dex/ssa_transformation.cc
@@ -16,9 +16,9 @@
#include "base/bit_vector-inl.h"
#include "base/logging.h"
+#include "base/scoped_arena_containers.h"
#include "compiler_ir.h"
#include "dataflow_iterator-inl.h"
-#include "utils/scoped_arena_containers.h"
#define NOTVISITED (-1)
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 2fca2e5..b756244 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -22,6 +22,7 @@
#include <vector>
#include "arch/instruction_set.h"
+#include "base/arena_allocator.h"
#include "base/mutex.h"
#include "base/timing_logger.h"
#include "class_reference.h"
@@ -38,7 +39,6 @@
#include "runtime.h"
#include "safe_map.h"
#include "thread_pool.h"
-#include "utils/arena_allocator.h"
#include "utils/dedupe_set.h"
#include "utils/swap_space.h"
#include "utils.h"
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index bcee563..ae9974d 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -14,9 +14,9 @@
* limitations under the License.
*/
+#include "base/arena_containers.h"
#include "bounds_check_elimination.h"
#include "nodes.h"
-#include "utils/arena_containers.h"
namespace art {
diff --git a/compiler/optimizing/bounds_check_elimination_test.cc b/compiler/optimizing/bounds_check_elimination_test.cc
index 662834a..17cb8f3 100644
--- a/compiler/optimizing/bounds_check_elimination_test.cc
+++ b/compiler/optimizing/bounds_check_elimination_test.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "base/arena_allocator.h"
#include "bounds_check_elimination.h"
#include "builder.h"
#include "gvn.h"
@@ -21,7 +22,6 @@
#include "nodes.h"
#include "optimizing_unit_test.h"
#include "side_effects_analysis.h"
-#include "utils/arena_allocator.h"
#include "gtest/gtest.h"
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index c510136..3e4a616 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -17,13 +17,13 @@
#ifndef ART_COMPILER_OPTIMIZING_BUILDER_H_
#define ART_COMPILER_OPTIMIZING_BUILDER_H_
+#include "base/arena_object.h"
#include "dex_file.h"
#include "dex_file-inl.h"
#include "driver/compiler_driver.h"
#include "driver/dex_compilation_unit.h"
#include "optimizing_compiler_stats.h"
#include "primitive.h"
-#include "utils/arena_object.h"
#include "utils/growable_array.h"
#include "nodes.h"
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index bf3ed14..5b395c8 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -636,6 +636,8 @@
} else if (current->IsIntConstant()) {
int32_t value = current->AsIntConstant()->GetValue();
stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kConstant, value);
+ } else if (current->IsNullConstant()) {
+ stack_map_stream_.AddDexRegisterEntry(DexRegisterMap::kConstant, 0);
} else {
DCHECK(current->IsFloatConstant());
int32_t value = bit_cast<float, int32_t>(current->AsFloatConstant()->GetValue());
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 6c78f10..f46a36d 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -238,6 +238,39 @@
void AllocateLocations(HInstruction* instruction);
+ // Tells whether the stack frame of the compiled method is
+ // considered "empty", that is either actually having a size of zero,
+ // or just containing the saved return address register.
+ bool HasEmptyFrame() const {
+ return GetFrameSize() == (CallPushesPC() ? GetWordSize() : 0);
+ }
+
+ static int32_t GetInt32ValueOf(HConstant* constant) {
+ if (constant->IsIntConstant()) {
+ return constant->AsIntConstant()->GetValue();
+ } else if (constant->IsNullConstant()) {
+ return 0;
+ } else {
+ DCHECK(constant->IsFloatConstant());
+ return bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue());
+ }
+ }
+
+ static int64_t GetInt64ValueOf(HConstant* constant) {
+ if (constant->IsIntConstant()) {
+ return constant->AsIntConstant()->GetValue();
+ } else if (constant->IsNullConstant()) {
+ return 0;
+ } else if (constant->IsFloatConstant()) {
+ return bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue());
+ } else if (constant->IsLongConstant()) {
+ return constant->AsLongConstant()->GetValue();
+ } else {
+ DCHECK(constant->IsDoubleConstant());
+ return bit_cast<double, int64_t>(constant->AsDoubleConstant()->GetValue());
+ }
+ }
+
protected:
CodeGenerator(HGraph* graph,
size_t number_of_core_registers,
@@ -312,10 +345,6 @@
return instruction_set == kX86 || instruction_set == kX86_64;
}
- bool HasEmptyFrame() const {
- return GetFrameSize() == (CallPushesPC() ? GetWordSize() : 0);
- }
-
// Arm64 has its own type for a label, so we need to templatize this method
// to share the logic.
template <typename T>
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 2a79f82..7b0231b 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -779,8 +779,8 @@
if (locations != nullptr && locations->Out().IsConstant()) {
HConstant* const_to_move = locations->Out().GetConstant();
- if (const_to_move->IsIntConstant()) {
- int32_t value = const_to_move->AsIntConstant()->GetValue();
+ if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
+ int32_t value = GetInt32ValueOf(const_to_move);
if (location.IsRegister()) {
__ LoadImmediate(location.AsRegister<Register>(), value);
} else {
@@ -947,8 +947,8 @@
__ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>()));
} else {
DCHECK(locations->InAt(1).IsConstant());
- int32_t value =
- locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
+ HConstant* constant = locations->InAt(1).GetConstant();
+ int32_t value = CodeGenerator::GetInt32ValueOf(constant);
ShifterOperand operand;
if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) {
__ cmp(left, operand);
@@ -1109,6 +1109,17 @@
UNUSED(constant);
}
+void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
+ locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant) {
+ // Will be generated at use site.
+ UNUSED(constant);
+}
+
void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
@@ -3399,9 +3410,9 @@
}
} else {
DCHECK(source.IsConstant()) << source;
- HInstruction* constant = source.GetConstant();
- if (constant->IsIntConstant()) {
- int32_t value = constant->AsIntConstant()->GetValue();
+ HConstant* constant = source.GetConstant();
+ if (constant->IsIntConstant() || constant->IsNullConstant()) {
+ int32_t value = CodeGenerator::GetInt32ValueOf(constant);
if (destination.IsRegister()) {
__ LoadImmediate(destination.AsRegister<Register>(), value);
} else {
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index ec716a4..8220207 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -491,18 +491,21 @@
Primitive::Type type = instruction->GetType();
DCHECK_NE(type, Primitive::kPrimVoid);
- if (instruction->IsIntConstant() || instruction->IsLongConstant()) {
- int64_t value = instruction->IsIntConstant() ? instruction->AsIntConstant()->GetValue()
- : instruction->AsLongConstant()->GetValue();
+ if (instruction->IsIntConstant()
+ || instruction->IsLongConstant()
+ || instruction->IsNullConstant()) {
+ int64_t value = GetInt64ValueOf(instruction->AsConstant());
if (location.IsRegister()) {
Register dst = RegisterFrom(location, type);
- DCHECK((instruction->IsIntConstant() && dst.Is32Bits()) ||
+ DCHECK(((instruction->IsIntConstant() || instruction->IsNullConstant()) && dst.Is32Bits()) ||
(instruction->IsLongConstant() && dst.Is64Bits()));
__ Mov(dst, value);
} else {
DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot());
UseScratchRegisterScope temps(GetVIXLAssembler());
- Register temp = instruction->IsIntConstant() ? temps.AcquireW() : temps.AcquireX();
+ Register temp = (instruction->IsIntConstant() || instruction->IsNullConstant())
+ ? temps.AcquireW()
+ : temps.AcquireX();
__ Mov(temp, value);
__ Str(temp, StackOperandFrom(location));
}
@@ -643,10 +646,12 @@
}
void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) {
- if (constant->IsIntConstant() || constant->IsLongConstant()) {
- __ Mov(Register(destination),
- constant->IsIntConstant() ? constant->AsIntConstant()->GetValue()
- : constant->AsLongConstant()->GetValue());
+ if (constant->IsIntConstant()) {
+ __ Mov(Register(destination), constant->AsIntConstant()->GetValue());
+ } else if (constant->IsLongConstant()) {
+ __ Mov(Register(destination), constant->AsLongConstant()->GetValue());
+ } else if (constant->IsNullConstant()) {
+ __ Mov(Register(destination), 0);
} else if (constant->IsFloatConstant()) {
__ Fmov(FPRegister(destination), constant->AsFloatConstant()->GetValue());
} else {
@@ -660,6 +665,8 @@
DCHECK(constant.IsConstant());
HConstant* cst = constant.GetConstant();
return (cst->IsIntConstant() && type == Primitive::kPrimInt) ||
+ // Null is mapped to a core W register, which we associate with kPrimInt.
+ (cst->IsNullConstant() && type == Primitive::kPrimInt) ||
(cst->IsLongConstant() && type == Primitive::kPrimLong) ||
(cst->IsFloatConstant() && type == Primitive::kPrimFloat) ||
(cst->IsDoubleConstant() && type == Primitive::kPrimDouble);
@@ -680,7 +687,9 @@
if (unspecified_type) {
HConstant* src_cst = source.IsConstant() ? source.GetConstant() : nullptr;
if (source.IsStackSlot() ||
- (src_cst != nullptr && (src_cst->IsIntConstant() || src_cst->IsFloatConstant()))) {
+ (src_cst != nullptr && (src_cst->IsIntConstant()
+ || src_cst->IsFloatConstant()
+ || src_cst->IsNullConstant()))) {
// For stack slots and 32bit constants, a 64bit type is appropriate.
type = destination.IsRegister() ? Primitive::kPrimInt : Primitive::kPrimFloat;
} else {
@@ -726,7 +735,7 @@
UseScratchRegisterScope temps(GetVIXLAssembler());
HConstant* src_cst = source.GetConstant();
CPURegister temp;
- if (src_cst->IsIntConstant()) {
+ if (src_cst->IsIntConstant() || src_cst->IsNullConstant()) {
temp = temps.AcquireW();
} else if (src_cst->IsLongConstant()) {
temp = temps.AcquireX();
@@ -1770,6 +1779,16 @@
UNUSED(constant);
}
+void LocationsBuilderARM64::VisitNullConstant(HNullConstant* constant) {
+ LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
+ locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorARM64::VisitNullConstant(HNullConstant* constant) {
+ // Will be generated at use site.
+ UNUSED(constant);
+}
+
void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 1a95f41..8a73eb4 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -602,13 +602,7 @@
__ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
} else if (source.IsConstant()) {
HConstant* constant = source.GetConstant();
- int32_t value;
- if (constant->IsIntConstant()) {
- value = constant->AsIntConstant()->GetValue();
- } else {
- DCHECK(constant->IsFloatConstant());
- value = bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue());
- }
+ int32_t value = GetInt32ValueOf(constant);
__ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
} else {
DCHECK(source.IsStackSlot());
@@ -674,8 +668,8 @@
if (locations != nullptr && locations->Out().IsConstant()) {
HConstant* const_to_move = locations->Out().GetConstant();
- if (const_to_move->IsIntConstant()) {
- Immediate imm(const_to_move->AsIntConstant()->GetValue());
+ if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
+ Immediate imm(GetInt32ValueOf(const_to_move));
if (location.IsRegister()) {
__ movl(location.AsRegister<Register>(), imm);
} else if (location.IsStackSlot()) {
@@ -925,7 +919,7 @@
locations->InAt(1).AsRegister<Register>());
} else if (locations->InAt(1).IsConstant()) {
HConstant* instruction = locations->InAt(1).GetConstant();
- Immediate imm(instruction->AsIntConstant()->GetValue());
+ Immediate imm(CodeGenerator::GetInt32ValueOf(instruction));
__ cmpl(locations->InAt(0).AsRegister<Register>(), imm);
} else {
__ cmpl(locations->InAt(0).AsRegister<Register>(),
@@ -994,6 +988,17 @@
UNUSED(constant);
}
+void LocationsBuilderX86::VisitNullConstant(HNullConstant* constant) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
+ locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorX86::VisitNullConstant(HNullConstant* constant) {
+ // Will be generated at use site.
+ UNUSED(constant);
+}
+
void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
@@ -3500,8 +3505,8 @@
}
} else if (source.IsConstant()) {
HConstant* constant = source.GetConstant();
- if (constant->IsIntConstant()) {
- Immediate imm(constant->AsIntConstant()->GetValue());
+ if (constant->IsIntConstant() || constant->IsNullConstant()) {
+ Immediate imm(CodeGenerator::GetInt32ValueOf(constant));
if (destination.IsRegister()) {
__ movl(destination.AsRegister<Register>(), imm);
} else {
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 88f1753..f7ec67f 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -607,13 +607,7 @@
source.AsFpuRegister<XmmRegister>());
} else if (source.IsConstant()) {
HConstant* constant = source.GetConstant();
- int32_t value;
- if (constant->IsFloatConstant()) {
- value = bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue());
- } else {
- DCHECK(constant->IsIntConstant());
- value = constant->AsIntConstant()->GetValue();
- }
+ int32_t value = GetInt32ValueOf(constant);
__ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), Immediate(value));
} else {
DCHECK(source.IsStackSlot()) << source;
@@ -657,8 +651,8 @@
if (locations != nullptr && locations->Out().IsConstant()) {
HConstant* const_to_move = locations->Out().GetConstant();
- if (const_to_move->IsIntConstant()) {
- Immediate imm(const_to_move->AsIntConstant()->GetValue());
+ if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
+ Immediate imm(GetInt32ValueOf(const_to_move));
if (location.IsRegister()) {
__ movl(location.AsRegister<CpuRegister>(), imm);
} else if (location.IsStackSlot()) {
@@ -814,7 +808,7 @@
if (rhs.IsRegister()) {
__ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
} else if (rhs.IsConstant()) {
- int32_t constant = rhs.GetConstant()->AsIntConstant()->GetValue();
+ int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
if (constant == 0) {
__ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
} else {
@@ -1034,6 +1028,17 @@
UNUSED(constant);
}
+void LocationsBuilderX86_64::VisitNullConstant(HNullConstant* constant) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
+ locations->SetOut(Location::ConstantLocation(constant));
+}
+
+void InstructionCodeGeneratorX86_64::VisitNullConstant(HNullConstant* constant) {
+ // Will be generated at use site.
+ UNUSED(constant);
+}
+
void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
@@ -3263,8 +3268,8 @@
}
} else if (source.IsConstant()) {
HConstant* constant = source.GetConstant();
- if (constant->IsIntConstant()) {
- int32_t value = constant->AsIntConstant()->GetValue();
+ if (constant->IsIntConstant() || constant->IsNullConstant()) {
+ int32_t value = CodeGenerator::GetInt32ValueOf(constant);
if (destination.IsRegister()) {
if (value == 0) {
__ xorl(destination.AsRegister<CpuRegister>(), destination.AsRegister<CpuRegister>());
diff --git a/compiler/optimizing/dominator_test.cc b/compiler/optimizing/dominator_test.cc
index b246c6f..7623e42 100644
--- a/compiler/optimizing/dominator_test.cc
+++ b/compiler/optimizing/dominator_test.cc
@@ -14,11 +14,11 @@
* limitations under the License.
*/
+#include "base/arena_allocator.h"
#include "builder.h"
#include "dex_instruction.h"
#include "nodes.h"
#include "optimizing_unit_test.h"
-#include "utils/arena_allocator.h"
#include "gtest/gtest.h"
diff --git a/compiler/optimizing/find_loops_test.cc b/compiler/optimizing/find_loops_test.cc
index e05d9b3..2bfecc6 100644
--- a/compiler/optimizing/find_loops_test.cc
+++ b/compiler/optimizing/find_loops_test.cc
@@ -14,13 +14,13 @@
* limitations under the License.
*/
+#include "base/arena_allocator.h"
#include "builder.h"
#include "dex_file.h"
#include "dex_instruction.h"
#include "nodes.h"
#include "optimizing_unit_test.h"
#include "ssa_liveness_analysis.h"
-#include "utils/arena_allocator.h"
#include "pretty_printer.h"
#include "gtest/gtest.h"
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 4ebb136..ef10428 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -285,6 +285,19 @@
}
}
+static Primitive::Type PrimitiveKind(Primitive::Type type) {
+ switch (type) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimInt:
+ return Primitive::kPrimInt;
+ default:
+ return type;
+ }
+}
+
void SSAChecker::VisitPhi(HPhi* phi) {
VisitInstruction(phi);
@@ -321,18 +334,17 @@
}
}
}
-}
-
-static Primitive::Type PrimitiveKind(Primitive::Type type) {
- switch (type) {
- case Primitive::kPrimBoolean:
- case Primitive::kPrimByte:
- case Primitive::kPrimShort:
- case Primitive::kPrimChar:
- case Primitive::kPrimInt:
- return Primitive::kPrimInt;
- default:
- return type;
+ // Ensure that the inputs have the same primitive kind as the phi.
+ for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
+ HInstruction* input = phi->InputAt(i);
+ if (PrimitiveKind(input->GetType()) != PrimitiveKind(phi->GetType())) {
+ AddError(StringPrintf(
+ "Input %d at index %zu of phi %d from block %d does not have the "
+ "same type as the phi: %s versus %s",
+ input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
+ Primitive::PrettyDescriptor(input->GetType()),
+ Primitive::PrettyDescriptor(phi->GetType())));
+ }
}
}
diff --git a/compiler/optimizing/graph_test.cc b/compiler/optimizing/graph_test.cc
index c59f836..4742e4d 100644
--- a/compiler/optimizing/graph_test.cc
+++ b/compiler/optimizing/graph_test.cc
@@ -14,12 +14,12 @@
* limitations under the License.
*/
+#include "base/arena_allocator.h"
#include "base/stringprintf.h"
#include "builder.h"
#include "nodes.h"
#include "optimizing_unit_test.h"
#include "pretty_printer.h"
-#include "utils/arena_allocator.h"
#include "gtest/gtest.h"
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 835bca6..c592737 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -184,6 +184,10 @@
output_ << " " << instruction->GetValue();
}
+ void VisitPhi(HPhi* phi) OVERRIDE {
+ output_ << " " << phi->GetRegNumber();
+ }
+
void PrintInstruction(HInstruction* instruction) {
output_ << instruction->DebugName();
instruction->Accept(this);
diff --git a/compiler/optimizing/gvn_test.cc b/compiler/optimizing/gvn_test.cc
index 4a48fee..a81d49a 100644
--- a/compiler/optimizing/gvn_test.cc
+++ b/compiler/optimizing/gvn_test.cc
@@ -14,12 +14,12 @@
* limitations under the License.
*/
+#include "base/arena_allocator.h"
#include "builder.h"
#include "gvn.h"
#include "nodes.h"
#include "optimizing_unit_test.h"
#include "side_effects_analysis.h"
-#include "utils/arena_allocator.h"
#include "gtest/gtest.h"
diff --git a/compiler/optimizing/linearize_test.cc b/compiler/optimizing/linearize_test.cc
index eb27965..f22b7a7 100644
--- a/compiler/optimizing/linearize_test.cc
+++ b/compiler/optimizing/linearize_test.cc
@@ -16,6 +16,7 @@
#include <fstream>
+#include "base/arena_allocator.h"
#include "base/stringprintf.h"
#include "builder.h"
#include "code_generator.h"
@@ -29,7 +30,6 @@
#include "pretty_printer.h"
#include "ssa_builder.h"
#include "ssa_liveness_analysis.h"
-#include "utils/arena_allocator.h"
#include "gtest/gtest.h"
diff --git a/compiler/optimizing/live_interval_test.cc b/compiler/optimizing/live_interval_test.cc
index ac8759c..28000c1 100644
--- a/compiler/optimizing/live_interval_test.cc
+++ b/compiler/optimizing/live_interval_test.cc
@@ -14,9 +14,9 @@
* limitations under the License.
*/
+#include "base/arena_allocator.h"
#include "optimizing_unit_test.h"
#include "ssa_liveness_analysis.h"
-#include "utils/arena_allocator.h"
#include "gtest/gtest.h"
diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc
index 0558b85..17914e8 100644
--- a/compiler/optimizing/live_ranges_test.cc
+++ b/compiler/optimizing/live_ranges_test.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "base/arena_allocator.h"
#include "builder.h"
#include "code_generator.h"
#include "code_generator_x86.h"
@@ -24,7 +25,6 @@
#include "optimizing_unit_test.h"
#include "prepare_for_register_allocation.h"
#include "ssa_liveness_analysis.h"
-#include "utils/arena_allocator.h"
#include "gtest/gtest.h"
diff --git a/compiler/optimizing/liveness_test.cc b/compiler/optimizing/liveness_test.cc
index c9be570..907eff1 100644
--- a/compiler/optimizing/liveness_test.cc
+++ b/compiler/optimizing/liveness_test.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "base/arena_allocator.h"
#include "builder.h"
#include "code_generator.h"
#include "code_generator_x86.h"
@@ -24,7 +25,6 @@
#include "optimizing_unit_test.h"
#include "prepare_for_register_allocation.h"
#include "ssa_liveness_analysis.h"
-#include "utils/arena_allocator.h"
#include "gtest/gtest.h"
diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h
index ebca1cc..198cc15 100644
--- a/compiler/optimizing/locations.h
+++ b/compiler/optimizing/locations.h
@@ -17,10 +17,10 @@
#ifndef ART_COMPILER_OPTIMIZING_LOCATIONS_H_
#define ART_COMPILER_OPTIMIZING_LOCATIONS_H_
+#include "base/arena_object.h"
#include "base/bit_field.h"
#include "base/bit_vector.h"
#include "base/value_object.h"
-#include "utils/arena_object.h"
#include "utils/growable_array.h"
namespace art {
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index cd36598..4a574b0 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -292,6 +292,15 @@
return true;
}
+HNullConstant* HGraph::GetNullConstant() {
+ if (cached_null_constant_ == nullptr) {
+ cached_null_constant_ = new (arena_) HNullConstant();
+ entry_block_->InsertInstructionBefore(cached_null_constant_,
+ entry_block_->GetLastInstruction());
+ }
+ return cached_null_constant_;
+}
+
void HLoopInformation::Add(HBasicBlock* block) {
blocks_.SetBit(block->GetBlockId());
}
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index fd88e42..c221404 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -17,12 +17,12 @@
#ifndef ART_COMPILER_OPTIMIZING_NODES_H_
#define ART_COMPILER_OPTIMIZING_NODES_H_
+#include "base/arena_object.h"
#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "invoke_type.h"
#include "locations.h"
#include "offsets.h"
#include "primitive.h"
-#include "utils/arena_object.h"
#include "utils/arena_bit_vector.h"
#include "utils/growable_array.h"
@@ -34,6 +34,7 @@
class HIntConstant;
class HInvoke;
class HGraphVisitor;
+class HNullConstant;
class HPhi;
class HSuspendCheck;
class LiveInterval;
@@ -194,6 +195,8 @@
return reverse_post_order_;
}
+ HNullConstant* GetNullConstant();
+
private:
HBasicBlock* FindCommonDominator(HBasicBlock* first, HBasicBlock* second) const;
void VisitBlockForDominatorTree(HBasicBlock* block,
@@ -233,6 +236,9 @@
// The current id to assign to a newly added instruction. See HInstruction.id_.
int32_t current_instruction_id_;
+ // Cached null constant that might be created when building SSA form.
+ HNullConstant* cached_null_constant_;
+
ART_FRIEND_TEST(GraphTest, IfSuccessorSimpleJoinBlock1);
DISALLOW_COPY_AND_ASSIGN(HGraph);
};
@@ -610,6 +616,7 @@
M(NewInstance, Instruction) \
M(Not, UnaryOperation) \
M(NotEqual, Condition) \
+ M(NullConstant, Instruction) \
M(NullCheck, Instruction) \
M(Or, BinaryOperation) \
M(ParallelMove, Instruction) \
@@ -914,7 +921,10 @@
// Does not apply for all instructions, but having this at top level greatly
// simplifies the null check elimination.
- virtual bool CanBeNull() const { return true; }
+ virtual bool CanBeNull() const {
+ DCHECK_EQ(GetType(), Primitive::kPrimNot) << "CanBeNull only applies to reference types";
+ return true;
+ }
virtual bool CanDoImplicitNullCheck() const { return false; }
@@ -1675,6 +1685,22 @@
DISALLOW_COPY_AND_ASSIGN(HDoubleConstant);
};
+class HNullConstant : public HConstant {
+ public:
+ HNullConstant() : HConstant(Primitive::kPrimNot) {}
+
+ bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ return true;
+ }
+
+ size_t ComputeHashCode() const OVERRIDE { return 0; }
+
+ DECLARE_INSTRUCTION(NullConstant);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HNullConstant);
+};
+
// Constants of the type int. Those can be from Dex instructions, or
// synthesized (for example with the if-eqz instruction).
class HIntConstant : public HConstant {
diff --git a/compiler/optimizing/nodes_test.cc b/compiler/optimizing/nodes_test.cc
index 5dbdc74..4cf22d3 100644
--- a/compiler/optimizing/nodes_test.cc
+++ b/compiler/optimizing/nodes_test.cc
@@ -14,8 +14,8 @@
* limitations under the License.
*/
+#include "base/arena_allocator.h"
#include "nodes.h"
-#include "utils/arena_allocator.h"
#include "gtest/gtest.h"
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index c518f33..080d6e0 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -19,6 +19,7 @@
#include <fstream>
#include <stdint.h>
+#include "base/arena_allocator.h"
#include "base/dumpable.h"
#include "base/timing_logger.h"
#include "bounds_check_elimination.h"
@@ -47,7 +48,6 @@
#include "ssa_phi_elimination.h"
#include "ssa_liveness_analysis.h"
#include "reference_type_propagation.h"
-#include "utils/arena_allocator.h"
namespace art {
@@ -376,7 +376,10 @@
compiler_driver,
codegen->GetInstructionSet(),
ArrayRef<const uint8_t>(allocator.GetMemory()),
- codegen->GetFrameSize(),
+ // Follow Quick's behavior and set the frame size to zero if it is
+ // considered "empty" (see the definition of
+ // art::CodeGenerator::HasEmptyFrame).
+ codegen->HasEmptyFrame() ? 0 : codegen->GetFrameSize(),
codegen->GetCoreSpillMask(),
codegen->GetFpuSpillMask(),
ArrayRef<const uint8_t>(stack_map));
@@ -400,17 +403,21 @@
codegen->BuildNativeGCMap(&gc_map, dex_compilation_unit);
compilation_stats_.RecordStat(MethodCompilationStat::kCompiledBaseline);
- return CompiledMethod::SwapAllocCompiledMethod(compiler_driver,
- codegen->GetInstructionSet(),
- ArrayRef<const uint8_t>(allocator.GetMemory()),
- codegen->GetFrameSize(),
- codegen->GetCoreSpillMask(),
- codegen->GetFpuSpillMask(),
- &src_mapping_table,
- AlignVectorSize(mapping_table),
- AlignVectorSize(vmap_table),
- AlignVectorSize(gc_map),
- ArrayRef<const uint8_t>());
+ return CompiledMethod::SwapAllocCompiledMethod(
+ compiler_driver,
+ codegen->GetInstructionSet(),
+ ArrayRef<const uint8_t>(allocator.GetMemory()),
+ // Follow Quick's behavior and set the frame size to zero if it is
+ // considered "empty" (see the definition of
+ // art::CodeGenerator::HasEmptyFrame).
+ codegen->HasEmptyFrame() ? 0 : codegen->GetFrameSize(),
+ codegen->GetCoreSpillMask(),
+ codegen->GetFpuSpillMask(),
+ &src_mapping_table,
+ AlignVectorSize(mapping_table),
+ AlignVectorSize(vmap_table),
+ AlignVectorSize(gc_map),
+ ArrayRef<const uint8_t>());
}
CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
diff --git a/compiler/optimizing/parallel_move_test.cc b/compiler/optimizing/parallel_move_test.cc
index bb7541d..44a3da2 100644
--- a/compiler/optimizing/parallel_move_test.cc
+++ b/compiler/optimizing/parallel_move_test.cc
@@ -14,9 +14,9 @@
* limitations under the License.
*/
+#include "base/arena_allocator.h"
#include "nodes.h"
#include "parallel_move_resolver.h"
-#include "utils/arena_allocator.h"
#include "gtest/gtest.h"
diff --git a/compiler/optimizing/pretty_printer_test.cc b/compiler/optimizing/pretty_printer_test.cc
index 9cf8235..293fde9 100644
--- a/compiler/optimizing/pretty_printer_test.cc
+++ b/compiler/optimizing/pretty_printer_test.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "base/arena_allocator.h"
#include "base/stringprintf.h"
#include "builder.h"
#include "dex_file.h"
@@ -21,7 +22,6 @@
#include "nodes.h"
#include "optimizing_unit_test.h"
#include "pretty_printer.h"
-#include "utils/arena_allocator.h"
#include "gtest/gtest.h"
diff --git a/compiler/optimizing/primitive_type_propagation.cc b/compiler/optimizing/primitive_type_propagation.cc
index 7e274f6..fe23fcf 100644
--- a/compiler/optimizing/primitive_type_propagation.cc
+++ b/compiler/optimizing/primitive_type_propagation.cc
@@ -40,6 +40,7 @@
// Re-compute and update the type of the instruction. Returns
// whether or not the type was changed.
bool PrimitiveTypePropagation::UpdateType(HPhi* phi) {
+ DCHECK(phi->IsLive());
Primitive::Type existing = phi->GetType();
Primitive::Type new_type = existing;
@@ -49,15 +50,20 @@
}
phi->SetType(new_type);
- if (new_type == Primitive::kPrimDouble || new_type == Primitive::kPrimFloat) {
+ if (new_type == Primitive::kPrimDouble
+ || new_type == Primitive::kPrimFloat
+ || new_type == Primitive::kPrimNot) {
// If the phi is of floating point type, we need to update its inputs to that
// type. For inputs that are phis, we need to recompute their types.
for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
HInstruction* input = phi->InputAt(i);
if (input->GetType() != new_type) {
- HInstruction* equivalent = SsaBuilder::GetFloatOrDoubleEquivalent(phi, input, new_type);
+ HInstruction* equivalent = (new_type == Primitive::kPrimNot)
+ ? SsaBuilder::GetReferenceTypeEquivalent(input)
+ : SsaBuilder::GetFloatOrDoubleEquivalent(phi, input, new_type);
phi->ReplaceInput(equivalent, i);
if (equivalent->IsPhi()) {
+ equivalent->AsPhi()->SetLive();
AddToWorklist(equivalent->AsPhi());
}
}
@@ -78,15 +84,9 @@
if (block->IsLoopHeader()) {
for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
HPhi* phi = it.Current()->AsPhi();
- // Set the initial type for the phi. Use the non back edge input for reaching
- // a fixed point faster.
- Primitive::Type phi_type = phi->GetType();
- // We merge with the existing type, that has been set by the SSA builder.
- DCHECK(phi_type == Primitive::kPrimVoid
- || phi_type == Primitive::kPrimFloat
- || phi_type == Primitive::kPrimDouble);
- phi->SetType(MergeTypes(phi->InputAt(0)->GetType(), phi->GetType()));
- AddToWorklist(phi);
+ if (phi->IsLive()) {
+ AddToWorklist(phi);
+ }
}
} else {
for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
@@ -95,7 +95,10 @@
// doing a reverse post-order visit, therefore either the phi users are
// non-loop phi and will be visited later in the visit, or are loop-phis,
// and they are already in the work list.
- UpdateType(it.Current()->AsPhi());
+ HPhi* phi = it.Current()->AsPhi();
+ if (phi->IsLive()) {
+ UpdateType(phi);
+ }
}
}
}
@@ -110,13 +113,14 @@
}
void PrimitiveTypePropagation::AddToWorklist(HPhi* instruction) {
+ DCHECK(instruction->IsLive());
worklist_.Add(instruction);
}
void PrimitiveTypePropagation::AddDependentInstructionsToWorklist(HPhi* instruction) {
for (HUseIterator<HInstruction*> it(instruction->GetUses()); !it.Done(); it.Advance()) {
HPhi* phi = it.Current()->GetUser()->AsPhi();
- if (phi != nullptr) {
+ if (phi != nullptr && phi->IsLive()) {
AddToWorklist(phi);
}
}
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 24e6837..4f17b6f 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -18,10 +18,6 @@
namespace art {
-// TODO: Only do the analysis on reference types. We currently have to handle
-// the `null` constant, that is represented as a `HIntConstant` and therefore
-// has the Primitive::kPrimInt type.
-
void ReferenceTypePropagation::Run() {
// Compute null status for instructions.
@@ -54,8 +50,10 @@
// Set the initial type for the phi. Use the non back edge input for reaching
// a fixed point faster.
HPhi* phi = it.Current()->AsPhi();
- AddToWorklist(phi);
- phi->SetCanBeNull(phi->InputAt(0)->CanBeNull());
+ if (phi->GetType() == Primitive::kPrimNot) {
+ AddToWorklist(phi);
+ phi->SetCanBeNull(phi->InputAt(0)->CanBeNull());
+ }
}
} else {
for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
@@ -64,7 +62,10 @@
// doing a reverse post-order visit, therefore either the phi users are
// non-loop phi and will be visited later in the visit, or are loop-phis,
// and they are already in the work list.
- UpdateNullability(it.Current()->AsPhi());
+ HPhi* phi = it.Current()->AsPhi();
+ if (phi->GetType() == Primitive::kPrimNot) {
+ UpdateNullability(phi);
+ }
}
}
}
@@ -79,6 +80,7 @@
}
void ReferenceTypePropagation::AddToWorklist(HPhi* instruction) {
+ DCHECK_EQ(instruction->GetType(), Primitive::kPrimNot);
worklist_.Add(instruction);
}
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index 0cc00c0..e5d06a9 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "base/arena_allocator.h"
#include "builder.h"
#include "code_generator.h"
#include "code_generator_x86.h"
@@ -25,7 +26,6 @@
#include "register_allocator.h"
#include "ssa_liveness_analysis.h"
#include "ssa_phi_elimination.h"
-#include "utils/arena_allocator.h"
#include "gtest/gtest.h"
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index c9a21aa..3dc7505 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -42,20 +42,33 @@
}
}
- // 3) Remove dead phis. This will remove phis that are only used by environments:
+ // 3) Mark dead phis. This will mark phis that are only used by environments:
// at the DEX level, the type of these phis does not need to be consistent, but
// our code generator will complain if the inputs of a phi do not have the same
- // type (modulo the special case of `null`).
- SsaDeadPhiElimination dead_phis(GetGraph());
- dead_phis.Run();
+ // type. The marking allows the type propagation to know which phis it needs
+ // to handle. We mark but do not eliminate: the elimination will be done in
+ // step 5).
+ {
+ SsaDeadPhiElimination dead_phis(GetGraph());
+ dead_phis.MarkDeadPhis();
+ }
// 4) Propagate types of phis. At this point, phis are typed void in the general
- // case, or float or double when we created a floating-point equivalent. So we
+ // case, or float/double/reference when we created an equivalent phi. So we
// need to propagate the types across phis to give them a correct type.
PrimitiveTypePropagation type_propagation(GetGraph());
type_propagation.Run();
- // 5) Clear locals.
+ // 5) Step 4) changes inputs of phis which may lead to dead phis again. We re-run
+ // the algorithm and this time elimimates them.
+ // TODO: Make this work with debug info and reference liveness. We currently
+ // eagerly remove phis used in environments.
+ {
+ SsaDeadPhiElimination dead_phis(GetGraph());
+ dead_phis.Run();
+ }
+
+ // 6) Clear locals.
// TODO: Move this to a dead code eliminator phase.
for (HInstructionIterator it(GetGraph()->GetEntryBlock()->GetInstructions());
!it.Done();
@@ -185,15 +198,24 @@
/**
* Because of Dex format, we might end up having the same phi being
- * used for non floating point operations and floating point operations. Because
- * we want the graph to be correctly typed (and thereafter avoid moves between
+ * used for non floating point operations and floating point / reference operations.
+ * Because we want the graph to be correctly typed (and thereafter avoid moves between
* floating point registers and core registers), we need to create a copy of the
- * phi with a floating point type.
+ * phi with a floating point / reference type.
*/
-static HPhi* GetFloatOrDoubleEquivalentOfPhi(HPhi* phi, Primitive::Type type) {
- // We place the floating point phi next to this phi.
+static HPhi* GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi* phi, Primitive::Type type) {
+ // We place the floating point /reference phi next to this phi.
HInstruction* next = phi->GetNext();
- if (next == nullptr || (next->AsPhi()->GetRegNumber() != phi->GetRegNumber())) {
+ if (next != nullptr
+ && next->AsPhi()->GetRegNumber() == phi->GetRegNumber()
+ && next->GetType() != type) {
+ // Move to the next phi to see if it is the one we are looking for.
+ next = next->GetNext();
+ }
+
+ if (next == nullptr
+ || (next->AsPhi()->GetRegNumber() != phi->GetRegNumber())
+ || (next->GetType() != type)) {
ArenaAllocator* allocator = phi->GetBlock()->GetGraph()->GetArena();
HPhi* new_phi = new (allocator) HPhi(allocator, phi->GetRegNumber(), phi->InputCount(), type);
for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
@@ -223,7 +245,7 @@
} else if (value->IsIntConstant()) {
return GetFloatEquivalent(value->AsIntConstant());
} else if (value->IsPhi()) {
- return GetFloatOrDoubleEquivalentOfPhi(value->AsPhi(), type);
+ return GetFloatDoubleOrReferenceEquivalentOfPhi(value->AsPhi(), type);
} else {
// For other instructions, we assume the verifier has checked that the dex format is correctly
// typed and the value in a dex register will not be used for both floating point and
@@ -234,12 +256,25 @@
}
}
+HInstruction* SsaBuilder::GetReferenceTypeEquivalent(HInstruction* value) {
+ if (value->IsIntConstant()) {
+ DCHECK_EQ(value->AsIntConstant()->GetValue(), 0);
+ return value->GetBlock()->GetGraph()->GetNullConstant();
+ } else {
+ DCHECK(value->IsPhi());
+ return GetFloatDoubleOrReferenceEquivalentOfPhi(value->AsPhi(), Primitive::kPrimNot);
+ }
+}
+
void SsaBuilder::VisitLoadLocal(HLoadLocal* load) {
HInstruction* value = current_locals_->GetInstructionAt(load->GetLocal()->GetRegNumber());
- if (load->GetType() != value->GetType()
- && (load->GetType() == Primitive::kPrimFloat || load->GetType() == Primitive::kPrimDouble)) {
- // If the operation requests a specific type, we make sure its input is of that type.
- value = GetFloatOrDoubleEquivalent(load, value, load->GetType());
+ // If the operation requests a specific type, we make sure its input is of that type.
+ if (load->GetType() != value->GetType()) {
+ if (load->GetType() == Primitive::kPrimFloat || load->GetType() == Primitive::kPrimDouble) {
+ value = GetFloatOrDoubleEquivalent(load, value, load->GetType());
+ } else if (load->GetType() == Primitive::kPrimNot) {
+ value = GetReferenceTypeEquivalent(value);
+ }
}
load->ReplaceWith(value);
load->GetBlock()->RemoveInstruction(load);
diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h
index 2eec87b..148e959 100644
--- a/compiler/optimizing/ssa_builder.h
+++ b/compiler/optimizing/ssa_builder.h
@@ -58,6 +58,8 @@
HInstruction* instruction,
Primitive::Type type);
+ static HInstruction* GetReferenceTypeEquivalent(HInstruction* instruction);
+
private:
// Locals for the current block being visited.
HEnvironment* current_locals_;
diff --git a/compiler/optimizing/ssa_phi_elimination.cc b/compiler/optimizing/ssa_phi_elimination.cc
index fd30c1b..f66a1c8 100644
--- a/compiler/optimizing/ssa_phi_elimination.cc
+++ b/compiler/optimizing/ssa_phi_elimination.cc
@@ -19,6 +19,11 @@
namespace art {
void SsaDeadPhiElimination::Run() {
+ MarkDeadPhis();
+ EliminateDeadPhis();
+}
+
+void SsaDeadPhiElimination::MarkDeadPhis() {
// Add to the worklist phis referenced by non-phi instructions.
for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
HBasicBlock* block = it.Current();
@@ -49,7 +54,9 @@
}
}
}
+}
+void SsaDeadPhiElimination::EliminateDeadPhis() {
// Remove phis that are not live. Visit in post order so that phis
// that are not inputs of loop phis can be removed when they have
// no users left (dead phis might use dead phis).
diff --git a/compiler/optimizing/ssa_phi_elimination.h b/compiler/optimizing/ssa_phi_elimination.h
index b789971..88a5279 100644
--- a/compiler/optimizing/ssa_phi_elimination.h
+++ b/compiler/optimizing/ssa_phi_elimination.h
@@ -34,6 +34,9 @@
void Run() OVERRIDE;
+ void MarkDeadPhis();
+ void EliminateDeadPhis();
+
private:
GrowableArray<HPhi*> worklist_;
diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc
index 7e90b37..7fc1ec6 100644
--- a/compiler/optimizing/ssa_test.cc
+++ b/compiler/optimizing/ssa_test.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "base/arena_allocator.h"
#include "base/stringprintf.h"
#include "builder.h"
#include "dex_file.h"
@@ -22,7 +23,6 @@
#include "optimizing_unit_test.h"
#include "pretty_printer.h"
#include "ssa_builder.h"
-#include "utils/arena_allocator.h"
#include "gtest/gtest.h"
diff --git a/compiler/utils/arena_allocator_test.cc b/compiler/utils/arena_allocator_test.cc
index 7156540..7065527 100644
--- a/compiler/utils/arena_allocator_test.cc
+++ b/compiler/utils/arena_allocator_test.cc
@@ -14,8 +14,8 @@
* limitations under the License.
*/
+#include "base/arena_allocator.h"
#include "gtest/gtest.h"
-#include "utils/arena_allocator.h"
#include "utils/arena_bit_vector.h"
namespace art {
diff --git a/compiler/utils/arena_bit_vector.cc b/compiler/utils/arena_bit_vector.cc
index f17e5a9..ddc0c81 100644
--- a/compiler/utils/arena_bit_vector.cc
+++ b/compiler/utils/arena_bit_vector.cc
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-#include "arena_allocator.h"
#include "arena_bit_vector.h"
+#include "base/arena_allocator.h"
+
namespace art {
template <typename ArenaAlloc>
diff --git a/compiler/utils/arena_bit_vector.h b/compiler/utils/arena_bit_vector.h
index e5e1b70..f2a7452 100644
--- a/compiler/utils/arena_bit_vector.h
+++ b/compiler/utils/arena_bit_vector.h
@@ -17,7 +17,7 @@
#ifndef ART_COMPILER_UTILS_ARENA_BIT_VECTOR_H_
#define ART_COMPILER_UTILS_ARENA_BIT_VECTOR_H_
-#include "arena_object.h"
+#include "base/arena_object.h"
#include "base/bit_vector.h"
namespace art {
diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc
index 1f44f19..a52e6eb 100644
--- a/compiler/utils/arm/assembler_arm.cc
+++ b/compiler/utils/arm/assembler_arm.cc
@@ -166,7 +166,7 @@
}
uint32_t Address::encodingArm() const {
- CHECK(IsAbsoluteUint(12, offset_));
+ CHECK(IsAbsoluteUint<12>(offset_));
uint32_t encoding;
if (is_immed_offset_) {
if (offset_ < 0) {
@@ -278,11 +278,12 @@
// Encoding for vfp load/store addressing.
uint32_t Address::vencoding() const {
+ CHECK(IsAbsoluteUint<10>(offset_)); // In the range -1020 to +1020.
+ CHECK_ALIGNED(offset_, 2); // Multiple of 4.
+
const uint32_t offset_mask = (1 << 12) - 1;
uint32_t encoding = encodingArm();
uint32_t offset = encoding & offset_mask;
- CHECK(IsAbsoluteUint(10, offset)); // In the range -1020 to +1020.
- CHECK_ALIGNED(offset, 2); // Multiple of 4.
CHECK((am_ == Offset) || (am_ == NegOffset));
uint32_t vencoding_value = (encoding & (0xf << kRnShift)) | (offset >> 2);
if (am_ == Offset) {
@@ -298,13 +299,13 @@
case kLoadSignedHalfword:
case kLoadUnsignedHalfword:
case kLoadWordPair:
- return IsAbsoluteUint(8, offset); // Addressing mode 3.
+ return IsAbsoluteUint<8>(offset); // Addressing mode 3.
case kLoadUnsignedByte:
case kLoadWord:
- return IsAbsoluteUint(12, offset); // Addressing mode 2.
+ return IsAbsoluteUint<12>(offset); // Addressing mode 2.
case kLoadSWord:
case kLoadDWord:
- return IsAbsoluteUint(10, offset); // VFP addressing mode.
+ return IsAbsoluteUint<10>(offset); // VFP addressing mode.
default:
LOG(FATAL) << "UNREACHABLE";
UNREACHABLE();
@@ -316,13 +317,13 @@
switch (type) {
case kStoreHalfword:
case kStoreWordPair:
- return IsAbsoluteUint(8, offset); // Addressing mode 3.
+ return IsAbsoluteUint<8>(offset); // Addressing mode 3.
case kStoreByte:
case kStoreWord:
- return IsAbsoluteUint(12, offset); // Addressing mode 2.
+ return IsAbsoluteUint<12>(offset); // Addressing mode 2.
case kStoreSWord:
case kStoreDWord:
- return IsAbsoluteUint(10, offset); // VFP addressing mode.
+ return IsAbsoluteUint<10>(offset); // VFP addressing mode.
default:
LOG(FATAL) << "UNREACHABLE";
UNREACHABLE();
@@ -336,12 +337,12 @@
case kLoadUnsignedHalfword:
case kLoadUnsignedByte:
case kLoadWord:
- return IsAbsoluteUint(12, offset);
+ return IsAbsoluteUint<12>(offset);
case kLoadSWord:
case kLoadDWord:
- return IsAbsoluteUint(10, offset); // VFP addressing mode.
+ return IsAbsoluteUint<10>(offset); // VFP addressing mode.
case kLoadWordPair:
- return IsAbsoluteUint(10, offset);
+ return IsAbsoluteUint<10>(offset);
default:
LOG(FATAL) << "UNREACHABLE";
UNREACHABLE();
@@ -354,12 +355,12 @@
case kStoreHalfword:
case kStoreByte:
case kStoreWord:
- return IsAbsoluteUint(12, offset);
+ return IsAbsoluteUint<12>(offset);
case kStoreSWord:
case kStoreDWord:
- return IsAbsoluteUint(10, offset); // VFP addressing mode.
+ return IsAbsoluteUint<10>(offset); // VFP addressing mode.
case kStoreWordPair:
- return IsAbsoluteUint(10, offset);
+ return IsAbsoluteUint<10>(offset);
default:
LOG(FATAL) << "UNREACHABLE";
UNREACHABLE();
diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc
index 8d1fb60..9579691 100644
--- a/compiler/utils/arm/assembler_arm32.cc
+++ b/compiler/utils/arm/assembler_arm32.cc
@@ -1254,7 +1254,7 @@
void Arm32Assembler::svc(uint32_t imm24) {
- CHECK(IsUint(24, imm24)) << imm24;
+ CHECK(IsUint<24>(imm24)) << imm24;
int32_t encoding = (AL << kConditionShift) | B27 | B26 | B25 | B24 | imm24;
Emit(encoding);
}
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index 5383c28..6d0571e 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -2080,7 +2080,7 @@
void Thumb2Assembler::svc(uint32_t imm8) {
- CHECK(IsUint(8, imm8)) << imm8;
+ CHECK(IsUint<8>(imm8)) << imm8;
int16_t encoding = B15 | B14 | B12 |
B11 | B10 | B9 | B8 |
imm8;
@@ -2089,7 +2089,7 @@
void Thumb2Assembler::bkpt(uint16_t imm8) {
- CHECK(IsUint(8, imm8)) << imm8;
+ CHECK(IsUint<8>(imm8)) << imm8;
int16_t encoding = B15 | B13 | B12 |
B11 | B10 | B9 |
imm8;
diff --git a/compiler/utils/growable_array.h b/compiler/utils/growable_array.h
index fd43ea6..821e28b 100644
--- a/compiler/utils/growable_array.h
+++ b/compiler/utils/growable_array.h
@@ -20,7 +20,7 @@
#include <stdint.h>
#include <stddef.h>
-#include "arena_object.h"
+#include "base/arena_object.h"
namespace art {
diff --git a/compiler/utils/swap_space.h b/compiler/utils/swap_space.h
index 2d0d77a..1f8f5da 100644
--- a/compiler/utils/swap_space.h
+++ b/compiler/utils/swap_space.h
@@ -23,12 +23,12 @@
#include <stdint.h>
#include <stddef.h>
+#include "base/debug_stack.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/mutex.h"
#include "mem_map.h"
#include "utils.h"
-#include "utils/debug_stack.h"
namespace art {
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index 03744e4..8f4208b 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -1290,7 +1290,7 @@
static const int kLongSize = 6;
int offset = label->Position() - buffer_.Size();
CHECK_LE(offset, 0);
- if (IsInt(8, offset - kShortSize)) {
+ if (IsInt<8>(offset - kShortSize)) {
EmitUint8(0x70 + condition);
EmitUint8((offset - kShortSize) & 0xFF);
} else {
@@ -1325,7 +1325,7 @@
static const int kLongSize = 5;
int offset = label->Position() - buffer_.Size();
CHECK_LE(offset, 0);
- if (IsInt(8, offset - kShortSize)) {
+ if (IsInt<8>(offset - kShortSize)) {
EmitUint8(0xEB);
EmitUint8((offset - kShortSize) & 0xFF);
} else {
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index 3a44ace..2dde907 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -35,10 +35,10 @@
int32_t value() const { return value_; }
- bool is_int8() const { return IsInt(8, value_); }
- bool is_uint8() const { return IsUint(8, value_); }
- bool is_int16() const { return IsInt(16, value_); }
- bool is_uint16() const { return IsUint(16, value_); }
+ bool is_int8() const { return IsInt<8>(value_); }
+ bool is_uint8() const { return IsUint<8>(value_); }
+ bool is_int16() const { return IsInt<16>(value_); }
+ bool is_uint16() const { return IsUint<16>(value_); }
private:
const int32_t value_;
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 556fa9b..f2704b7 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -1515,7 +1515,7 @@
// See whether imm can be represented as a sign-extended 8bit value.
int32_t v32 = static_cast<int32_t>(imm.value());
- if (IsInt32(8, v32)) {
+ if (IsInt<8>(v32)) {
// Sign-extension works.
EmitUint8(0x6B);
EmitOperand(reg.LowBits(), Operand(reg));
@@ -1555,7 +1555,7 @@
// See whether imm can be represented as a sign-extended 8bit value.
int64_t v64 = imm.value();
- if (IsInt64(8, v64)) {
+ if (IsInt<8>(v64)) {
// Sign-extension works.
EmitUint8(0x6B);
EmitOperand(reg.LowBits(), Operand(reg));
@@ -1705,7 +1705,7 @@
void X86_64Assembler::enter(const Immediate& imm) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xC8);
- CHECK(imm.is_uint16());
+ CHECK(imm.is_uint16()) << imm.value();
EmitUint8(imm.value() & 0xFF);
EmitUint8((imm.value() >> 8) & 0xFF);
EmitUint8(0x00);
@@ -1759,7 +1759,7 @@
static const int kLongSize = 6;
int offset = label->Position() - buffer_.Size();
CHECK_LE(offset, 0);
- if (IsInt(8, offset - kShortSize)) {
+ if (IsInt<8>(offset - kShortSize)) {
EmitUint8(0x70 + condition);
EmitUint8((offset - kShortSize) & 0xFF);
} else {
@@ -1796,7 +1796,7 @@
static const int kLongSize = 5;
int offset = label->Position() - buffer_.Size();
CHECK_LE(offset, 0);
- if (IsInt(8, offset - kShortSize)) {
+ if (IsInt<8>(offset - kShortSize)) {
EmitUint8(0xEB);
EmitUint8((offset - kShortSize) & 0xFF);
} else {
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index a1c704e..5dfcf45 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -42,15 +42,11 @@
int64_t value() const { return value_; }
- bool is_int8() const { return IsInt(8, value_); }
- bool is_uint8() const { return IsUint(8, value_); }
- bool is_int16() const { return IsInt(16, value_); }
- bool is_uint16() const { return IsUint(16, value_); }
- bool is_int32() const {
- // This does not work on 32b machines: return IsInt(32, value_);
- int64_t limit = static_cast<int64_t>(1) << 31;
- return (-limit <= value_) && (value_ < limit);
- }
+ bool is_int8() const { return IsInt<8>(value_); }
+ bool is_uint8() const { return IsUint<8>(value_); }
+ bool is_int16() const { return IsInt<16>(value_); }
+ bool is_uint16() const { return IsUint<16>(value_); }
+ bool is_int32() const { return IsInt<32>(value_); }
private:
const int64_t value_;
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index 6df4144..00f508b 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -44,10 +44,10 @@
TEST(AssemblerX86_64, SignExtension) {
// 32bit.
for (int32_t i = 0; i < 128; i++) {
- EXPECT_TRUE(IsInt32(8, i)) << i;
+ EXPECT_TRUE(IsInt<8>(i)) << i;
}
for (int32_t i = 128; i < 255; i++) {
- EXPECT_FALSE(IsInt32(8, i)) << i;
+ EXPECT_FALSE(IsInt<8>(i)) << i;
}
// Do some higher ones randomly.
std::random_device rd;
@@ -55,54 +55,65 @@
std::uniform_int_distribution<int32_t> uniform_dist(256, INT32_MAX);
for (size_t i = 0; i < kRandomIterations; i++) {
int32_t value = uniform_dist(e1);
- EXPECT_FALSE(IsInt32(8, value)) << value;
+ EXPECT_FALSE(IsInt<8>(value)) << value;
}
// Negative ones.
for (int32_t i = -1; i >= -128; i--) {
- EXPECT_TRUE(IsInt32(8, i)) << i;
+ EXPECT_TRUE(IsInt<8>(i)) << i;
}
for (int32_t i = -129; i > -256; i--) {
- EXPECT_FALSE(IsInt32(8, i)) << i;
+ EXPECT_FALSE(IsInt<8>(i)) << i;
}
// Do some lower ones randomly.
std::uniform_int_distribution<int32_t> uniform_dist2(INT32_MIN, -256);
for (size_t i = 0; i < 100; i++) {
int32_t value = uniform_dist2(e1);
- EXPECT_FALSE(IsInt32(8, value)) << value;
+ EXPECT_FALSE(IsInt<8>(value)) << value;
}
// 64bit.
for (int64_t i = 0; i < 128; i++) {
- EXPECT_TRUE(IsInt64(8, i)) << i;
+ EXPECT_TRUE(IsInt<8>(i)) << i;
}
for (int32_t i = 128; i < 255; i++) {
- EXPECT_FALSE(IsInt64(8, i)) << i;
+ EXPECT_FALSE(IsInt<8>(i)) << i;
}
// Do some higher ones randomly.
std::uniform_int_distribution<int64_t> uniform_dist3(256, INT64_MAX);
for (size_t i = 0; i < 100; i++) {
int64_t value = uniform_dist3(e1);
- EXPECT_FALSE(IsInt64(8, value)) << value;
+ EXPECT_FALSE(IsInt<8>(value)) << value;
}
// Negative ones.
for (int64_t i = -1; i >= -128; i--) {
- EXPECT_TRUE(IsInt64(8, i)) << i;
+ EXPECT_TRUE(IsInt<8>(i)) << i;
}
for (int64_t i = -129; i > -256; i--) {
- EXPECT_FALSE(IsInt64(8, i)) << i;
+ EXPECT_FALSE(IsInt<8>(i)) << i;
}
// Do some lower ones randomly.
std::uniform_int_distribution<int64_t> uniform_dist4(INT64_MIN, -256);
for (size_t i = 0; i < kRandomIterations; i++) {
int64_t value = uniform_dist4(e1);
- EXPECT_FALSE(IsInt64(8, value)) << value;
+ EXPECT_FALSE(IsInt<8>(value)) << value;
}
+
+ int64_t value = INT64_C(0x1200000010);
+ x86_64::Immediate imm(value);
+ EXPECT_FALSE(imm.is_int8());
+ EXPECT_FALSE(imm.is_int16());
+ EXPECT_FALSE(imm.is_int32());
+ value = INT64_C(0x8000000000000001);
+ x86_64::Immediate imm2(value);
+ EXPECT_FALSE(imm2.is_int8());
+ EXPECT_FALSE(imm2.is_int16());
+ EXPECT_FALSE(imm2.is_int32());
}
struct X86_64CpuRegisterCompare {
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 4714610..c647cc2 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -22,10 +22,12 @@
atomic.cc.arm \
barrier.cc \
base/allocator.cc \
+ base/arena_allocator.cc \
base/bit_vector.cc \
base/hex_dump.cc \
base/logging.cc \
base/mutex.cc \
+ base/scoped_arena_allocator.cc \
base/scoped_flock.cc \
base/stringpiece.cc \
base/stringprintf.cc \
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index beacd49..c2acdd1 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1462,7 +1462,7 @@
// Restore GPRs.
movl 40(%esp), %ecx // Restore ecx.
- movl 48(%esp), %edx // Restore edx.
+ movl 44(%esp), %edx // Restore edx.
movl 48(%esp), %ebx // Restore ebx.
movl 52(%esp), %ebp // Restore ebp.
movl 56(%esp), %esi // Restore esi.
diff --git a/compiler/utils/arena_allocator.cc b/runtime/base/arena_allocator.cc
similarity index 98%
rename from compiler/utils/arena_allocator.cc
rename to runtime/base/arena_allocator.cc
index a80ad93..b3f812e 100644
--- a/compiler/utils/arena_allocator.cc
+++ b/runtime/base/arena_allocator.cc
@@ -19,8 +19,8 @@
#include <numeric>
#include "arena_allocator.h"
-#include "base/logging.h"
-#include "base/mutex.h"
+#include "logging.h"
+#include "mutex.h"
#include "thread-inl.h"
#include <memcheck/memcheck.h>
diff --git a/compiler/utils/arena_allocator.h b/runtime/base/arena_allocator.h
similarity index 95%
rename from compiler/utils/arena_allocator.h
rename to runtime/base/arena_allocator.h
index e730fd7..9237391 100644
--- a/compiler/utils/arena_allocator.h
+++ b/runtime/base/arena_allocator.h
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_UTILS_ARENA_ALLOCATOR_H_
-#define ART_COMPILER_UTILS_ARENA_ALLOCATOR_H_
+#ifndef ART_RUNTIME_BASE_ARENA_ALLOCATOR_H_
+#define ART_RUNTIME_BASE_ARENA_ALLOCATOR_H_
#include <stdint.h>
#include <stddef.h>
-#include "base/macros.h"
-#include "base/mutex.h"
+#include "debug_stack.h"
+#include "macros.h"
#include "mem_map.h"
+#include "mutex.h"
#include "utils.h"
-#include "utils/debug_stack.h"
namespace art {
@@ -180,7 +180,7 @@
if (UNLIKELY(running_on_valgrind_)) {
return AllocValgrind(bytes, kind);
}
- bytes = RoundUp(bytes, 8);
+ bytes = RoundUp(bytes, kAlignment);
if (UNLIKELY(ptr_ + bytes > end_)) {
// Obtain a new block.
ObtainNewArenaForAllocation(bytes);
@@ -205,6 +205,8 @@
MemStats GetMemStats() const;
private:
+ static constexpr size_t kAlignment = 8;
+
void UpdateBytesAllocated();
ArenaPool* pool_;
@@ -235,4 +237,4 @@
} // namespace art
-#endif // ART_COMPILER_UTILS_ARENA_ALLOCATOR_H_
+#endif // ART_RUNTIME_BASE_ARENA_ALLOCATOR_H_
diff --git a/compiler/utils/arena_containers.h b/runtime/base/arena_containers.h
similarity index 96%
rename from compiler/utils/arena_containers.h
rename to runtime/base/arena_containers.h
index a7a7438..162eb16 100644
--- a/compiler/utils/arena_containers.h
+++ b/runtime/base/arena_containers.h
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_UTILS_ARENA_CONTAINERS_H_
-#define ART_COMPILER_UTILS_ARENA_CONTAINERS_H_
+#ifndef ART_RUNTIME_BASE_ARENA_CONTAINERS_H_
+#define ART_RUNTIME_BASE_ARENA_CONTAINERS_H_
#include <deque>
#include <queue>
#include <set>
#include <vector>
-#include "utils/arena_allocator.h"
+#include "arena_allocator.h"
#include "safe_map.h"
namespace art {
@@ -203,4 +203,4 @@
} // namespace art
-#endif // ART_COMPILER_UTILS_ARENA_CONTAINERS_H_
+#endif // ART_RUNTIME_BASE_ARENA_CONTAINERS_H_
diff --git a/compiler/utils/arena_object.h b/runtime/base/arena_object.h
similarity index 91%
rename from compiler/utils/arena_object.h
rename to runtime/base/arena_object.h
index d64c419..ab97d0c 100644
--- a/compiler/utils/arena_object.h
+++ b/runtime/base/arena_object.h
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_UTILS_ARENA_OBJECT_H_
-#define ART_COMPILER_UTILS_ARENA_OBJECT_H_
+#ifndef ART_RUNTIME_BASE_ARENA_OBJECT_H_
+#define ART_RUNTIME_BASE_ARENA_OBJECT_H_
-#include "arena_allocator.h"
+#include "base/arena_allocator.h"
#include "base/logging.h"
#include "scoped_arena_allocator.h"
@@ -64,4 +64,4 @@
} // namespace art
-#endif // ART_COMPILER_UTILS_ARENA_OBJECT_H_
+#endif // ART_RUNTIME_BASE_ARENA_OBJECT_H_
diff --git a/compiler/utils/debug_stack.h b/runtime/base/debug_stack.h
similarity index 96%
rename from compiler/utils/debug_stack.h
rename to runtime/base/debug_stack.h
index 1bb0624..03f4575 100644
--- a/compiler/utils/debug_stack.h
+++ b/runtime/base/debug_stack.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_UTILS_DEBUG_STACK_H_
-#define ART_COMPILER_UTILS_DEBUG_STACK_H_
+#ifndef ART_RUNTIME_BASE_DEBUG_STACK_H_
+#define ART_RUNTIME_BASE_DEBUG_STACK_H_
#include "base/logging.h"
#include "base/macros.h"
@@ -135,4 +135,4 @@
} // namespace art
-#endif // ART_COMPILER_UTILS_DEBUG_STACK_H_
+#endif // ART_RUNTIME_BASE_DEBUG_STACK_H_
diff --git a/compiler/utils/scoped_arena_allocator.cc b/runtime/base/scoped_arena_allocator.cc
similarity index 98%
rename from compiler/utils/scoped_arena_allocator.cc
rename to runtime/base/scoped_arena_allocator.cc
index d9e0619..4a7be38 100644
--- a/compiler/utils/scoped_arena_allocator.cc
+++ b/runtime/base/scoped_arena_allocator.cc
@@ -16,7 +16,7 @@
#include "scoped_arena_allocator.h"
-#include "utils/arena_allocator.h"
+#include "arena_allocator.h"
#include <memcheck/memcheck.h>
namespace art {
diff --git a/compiler/utils/scoped_arena_allocator.h b/runtime/base/scoped_arena_allocator.h
similarity index 93%
rename from compiler/utils/scoped_arena_allocator.h
rename to runtime/base/scoped_arena_allocator.h
index c46acbc..bbedeac 100644
--- a/compiler/utils/scoped_arena_allocator.h
+++ b/runtime/base/scoped_arena_allocator.h
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_UTILS_SCOPED_ARENA_ALLOCATOR_H_
-#define ART_COMPILER_UTILS_SCOPED_ARENA_ALLOCATOR_H_
+#ifndef ART_RUNTIME_BASE_SCOPED_ARENA_ALLOCATOR_H_
+#define ART_RUNTIME_BASE_SCOPED_ARENA_ALLOCATOR_H_
-#include "base/logging.h"
-#include "base/macros.h"
-#include "utils/arena_allocator.h"
-#include "utils/debug_stack.h"
+#include "arena_allocator.h"
+#include "debug_stack.h"
#include "globals.h"
+#include "logging.h"
+#include "macros.h"
namespace art {
@@ -147,4 +147,4 @@
} // namespace art
-#endif // ART_COMPILER_UTILS_SCOPED_ARENA_ALLOCATOR_H_
+#endif // ART_RUNTIME_BASE_SCOPED_ARENA_ALLOCATOR_H_
diff --git a/compiler/utils/scoped_arena_containers.h b/runtime/base/scoped_arena_containers.h
similarity index 95%
rename from compiler/utils/scoped_arena_containers.h
rename to runtime/base/scoped_arena_containers.h
index df93b27..664a909 100644
--- a/compiler/utils/scoped_arena_containers.h
+++ b/runtime/base/scoped_arena_containers.h
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-#ifndef ART_COMPILER_UTILS_SCOPED_ARENA_CONTAINERS_H_
-#define ART_COMPILER_UTILS_SCOPED_ARENA_CONTAINERS_H_
+#ifndef ART_RUNTIME_BASE_SCOPED_ARENA_CONTAINERS_H_
+#define ART_RUNTIME_BASE_SCOPED_ARENA_CONTAINERS_H_
#include <deque>
#include <queue>
#include <set>
#include <vector>
-#include "utils/arena_containers.h" // For ArenaAllocatorAdapterKind.
-#include "utils/scoped_arena_allocator.h"
+#include "arena_containers.h" // For ArenaAllocatorAdapterKind.
+#include "scoped_arena_allocator.h"
#include "safe_map.h"
namespace art {
@@ -190,4 +190,4 @@
} // namespace art
-#endif // ART_COMPILER_UTILS_SCOPED_ARENA_CONTAINERS_H_
+#endif // ART_RUNTIME_BASE_SCOPED_ARENA_CONTAINERS_H_
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index d8166e2..ee66b49 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4812,7 +4812,7 @@
if (klass->IsInterface()) {
// No vtable.
size_t count = klass->NumVirtualMethods();
- if (!IsUint(16, count)) {
+ if (!IsUint<16>(count)) {
ThrowClassFormatError(klass.Get(), "Too many methods on interface: %zd", count);
return false;
}
@@ -5033,7 +5033,7 @@
local_method->SetMethodIndex(actual_count);
++actual_count;
}
- if (!IsUint(16, actual_count)) {
+ if (!IsUint<16>(actual_count)) {
ThrowClassFormatError(klass.Get(), "Too many methods defined on class: %zd", actual_count);
return false;
}
@@ -5049,7 +5049,7 @@
klass->SetVTable(vtable.Get());
} else {
CHECK_EQ(klass.Get(), GetClassRoot(kJavaLangObject));
- if (!IsUint(16, num_virtual_methods)) {
+ if (!IsUint<16>(num_virtual_methods)) {
ThrowClassFormatError(klass.Get(), "Too many methods: %d",
static_cast<int>(num_virtual_methods));
return false;
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 94d62db..19a4bd0 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -1164,15 +1164,15 @@
break;
case kByte:
jval_.i = ReadSignedInt(ptr_, value_arg);
- CHECK(IsInt(8, jval_.i));
+ CHECK(IsInt<8>(jval_.i));
break;
case kShort:
jval_.i = ReadSignedInt(ptr_, value_arg);
- CHECK(IsInt(16, jval_.i));
+ CHECK(IsInt<16>(jval_.i));
break;
case kChar:
jval_.i = ReadUnsignedInt(ptr_, value_arg, false);
- CHECK(IsUint(16, jval_.i));
+ CHECK(IsUint<16>(jval_.i));
break;
case kInt:
jval_.i = ReadSignedInt(ptr_, value_arg);
diff --git a/runtime/utils.h b/runtime/utils.h
index 1c2576c..0fbc9df 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -22,6 +22,7 @@
#include <limits>
#include <memory>
#include <string>
+#include <type_traits>
#include <vector>
#include "arch/instruction_set.h"
@@ -115,32 +116,45 @@
return (-limit <= value) && (value < limit);
}
-static inline bool IsInt32(int N, int32_t value) {
- CHECK_LT(0, N);
- CHECK_LT(static_cast<size_t>(N), 8 * sizeof(int32_t));
- int32_t limit = static_cast<int32_t>(1) << (N - 1);
- return (-limit <= value) && (value < limit);
+template <typename T>
+static constexpr T GetIntLimit(size_t bits) {
+ return
+ DCHECK_CONSTEXPR(bits > 0, "bits cannot be zero", 0)
+ DCHECK_CONSTEXPR(bits < kBitsPerByte * sizeof(T), "kBits must be < max.", 0)
+ static_cast<T>(1) << (bits - 1);
}
-static inline bool IsInt64(int N, int64_t value) {
- CHECK_LT(0, N);
- CHECK_LT(static_cast<size_t>(N), 8 * sizeof(int64_t));
- int64_t limit = static_cast<int64_t>(1) << (N - 1);
- return (-limit <= value) && (value < limit);
+template <size_t kBits, typename T>
+static constexpr bool IsInt(T value) {
+ static_assert(kBits > 0, "kBits cannot be zero.");
+ static_assert(kBits <= kBitsPerByte * sizeof(T), "kBits must be <= max.");
+ static_assert(std::is_signed<T>::value, "Needs a signed type.");
+ // Corner case for "use all bits." Can't use the limits, as they would overflow, but it is
+ // trivially true.
+ return (kBits == kBitsPerByte * sizeof(T)) ?
+ true :
+ (-GetIntLimit<T>(kBits) <= value) && (value < GetIntLimit<T>(kBits));
}
-static inline bool IsUint(int N, intptr_t value) {
- CHECK_LT(0, N);
- CHECK_LT(N, kBitsPerIntPtrT);
- intptr_t limit = static_cast<intptr_t>(1) << N;
- return (0 <= value) && (value < limit);
+template <size_t kBits, typename T>
+static constexpr bool IsUint(T value) {
+ static_assert(kBits > 0, "kBits cannot be zero.");
+ static_assert(kBits <= kBitsPerByte * sizeof(T), "kBits must be <= max.");
+ static_assert(std::is_integral<T>::value, "Needs an integral type.");
+ // Corner case for "use all bits." Can't use the limits, as they would overflow, but it is
+ // trivially true.
+ return (0 <= value) &&
+ (kBits == kBitsPerByte * sizeof(T) ||
+ (static_cast<typename std::make_unsigned<T>::type>(value) <=
+ GetIntLimit<typename std::make_unsigned<T>::type>(kBits + 1) - 1));
}
-static inline bool IsAbsoluteUint(int N, intptr_t value) {
- CHECK_LT(0, N);
- CHECK_LT(N, kBitsPerIntPtrT);
- if (value < 0) value = -value;
- return IsUint(N, value);
+template <size_t kBits, typename T>
+static constexpr bool IsAbsoluteUint(T value) {
+ static_assert(kBits <= kBitsPerByte * sizeof(T), "kBits must be < max.");
+ return (kBits == kBitsPerByte * sizeof(T)) ?
+ true :
+ IsUint<kBits, T>(value < 0 ? -value : value);
}
static inline uint16_t Low16Bits(uint32_t value) {
diff --git a/test/099-vmdebug/check b/test/099-vmdebug/check
index 7b47ac1..57111bc 100755
--- a/test/099-vmdebug/check
+++ b/test/099-vmdebug/check
@@ -15,6 +15,6 @@
# limitations under the License.
# Strip the process pids and line numbers from exact error messages.
-sed -e 's/^art E.*\] //' "$2" > "$2.tmp"
+sed -e '/^art E.*\] /d' "$2" > "$2.tmp"
diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
diff --git a/test/099-vmdebug/expected.txt b/test/099-vmdebug/expected.txt
index 392efe5..579f98f 100644
--- a/test/099-vmdebug/expected.txt
+++ b/test/099-vmdebug/expected.txt
@@ -7,17 +7,13 @@
status=0
Test starting when already started
status=1
-Trace already in progress, ignoring this request
status=1
Test stopping when already stopped
status=0
-Trace stop requested, but no trace currently running
status=0
Test tracing with empty filename
-Unable to open trace file '': No such file or directory
Got expected exception
Test tracing with bogus (< 1024 && != 0) filesize
Got expected exception
Test sampling with bogus (<= 0) interval
-Invalid sampling interval: 0
Got expected exception
diff --git a/test/109-suspend-check/src/Main.java b/test/109-suspend-check/src/Main.java
index cd5130d..8046d75 100644
--- a/test/109-suspend-check/src/Main.java
+++ b/test/109-suspend-check/src/Main.java
@@ -19,30 +19,33 @@
public static void main(String[] args) {
System.out.println("Running (" + TEST_TIME + " seconds) ...");
- InfiniteForLoop forLoop = new InfiniteForLoop();
- InfiniteWhileLoop whileLoop = new InfiniteWhileLoop();
- InfiniteWhileLoopWithIntrinsic whileLoopWithIntrinsic =
- new InfiniteWhileLoopWithIntrinsic();
InfiniteDoWhileLoopWithLong doWhileLoopWithLong = new InfiniteDoWhileLoopWithLong();
- InfiniteDoWhileLoop doWhileLoop = new InfiniteDoWhileLoop();
- MakeGarbage garbage = new MakeGarbage();
- forLoop.start();
- whileLoop.start();
- whileLoopWithIntrinsic.start();
+ SimpleLoopThread[] simpleLoops = {
+ new InfiniteForLoop(),
+ new InfiniteWhileLoop(),
+ new InfiniteWhileLoopWithIntrinsic(),
+ new InfiniteDoWhileLoop(),
+ new MakeGarbage(),
+ new InfiniteWhileLoopWithSpecialReturnArgOrConst(new SpecialMethods1()),
+ new InfiniteWhileLoopWithSpecialReturnArgOrConst(new SpecialMethods2()),
+ new InfiniteWhileLoopWithSpecialPutOrNop(new SpecialMethods1()),
+ new InfiniteWhileLoopWithSpecialPutOrNop(new SpecialMethods2()),
+ new InfiniteWhileLoopWithSpecialConstOrIGet(new SpecialMethods1()),
+ new InfiniteWhileLoopWithSpecialConstOrIGet(new SpecialMethods2()),
+ };
doWhileLoopWithLong.start();
- doWhileLoop.start();
- garbage.start();
+ for (SimpleLoopThread loop : simpleLoops) {
+ loop.start();
+ }
for (int i = 0; i < TEST_TIME; i++) {
Runtime.getRuntime().gc();
System.out.println(".");
sleep(1000);
}
- forLoop.stopNow();
- whileLoop.stopNow();
- whileLoopWithIntrinsic.stopNow();
doWhileLoopWithLong.stopNow();
- doWhileLoop.stopNow();
- garbage.stopNow();
+ for (SimpleLoopThread loop : simpleLoops) {
+ loop.stopNow();
+ }
System.out.println("Done.");
}
@@ -55,8 +58,84 @@
}
}
-class InfiniteWhileLoopWithIntrinsic extends Thread {
- volatile private boolean keepGoing = true;
+class SimpleLoopThread extends Thread {
+ volatile protected boolean keepGoing = true;
+ public void stopNow() {
+ keepGoing = false;
+ }
+}
+
+interface SpecialMethodInterface {
+ long ReturnArgOrConst(long arg);
+ void PutOrNop(long arg);
+ long ConstOrIGet();
+}
+
+class SpecialMethods1 implements SpecialMethodInterface {
+ public long ReturnArgOrConst(long arg) {
+ return 42L;
+ }
+ public void PutOrNop(long arg) {
+ }
+ public long ConstOrIGet() {
+ return 42L;
+ }
+}
+
+class SpecialMethods2 implements SpecialMethodInterface {
+ public long value = 42L;
+ public long ReturnArgOrConst(long arg) {
+ return arg;
+ }
+ public void PutOrNop(long arg) {
+ value = arg;
+ }
+ public long ConstOrIGet() {
+ return value;
+ }
+}
+
+class InfiniteWhileLoopWithSpecialReturnArgOrConst extends SimpleLoopThread {
+ private SpecialMethodInterface smi;
+ public InfiniteWhileLoopWithSpecialReturnArgOrConst(SpecialMethodInterface smi) {
+ this.smi = smi;
+ }
+ public void run() {
+ long i = 0L;
+ while (keepGoing) {
+ i += smi.ReturnArgOrConst(i);
+ }
+ }
+}
+
+class InfiniteWhileLoopWithSpecialPutOrNop extends SimpleLoopThread {
+ private SpecialMethodInterface smi;
+ public InfiniteWhileLoopWithSpecialPutOrNop(SpecialMethodInterface smi) {
+ this.smi = smi;
+ }
+ public void run() {
+ long i = 0L;
+ while (keepGoing) {
+ smi.PutOrNop(i);
+ i++;
+ }
+ }
+}
+
+class InfiniteWhileLoopWithSpecialConstOrIGet extends SimpleLoopThread {
+ private SpecialMethodInterface smi;
+ public InfiniteWhileLoopWithSpecialConstOrIGet(SpecialMethodInterface smi) {
+ this.smi = smi;
+ }
+ public void run() {
+ long i = 0L;
+ while (keepGoing) {
+ i += smi.ConstOrIGet();
+ }
+ }
+}
+
+class InfiniteWhileLoopWithIntrinsic extends SimpleLoopThread {
private String[] strings = { "a", "b", "c", "d" };
private int sum = 0;
public void run() {
@@ -66,9 +145,6 @@
sum += strings[i & 3].length();
}
}
- public void stopNow() {
- keepGoing = false;
- }
}
class InfiniteDoWhileLoopWithLong extends Thread {
@@ -84,55 +160,37 @@
}
}
-class InfiniteWhileLoop extends Thread {
- volatile private boolean keepGoing = true;
+class InfiniteWhileLoop extends SimpleLoopThread {
public void run() {
int i = 0;
while (keepGoing) {
i++;
}
}
- public void stopNow() {
- keepGoing = false;
- }
}
-class InfiniteDoWhileLoop extends Thread {
- volatile private boolean keepGoing = true;
+class InfiniteDoWhileLoop extends SimpleLoopThread {
public void run() {
int i = 0;
do {
i++;
} while (keepGoing);
}
- public void stopNow() {
- keepGoing = false;
- }
}
-class InfiniteForLoop extends Thread {
- int count = 100000;
- volatile private boolean keepGoing = true;
+class InfiniteForLoop extends SimpleLoopThread {
public void run() {
int i = 0;
for (int j = 0; keepGoing; j++) {
i += j;
}
}
- public void stopNow() {
- keepGoing = false;
- }
}
-
-class MakeGarbage extends Thread {
- volatile private boolean keepGoing = true;
+class MakeGarbage extends SimpleLoopThread {
public void run() {
while (keepGoing) {
byte[] garbage = new byte[100000];
}
}
- public void stopNow() {
- keepGoing = false;
- }
}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index a8f2001..c8e0ec5 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -271,6 +271,19 @@
TEST_ART_BROKEN_FALLBACK_RUN_TESTS :=
+# This test dynamically enables tracing to force a deoptimization. This makes the test meaningless
+# when already tracing, and writes an error message that we do not want to check for.
+TEST_ART_BROKEN_TRACING_RUN_TESTS := \
+ 802-deoptimization
+
+ifneq (,$(filter trace,$(TRACE_TYPES)))
+ ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+ $(COMPILER_TYPES),$(RELOCATE_TYPES),trace,$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES), \
+ $(PICTEST_TYPES),$(TEST_ART_BROKEN_TRACING_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+endif
+
+TEST_ART_BROKEN_TRACING_RUN_TESTS :=
+
# The following tests use libarttest.so, which is linked against libartd.so, so will
# not work when libart.so is the one loaded.
# TODO: Find a way to run these tests in ndebug mode.