Merge "Revert "Interpreter: Add support for direct handle invokes on methods.""
diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc
index 140c7f0..663cbaf 100644
--- a/compiler/optimizing/induction_var_range.cc
+++ b/compiler/optimizing/induction_var_range.cc
@@ -162,17 +162,17 @@
/*out*/bool* needs_taken_test) {
bool is_last_value = false;
int64_t stride_value = 0;
- return GenerateCode(context,
- instruction,
- is_last_value,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr, // nothing generated yet
- &stride_value,
- needs_finite_test,
- needs_taken_test)
+ return GenerateRangeOrLastValue(context,
+ instruction,
+ is_last_value,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr, // nothing generated yet
+ &stride_value,
+ needs_finite_test,
+ needs_taken_test)
&& (stride_value == -1 ||
stride_value == 0 ||
stride_value == 1); // avoid wrap-around anomalies.
@@ -187,17 +187,17 @@
bool is_last_value = false;
int64_t stride_value = 0;
bool b1, b2; // unused
- if (!GenerateCode(context,
- instruction,
- is_last_value,
- graph,
- block,
- lower,
- upper,
- nullptr,
- &stride_value,
- &b1,
- &b2)) {
+ if (!GenerateRangeOrLastValue(context,
+ instruction,
+ is_last_value,
+ graph,
+ block,
+ lower,
+ upper,
+ nullptr,
+ &stride_value,
+ &b1,
+ &b2)) {
LOG(FATAL) << "Failed precondition: CanGenerateRange()";
}
}
@@ -209,17 +209,17 @@
bool is_last_value = false;
int64_t stride_value = 0;
bool b1, b2; // unused
- if (!GenerateCode(context,
- context,
- is_last_value,
- graph,
- block,
- nullptr,
- nullptr,
- &taken_test,
- &stride_value,
- &b1,
- &b2)) {
+ if (!GenerateRangeOrLastValue(context,
+ context,
+ is_last_value,
+ graph,
+ block,
+ nullptr,
+ nullptr,
+ &taken_test,
+ &stride_value,
+ &b1,
+ &b2)) {
LOG(FATAL) << "Failed precondition: CanGenerateRange()";
}
return taken_test;
@@ -230,17 +230,17 @@
int64_t stride_value = 0;
bool needs_finite_test = false;
bool needs_taken_test = false;
- return GenerateCode(instruction,
- instruction,
- is_last_value,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr, // nothing generated yet
- &stride_value,
- &needs_finite_test,
- &needs_taken_test)
+ return GenerateRangeOrLastValue(instruction,
+ instruction,
+ is_last_value,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr, // nothing generated yet
+ &stride_value,
+ &needs_finite_test,
+ &needs_taken_test)
&& !needs_finite_test && !needs_taken_test;
}
@@ -251,17 +251,17 @@
bool is_last_value = true;
int64_t stride_value = 0;
bool b1, b2; // unused
- if (!GenerateCode(instruction,
- instruction,
- is_last_value,
- graph,
- block,
- &last_value,
- &last_value,
- nullptr,
- &stride_value,
- &b1,
- &b2)) {
+ if (!GenerateRangeOrLastValue(instruction,
+ instruction,
+ is_last_value,
+ graph,
+ block,
+ &last_value,
+ &last_value,
+ nullptr,
+ &stride_value,
+ &b1,
+ &b2)) {
LOG(FATAL) << "Failed precondition: CanGenerateLastValue()";
}
return last_value;
@@ -280,6 +280,12 @@
}
}
+bool InductionVarRange::IsFinite(HLoopInformation* loop) const {
+ HInductionVarAnalysis::InductionInfo *trip =
+ induction_analysis_->LookupInfo(loop, GetLoopControl(loop));
+ return trip != nullptr && !IsUnsafeTripCount(trip);
+}
+
//
// Private class methods.
//
@@ -732,17 +738,17 @@
return Value();
}
-bool InductionVarRange::GenerateCode(HInstruction* context,
- HInstruction* instruction,
- bool is_last_value,
- HGraph* graph,
- HBasicBlock* block,
- /*out*/HInstruction** lower,
- /*out*/HInstruction** upper,
- /*out*/HInstruction** taken_test,
- /*out*/int64_t* stride_value,
- /*out*/bool* needs_finite_test,
- /*out*/bool* needs_taken_test) const {
+bool InductionVarRange::GenerateRangeOrLastValue(HInstruction* context,
+ HInstruction* instruction,
+ bool is_last_value,
+ HGraph* graph,
+ HBasicBlock* block,
+ /*out*/HInstruction** lower,
+ /*out*/HInstruction** upper,
+ /*out*/HInstruction** taken_test,
+ /*out*/int64_t* stride_value,
+ /*out*/bool* needs_finite_test,
+ /*out*/bool* needs_taken_test) const {
HLoopInformation* loop = nullptr;
HInductionVarAnalysis::InductionInfo* info = nullptr;
HInductionVarAnalysis::InductionInfo* trip = nullptr;
@@ -760,12 +766,17 @@
*needs_taken_test = IsBodyTripCount(trip);
// Handle last value request.
if (is_last_value) {
- if (info->induction_class != HInductionVarAnalysis::kLinear) {
- return false;
- } else if (*stride_value > 0) {
- lower = nullptr;
+ if (info->induction_class == HInductionVarAnalysis::kLinear) {
+ if (*stride_value > 0) {
+ lower = nullptr;
+ } else {
+ upper = nullptr;
+ }
+ } else if (info->induction_class == HInductionVarAnalysis::kPeriodic) {
+ DCHECK(!in_body);
+ return GenerateLastValuePeriodic(info, trip, graph, block, lower, needs_taken_test);
} else {
- upper = nullptr;
+ return false;
}
}
// Code generation for taken test: generate the code when requested or otherwise analyze
@@ -787,6 +798,56 @@
GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false);
}
+bool InductionVarRange::GenerateLastValuePeriodic(HInductionVarAnalysis::InductionInfo* info,
+ HInductionVarAnalysis::InductionInfo* trip,
+ HGraph* graph,
+ HBasicBlock* block,
+ /*out*/HInstruction** result,
+ /*out*/bool* needs_taken_test) const {
+ DCHECK(info->induction_class == HInductionVarAnalysis::kPeriodic);
+ // Count period.
+ int32_t period = 1;
+ for (HInductionVarAnalysis::InductionInfo* p = info;
+ p->induction_class == HInductionVarAnalysis::kPeriodic;
+ p = p->op_b, ++period) {}
+ // Handle periodic(x, y) case for restricted types.
+ if (period != 2 ||
+ trip->op_a->type != Primitive::kPrimInt ||
+ (info->type != Primitive::kPrimInt && info->type != Primitive::kPrimBoolean)) {
+ return false; // TODO: easy to generalize
+ }
+ HInstruction* x_instr = nullptr;
+ HInstruction* y_instr = nullptr;
+ HInstruction* trip_expr = nullptr;
+ if (GenerateCode(info->op_a, nullptr, graph, block, graph ? &x_instr : nullptr, false, false) &&
+ GenerateCode(info->op_b, nullptr, graph, block, graph ? &y_instr : nullptr, false, false) &&
+ GenerateCode(trip->op_a, nullptr, graph, block, graph ? &trip_expr : nullptr, false, false)) {
+ // During actual code generation (graph != nullptr),
+ // generate is_even ? x : y select instruction.
+ if (graph != nullptr) {
+ HInstruction* is_even = Insert(block, new (graph->GetArena()) HEqual(
+ Insert(block, new (graph->GetArena()) HAnd(
+ Primitive::kPrimInt, trip_expr, graph->GetIntConstant(1))),
+ graph->GetIntConstant(0), kNoDexPc));
+ *result = Insert(block, new (graph->GetArena()) HSelect(is_even, x_instr, y_instr, kNoDexPc));
+ }
+ // Guard select with taken test if needed.
+ if (*needs_taken_test) {
+ HInstruction* taken_test = nullptr;
+ if (!GenerateCode(
+ trip->op_b, nullptr, graph, block, graph ? &taken_test : nullptr, false, false)) {
+ return false;
+ } else if (graph != nullptr) {
+ *result = Insert(block,
+ new (graph->GetArena()) HSelect(taken_test, *result, x_instr, kNoDexPc));
+ }
+ *needs_taken_test = false; // taken care of
+ }
+ return true;
+ }
+ return false;
+}
+
bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info,
HInductionVarAnalysis::InductionInfo* trip,
HGraph* graph, // when set, code is generated
@@ -812,6 +873,7 @@
// Invariants.
switch (info->operation) {
case HInductionVarAnalysis::kAdd:
+ case HInductionVarAnalysis::kXor:
case HInductionVarAnalysis::kLT:
case HInductionVarAnalysis::kLE:
case HInductionVarAnalysis::kGT:
@@ -823,6 +885,8 @@
switch (info->operation) {
case HInductionVarAnalysis::kAdd:
operation = new (graph->GetArena()) HAdd(type, opa, opb); break;
+ case HInductionVarAnalysis::kXor:
+ operation = new (graph->GetArena()) HXor(type, opa, opb); break;
case HInductionVarAnalysis::kLT:
operation = new (graph->GetArena()) HLessThan(opa, opb); break;
case HInductionVarAnalysis::kLE:
diff --git a/compiler/optimizing/induction_var_range.h b/compiler/optimizing/induction_var_range.h
index 8951300..2f70046 100644
--- a/compiler/optimizing/induction_var_range.h
+++ b/compiler/optimizing/induction_var_range.h
@@ -139,6 +139,11 @@
induction_analysis_->VisitLoop(loop);
}
+ /**
+ * Checks if header logic of a loop terminates.
+ */
+ bool IsFinite(HLoopInformation* loop) const;
+
private:
/*
* Enum used in IsConstant() request.
@@ -218,17 +223,24 @@
* success. With values nullptr, the method can be used to determine if code generation
* would be successful without generating actual code yet.
*/
- bool GenerateCode(HInstruction* context,
- HInstruction* instruction,
- bool is_last_val,
- HGraph* graph,
- HBasicBlock* block,
- /*out*/ HInstruction** lower,
- /*out*/ HInstruction** upper,
- /*out*/ HInstruction** taken_test,
- /*out*/ int64_t* stride_value,
- /*out*/ bool* needs_finite_test,
- /*out*/ bool* needs_taken_test) const;
+ bool GenerateRangeOrLastValue(HInstruction* context,
+ HInstruction* instruction,
+ bool is_last_val,
+ HGraph* graph,
+ HBasicBlock* block,
+ /*out*/ HInstruction** lower,
+ /*out*/ HInstruction** upper,
+ /*out*/ HInstruction** taken_test,
+ /*out*/ int64_t* stride_value,
+ /*out*/ bool* needs_finite_test,
+ /*out*/ bool* needs_taken_test) const;
+
+ bool GenerateLastValuePeriodic(HInductionVarAnalysis::InductionInfo* info,
+ HInductionVarAnalysis::InductionInfo* trip,
+ HGraph* graph,
+ HBasicBlock* block,
+ /*out*/HInstruction** result,
+ /*out*/ bool* needs_taken_test) const;
bool GenerateCode(HInductionVarAnalysis::InductionInfo* info,
HInductionVarAnalysis::InductionInfo* trip,
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 7347686..820fa29 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -168,7 +168,9 @@
const int16_t declaring_class_def_index_; // declaring class's def's dex index.
bool value_killed_by_loop_side_effects_; // value of this location may be killed by loop
// side effects because this location is stored
- // into inside a loop.
+ // into inside a loop. This gives
+ // better info on whether a singleton's location
+ // value may be killed by loop side effects.
DISALLOW_COPY_AND_ASSIGN(HeapLocation);
};
@@ -420,8 +422,26 @@
void VisitInstanceFieldSet(HInstanceFieldSet* instruction) OVERRIDE {
HeapLocation* location = VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo());
has_heap_stores_ = true;
- if (instruction->GetBlock()->GetLoopInformation() != nullptr) {
- location->SetValueKilledByLoopSideEffects(true);
+ if (location->GetReferenceInfo()->IsSingleton()) {
+ // A singleton's location value may be killed by loop side effects if it's
+ // defined before that loop, and it's stored into inside that loop.
+ HLoopInformation* loop_info = instruction->GetBlock()->GetLoopInformation();
+ if (loop_info != nullptr) {
+ HInstruction* ref = location->GetReferenceInfo()->GetReference();
+ DCHECK(ref->IsNewInstance());
+ if (loop_info->IsDefinedOutOfTheLoop(ref)) {
+ // ref's location value may be killed by this loop's side effects.
+ location->SetValueKilledByLoopSideEffects(true);
+ } else {
+ // ref is defined inside this loop so this loop's side effects cannot
+ // kill its location value at the loop header since ref/its location doesn't
+ // exist yet at the loop header.
+ }
+ }
+ } else {
+ // For non-singletons, value_killed_by_loop_side_effects_ is inited to
+ // true.
+ DCHECK_EQ(location->IsValueKilledByLoopSideEffects(), true);
}
}
@@ -810,9 +830,6 @@
if (loop_info != nullptr) {
// instruction is a store in the loop so the loop must does write.
DCHECK(side_effects_.GetLoopEffects(loop_info->GetHeader()).DoesAnyWrite());
- // If it's a singleton, IsValueKilledByLoopSideEffects() must be true.
- DCHECK(!ref_info->IsSingleton() ||
- heap_location_collector_.GetHeapLocation(idx)->IsValueKilledByLoopSideEffects());
if (loop_info->IsDefinedOutOfTheLoop(original_ref)) {
DCHECK(original_ref->GetBlock()->Dominates(loop_info->GetPreHeader()));
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index 33fa87d..703a104 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -20,17 +20,37 @@
namespace art {
-// TODO: Generalize to cycles, as found by induction analysis?
+// Detects a potential induction cycle. Note that the actual induction
+// information is queried later if its last value is really needed.
static bool IsPhiInduction(HPhi* phi, ArenaSet<HInstruction*>* iset) {
DCHECK(iset->empty());
HInputsRef inputs = phi->GetInputs();
- if (inputs.size() == 2 && (inputs[1]->IsAdd() || inputs[1]->IsSub())) {
- HInstruction* addsub = inputs[1];
- if (addsub->InputAt(0) == phi || addsub->InputAt(1) == phi) {
- if (addsub->GetUses().HasExactlyOneElement()) {
- iset->insert(phi);
- iset->insert(addsub);
- return true;
+ if (inputs.size() == 2) {
+ HLoopInformation* loop_info = phi->GetBlock()->GetLoopInformation();
+ HInstruction* op = inputs[1];
+ if (op->GetBlock()->GetLoopInformation() == loop_info) {
+ // Chase a simple chain back to phi.
+ while (!op->IsPhi()) {
+ // Binary operation with single use in same loop.
+ if (!op->IsBinaryOperation() || !op->GetUses().HasExactlyOneElement()) {
+ return false;
+ }
+ // Chase back either through left or right operand.
+ iset->insert(op);
+ HInstruction* a = op->InputAt(0);
+ HInstruction* b = op->InputAt(1);
+ if (a->GetBlock()->GetLoopInformation() == loop_info && b != phi) {
+ op = a;
+ } else if (b->GetBlock()->GetLoopInformation() == loop_info) {
+ op = b;
+ } else {
+ return false;
+ }
+ }
+ // Closed the cycle?
+ if (op == phi) {
+ iset->insert(phi);
+ return true;
}
}
}
@@ -62,16 +82,23 @@
return false;
}
+// Does the loop-body consist of induction cycle and direct control flow only?
static bool IsEmptyBody(HBasicBlock* block, ArenaSet<HInstruction*>* iset) {
- HInstruction* phi = block->GetFirstPhi();
- HInstruction* i = block->GetFirstInstruction();
- return phi == nullptr && iset->find(i) != iset->end() &&
- i->GetNext() != nullptr && i->GetNext()->IsGoto();
+ if (block->GetFirstPhi() == nullptr) {
+ for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
+ HInstruction* instruction = it.Current();
+ if (!instruction->IsGoto() && iset->find(instruction) == iset->end()) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
}
+// Remove the instruction from the graph. A bit more elaborate than the usual
+// instruction removal, since there may be a cycle in the use structure.
static void RemoveFromCycle(HInstruction* instruction) {
- // A bit more elaborate than the usual instruction removal,
- // since there may be a cycle in the use structure.
instruction->RemoveAsUserOfAllInputs();
instruction->RemoveEnvironmentUsers();
instruction->GetBlock()->RemoveInstructionOrPhi(instruction, /*ensure_safety=*/ false);
@@ -196,7 +223,9 @@
}
SimplifyInduction(node);
SimplifyBlocks(node);
- RemoveIfEmptyLoop(node);
+ if (node->inner == nullptr) {
+ RemoveIfEmptyInnerLoop(node);
+ }
}
}
@@ -233,7 +262,7 @@
block->RemoveInstruction(instruction);
}
}
- // Remove trivial control flow blocks from the loop body, again usually resulting
+ // Remove trivial control flow blocks from the loop-body, again usually resulting
// from eliminating induction cycles.
if (block->GetPredecessors().size() == 1 &&
block->GetSuccessors().size() == 1 &&
@@ -252,9 +281,13 @@
}
}
-void HLoopOptimization::RemoveIfEmptyLoop(LoopNode* node) {
+void HLoopOptimization::RemoveIfEmptyInnerLoop(LoopNode* node) {
HBasicBlock* header = node->loop_info->GetHeader();
HBasicBlock* preheader = node->loop_info->GetPreHeader();
+ // Ensure loop header logic is finite.
+ if (!induction_range_.IsFinite(node->loop_info)) {
+ return;
+ }
// Ensure there is only a single loop-body (besides the header).
HBasicBlock* body = nullptr;
for (HBlocksInLoopIterator it(*node->loop_info); !it.Done(); it.Advance()) {
diff --git a/compiler/optimizing/loop_optimization.h b/compiler/optimizing/loop_optimization.h
index 9c4b462..4113357 100644
--- a/compiler/optimizing/loop_optimization.h
+++ b/compiler/optimizing/loop_optimization.h
@@ -62,7 +62,7 @@
void SimplifyInduction(LoopNode* node);
void SimplifyBlocks(LoopNode* node);
- void RemoveIfEmptyLoop(LoopNode* node);
+ void RemoveIfEmptyInnerLoop(LoopNode* node);
bool IsOnlyUsedAfterLoop(HLoopInformation* loop_info,
HInstruction* instruction,
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 54e52e5..c3321e1 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -2117,7 +2117,7 @@
mov %r8d, %ecx
cmovg %r9d, %ecx
/* Going into loop to compare each character */
- jecxz .Lstring_compareto_keep_length // check loop counter (if 0 then stop)
+ jecxz .Lstring_compareto_keep_length1 // check loop counter (if 0 then stop)
.Lstring_compareto_loop_comparison_this_compressed:
movzbl (%edi), %r8d // move *(this_cur_char) byte to long
movzwl (%esi), %r9d // move *(that_cur_char) word to long
@@ -2126,6 +2126,7 @@
subl %r9d, %r8d
loope .Lstring_compareto_loop_comparison_this_compressed
cmovne %r8d, %eax // return eax = *(this_cur_char) - *(that_cur_char)
+.Lstring_compareto_keep_length1:
ret
.Lstring_compareto_that_is_compressed:
andl LITERAL(0x7FFFFFFF), %r9d
@@ -2134,7 +2135,7 @@
mov %r8d, %ecx
cmovg %r9d, %ecx
/* Comparison this (8-bit) and that (16-bit) */
- jecxz .Lstring_compareto_keep_length // check loop counter (if 0, don't compare)
+ jecxz .Lstring_compareto_keep_length2 // check loop counter (if 0, don't compare)
.Lstring_compareto_loop_comparison_that_compressed:
movzwl (%edi), %r8d // move *(this_cur_char) word to long
movzbl (%esi), %r9d // move *(that_cur_chat) byte to long
@@ -2143,6 +2144,7 @@
subl %r9d, %r8d
loope .Lstring_compareto_loop_comparison_that_compressed
cmovne %r8d, %eax // return eax = *(this_cur_char) - *(that_cur_char)
+.Lstring_compareto_keep_length2:
ret
.Lstring_compareto_both_compressed:
andl LITERAL(0x7FFFFFFF), %r9d
@@ -2151,9 +2153,9 @@
movl %r8d, %eax
subl %r9d, %eax
cmovg %r9d, %ecx
- jecxz .Lstring_compareto_keep_length
+ jecxz .Lstring_compareto_keep_length3
repe cmpsb
- je .Lstring_compareto_keep_length
+ je .Lstring_compareto_keep_length3
movzbl -1(%edi), %eax // get last compared char from this string (8-bit)
movzbl -1(%esi), %ecx // get last compared char from comp string (8-bit)
jmp .Lstring_compareto_count_difference
@@ -2171,14 +2173,14 @@
* esi: pointer to comp string data
* edi: pointer to this string data
*/
- jecxz .Lstring_compareto_keep_length
+ jecxz .Lstring_compareto_keep_length3
repe cmpsw // find nonmatching chars in [%esi] and [%edi], up to length %ecx
- je .Lstring_compareto_keep_length
+ je .Lstring_compareto_keep_length3
movzwl -2(%edi), %eax // get last compared char from this string (16-bit)
movzwl -2(%esi), %ecx // get last compared char from comp string (16-bit)
.Lstring_compareto_count_difference:
subl %ecx, %eax // return the difference
-.Lstring_compareto_keep_length:
+.Lstring_compareto_keep_length3:
ret
END_FUNCTION art_quick_string_compareto
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index dba9b8f..126187f 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -36,7 +36,8 @@
return FindClass(self, descriptor, ScopedNullHandle<mirror::ClassLoader>());
}
-inline mirror::Class* ClassLinker::FindArrayClass(Thread* self, mirror::Class** element_class) {
+inline mirror::Class* ClassLinker::FindArrayClass(Thread* self,
+ ObjPtr<mirror::Class>* element_class) {
for (size_t i = 0; i < kFindArrayCacheSize; ++i) {
// Read the cached array class once to avoid races with other threads setting it.
mirror::Class* array_class = find_array_class_cache_[i].Read();
@@ -49,7 +50,7 @@
descriptor += (*element_class)->GetDescriptor(&temp);
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::ClassLoader> class_loader(hs.NewHandle((*element_class)->GetClassLoader()));
- HandleWrapper<mirror::Class> h_element_class(hs.NewHandleWrapper(element_class));
+ HandleWrapperObjPtr<mirror::Class> h_element_class(hs.NewHandleWrapper(element_class));
mirror::Class* array_class = FindClass(self, descriptor.c_str(), class_loader);
if (array_class != nullptr) {
// Benign races in storing array class and incrementing index.
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index d07aa89..63de76c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1962,7 +1962,7 @@
// Add 100 in case new classes get loaded when we are filling in the object array.
class_table_size = NumZygoteClasses() + NumNonZygoteClasses() + 100;
}
- mirror::Class* class_type = mirror::Class::GetJavaLangClass();
+ ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass();
mirror::Class* array_of_class = FindArrayClass(self, &class_type);
classes.Assign(
mirror::ObjectArray<mirror::Class>::Alloc(self, array_of_class, class_table_size));
@@ -2294,7 +2294,7 @@
const char* descriptor,
size_t hash,
Handle<mirror::ClassLoader> class_loader,
- mirror::Class** result) {
+ ObjPtr<mirror::Class>* result) {
// Termination case: boot class-loader.
if (IsBootClassLoader(soa, class_loader.Get())) {
// The boot class loader, search the boot class path.
@@ -2452,12 +2452,12 @@
}
} else {
ScopedObjectAccessUnchecked soa(self);
- mirror::Class* cp_klass;
+ ObjPtr<mirror::Class> cp_klass;
if (FindClassInPathClassLoader(soa, self, descriptor, hash, class_loader, &cp_klass)) {
// The chain was understood. So the value in cp_klass is either the class we were looking
// for, or not found.
if (cp_klass != nullptr) {
- return cp_klass;
+ return cp_klass.Ptr();
}
// TODO: We handle the boot classpath loader in FindClassInPathClassLoader. Try to unify this
// and the branch above. TODO: throw the right exception here.
@@ -7798,7 +7798,7 @@
// other than by looking at the shorty ?
const size_t num_method_args = strlen(dex_file.StringDataByIdx(proto_id.shorty_idx_)) - 1;
- mirror::Class* class_type = mirror::Class::GetJavaLangClass();
+ ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass();
mirror::Class* array_of_class = FindArrayClass(self, &class_type);
Handle<mirror::ObjectArray<mirror::Class>> method_params(hs.NewHandle(
mirror::ObjectArray<mirror::Class>::Alloc(self, array_of_class, num_method_args)));
@@ -8153,12 +8153,12 @@
}
}
-void ClassLinker::InsertDexFileInToClassLoader(mirror::Object* dex_file,
- mirror::ClassLoader* class_loader) {
+void ClassLinker::InsertDexFileInToClassLoader(ObjPtr<mirror::Object> dex_file,
+ ObjPtr<mirror::ClassLoader> class_loader) {
DCHECK(dex_file != nullptr);
Thread* const self = Thread::Current();
WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
- ClassTable* const table = ClassTableForClassLoader(class_loader);
+ ClassTable* const table = ClassTableForClassLoader(class_loader.Ptr());
DCHECK(table != nullptr);
if (table->InsertStrongRoot(dex_file) && class_loader != nullptr) {
// It was not already inserted, perform the write barrier to let the GC know the class loader's
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 70cc768..6437010 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -181,7 +181,7 @@
const char* descriptor,
size_t hash,
Handle<mirror::ClassLoader> class_loader,
- mirror::Class** result)
+ ObjPtr<mirror::Class>* result)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!dex_lock_);
@@ -192,7 +192,7 @@
REQUIRES(!dex_lock_);
// Finds the array class given for the element class.
- mirror::Class* FindArrayClass(Thread* self, mirror::Class** element_class)
+ mirror::Class* FindArrayClass(Thread* self, ObjPtr<mirror::Class>* element_class)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!dex_lock_);
@@ -606,7 +606,8 @@
REQUIRES_SHARED(Locks::mutator_lock_);
// May be called with null class_loader due to legacy code. b/27954959
- void InsertDexFileInToClassLoader(mirror::Object* dex_file, mirror::ClassLoader* class_loader)
+ void InsertDexFileInToClassLoader(ObjPtr<mirror::Object> dex_file,
+ ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES(!Locks::classlinker_classes_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 6279717..4fac830 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -216,7 +216,7 @@
EXPECT_STREQ(direct_interface0->GetDescriptor(&temp), "Ljava/lang/Cloneable;");
ObjPtr<mirror::Class> direct_interface1 = mirror::Class::GetDirectInterface(self, array, 1);
EXPECT_STREQ(direct_interface1->GetDescriptor(&temp), "Ljava/io/Serializable;");
- mirror::Class* array_ptr = array->GetComponentType();
+ ObjPtr<mirror::Class> array_ptr = array->GetComponentType();
EXPECT_OBJ_PTR_EQ(class_linker_->FindArrayClass(self, &array_ptr), array.Get());
PointerSize pointer_size = class_linker_->GetImagePointerSize();
diff --git a/runtime/class_table.cc b/runtime/class_table.cc
index 2ae7e8c..d435050 100644
--- a/runtime/class_table.cc
+++ b/runtime/class_table.cc
@@ -156,7 +156,7 @@
return ComputeModifiedUtf8Hash(descriptor);
}
-bool ClassTable::InsertStrongRoot(mirror::Object* obj) {
+bool ClassTable::InsertStrongRoot(ObjPtr<mirror::Object> obj) {
WriterMutexLock mu(Thread::Current(), lock_);
DCHECK(obj != nullptr);
for (GcRoot<mirror::Object>& root : strong_roots_) {
@@ -167,7 +167,7 @@
strong_roots_.push_back(GcRoot<mirror::Object>(obj));
// If `obj` is a dex cache associated with a new oat file with GC roots, add it to oat_files_.
if (obj->IsDexCache()) {
- const DexFile* dex_file = down_cast<mirror::DexCache*>(obj)->GetDexFile();
+ const DexFile* dex_file = ObjPtr<mirror::DexCache>::DownCast(obj)->GetDexFile();
if (dex_file != nullptr && dex_file->GetOatDexFile() != nullptr) {
const OatFile* oat_file = dex_file->GetOatDexFile()->GetOatFile();
if (!oat_file->GetBssGcRoots().empty() && !ContainsElement(oat_files_, oat_file)) {
diff --git a/runtime/class_table.h b/runtime/class_table.h
index acb15c7..20e434d 100644
--- a/runtime/class_table.h
+++ b/runtime/class_table.h
@@ -27,6 +27,7 @@
#include "base/mutex.h"
#include "dex_file.h"
#include "gc_root.h"
+#include "obj_ptr.h"
#include "object_callbacks.h"
#include "runtime.h"
@@ -136,7 +137,7 @@
REQUIRES_SHARED(Locks::mutator_lock_);
// Return true if we inserted the strong root, false if it already exists.
- bool InsertStrongRoot(mirror::Object* obj)
+ bool InsertStrongRoot(ObjPtr<mirror::Object> obj)
REQUIRES(!lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index 576c4aa..e538334 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -254,7 +254,7 @@
return nullptr;
}
- mirror::Class* annotation_member_class =
+ ObjPtr<mirror::Class> annotation_member_class =
soa.Decode<mirror::Class>(WellKnownClasses::libcore_reflect_AnnotationMember).Ptr();
mirror::Class* annotation_member_array_class =
class_linker->FindArrayClass(self, &annotation_member_class);
@@ -731,7 +731,7 @@
if (annotation_item == nullptr) {
return nullptr;
}
- mirror::Class* string_class = mirror::String::GetJavaLangString();
+ ObjPtr<mirror::Class> string_class = mirror::String::GetJavaLangString();
Handle<mirror::Class> string_array_class(hs.NewHandle(
Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &string_class)));
if (string_array_class.Get() == nullptr) {
@@ -757,7 +757,7 @@
if (annotation_item == nullptr) {
return nullptr;
}
- mirror::Class* class_class = mirror::Class::GetJavaLangClass();
+ ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass();
Handle<mirror::Class> class_array_class(hs.NewHandle(
Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &class_class)));
if (class_array_class.Get() == nullptr) {
@@ -839,8 +839,8 @@
Thread* self = Thread::Current();
ScopedObjectAccessUnchecked soa(self);
StackHandleScope<1> hs(self);
- mirror::Class* annotation_array_class =
- soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array).Ptr();
+ ObjPtr<mirror::Class> annotation_array_class =
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array);
mirror::Class* annotation_array_array_class =
Runtime::Current()->GetClassLinker()->FindArrayClass(self, &annotation_array_class);
if (annotation_array_array_class == nullptr) {
@@ -1049,7 +1049,7 @@
StackHandleScope<5> hs(Thread::Current());
// Extract the parameters' names String[].
- mirror::Class* string_class = mirror::String::GetJavaLangString();
+ ObjPtr<mirror::Class> string_class = mirror::String::GetJavaLangString();
Handle<mirror::Class> string_array_class(hs.NewHandle(
Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &string_class)));
if (UNLIKELY(string_array_class.Get() == nullptr)) {
@@ -1139,7 +1139,7 @@
return nullptr;
}
StackHandleScope<1> hs(Thread::Current());
- mirror::Class* class_class = mirror::Class::GetJavaLangClass();
+ ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass();
Handle<mirror::Class> class_array_class(hs.NewHandle(
Runtime::Current()->GetClassLinker()->FindArrayClass(hs.Self(), &class_class)));
if (class_array_class.Get() == nullptr) {
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 45bd87b..f4a3aea 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -1246,9 +1246,6 @@
<< " total=" << seen_backtrace_count_.LoadRelaxed() +
unique_backtrace_count_.LoadRelaxed();
}
- // Delete any still registered allocation listener.
- AllocationListener* l = GetAndOverwriteAllocationListener(&alloc_listener_, nullptr);
- delete l;
VLOG(heap) << "Finished ~Heap()";
}
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index 0030326..2d5d7cb 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -155,11 +155,12 @@
large_objects_.Put(obj, LargeObject {mem_map, false /* not zygote */});
const size_t allocation_size = mem_map->BaseSize();
DCHECK(bytes_allocated != nullptr);
- begin_ = std::min(begin_, reinterpret_cast<uint8_t*>(obj));
- uint8_t* obj_end = reinterpret_cast<uint8_t*>(obj) + allocation_size;
- if (end_ == nullptr || obj_end > end_) {
- end_ = obj_end;
+
+ if (begin_ == nullptr || begin_ > reinterpret_cast<uint8_t*>(obj)) {
+ begin_ = reinterpret_cast<uint8_t*>(obj);
}
+ end_ = std::max(end_, reinterpret_cast<uint8_t*>(obj) + allocation_size);
+
*bytes_allocated = allocation_size;
if (usable_size != nullptr) {
*usable_size = allocation_size;
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index 6109ec6..130c10d 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -58,17 +58,15 @@
}
}
-IndirectReferenceTable::IndirectReferenceTable(size_t initialCount,
- size_t maxCount, IndirectRefKind desiredKind,
+IndirectReferenceTable::IndirectReferenceTable(size_t max_count,
+ IndirectRefKind desired_kind,
bool abort_on_error)
- : kind_(desiredKind),
- max_entries_(maxCount) {
- CHECK_GT(initialCount, 0U);
- CHECK_LE(initialCount, maxCount);
- CHECK_NE(desiredKind, kHandleScopeOrInvalid);
+ : kind_(desired_kind),
+ max_entries_(max_count) {
+ CHECK_NE(desired_kind, kHandleScopeOrInvalid);
std::string error_str;
- const size_t table_bytes = maxCount * sizeof(IrtEntry);
+ const size_t table_bytes = max_count * sizeof(IrtEntry);
table_mem_map_.reset(MemMap::MapAnonymous("indirect ref table", nullptr, table_bytes,
PROT_READ | PROT_WRITE, false, false, &error_str));
if (abort_on_error) {
diff --git a/runtime/indirect_reference_table.h b/runtime/indirect_reference_table.h
index 64de7a8..1762b10 100644
--- a/runtime/indirect_reference_table.h
+++ b/runtime/indirect_reference_table.h
@@ -259,8 +259,7 @@
public:
// WARNING: When using with abort_on_error = false, the object may be in a partially
// initialized state. Use IsValid() to check.
- IndirectReferenceTable(size_t initialCount, size_t maxCount, IndirectRefKind kind,
- bool abort_on_error = true);
+ IndirectReferenceTable(size_t max_count, IndirectRefKind kind, bool abort_on_error = true);
~IndirectReferenceTable();
diff --git a/runtime/indirect_reference_table_test.cc b/runtime/indirect_reference_table_test.cc
index 1699110..7b28f0b 100644
--- a/runtime/indirect_reference_table_test.cc
+++ b/runtime/indirect_reference_table_test.cc
@@ -48,9 +48,8 @@
ScopedLogSeverity sls(LogSeverity::FATAL);
ScopedObjectAccess soa(Thread::Current());
- static const size_t kTableInitial = 10;
static const size_t kTableMax = 20;
- IndirectReferenceTable irt(kTableInitial, kTableMax, kGlobal);
+ IndirectReferenceTable irt(kTableMax, kGlobal);
mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
StackHandleScope<4> hs(soa.Self());
@@ -230,6 +229,7 @@
// Test table resizing.
// These ones fit...
+ static const size_t kTableInitial = kTableMax / 2;
IndirectRef manyRefs[kTableInitial];
for (size_t i = 0; i < kTableInitial; i++) {
manyRefs[i] = irt.Add(cookie, obj0.Get());
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index a73970b..36e8608 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -647,7 +647,15 @@
} else {
MutexLock mu(self, *Locks::runtime_shutdown_lock_);
SetQuickAllocEntryPointsInstrumented(instrumented);
- ResetQuickAllocEntryPoints();
+
+ // Note: ResetQuickAllocEntryPoints only works when the runtime is started. Manually run the
+ // update for just this thread.
+ // Note: self may be null. One of those paths is setting instrumentation in the Heap
+ // constructor for gcstress mode.
+ if (self != nullptr) {
+ ResetQuickAllocEntryPointsForThread(self, nullptr);
+ }
+
alloc_entrypoints_instrumented_ = instrumented;
}
}
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 4a3654b..4347c37 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -1472,13 +1472,17 @@
uint32_t* args, JValue* result) {
int32_t length = args[1];
DCHECK_GE(length, 0);
- mirror::Class* element_class = reinterpret_cast<mirror::Object*>(args[0])->AsClass();
+ ObjPtr<mirror::Class> element_class = reinterpret_cast<mirror::Object*>(args[0])->AsClass();
Runtime* runtime = Runtime::Current();
- mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(self, &element_class);
+ ObjPtr<mirror::Class> array_class =
+ runtime->GetClassLinker()->FindArrayClass(self, &element_class);
DCHECK(array_class != nullptr);
gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator();
- result->SetL(mirror::Array::Alloc<true, true>(self, array_class, length,
- array_class->GetComponentSizeShift(), allocator));
+ result->SetL(mirror::Array::Alloc<true, true>(self,
+ array_class,
+ length,
+ array_class->GetComponentSizeShift(),
+ allocator));
}
void UnstartedRuntime::UnstartedJNIVMStackGetCallingClassLoader(
@@ -1601,10 +1605,10 @@
ThrowNegativeArraySizeException(length);
return;
}
- mirror::Class* element_class = reinterpret_cast<mirror::Class*>(args[0])->AsClass();
+ ObjPtr<mirror::Class> element_class = reinterpret_cast<mirror::Class*>(args[0])->AsClass();
Runtime* runtime = Runtime::Current();
ClassLinker* class_linker = runtime->GetClassLinker();
- mirror::Class* array_class = class_linker->FindArrayClass(self, &element_class);
+ ObjPtr<mirror::Class> array_class = class_linker->FindArrayClass(self, &element_class);
if (UNLIKELY(array_class == nullptr)) {
CHECK(self->IsExceptionPending());
return;
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index 6a4add3..b190c81 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -81,20 +81,21 @@
static mirror::ObjectArray<mirror::Object>* CreateObjectArray(
Thread* self,
- mirror::Class* component_type,
+ ObjPtr<mirror::Class> component_type,
const StackHandleScope<3>& data)
REQUIRES_SHARED(Locks::mutator_lock_) {
Runtime* runtime = Runtime::Current();
- mirror::Class* array_type = runtime->GetClassLinker()->FindArrayClass(self, &component_type);
+ ObjPtr<mirror::Class> array_type =
+ runtime->GetClassLinker()->FindArrayClass(self, &component_type);
CHECK(array_type != nullptr);
- mirror::ObjectArray<mirror::Object>* result =
+ ObjPtr<mirror::ObjectArray<mirror::Object>> result =
mirror::ObjectArray<mirror::Object>::Alloc(self, array_type, 3);
CHECK(result != nullptr);
for (size_t i = 0; i < 3; ++i) {
result->Set(static_cast<int32_t>(i), data.GetReference(i));
CHECK(!self->IsExceptionPending());
}
- return result;
+ return result.Ptr();
}
static void CheckObjectArray(mirror::ObjectArray<mirror::Object>* array,
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index f2bda05..99edb7c 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -42,11 +42,9 @@
namespace art {
-static size_t gGlobalsInitial = 512; // Arbitrary.
-static size_t gGlobalsMax = 51200; // Arbitrary sanity check. (Must fit in 16 bits.)
+static constexpr size_t kGlobalsMax = 51200; // Arbitrary sanity check. (Must fit in 16 bits.)
-static const size_t kWeakGlobalsInitial = 16; // Arbitrary.
-static const size_t kWeakGlobalsMax = 51200; // Arbitrary sanity check. (Must fit in 16 bits.)
+static constexpr size_t kWeakGlobalsMax = 51200; // Arbitrary sanity check. (Must fit in 16 bits.)
bool JavaVMExt::IsBadJniVersion(int version) {
// We don't support JNI_VERSION_1_1. These are the only other valid versions.
@@ -422,10 +420,10 @@
tracing_enabled_(runtime_options.Exists(RuntimeArgumentMap::JniTrace)
|| VLOG_IS_ON(third_party_jni)),
trace_(runtime_options.GetOrDefault(RuntimeArgumentMap::JniTrace)),
- globals_(gGlobalsInitial, gGlobalsMax, kGlobal),
+ globals_(kGlobalsMax, kGlobal),
libraries_(new Libraries),
unchecked_functions_(&gJniInvokeInterface),
- weak_globals_(kWeakGlobalsInitial, kWeakGlobalsMax, kWeakGlobal),
+ weak_globals_(kWeakGlobalsMax, kWeakGlobal),
allow_accessing_weak_globals_(true),
weak_globals_add_condition_("weak globals add condition",
(CHECK(Locks::jni_weak_globals_lock_ != nullptr),
diff --git a/runtime/jni_env_ext.cc b/runtime/jni_env_ext.cc
index 3c749d0..39f4d97 100644
--- a/runtime/jni_env_ext.cc
+++ b/runtime/jni_env_ext.cc
@@ -33,8 +33,6 @@
static constexpr size_t kMonitorsInitial = 32; // Arbitrary.
static constexpr size_t kMonitorsMax = 4096; // Arbitrary sanity check.
-static constexpr size_t kLocalsInitial = 64; // Arbitrary.
-
// Checking "locals" requires the mutator lock, but at creation time we're really only interested
// in validity, which isn't changing. To avoid grabbing the mutator lock, factored out and tagged
// with NO_THREAD_SAFETY_ANALYSIS.
@@ -71,7 +69,7 @@
: self(self_in),
vm(vm_in),
local_ref_cookie(IRT_FIRST_SEGMENT),
- locals(kLocalsInitial, kLocalsMax, kLocal, false),
+ locals(kLocalsInitial, kLocal, false),
check_jni(false),
runtime_deleted(false),
critical(0),
diff --git a/runtime/jni_env_ext.h b/runtime/jni_env_ext.h
index 121f848..549f8c5 100644
--- a/runtime/jni_env_ext.h
+++ b/runtime/jni_env_ext.h
@@ -29,9 +29,9 @@
class JavaVMExt;
-// Maximum number of local references in the indirect reference table. The value is arbitrary but
+// Number of local references in the indirect reference table. The value is arbitrary but
// low enough that it forces sanity checks.
-static constexpr size_t kLocalsMax = 512;
+static constexpr size_t kLocalsInitial = 512;
struct JNIEnvExt : public JNIEnv {
static JNIEnvExt* Create(Thread* self, JavaVMExt* vm);
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 8eebe56..db2453d 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -1904,11 +1904,12 @@
// Compute the array class corresponding to the given element class.
ScopedObjectAccess soa(env);
- mirror::Class* array_class;
+ ObjPtr<mirror::Class> array_class;
{
- mirror::Class* element_class = soa.Decode<mirror::Class>(element_jclass).Ptr();
+ ObjPtr<mirror::Class> element_class = soa.Decode<mirror::Class>(element_jclass).Ptr();
if (UNLIKELY(element_class->IsPrimitive())) {
- soa.Vm()->JniAbortF("NewObjectArray", "not an object type: %s",
+ soa.Vm()->JniAbortF("NewObjectArray",
+ "not an object type: %s",
PrettyDescriptor(element_class).c_str());
return nullptr;
}
@@ -2394,13 +2395,13 @@
const char* caller)
REQUIRES_SHARED(Locks::mutator_lock_) {
// TODO: we should try to expand the table if necessary.
- if (desired_capacity < 0 || desired_capacity > static_cast<jint>(kLocalsMax)) {
+ if (desired_capacity < 0 || desired_capacity > static_cast<jint>(kLocalsInitial)) {
LOG(ERROR) << "Invalid capacity given to " << caller << ": " << desired_capacity;
return JNI_ERR;
}
// TODO: this isn't quite right, since "capacity" includes holes.
const size_t capacity = soa.Env()->locals.Capacity();
- bool okay = (static_cast<jint>(kLocalsMax - capacity) >= desired_capacity);
+ bool okay = (static_cast<jint>(kLocalsInitial - capacity) >= desired_capacity);
if (!okay) {
soa.Self()->ThrowOutOfMemoryError(caller);
}
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index fbd670c..9622a8e 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -865,6 +865,11 @@
GetStaticMethodIdBadArgumentTest(true);
}
+static size_t GetLocalsCapacity(JNIEnv* env) {
+ ScopedObjectAccess soa(Thread::Current());
+ return reinterpret_cast<JNIEnvExt*>(env)->locals.Capacity();
+}
+
TEST_F(JniInternalTest, FromReflectedField_ToReflectedField) {
jclass jlrField = env_->FindClass("java/lang/reflect/Field");
jclass c = env_->FindClass("java/lang/String");
@@ -873,11 +878,15 @@
ASSERT_NE(fid, nullptr);
// Turn the fid into a java.lang.reflect.Field...
jobject field = env_->ToReflectedField(c, fid, JNI_FALSE);
- for (size_t i = 0; i <= kLocalsMax; ++i) {
+ size_t capacity_before = GetLocalsCapacity(env_);
+ for (size_t i = 0; i <= 10; ++i) {
// Regression test for b/18396311, ToReflectedField leaking local refs causing a local
// reference table overflows with 512 references to ArtField
env_->DeleteLocalRef(env_->ToReflectedField(c, fid, JNI_FALSE));
}
+ size_t capacity_after = GetLocalsCapacity(env_);
+ ASSERT_EQ(capacity_before, capacity_after);
+
ASSERT_NE(c, nullptr);
ASSERT_TRUE(env_->IsInstanceOf(field, jlrField));
// ...and back again.
@@ -911,11 +920,14 @@
ASSERT_NE(mid, nullptr);
// Turn the mid into a java.lang.reflect.Constructor...
jobject method = env_->ToReflectedMethod(c, mid, JNI_FALSE);
- for (size_t i = 0; i <= kLocalsMax; ++i) {
+ size_t capacity_before = GetLocalsCapacity(env_);
+ for (size_t i = 0; i <= 10; ++i) {
// Regression test for b/18396311, ToReflectedMethod leaking local refs causing a local
// reference table overflows with 512 references to ArtMethod
env_->DeleteLocalRef(env_->ToReflectedMethod(c, mid, JNI_FALSE));
}
+ size_t capacity_after = GetLocalsCapacity(env_);
+ ASSERT_EQ(capacity_before, capacity_after);
ASSERT_NE(method, nullptr);
ASSERT_TRUE(env_->IsInstanceOf(method, jlrConstructor));
// ...and back again.
@@ -2295,7 +2307,7 @@
// The segment_state_ field is private, and we want to avoid friend declaration. So we'll check
// by modifying memory.
// The parameters don't really matter here.
- IndirectReferenceTable irt(5, 5, IndirectRefKind::kGlobal, true);
+ IndirectReferenceTable irt(5, IndirectRefKind::kGlobal, true);
uint32_t old_state = irt.GetSegmentState();
// Write some new state directly. We invert parts of old_state to ensure a new value.
diff --git a/runtime/mirror/array.cc b/runtime/mirror/array.cc
index 1aa38dd..8afa4aa 100644
--- a/runtime/mirror/array.cc
+++ b/runtime/mirror/array.cc
@@ -60,7 +60,7 @@
for (int32_t i = 0; i < array_length; i++) {
StackHandleScope<1> hs2(self);
Handle<mirror::Class> h_component_type(hs2.NewHandle(array_class->GetComponentType()));
- Array* sub_array = RecursiveCreateMultiArray(self, h_component_type,
+ ObjPtr<Array> sub_array = RecursiveCreateMultiArray(self, h_component_type,
current_dimension + 1, dimensions);
if (UNLIKELY(sub_array == nullptr)) {
CHECK(self->IsExceptionPending());
@@ -93,7 +93,7 @@
// Find/generate the array class.
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- mirror::Class* element_class_ptr = element_class.Get();
+ ObjPtr<mirror::Class> element_class_ptr = element_class.Get();
StackHandleScope<1> hs(self);
MutableHandle<mirror::Class> array_class(
hs.NewHandle(class_linker->FindArrayClass(self, &element_class_ptr)));
@@ -102,7 +102,7 @@
return nullptr;
}
for (int32_t i = 1; i < dimensions->GetLength(); ++i) {
- mirror::Class* array_class_ptr = array_class.Get();
+ ObjPtr<mirror::Class> array_class_ptr = array_class.Get();
array_class.Assign(class_linker->FindArrayClass(self, &array_class_ptr));
if (UNLIKELY(array_class.Get() == nullptr)) {
CHECK(self->IsExceptionPending());
@@ -110,11 +110,11 @@
}
}
// Create the array.
- Array* new_array = RecursiveCreateMultiArray(self, array_class, 0, dimensions);
+ ObjPtr<Array> new_array = RecursiveCreateMultiArray(self, array_class, 0, dimensions);
if (UNLIKELY(new_array == nullptr)) {
CHECK(self->IsExceptionPending());
}
- return new_array;
+ return new_array.Ptr();
}
void Array::ThrowArrayIndexOutOfBoundsException(int32_t index) {
@@ -136,12 +136,13 @@
heap->GetCurrentNonMovingAllocator();
const auto component_size = GetClass()->GetComponentSize();
const auto component_shift = GetClass()->GetComponentSizeShift();
- Array* new_array = Alloc<true>(self, GetClass(), new_length, component_shift, allocator_type);
+ ObjPtr<Array> new_array = Alloc<true>(self, GetClass(), new_length, component_shift, allocator_type);
if (LIKELY(new_array != nullptr)) {
- memcpy(new_array->GetRawData(component_size, 0), h_this->GetRawData(component_size, 0),
+ memcpy(new_array->GetRawData(component_size, 0),
+ h_this->GetRawData(component_size, 0),
std::min(h_this->GetLength(), new_length) << component_shift);
}
- return new_array;
+ return new_array.Ptr();
}
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index 86b5e7a..be849a3 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -44,8 +44,8 @@
return StringDexCachePair::Lookup(GetStrings(), string_idx, NumStrings()).Read();
}
-inline void DexCache::SetResolvedString(uint32_t string_idx, mirror::String* resolved) {
- StringDexCachePair::Assign(GetStrings(), string_idx, resolved, NumStrings());
+inline void DexCache::SetResolvedString(uint32_t string_idx, ObjPtr<mirror::String> resolved) {
+ StringDexCachePair::Assign(GetStrings(), string_idx, resolved.Ptr(), NumStrings());
Runtime* const runtime = Runtime::Current();
if (UNLIKELY(runtime->IsActiveTransaction())) {
DCHECK(runtime->IsAotCompiler());
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index c3c7ab4..d728f90 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -215,7 +215,7 @@
mirror::String* GetResolvedString(uint32_t string_idx) ALWAYS_INLINE
REQUIRES_SHARED(Locks::mutator_lock_);
- void SetResolvedString(uint32_t string_idx, mirror::String* resolved) ALWAYS_INLINE
+ void SetResolvedString(uint32_t string_idx, ObjPtr<mirror::String> resolved) ALWAYS_INLINE
REQUIRES_SHARED(Locks::mutator_lock_);
// Clear a string for a string_idx, used to undo string intern transactions to make sure
diff --git a/runtime/mirror/method_type_test.cc b/runtime/mirror/method_type_test.cc
index a968bff..03ab930 100644
--- a/runtime/mirror/method_type_test.cc
+++ b/runtime/mirror/method_type_test.cc
@@ -52,7 +52,7 @@
soa.Self(), FullyQualifiedType(return_type).c_str(), boot_class_loader));
CHECK(return_clazz.Get() != nullptr);
- mirror::Class* class_type = mirror::Class::GetJavaLangClass();
+ ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass();
mirror::Class* class_array_type = class_linker->FindArrayClass(self, &class_type);
Handle<mirror::ObjectArray<mirror::Class>> param_classes = hs.NewHandle(
mirror::ObjectArray<mirror::Class>::Alloc(self, class_array_type, param_types.size()));
diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc
index ed1103f..d60274f 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -292,38 +292,41 @@
if (lhs == rhs) {
return 0;
}
- // TODO: is this still true?
- // The annoying part here is that 0x00e9 - 0xffff != 0x00ea,
- // because the interpreter converts the characters to 32-bit integers
- // *without* sign extension before it subtracts them (which makes some
- // sense since "char" is unsigned). So what we get is the result of
- // 0x000000e9 - 0x0000ffff, which is 0xffff00ea.
- int32_t lhsCount = lhs->GetLength();
- int32_t rhsCount = rhs->GetLength();
- int32_t countDiff = lhsCount - rhsCount;
- int32_t minCount = (countDiff < 0) ? lhsCount : rhsCount;
+ int32_t lhs_count = lhs->GetLength();
+ int32_t rhs_count = rhs->GetLength();
+ int32_t count_diff = lhs_count - rhs_count;
+ int32_t min_count = (count_diff < 0) ? lhs_count : rhs_count;
if (lhs->IsCompressed() && rhs->IsCompressed()) {
- int32_t comparison = memcmp(lhs->GetValueCompressed(),
- rhs->GetValueCompressed(),
- minCount * sizeof(uint8_t));
- if (comparison != 0) {
- return comparison;
+ const uint8_t* lhs_chars = lhs->GetValueCompressed();
+ const uint8_t* rhs_chars = rhs->GetValueCompressed();
+ for (int32_t i = 0; i < min_count; ++i) {
+ int32_t char_diff = static_cast<int32_t>(lhs_chars[i]) - static_cast<int32_t>(rhs_chars[i]);
+ if (char_diff != 0) {
+ return char_diff;
+ }
}
} else if (lhs->IsCompressed() || rhs->IsCompressed()) {
- for (int32_t i = 0; i < minCount; ++i) {
- if (lhs->CharAt(i) != rhs->CharAt(i)) {
- return static_cast<int32_t>(lhs->CharAt(i)) - static_cast<int32_t>(rhs->CharAt(i));
+ const uint8_t* compressed_chars =
+ lhs->IsCompressed() ? lhs->GetValueCompressed() : rhs->GetValueCompressed();
+ const uint16_t* uncompressed_chars = lhs->IsCompressed() ? rhs->GetValue() : lhs->GetValue();
+ for (int32_t i = 0; i < min_count; ++i) {
+ int32_t char_diff =
+ static_cast<int32_t>(compressed_chars[i]) - static_cast<int32_t>(uncompressed_chars[i]);
+ if (char_diff != 0) {
+ return lhs->IsCompressed() ? char_diff : -char_diff;
}
}
} else {
- const uint16_t* lhsChars = lhs->GetValue();
- const uint16_t* rhsChars = rhs->GetValue();
- int32_t otherRes = MemCmp16(lhsChars, rhsChars, minCount);
- if (otherRes != 0) {
- return otherRes;
+ const uint16_t* lhs_chars = lhs->GetValue();
+ const uint16_t* rhs_chars = rhs->GetValue();
+ // FIXME: The MemCmp16() name is misleading. It returns the char difference on mismatch
+ // where memcmp() only guarantees that the returned value has the same sign.
+ int32_t char_diff = MemCmp16(lhs_chars, rhs_chars, min_count);
+ if (char_diff != 0) {
+ return char_diff;
}
}
- return countDiff;
+ return count_diff;
}
void String::VisitRoots(RootVisitor* visitor) {
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 086da60..df0849a 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -218,7 +218,7 @@
{
ScopedObjectAccess soa(env);
ObjPtr<mirror::Object> dex_files_object = soa.Decode<mirror::Object>(cookie);
- mirror::LongArray* long_dex_files = dex_files_object->AsLongArray();
+ ObjPtr<mirror::LongArray> long_dex_files = dex_files_object->AsLongArray();
// Delete dex files associated with this dalvik.system.DexFile since there should not be running
// code using it. dex_files is a vector due to multidex.
ClassLinker* const class_linker = runtime->GetClassLinker();
@@ -279,15 +279,15 @@
Handle<mirror::ClassLoader> class_loader(
hs.NewHandle(soa.Decode<mirror::ClassLoader>(javaLoader)));
class_linker->RegisterDexFile(*dex_file, class_loader.Get());
- mirror::Class* result = class_linker->DefineClass(soa.Self(),
- descriptor.c_str(),
- hash,
- class_loader,
- *dex_file,
- *dex_class_def);
+ ObjPtr<mirror::Class> result = class_linker->DefineClass(soa.Self(),
+ descriptor.c_str(),
+ hash,
+ class_loader,
+ *dex_file,
+ *dex_class_def);
// Add the used dex file. This only required for the DexFile.loadClass API since normal
// class loaders already keep their dex files live.
- class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object>(dexFile).Ptr(),
+ class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object>(dexFile),
class_loader.Get());
if (result != nullptr) {
VLOG(class_linker) << "DexFile_defineClassNative returning " << result
diff --git a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc b/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
index e32545b..db245aa 100644
--- a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
+++ b/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
@@ -150,14 +150,18 @@
Handle<mirror::ClassLoader> class_loader(
handle_scope.NewHandle(soa.Decode<mirror::ClassLoader>(loader)));
class_linker->RegisterDexFile(*dex_file, class_loader.Get());
- mirror::Class* result = class_linker->DefineClass(
- soa.Self(), class_descriptor, hash, class_loader, *dex_file, *dex_class_def);
+ ObjPtr<mirror::Class> result = class_linker->DefineClass(
+ soa.Self(),
+ class_descriptor,
+ hash, class_loader,
+ *dex_file,
+ *dex_class_def);
if (result != nullptr) {
// Ensure the class table has a strong reference to the
// InMemoryClassLoader/DexData instance now that a class has
// been loaded.
- class_linker->InsertDexFileInToClassLoader(
- soa.Decode<mirror::Object>(dexData).Ptr(), class_loader.Get());
+ class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object>(dexData),
+ class_loader.Get());
return soa.AddLocalReference<jclass>(result);
}
}
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index e458e2d..888fddb 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -74,21 +74,23 @@
ThrowNegativeArraySizeException(length);
return nullptr;
}
- mirror::Class* element_class = soa.Decode<mirror::Class>(javaElementClass).Ptr();
+ ObjPtr<mirror::Class> element_class = soa.Decode<mirror::Class>(javaElementClass);
if (UNLIKELY(element_class == nullptr)) {
ThrowNullPointerException("element class == null");
return nullptr;
}
Runtime* runtime = Runtime::Current();
- mirror::Class* array_class =
+ ObjPtr<mirror::Class> array_class =
runtime->GetClassLinker()->FindArrayClass(soa.Self(), &element_class);
if (UNLIKELY(array_class == nullptr)) {
return nullptr;
}
gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentNonMovingAllocator();
- mirror::Array* result = mirror::Array::Alloc<true>(soa.Self(), array_class, length,
- array_class->GetComponentSizeShift(),
- allocator);
+ ObjPtr<mirror::Array> result = mirror::Array::Alloc<true>(soa.Self(),
+ array_class,
+ length,
+ array_class->GetComponentSizeShift(),
+ allocator);
return soa.AddLocalReference<jobject>(result);
}
@@ -99,21 +101,24 @@
ThrowNegativeArraySizeException(length);
return nullptr;
}
- mirror::Class* element_class = soa.Decode<mirror::Class>(javaElementClass).Ptr();
+ ObjPtr<mirror::Class> element_class = soa.Decode<mirror::Class>(javaElementClass);
if (UNLIKELY(element_class == nullptr)) {
ThrowNullPointerException("element class == null");
return nullptr;
}
Runtime* runtime = Runtime::Current();
- mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(),
- &element_class);
+ ObjPtr<mirror::Class> array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(),
+ &element_class);
if (UNLIKELY(array_class == nullptr)) {
return nullptr;
}
gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator();
- mirror::Array* result = mirror::Array::Alloc<true, true>(soa.Self(), array_class, length,
- array_class->GetComponentSizeShift(),
- allocator);
+ ObjPtr<mirror::Array> result = mirror::Array::Alloc<true, true>(
+ soa.Self(),
+ array_class,
+ length,
+ array_class->GetComponentSizeShift(),
+ allocator);
return soa.AddLocalReference<jobject>(result);
}
@@ -127,7 +132,7 @@
ThrowIllegalArgumentException("not an array");
return 0;
}
- if (Runtime::Current()->GetHeap()->IsMovableObject(array.Ptr())) {
+ if (Runtime::Current()->GetHeap()->IsMovableObject(array)) {
ThrowRuntimeException("Trying to get address of movable array object");
return 0;
}
@@ -263,7 +268,7 @@
Runtime::Current()->GetHeap()->GetTaskProcessor()->RunAllTasks(ThreadForEnv(env));
}
-typedef std::map<std::string, mirror::String*> StringTable;
+typedef std::map<std::string, ObjPtr<mirror::String>> StringTable;
class PreloadDexCachesStringsVisitor : public SingleRootVisitor {
public:
@@ -271,7 +276,7 @@
void VisitRoot(mirror::Object* root, const RootInfo& info ATTRIBUTE_UNUSED)
OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::String* string = root->AsString();
+ ObjPtr<mirror::String> string = root->AsString();
table_->operator[](string->ToModifiedUtf8()) = string;
}
@@ -283,7 +288,7 @@
static void PreloadDexCachesResolveString(
Handle<mirror::DexCache> dex_cache, uint32_t string_idx, StringTable& strings)
REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::String* string = dex_cache->GetResolvedString(string_idx);
+ ObjPtr<mirror::String> string = dex_cache->GetResolvedString(string_idx);
if (string != nullptr) {
return;
}
@@ -298,10 +303,11 @@
}
// Based on ClassLinker::ResolveType.
-static void PreloadDexCachesResolveType(
- Thread* self, mirror::DexCache* dex_cache, uint32_t type_idx)
+static void PreloadDexCachesResolveType(Thread* self,
+ ObjPtr<mirror::DexCache> dex_cache,
+ uint32_t type_idx)
REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::Class* klass = dex_cache->GetResolvedType(type_idx);
+ ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(type_idx);
if (klass != nullptr) {
return;
}
@@ -364,7 +370,7 @@
}
const DexFile* dex_file = dex_cache->GetDexFile();
const DexFile::MethodId& method_id = dex_file->GetMethodId(method_idx);
- mirror::Class* klass = dex_cache->GetResolvedType(method_id.class_idx_);
+ ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(method_id.class_idx_);
if (klass == nullptr) {
return;
}
@@ -439,25 +445,25 @@
Thread* const self = Thread::Current();
for (const DexFile* dex_file : class_linker->GetBootClassPath()) {
CHECK(dex_file != nullptr);
- mirror::DexCache* const dex_cache = class_linker->FindDexCache(self, *dex_file, true);
+ ObjPtr<mirror::DexCache> const dex_cache = class_linker->FindDexCache(self, *dex_file, true);
// If dex cache was deallocated, just continue.
if (dex_cache == nullptr) {
continue;
}
for (size_t j = 0; j < dex_cache->NumStrings(); j++) {
- mirror::String* string = dex_cache->GetResolvedString(j);
+ ObjPtr<mirror::String> string = dex_cache->GetResolvedString(j);
if (string != nullptr) {
filled->num_strings++;
}
}
for (size_t j = 0; j < dex_cache->NumResolvedTypes(); j++) {
- mirror::Class* klass = dex_cache->GetResolvedType(j);
+ ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(j);
if (klass != nullptr) {
filled->num_types++;
}
}
for (size_t j = 0; j < dex_cache->NumResolvedFields(); j++) {
- ArtField* field = class_linker->GetResolvedField(j, dex_cache);
+ ArtField* field = class_linker->GetResolvedField(j, dex_cache.Ptr());
if (field != nullptr) {
filled->num_fields++;
}
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index 0dd8cdd..36825cb 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -87,10 +87,10 @@
bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(class_loader == nullptr);
- mirror::Class* c = GetMethod()->GetDeclaringClass();
+ ObjPtr<mirror::Class> c = GetMethod()->GetDeclaringClass();
// c is null for runtime methods.
if (c != nullptr) {
- mirror::Object* cl = c->GetClassLoader();
+ ObjPtr<mirror::Object> cl = c->GetClassLoader();
if (cl != nullptr) {
class_loader = cl;
return false;
@@ -99,7 +99,7 @@
return true;
}
- mirror::Object* class_loader;
+ ObjPtr<mirror::Object> class_loader;
};
ScopedFastNativeObjectAccess soa(env);
ClosestUserClassLoaderVisitor visitor(soa.Self());
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index ceb37c4..ac5dbda 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -497,13 +497,13 @@
// Pending exception from GetDeclaredClasses.
return nullptr;
}
- mirror::Class* class_class = mirror::Class::GetJavaLangClass();
- mirror::Class* class_array_class =
+ ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass();
+ ObjPtr<mirror::Class> class_array_class =
Runtime::Current()->GetClassLinker()->FindArrayClass(soa.Self(), &class_class);
if (class_array_class == nullptr) {
return nullptr;
}
- mirror::ObjectArray<mirror::Class>* empty_array =
+ ObjPtr<mirror::ObjectArray<mirror::Class>> empty_array =
mirror::ObjectArray<mirror::Class>::Alloc(soa.Self(), class_array_class, 0);
return soa.AddLocalReference<jobjectArray>(empty_array);
}
@@ -527,7 +527,7 @@
if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
return nullptr;
}
- mirror::Object* method = annotations::GetEnclosingMethod(klass);
+ ObjPtr<mirror::Object> method = annotations::GetEnclosingMethod(klass);
if (method != nullptr) {
if (soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Constructor) ==
method->GetClass()) {
@@ -544,7 +544,7 @@
if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
return nullptr;
}
- mirror::Object* method = annotations::GetEnclosingMethod(klass);
+ ObjPtr<mirror::Object> method = annotations::GetEnclosingMethod(klass);
if (method != nullptr) {
if (soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Method) ==
method->GetClass()) {
@@ -660,7 +660,7 @@
// Invoke the string allocator to return an empty string for the string class.
if (klass->IsStringClass()) {
gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
- mirror::Object* obj = mirror::String::AllocEmptyString<true>(soa.Self(), allocator_type);
+ ObjPtr<mirror::Object> obj = mirror::String::AllocEmptyString<true>(soa.Self(), allocator_type);
if (UNLIKELY(soa.Self()->IsExceptionPending())) {
return nullptr;
} else {
diff --git a/runtime/native/java_lang_DexCache.cc b/runtime/native/java_lang_DexCache.cc
index 1fd7ed1..71379a5 100644
--- a/runtime/native/java_lang_DexCache.cc
+++ b/runtime/native/java_lang_DexCache.cc
@@ -68,7 +68,7 @@
ScopedFastNativeObjectAccess soa(env);
ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
CHECK_LT(static_cast<size_t>(type_index), dex_cache->NumResolvedTypes());
- dex_cache->SetResolvedType(type_index, soa.Decode<mirror::Class>(type).Ptr());
+ dex_cache->SetResolvedType(type_index, soa.Decode<mirror::Class>(type));
}
static void DexCache_setResolvedString(JNIEnv* env, jobject javaDexCache, jint string_index,
@@ -76,7 +76,7 @@
ScopedFastNativeObjectAccess soa(env);
ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
CHECK_LT(static_cast<size_t>(string_index), dex_cache->GetDexFile()->NumStringIds());
- dex_cache->SetResolvedString(string_index, soa.Decode<mirror::String>(string).Ptr());
+ dex_cache->SetResolvedString(string_index, soa.Decode<mirror::String>(string));
}
static JNINativeMethod gMethods[] = {
diff --git a/runtime/native/java_lang_String.cc b/runtime/native/java_lang_String.cc
index 5a49c20..ea266d1 100644
--- a/runtime/native/java_lang_String.cc
+++ b/runtime/native/java_lang_String.cc
@@ -57,7 +57,8 @@
int32_t length_this = string_this->GetLength();
int32_t length_arg = string_arg->GetLength();
if (length_arg > 0 && length_this > 0) {
- mirror::String* result = mirror::String::AllocFromStrings(soa.Self(), string_this, string_arg);
+ ObjPtr<mirror::String> result =
+ mirror::String::AllocFromStrings(soa.Self(), string_this, string_arg);
return soa.AddLocalReference<jstring>(result);
}
jobject string_original = (length_this == 0) ? java_string_arg : java_this;
@@ -76,8 +77,11 @@
StackHandleScope<1> hs(soa.Self());
Handle<mirror::String> string_this(hs.NewHandle(soa.Decode<mirror::String>(java_this)));
gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
- mirror::String* result = mirror::String::AllocFromString<true>(soa.Self(), length, string_this,
- start, allocator_type);
+ ObjPtr<mirror::String> result = mirror::String::AllocFromString<true>(soa.Self(),
+ length,
+ string_this,
+ start,
+ allocator_type);
return soa.AddLocalReference<jstring>(result);
}
diff --git a/runtime/native/java_lang_StringFactory.cc b/runtime/native/java_lang_StringFactory.cc
index 119f2b8..e0738a4 100644
--- a/runtime/native/java_lang_StringFactory.cc
+++ b/runtime/native/java_lang_StringFactory.cc
@@ -44,9 +44,12 @@
return nullptr;
}
gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
- mirror::String* result = mirror::String::AllocFromByteArray<true>(soa.Self(), byte_count,
- byte_array, offset, high,
- allocator_type);
+ ObjPtr<mirror::String> result = mirror::String::AllocFromByteArray<true>(soa.Self(),
+ byte_count,
+ byte_array,
+ offset,
+ high,
+ allocator_type);
return soa.AddLocalReference<jstring>(result);
}
@@ -58,9 +61,11 @@
StackHandleScope<1> hs(soa.Self());
Handle<mirror::CharArray> char_array(hs.NewHandle(soa.Decode<mirror::CharArray>(java_data)));
gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
- mirror::String* result = mirror::String::AllocFromCharArray<true>(soa.Self(), char_count,
- char_array, offset,
- allocator_type);
+ ObjPtr<mirror::String> result = mirror::String::AllocFromCharArray<true>(soa.Self(),
+ char_count,
+ char_array,
+ offset,
+ allocator_type);
return soa.AddLocalReference<jstring>(result);
}
@@ -73,8 +78,11 @@
StackHandleScope<1> hs(soa.Self());
Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String>(to_copy)));
gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
- mirror::String* result = mirror::String::AllocFromString<true>(soa.Self(), string->GetLength(),
- string, 0, allocator_type);
+ ObjPtr<mirror::String> result = mirror::String::AllocFromString<true>(soa.Self(),
+ string->GetLength(),
+ string,
+ 0,
+ allocator_type);
return soa.AddLocalReference<jstring>(result);
}
diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc
index 3f5fa73..eaf2d65 100644
--- a/runtime/native/java_lang_System.cc
+++ b/runtime/native/java_lang_System.cc
@@ -71,8 +71,8 @@
ThrowArrayStoreException_NotAnArray("destination", dstObject);
return;
}
- mirror::Array* srcArray = srcObject->AsArray();
- mirror::Array* dstArray = dstObject->AsArray();
+ ObjPtr<mirror::Array> srcArray = srcObject->AsArray();
+ ObjPtr<mirror::Array> dstArray = dstObject->AsArray();
// Bounds checking.
if (UNLIKELY(srcPos < 0) || UNLIKELY(dstPos < 0) || UNLIKELY(count < 0) ||
@@ -85,8 +85,8 @@
return;
}
- mirror::Class* dstComponentType = dstArray->GetClass()->GetComponentType();
- mirror::Class* srcComponentType = srcArray->GetClass()->GetComponentType();
+ ObjPtr<mirror::Class> dstComponentType = dstArray->GetClass()->GetComponentType();
+ ObjPtr<mirror::Class> srcComponentType = srcArray->GetClass()->GetComponentType();
Primitive::Type dstComponentPrimitiveType = dstComponentType->GetPrimitiveType();
if (LIKELY(srcComponentType == dstComponentType)) {
@@ -143,8 +143,10 @@
return;
}
// Arrays hold distinct types and so therefore can't alias - use memcpy instead of memmove.
- mirror::ObjectArray<mirror::Object>* dstObjArray = dstArray->AsObjectArray<mirror::Object>();
- mirror::ObjectArray<mirror::Object>* srcObjArray = srcArray->AsObjectArray<mirror::Object>();
+ ObjPtr<mirror::ObjectArray<mirror::Object>> dstObjArray =
+ dstArray->AsObjectArray<mirror::Object>();
+ ObjPtr<mirror::ObjectArray<mirror::Object>> srcObjArray =
+ srcArray->AsObjectArray<mirror::Object>();
// If we're assigning into say Object[] then we don't need per element checks.
if (dstComponentType->IsAssignableFrom(srcComponentType)) {
dstObjArray->AssignableMemcpy(dstPos, srcObjArray, srcPos, count);
@@ -157,8 +159,9 @@
// Template to convert general array to that of its specific primitive type.
template <typename T>
-inline T* AsPrimitiveArray(mirror::Array* array) {
- return down_cast<T*>(array);
+inline ObjPtr<T> AsPrimitiveArray(ObjPtr<mirror::Array> array)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return ObjPtr<T>::DownCast(array);
}
template <typename T, Primitive::Type kPrimType>
@@ -168,8 +171,8 @@
ObjPtr<mirror::Object> srcObject = soa.Decode<mirror::Object>(javaSrc);
ObjPtr<mirror::Object> dstObject = soa.Decode<mirror::Object>(javaDst);
DCHECK(dstObject != nullptr);
- mirror::Array* srcArray = srcObject->AsArray();
- mirror::Array* dstArray = dstObject->AsArray();
+ ObjPtr<mirror::Array> srcArray = srcObject->AsArray();
+ ObjPtr<mirror::Array> dstArray = dstObject->AsArray();
DCHECK_GE(count, 0);
DCHECK_EQ(srcArray->GetClass(), dstArray->GetClass());
DCHECK_EQ(srcArray->GetClass()->GetComponentType()->GetPrimitiveType(), kPrimType);
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index 73d12f1..1fe89bf 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -37,24 +37,24 @@
ClassLinker* cl = Runtime::Current()->GetClassLinker();
std::string descriptor(DotToDescriptor(name.c_str()));
const size_t descriptor_hash = ComputeModifiedUtf8Hash(descriptor.c_str());
- mirror::Class* c = cl->LookupClass(soa.Self(),
- descriptor.c_str(),
- descriptor_hash,
- loader.Ptr());
+ ObjPtr<mirror::Class> c = cl->LookupClass(soa.Self(),
+ descriptor.c_str(),
+ descriptor_hash,
+ loader.Ptr());
if (c != nullptr && c->IsResolved()) {
return soa.AddLocalReference<jclass>(c);
}
// If class is erroneous, throw the earlier failure, wrapped in certain cases. See b/28787733.
if (c != nullptr && c->IsErroneous()) {
- cl->ThrowEarlierClassFailure(c);
+ cl->ThrowEarlierClassFailure(c.Ptr());
Thread* self = soa.Self();
- mirror::Class* eiie_class =
+ ObjPtr<mirror::Class> eiie_class =
self->DecodeJObject(WellKnownClasses::java_lang_ExceptionInInitializerError)->AsClass();
- mirror::Class* iae_class =
+ ObjPtr<mirror::Class> iae_class =
self->DecodeJObject(WellKnownClasses::java_lang_IllegalAccessError)->AsClass();
- mirror::Class* ncdfe_class =
+ ObjPtr<mirror::Class> ncdfe_class =
self->DecodeJObject(WellKnownClasses::java_lang_NoClassDefFoundError)->AsClass();
- mirror::Class* exception = self->GetException()->GetClass();
+ ObjPtr<mirror::Class> exception = self->GetException()->GetClass();
if (exception == eiie_class || exception == iae_class || exception == ncdfe_class) {
self->ThrowNewWrappedException("Ljava/lang/ClassNotFoundException;",
PrettyDescriptor(c).c_str());
diff --git a/runtime/native/java_lang_ref_FinalizerReference.cc b/runtime/native/java_lang_ref_FinalizerReference.cc
index 1f03c7c..c7d06f4 100644
--- a/runtime/native/java_lang_ref_FinalizerReference.cc
+++ b/runtime/native/java_lang_ref_FinalizerReference.cc
@@ -28,8 +28,7 @@
static jboolean FinalizerReference_makeCircularListIfUnenqueued(JNIEnv* env, jobject javaThis) {
ScopedFastNativeObjectAccess soa(env);
ObjPtr<mirror::FinalizerReference> ref = soa.Decode<mirror::FinalizerReference>(javaThis);
- return Runtime::Current()->GetHeap()->GetReferenceProcessor()->MakeCircularListIfUnenqueued(
- ref.Ptr());
+ return Runtime::Current()->GetHeap()->GetReferenceProcessor()->MakeCircularListIfUnenqueued(ref);
}
static JNINativeMethod gMethods[] = {
diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc
index 6f2da33..d827f81 100644
--- a/runtime/native/java_lang_reflect_Array.cc
+++ b/runtime/native/java_lang_reflect_Array.cc
@@ -40,8 +40,9 @@
DCHECK_EQ(dimensions_obj->GetClass()->GetComponentType()->GetPrimitiveType(),
Primitive::kPrimInt);
Handle<mirror::IntArray> dimensions_array(
- hs.NewHandle(down_cast<mirror::IntArray*>(dimensions_obj.Ptr())));
- mirror::Array* new_array = mirror::Array::CreateMultiArray(soa.Self(), element_class,
+ hs.NewHandle(ObjPtr<mirror::IntArray>::DownCast(dimensions_obj)));
+ mirror::Array* new_array = mirror::Array::CreateMultiArray(soa.Self(),
+ element_class,
dimensions_array);
return soa.AddLocalReference<jobject>(new_array);
}
@@ -53,17 +54,20 @@
ThrowNegativeArraySizeException(length);
return nullptr;
}
- mirror::Class* element_class = soa.Decode<mirror::Class>(javaElementClass).Ptr();
+ ObjPtr<mirror::Class> element_class = soa.Decode<mirror::Class>(javaElementClass);
Runtime* runtime = Runtime::Current();
ClassLinker* class_linker = runtime->GetClassLinker();
- mirror::Class* array_class = class_linker->FindArrayClass(soa.Self(), &element_class);
+ ObjPtr<mirror::Class> array_class = class_linker->FindArrayClass(soa.Self(), &element_class);
if (UNLIKELY(array_class == nullptr)) {
CHECK(soa.Self()->IsExceptionPending());
return nullptr;
}
DCHECK(array_class->IsObjectArrayClass());
- mirror::Array* new_array = mirror::ObjectArray<mirror::Object*>::Alloc(
- soa.Self(), array_class, length, runtime->GetHeap()->GetCurrentAllocator());
+ ObjPtr<mirror::Array> new_array = mirror::ObjectArray<mirror::Object*>::Alloc(
+ soa.Self(),
+ array_class,
+ length,
+ runtime->GetHeap()->GetCurrentAllocator());
return soa.AddLocalReference<jobject>(new_array);
}
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index 505f85d..a81ba7d 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -39,13 +39,13 @@
annotations::GetExceptionTypesForMethod(method);
if (result_array == nullptr) {
// Return an empty array instead of a null pointer.
- mirror::Class* class_class = mirror::Class::GetJavaLangClass();
- mirror::Class* class_array_class =
+ ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass();
+ ObjPtr<mirror::Class> class_array_class =
Runtime::Current()->GetClassLinker()->FindArrayClass(soa.Self(), &class_class);
if (class_array_class == nullptr) {
return nullptr;
}
- mirror::ObjectArray<mirror::Class>* empty_array =
+ ObjPtr<mirror::ObjectArray<mirror::Class>> empty_array =
mirror::ObjectArray<mirror::Class>::Alloc(soa.Self(), class_array_class, 0);
return soa.AddLocalReference<jobjectArray>(empty_array);
} else {
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index b5f2f7c..a6589bc 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -44,7 +44,7 @@
ScopedFastNativeObjectAccess soa(env);
ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
if (method->GetDeclaringClass()->IsProxyClass()) {
- mirror::Class* klass = method->GetDeclaringClass();
+ ObjPtr<mirror::Class> klass = method->GetDeclaringClass();
int throws_index = -1;
size_t i = 0;
for (const auto& m : klass->GetDeclaredVirtualMethods(kRuntimePointerSize)) {
@@ -62,8 +62,8 @@
annotations::GetExceptionTypesForMethod(method);
if (result_array == nullptr) {
// Return an empty array instead of a null pointer
- mirror::Class* class_class = mirror::Class::GetJavaLangClass();
- mirror::Class* class_array_class =
+ ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass();
+ ObjPtr<mirror::Class> class_array_class =
Runtime::Current()->GetClassLinker()->FindArrayClass(soa.Self(), &class_class);
if (class_array_class == nullptr) {
return nullptr;
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index 670c4ac..cdf4b14 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -305,7 +305,8 @@
}
template<typename T>
-static void copyToArray(jlong srcAddr, mirror::PrimitiveArray<T>* array,
+static void copyToArray(jlong srcAddr,
+ ObjPtr<mirror::PrimitiveArray<T>> array,
size_t array_offset,
size_t size)
REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -318,7 +319,8 @@
}
template<typename T>
-static void copyFromArray(jlong dstAddr, mirror::PrimitiveArray<T>* array,
+static void copyFromArray(jlong dstAddr,
+ ObjPtr<mirror::PrimitiveArray<T>> array,
size_t array_offset,
size_t size)
REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -347,15 +349,15 @@
size_t sz = (size_t)size;
size_t dst_offset = (size_t)dstOffset;
ObjPtr<mirror::Object> dst = soa.Decode<mirror::Object>(dstObj);
- mirror::Class* component_type = dst->GetClass()->GetComponentType();
+ ObjPtr<mirror::Class> component_type = dst->GetClass()->GetComponentType();
if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
- copyToArray(srcAddr, dst->AsByteSizedArray(), dst_offset, sz);
+ copyToArray(srcAddr, MakeObjPtr(dst->AsByteSizedArray()), dst_offset, sz);
} else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
- copyToArray(srcAddr, dst->AsShortSizedArray(), dst_offset, sz);
+ copyToArray(srcAddr, MakeObjPtr(dst->AsShortSizedArray()), dst_offset, sz);
} else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
- copyToArray(srcAddr, dst->AsIntArray(), dst_offset, sz);
+ copyToArray(srcAddr, MakeObjPtr(dst->AsIntArray()), dst_offset, sz);
} else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
- copyToArray(srcAddr, dst->AsLongArray(), dst_offset, sz);
+ copyToArray(srcAddr, MakeObjPtr(dst->AsLongArray()), dst_offset, sz);
} else {
ThrowIllegalAccessException("not a primitive array");
}
@@ -378,15 +380,15 @@
size_t sz = (size_t)size;
size_t src_offset = (size_t)srcOffset;
ObjPtr<mirror::Object> src = soa.Decode<mirror::Object>(srcObj);
- mirror::Class* component_type = src->GetClass()->GetComponentType();
+ ObjPtr<mirror::Class> component_type = src->GetClass()->GetComponentType();
if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
- copyFromArray(dstAddr, src->AsByteSizedArray(), src_offset, sz);
+ copyFromArray(dstAddr, MakeObjPtr(src->AsByteSizedArray()), src_offset, sz);
} else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
- copyFromArray(dstAddr, src->AsShortSizedArray(), src_offset, sz);
+ copyFromArray(dstAddr, MakeObjPtr(src->AsShortSizedArray()), src_offset, sz);
} else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
- copyFromArray(dstAddr, src->AsIntArray(), src_offset, sz);
+ copyFromArray(dstAddr, MakeObjPtr(src->AsIntArray()), src_offset, sz);
} else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
- copyFromArray(dstAddr, src->AsLongArray(), src_offset, sz);
+ copyFromArray(dstAddr, MakeObjPtr(src->AsLongArray()), src_offset, sz);
} else {
ThrowIllegalAccessException("not a primitive array");
}
diff --git a/runtime/openjdkjvmti/events.cc b/runtime/openjdkjvmti/events.cc
index 450f85e..59e01ea 100644
--- a/runtime/openjdkjvmti/events.cc
+++ b/runtime/openjdkjvmti/events.cc
@@ -40,6 +40,8 @@
#include "mirror/object.h"
#include "runtime.h"
#include "ScopedLocalRef.h"
+#include "scoped_thread_state_change-inl.h"
+#include "thread-inl.h"
namespace openjdkjvmti {
@@ -172,6 +174,10 @@
};
static void SetupObjectAllocationTracking(art::gc::AllocationListener* listener, bool enable) {
+ // We must not hold the mutator lock here, but if we're in FastJNI, for example, we might. For
+ // now, do a workaround: (possibly) acquire and release.
+ art::ScopedObjectAccess soa(art::Thread::Current());
+ art::ScopedThreadSuspension sts(soa.Self(), art::ThreadState::kSuspended);
if (enable) {
art::Runtime::Current()->GetHeap()->SetAllocationListener(listener);
} else {
@@ -213,6 +219,8 @@
return ERR(INVALID_EVENT_TYPE);
}
+ bool old_state = global_mask.Test(event);
+
if (mode == JVMTI_ENABLE) {
env->event_masks.EnableEvent(thread, event);
global_mask.Set(event);
@@ -233,8 +241,12 @@
global_mask.Set(event, union_value);
}
+ bool new_state = global_mask.Test(event);
+
// Handle any special work required for the event type.
- HandleEventType(event, mode == JVMTI_ENABLE);
+ if (new_state != old_state) {
+ HandleEventType(event, mode == JVMTI_ENABLE);
+ }
return ERR(NONE);
}
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index a84668b..626d9cf 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -748,7 +748,7 @@
DCHECK(result->IsObjectClass());
return result;
}
- mirror::Class* common_elem = ClassJoin(s_ct, t_ct);
+ ObjPtr<mirror::Class> common_elem = ClassJoin(s_ct, t_ct);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
mirror::Class* array_class = class_linker->FindArrayClass(Thread::Current(), &common_elem);
DCHECK(array_class != nullptr);
diff --git a/test/021-string2/src/Main.java b/test/021-string2/src/Main.java
index d1ea0b1..a848fba 100644
--- a/test/021-string2/src/Main.java
+++ b/test/021-string2/src/Main.java
@@ -89,5 +89,424 @@
Method fromUTF8ByteArray = Strings.getDeclaredMethod("fromUTF8ByteArray", byte[].class);
String result = (String) fromUTF8ByteArray.invoke(null, new byte[] {'O', 'K'});
System.out.println(result);
+
+ testCompareToAndEquals();
+ testIndexOf();
}
+
+ public static void testCompareToAndEquals() {
+ String[] strings = {
+ // Special: empty string.
+ "",
+ // Category 0, ASCII strings:
+ // "0123456789abcdef".substring(0, index + 1)
+ "0",
+ "01",
+ "012",
+ "0123",
+ "01234",
+ "012345",
+ "0123456",
+ "01234567",
+ "012345678",
+ "0123456789",
+ "0123456789a",
+ "0123456789ab",
+ "0123456789abc",
+ "0123456789abcd",
+ "0123456789abcde",
+ "0123456789abcdef",
+ // Category 1, ASCII strings:
+ // "0123456789abcdef".substring(0, index) + "x"
+ "x",
+ "0x",
+ "01x",
+ "012x",
+ "0123x",
+ "01234x",
+ "012345x",
+ "0123456x",
+ "01234567x",
+ "012345678x",
+ "0123456789x",
+ "0123456789ax",
+ "0123456789abx",
+ "0123456789abcx",
+ "0123456789abcdx",
+ "0123456789abcdex",
+ // Category 2, ASCII strings,
+ // "0123456789abcdef".substring(0, index) + "x" +
+ // "0123456789abcdef".substring(index + 1)
+ "x123456789abcdef",
+ "0x23456789abcdef",
+ "01x3456789abcdef",
+ "012x456789abcdef",
+ "0123x56789abcdef",
+ "01234x6789abcdef",
+ "012345x789abcdef",
+ "0123456x89abcdef",
+ "01234567x9abcdef",
+ "012345678xabcdef",
+ "0123456789xbcdef",
+ "0123456789axcdef",
+ "0123456789abxdef",
+ "0123456789abcxef",
+ "0123456789abcdxf",
+ "0123456789abcdex",
+ // Category 3, ASCII strings:
+ // "z" + "0123456789abcdef".substring(1, index + 1)
+ "z",
+ "z1",
+ "z12",
+ "z123",
+ "z1234",
+ "z12345",
+ "z123456",
+ "z1234567",
+ "z12345678",
+ "z123456789",
+ "z123456789a",
+ "z123456789ab",
+ "z123456789abc",
+ "z123456789abcd",
+ "z123456789abcde",
+ "z123456789abcdef",
+ // Category 4, non-ASCII strings:
+ // "0123456789abcdef".substring(0, index) + "\u0440"
+ "\u0440",
+ "0\u0440",
+ "01\u0440",
+ "012\u0440",
+ "0123\u0440",
+ "01234\u0440",
+ "012345\u0440",
+ "0123456\u0440",
+ "01234567\u0440",
+ "012345678\u0440",
+ "0123456789\u0440",
+ "0123456789a\u0440",
+ "0123456789ab\u0440",
+ "0123456789abc\u0440",
+ "0123456789abcd\u0440",
+ "0123456789abcde\u0440",
+ // Category 5, non-ASCII strings:
+ // "0123456789abcdef".substring(0, index) + "\u0440" +
+ // "0123456789abcdef".substring(index + 1)
+ "\u0440123456789abcdef",
+ "0\u044023456789abcdef",
+ "01\u04403456789abcdef",
+ "012\u0440456789abcdef",
+ "0123\u044056789abcdef",
+ "01234\u04406789abcdef",
+ "012345\u0440789abcdef",
+ "0123456\u044089abcdef",
+ "01234567\u04409abcdef",
+ "012345678\u0440abcdef",
+ "0123456789\u0440bcdef",
+ "0123456789a\u0440cdef",
+ "0123456789ab\u0440def",
+ "0123456789abc\u0440ef",
+ "0123456789abcd\u0440f",
+ "0123456789abcde\u0440",
+ // Category 6, ASCII strings:
+ // "\u0443" + "0123456789abcdef".substring(1, index + 1)
+ "\u0443",
+ "\u04431",
+ "\u044312",
+ "\u0443123",
+ "\u04431234",
+ "\u044312345",
+ "\u0443123456",
+ "\u04431234567",
+ "\u044312345678",
+ "\u0443123456789",
+ "\u0443123456789a",
+ "\u0443123456789ab",
+ "\u0443123456789abc",
+ "\u0443123456789abcd",
+ "\u0443123456789abcde",
+ "\u0443123456789abcdef",
+ // Category 7, non-ASCII strings:
+ // "0123456789abcdef".substring(0, index) + "\u0482"
+ "\u0482",
+ "0\u0482",
+ "01\u0482",
+ "012\u0482",
+ "0123\u0482",
+ "01234\u0482",
+ "012345\u0482",
+ "0123456\u0482",
+ "01234567\u0482",
+ "012345678\u0482",
+ "0123456789\u0482",
+ "0123456789a\u0482",
+ "0123456789ab\u0482",
+ "0123456789abc\u0482",
+ "0123456789abcd\u0482",
+ "0123456789abcde\u0482",
+ // Category 8, non-ASCII strings:
+ // "0123456789abcdef".substring(0, index) + "\u0482" +
+ // "0123456789abcdef".substring(index + 1)
+ "\u0482123456789abcdef",
+ "0\u048223456789abcdef",
+ "01\u04823456789abcdef",
+ "012\u0482456789abcdef",
+ "0123\u048256789abcdef",
+ "01234\u04826789abcdef",
+ "012345\u0482789abcdef",
+ "0123456\u048289abcdef",
+ "01234567\u04829abcdef",
+ "012345678\u0482abcdef",
+ "0123456789\u0482bcdef",
+ "0123456789a\u0482cdef",
+ "0123456789ab\u0482def",
+ "0123456789abc\u0482ef",
+ "0123456789abcd\u0482f",
+ "0123456789abcde\u0482",
+ // Category 9, ASCII strings:
+ // "\u0489" + "0123456789abcdef".substring(1, index + 1)
+ "\u0489",
+ "\u04891",
+ "\u048912",
+ "\u0489123",
+ "\u04891234",
+ "\u048912345",
+ "\u0489123456",
+ "\u04891234567",
+ "\u048912345678",
+ "\u0489123456789",
+ "\u0489123456789a",
+ "\u0489123456789ab",
+ "\u0489123456789abc",
+ "\u0489123456789abcd",
+ "\u0489123456789abcde",
+ "\u0489123456789abcdef",
+ };
+ int length = strings.length;
+ Assert.assertEquals(1 + 16 * 10, length);
+ for (int i = 0; i != length; ++i) {
+ String lhs = strings[i];
+ for (int j = 0; j != length; ++j) {
+ String rhs = strings[j];
+ int result = $noinline$compareTo(lhs, rhs);
+ final int expected;
+ if (i == 0 || j == 0 || i == j) {
+ // One of the strings is empty or the strings are the same.
+ expected = lhs.length() - rhs.length();
+ } else {
+ int i_category = (i - 1) / 16;
+ int i_index = (i - 1) % 16;
+ int j_category = (j - 1) / 16;
+ int j_index = (j - 1) % 16;
+ int min_ij_index = (i_index < j_index) ? i_index : j_index;
+ if (i_category == j_category) {
+ switch (i_category) {
+ case 0: case 3: case 6: case 9:
+ // Differs in length.
+ expected = lhs.length() - rhs.length();
+ break;
+ case 1: case 2: case 4: case 5: case 7: case 8:
+ // Differs in charAt(min_ij_index).
+ expected = lhs.charAt(min_ij_index) - rhs.charAt(min_ij_index);
+ break;
+ default: throw new Error("Unexpected category.");
+ }
+ } else if (i_category == 3 || i_category == 6 || i_category == 9 ||
+ j_category == 3 || j_category == 6 || j_category == 9) {
+ // In these categories, charAt(0) differs from other categories' strings.
+ expected = lhs.charAt(0) - rhs.charAt(0);
+ } else if (// Category 0 string is a prefix to any longer string in
+ // remaining categories.
+ (i_category == 0 && i_index < j_index) ||
+ (j_category == 0 && j_index < i_index) ||
+ // Category 2 string is a prefix to category 3 string at the same
+ // index. Similar for categories 4 and 5 and also 7 and 8.
+ // This includes matching last strings of these pairs of categories.
+ (i_index == j_index &&
+ ((i_category == 1 && j_category == 2) ||
+ (i_category == 2 && j_category == 1) ||
+ (i_category == 4 && j_category == 5) ||
+ (i_category == 5 && j_category == 4) ||
+ (i_category == 7 && j_category == 8) ||
+ (i_category == 8 && j_category == 7)))) {
+ // Differs in length.
+ expected = lhs.length() - rhs.length();
+ } else {
+ // The remaining cases differ in charAt(min_ij_index), the characters
+ // before that are "0123456789abcdef".substring(0, min_ij_index).
+ for (int k = 0; k < min_ij_index; ++k) {
+ Assert.assertEquals("0123456789abcdef".charAt(k), lhs.charAt(k));
+ Assert.assertEquals("0123456789abcdef".charAt(k), rhs.charAt(k));
+ }
+ expected = lhs.charAt(min_ij_index) - rhs.charAt(min_ij_index);
+ Assert.assertFalse(expected == 0);
+ }
+ }
+ if (expected != result) {
+ throw new Error(
+ "Mismatch at i=" + i + ", j=" + j + ", expected=" + expected +
+ ", result=" + result);
+ }
+ boolean equalsExpected =
+ (i == j) ||
+ // Last string in categories 1 and 2.
+ (i == 32 && j == 48) || (i == 48 && j == 32) ||
+ // Last string in categories 4 and 5.
+ (i == 80 && j == 96) || (i == 96 && j == 80) ||
+ // Last string in categories 7 and 8.
+ (i == 128 && j == 144) || (i == 144 && j == 128);
+ Assert.assertEquals(equalsExpected, $noinline$equals(lhs, rhs));
+ }
+ }
+
+ try {
+ $noinline$compareTo("", null);
+ Assert.fail();
+ } catch (NullPointerException expected) {
+ }
+ try {
+ $noinline$compareTo(null, "");
+ Assert.fail();
+ } catch (NullPointerException expected) {
+ }
+
+ Assert.assertFalse($noinline$equals("", null));
+ try {
+ $noinline$equals(null, "");
+ Assert.fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ public static void testIndexOf() {
+ String[] prefixes = {
+ "",
+ "0",
+ "01",
+ "012",
+ "0123",
+ "01234",
+ "012345",
+ "0123456",
+ "01234567",
+ "012345678",
+ "0123456789",
+ "0123456789a",
+ "0123456789ab",
+ "0123456789abc",
+ "0123456789abcd",
+ "0123456789abcdef",
+ };
+ String[] cores = {
+ "",
+ "x",
+ "xx",
+ "xxx",
+ "xxxx",
+ "xxxxx",
+ "xxxxxx",
+ "xxxxxxx",
+ "xxxxxxxx",
+ "xzx",
+ "xxzx",
+ "xxxzx",
+ "xxxxzx",
+ "xxxxxzx",
+ "xxxxxxzx",
+ "xxxxxxxzx",
+ "xxxxxxxxzx",
+ "\u0440",
+ "\u0440\u0440",
+ "\u0440\u0440\u0440",
+ "\u0440\u0440\u0440\u0440",
+ "\u0440\u0440\u0440\u0440\u0440",
+ "\u0440\u0440\u0440\u0440\u0440\u0440",
+ "\u0440\u0440\u0440\u0440\u0440\u0440\u0440",
+ "\u0440\u0440\u0440\u0440\u0440\u0440\u0440\u0440",
+ "\u0440z\u0440",
+ "\u0440\u0440z\u0440",
+ "\u0440\u0440\u0440z\u0440",
+ "\u0440\u0440\u0440\u0440z\u0440",
+ "\u0440\u0440\u0440\u0440\u0440z\u0440",
+ "\u0440\u0440\u0440\u0440\u0440\u0440z\u0440",
+ "\u0440\u0440\u0440\u0440\u0440\u0440\u0440z\u0440",
+ "\u0440\u0440\u0440\u0440\u0440\u0440\u0440\u0440z\u0440",
+ };
+ String[] suffixes = {
+ "",
+ "y",
+ "yy",
+ "yyy",
+ "yyyy",
+ "yyyyy",
+ "yyyyyy",
+ "yyyyyyy",
+ "yyyyyyyy",
+ "\u0441",
+ "y\u0441",
+ "yy\u0441",
+ "yyy\u0441",
+ "yyyy\u0441",
+ "yyyyy\u0441",
+ "yyyyyy\u0441",
+ "yyyyyyy\u0441",
+ "yyyyyyyy\u0441",
+ };
+ for (String p : prefixes) {
+ for (String c : cores) {
+ for (String s : suffixes) {
+ String full = p + c + s;
+ int expX = (c.isEmpty() || c.charAt(0) != 'x') ? -1 : p.length();
+ int exp0440 = (c.isEmpty() || c.charAt(0) != '\u0440') ? -1 : p.length();
+ Assert.assertEquals(expX, $noinline$indexOf(full, 'x'));
+ Assert.assertEquals(exp0440, $noinline$indexOf(full, '\u0440'));
+ Assert.assertEquals(expX, $noinline$indexOf(full, 'x', -1));
+ Assert.assertEquals(exp0440, $noinline$indexOf(full, '\u0440', -1));
+ Assert.assertEquals(-1, $noinline$indexOf(full, 'x', full.length() + 1));
+ Assert.assertEquals(-1, $noinline$indexOf(full, '\u0440', full.length() + 1));
+ for (int from = 0; from != full.length(); ++from) {
+ final int eX;
+ final int e0440;
+ if (from <= p.length()) {
+ eX = expX;
+ e0440 = exp0440;
+ } else if (from >= p.length() + c.length()) {
+ eX = -1;
+ e0440 = -1;
+ } else if (full.charAt(from) == 'z') {
+ eX = (full.charAt(from + 1) != 'x') ? -1 : from + 1;
+ e0440 = (full.charAt(from + 1) != '\u0440') ? -1 : from + 1;
+ } else {
+ eX = (full.charAt(from) != 'x') ? -1 : from;
+ e0440 = (full.charAt(from) != '\u0440') ? -1 : from;
+ }
+ Assert.assertEquals(eX, $noinline$indexOf(full, 'x', from));
+ Assert.assertEquals(e0440, $noinline$indexOf(full, '\u0440', from));
+ }
+ }
+ }
+ }
+ }
+
+ public static int $noinline$compareTo(String lhs, String rhs) {
+ if (doThrow) { throw new Error(); }
+ return lhs.compareTo(rhs);
+ }
+
+ public static boolean $noinline$equals(String lhs, String rhs) {
+ if (doThrow) { throw new Error(); }
+ return lhs.equals(rhs);
+ }
+
+ public static int $noinline$indexOf(String lhs, int ch) {
+ if (doThrow) { throw new Error(); }
+ return lhs.indexOf(ch);
+ }
+
+ public static int $noinline$indexOf(String lhs, int ch, int fromIndex) {
+ if (doThrow) { throw new Error(); }
+ return lhs.indexOf(ch, fromIndex);
+ }
+
+ public static boolean doThrow = false;
}
diff --git a/test/530-checker-lse/src/Main.java b/test/530-checker-lse/src/Main.java
index 89875d7..6b0dedf 100644
--- a/test/530-checker-lse/src/Main.java
+++ b/test/530-checker-lse/src/Main.java
@@ -717,6 +717,33 @@
return sumWithFilter(array, filter);
}
+ private static int mI = 0;
+ private static float mF = 0f;
+
+ /// CHECK-START: float Main.testAllocationEliminationWithLoops() load_store_elimination (before)
+ /// CHECK: NewInstance
+ /// CHECK: NewInstance
+ /// CHECK: NewInstance
+
+ /// CHECK-START: float Main.testAllocationEliminationWithLoops() load_store_elimination (after)
+ /// CHECK-NOT: NewInstance
+
+ private static float testAllocationEliminationWithLoops() {
+ for (int i0 = 0; i0 < 5; i0++) {
+ for (int i1 = 0; i1 < 5; i1++) {
+ for (int i2 = 0; i2 < 5; i2++) {
+ int lI0 = ((int) new Integer(((int) new Integer(mI))));
+ if (((boolean) new Boolean(false))) {
+ for (int i3 = 576 - 1; i3 >= 0; i3--) {
+ mF -= 976981405.0f;
+ }
+ }
+ }
+ }
+ }
+ return 1.0f;
+ }
+
static void assertIntEquals(int result, int expected) {
if (expected != result) {
throw new Error("Expected: " + expected + ", found: " + result);
@@ -779,6 +806,8 @@
assertIntEquals($noinline$testHSelect(true), 0xdead);
int[] array = {2, 5, 9, -1, -3, 10, 8, 4};
assertIntEquals(sumWithinRange(array, 1, 5), 11);
+ assertFloatEquals(testAllocationEliminationWithLoops(), 1.0f);
+ assertFloatEquals(mF, 0f);
}
static boolean sFlag;
diff --git a/test/618-checker-induction/src/Main.java b/test/618-checker-induction/src/Main.java
index 5c789cd..b5606bd 100644
--- a/test/618-checker-induction/src/Main.java
+++ b/test/618-checker-induction/src/Main.java
@@ -31,6 +31,26 @@
}
}
+ /// CHECK-START: void Main.deadSingleLoop() loop_optimization (before)
+ /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:none
+ //
+ /// CHECK-START: void Main.deadSingleLoop() loop_optimization (after)
+ /// CHECK-NOT: Phi loop:{{B\d+}} outer_loop:none
+ static void deadSingleLoopN(int n) {
+ for (int i = 0; i < n; i++) {
+ }
+ }
+
+ /// CHECK-START: void Main.potentialInfiniteLoop(int) loop_optimization (before)
+ /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:none
+ //
+ /// CHECK-START: void Main.potentialInfiniteLoop(int) loop_optimization (after)
+ /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:none
+ static void potentialInfiniteLoop(int n) {
+ for (int i = 0; i <= n; i++) { // loops forever when n = MAX_INT
+ }
+ }
+
/// CHECK-START: void Main.deadNestedLoops() loop_optimization (before)
/// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
/// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:<<Loop>>
@@ -160,6 +180,10 @@
/// CHECK-START: int Main.closedFormInductionUp() loop_optimization (after)
/// CHECK-NOT: Phi loop:{{B\d+}} outer_loop:none
/// CHECK-DAG: Return loop:none
+ //
+ /// CHECK-START: int Main.closedFormInductionUp() instruction_simplifier$after_bce (after)
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant 12395
+ /// CHECK-DAG: Return [<<Int>>] loop:none
static int closedFormInductionUp() {
int closed = 12345;
for (int i = 0; i < 10; i++) {
@@ -194,6 +218,10 @@
/// CHECK-NOT: Phi loop:{{B\d+}} outer_loop:none
/// CHECK-NOT: Phi loop:{{B\d+}} outer_loop:loop{{B\d+}}
/// CHECK-DAG: Return loop:none
+ //
+ /// CHECK-START: int Main.closedFormNested() instruction_simplifier$after_bce (after)
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant 100
+ /// CHECK-DAG: Return [<<Int>>] loop:none
static int closedFormNested() {
int closed = 0;
for (int i = 0; i < 10; i++) {
@@ -215,6 +243,10 @@
/// CHECK-NOT: Phi loop:{{B\d+}} outer_loop:none
/// CHECK-NOT: Phi loop:{{B\d+}} outer_loop:loop{{B\d+}}
/// CHECK-DAG: Return loop:none
+ //
+ /// CHECK-START: int Main.closedFormNestedAlt() instruction_simplifier$after_bce (after)
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant 15082
+ /// CHECK-DAG: Return [<<Int>>] loop:none
static int closedFormNestedAlt() {
int closed = 12345;
for (int i = 0; i < 17; i++) {
@@ -293,14 +325,29 @@
/// CHECK-START: int Main.mainIndexReturned() loop_optimization (after)
/// CHECK-NOT: Phi loop:{{B\d+}} outer_loop:none
/// CHECK-DAG: Return loop:none
+ //
+ /// CHECK-START: int Main.mainIndexReturned() instruction_simplifier$after_bce (after)
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant 10
+ /// CHECK-DAG: Return [<<Int>>] loop:none
static int mainIndexReturned() {
int i;
for (i = 0; i < 10; i++);
return i;
}
- // If ever replaced by closed form, last value should be correct!
- static int periodicReturned() {
+ /// CHECK-START: int Main.periodicReturned9() loop_optimization (before)
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Return [<<Phi2>>] loop:none
+ //
+ /// CHECK-START: int Main.periodicReturned9() loop_optimization (after)
+ /// CHECK-NOT: Phi loop:{{B\d+}} outer_loop:none
+ /// CHECK-DAG: Return loop:none
+ //
+ /// CHECK-START: int Main.periodicReturned9() instruction_simplifier$after_bce (after)
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant 1
+ /// CHECK-DAG: Return [<<Int>>] loop:none
+ static int periodicReturned9() {
int k = 0;
for (int i = 0; i < 9; i++) {
k = 1 - k;
@@ -308,6 +355,26 @@
return k;
}
+ /// CHECK-START: int Main.periodicReturned10() loop_optimization (before)
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Return [<<Phi2>>] loop:none
+ //
+ /// CHECK-START: int Main.periodicReturned10() loop_optimization (after)
+ /// CHECK-NOT: Phi loop:{{B\d+}} outer_loop:none
+ /// CHECK-DAG: Return loop:none
+ //
+ /// CHECK-START: int Main.periodicReturned10() instruction_simplifier$after_bce (after)
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant 0
+ /// CHECK-DAG: Return [<<Int>>] loop:none
+ static int periodicReturned10() {
+ int k = 0;
+ for (int i = 0; i < 10; i++) {
+ k = 1 - k;
+ }
+ return k;
+ }
+
// If ever replaced by closed form, last value should be correct!
private static int getSum21() {
int k = 0;
@@ -326,7 +393,14 @@
return i;
}
- // If ever replaced by closed form, last value should be correct!
+ /// CHECK-START: int Main.periodicReturnedN(int) loop_optimization (before)
+ /// CHECK-DAG: <<Phi1:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none
+ /// CHECK-DAG: <<Phi2:i\d+>> Phi loop:<<Loop>> outer_loop:none
+ /// CHECK-DAG: Return [<<Phi2>>] loop:none
+ //
+ /// CHECK-START: int Main.periodicReturnedN(int) loop_optimization (after)
+ /// CHECK-NOT: Phi loop:{{B\d+}} outer_loop:none
+ /// CHECK-DAG: Return loop:none
static int periodicReturnedN(int n) {
int k = 0;
for (int i = 0; i < n; i++) {
@@ -371,6 +445,10 @@
/// CHECK-START: int Main.closedFeed() loop_optimization (after)
/// CHECK-NOT: Phi loop:{{B\d+}} outer_loop:none
/// CHECK-DAG: Return loop:none
+ //
+ /// CHECK-START: int Main.closedFeed() instruction_simplifier$after_bce (after)
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant 20
+ /// CHECK-DAG: Return [<<Int>>] loop:none
private static int closedFeed() {
int closed = 0;
for (int i = 0; i < 10; i++) {
@@ -392,6 +470,10 @@
/// CHECK-START: int Main.closedLargeUp() loop_optimization (after)
/// CHECK-NOT: Phi loop:B\d+ outer_loop:none
/// CHECK-DAG: Return loop:none
+ //
+ /// CHECK-START: int Main.closedLargeUp() instruction_simplifier$after_bce (after)
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant -10
+ /// CHECK-DAG: Return [<<Int>>] loop:none
private static int closedLargeUp() {
int closed = 0;
for (int i = 0; i < 10; i++) {
@@ -408,6 +490,10 @@
/// CHECK-START: int Main.closedLargeDown() loop_optimization (after)
/// CHECK-NOT: Phi loop:B\d+ outer_loop:none
/// CHECK-DAG: Return loop:none
+ //
+ /// CHECK-START: int Main.closedLargeDown() instruction_simplifier$after_bce (after)
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant 10
+ /// CHECK-DAG: Return [<<Int>>] loop:none
private static int closedLargeDown() {
int closed = 0;
for (int i = 0; i < 10; i++) {
@@ -427,6 +513,10 @@
/// CHECK-START: int Main.waterFall() loop_optimization (after)
/// CHECK-NOT: Phi loop:B\d+ outer_loop:none
/// CHECK-DAG: Return loop:none
+ //
+ /// CHECK-START: int Main.waterFall() instruction_simplifier$after_bce (after)
+ /// CHECK-DAG: <<Int:i\d+>> IntConstant 50
+ /// CHECK-DAG: Return [<<Int>>] loop:none
private static int waterFall() {
int i = 0;
for (; i < 10; i++);
@@ -469,6 +559,8 @@
public static void main(String[] args) {
deadSingleLoop();
+ deadSingleLoopN(4);
+ potentialInfiniteLoop(4);
deadNestedLoops();
deadNestedAndFollowingLoops();
@@ -512,7 +604,8 @@
}
expectEquals(10, mainIndexReturned());
- expectEquals(1, periodicReturned());
+ expectEquals(1, periodicReturned9());
+ expectEquals(0, periodicReturned10());
expectEquals(21, getSum21());
for (int n = -4; n < 4; n++) {
int tc = (n <= 0) ? 0 : n;
diff --git a/test/904-object-allocation/src/Main.java b/test/904-object-allocation/src/Main.java
index 9a089bd..fc8a112 100644
--- a/test/904-object-allocation/src/Main.java
+++ b/test/904-object-allocation/src/Main.java
@@ -40,7 +40,11 @@
}
public static void doTest(ArrayList<Object> l) throws Exception {
- setupObjectAllocCallback();
+ // Disable the global registration from OnLoad, to get into a known state.
+ enableAllocationTracking(null, false);
+
+ // Enable actual logging callback.
+ setupObjectAllocCallback(true);
enableAllocationTracking(null, true);
@@ -74,6 +78,11 @@
testThread(l, false, true);
l.add(new Byte((byte)0));
+
+ // Disable actual logging callback and re-enable tracking, so we can keep the event enabled and
+ // check that shutdown works correctly.
+ setupObjectAllocCallback(false);
+ enableAllocationTracking(null, true);
}
private static void testThread(final ArrayList<Object> l, final boolean sameThread,
@@ -82,6 +91,8 @@
final SimpleBarrier trackBarrier = new SimpleBarrier(1);
final SimpleBarrier disableBarrier = new SimpleBarrier(1);
+ final Thread thisThread = Thread.currentThread();
+
Thread t = new Thread() {
public void run() {
try {
@@ -95,7 +106,7 @@
l.add(new Double(0.0));
if (disableTracking) {
- enableAllocationTracking(sameThread ? this : Thread.currentThread(), false);
+ enableAllocationTracking(sameThread ? this : thisThread, false);
}
}
};
@@ -127,6 +138,6 @@
}
}
- private static native void setupObjectAllocCallback();
+ private static native void setupObjectAllocCallback(boolean enable);
private static native void enableAllocationTracking(Thread thread, boolean enable);
}
diff --git a/test/904-object-allocation/tracking.cc b/test/904-object-allocation/tracking.cc
index b22fc6c..57bfed5 100644
--- a/test/904-object-allocation/tracking.cc
+++ b/test/904-object-allocation/tracking.cc
@@ -58,10 +58,10 @@
}
extern "C" JNIEXPORT void JNICALL Java_Main_setupObjectAllocCallback(
- JNIEnv* env ATTRIBUTE_UNUSED, jclass klass ATTRIBUTE_UNUSED) {
+ JNIEnv* env ATTRIBUTE_UNUSED, jclass klass ATTRIBUTE_UNUSED, jboolean enable) {
jvmtiEventCallbacks callbacks;
memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
- callbacks.VMObjectAlloc = ObjectAllocated;
+ callbacks.VMObjectAlloc = enable ? ObjectAllocated : nullptr;
jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
if (ret != JVMTI_ERROR_NONE) {
@@ -94,6 +94,7 @@
printf("Unable to get jvmti env!\n");
return 1;
}
+ jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, nullptr);
return 0;
}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 34f8838..3bf7e4b 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -491,6 +491,7 @@
# between those runs to be able to have precise checks.
TEST_ART_BROKEN_JIT_RUN_TESTS := \
137-cfi \
+ 904-object-allocation \
906-iterate-heap \
ifneq (,$(filter jit,$(COMPILER_TYPES)))
diff --git a/tools/ahat/README.txt b/tools/ahat/README.txt
index 8604ff0..dbc1102 100644
--- a/tools/ahat/README.txt
+++ b/tools/ahat/README.txt
@@ -74,7 +74,9 @@
* Instance.isRoot and Instance.getRootTypes.
Release History:
- 0.8 Pending
+ 0.9 Pending
+
+ 0.8 Oct 18, 2016
Show sample path from GC root with field names in place of dominator path.
0.7 Aug 16, 2016
diff --git a/tools/ahat/src/manifest.txt b/tools/ahat/src/manifest.txt
index cac53c5..1993910 100644
--- a/tools/ahat/src/manifest.txt
+++ b/tools/ahat/src/manifest.txt
@@ -1,4 +1,4 @@
Name: ahat/
Implementation-Title: ahat
-Implementation-Version: 0.7
+Implementation-Version: 0.8
Main-Class: com.android.ahat.Main
diff --git a/tools/libcore_failures_concurrent_collector.txt b/tools/libcore_failures_concurrent_collector.txt
deleted file mode 100644
index 0e289a6..0000000
--- a/tools/libcore_failures_concurrent_collector.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * This file contains expectations for ART's buildbot's concurrent collector
- * configurations. The purpose of this file is to temporary and quickly list
- * failing tests and not break the bots on the CC configurations, until they
- * are fixed or until the libcore expectation files get properly updated. The
- * script that uses this file is art/tools/run-libcore-tests.sh.
- *
- * It is also used to enable AOSP experiments, and not mess up with CTS's
- * expectations.
- */
-
-[
-]
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index 01c7f20..41faa69 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -43,10 +43,6 @@
done
expectations="--expectations art/tools/libcore_failures.txt"
-if [ "x$ART_USE_READ_BARRIER" = xtrue ]; then
- # Tolerate some more failures on the concurrent collector configurations.
- expectations="$expectations --expectations art/tools/libcore_failures_concurrent_collector.txt"
-fi
emulator="no"
if [ "$ANDROID_SERIAL" = "emulator-5554" ]; then