diff options
58 files changed, 1087 insertions, 354 deletions
diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc index 140c7f0c40..663cbaf2de 100644 --- a/compiler/optimizing/induction_var_range.cc +++ b/compiler/optimizing/induction_var_range.cc @@ -162,17 +162,17 @@ bool InductionVarRange::CanGenerateRange(HInstruction* context, /*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 @@ void InductionVarRange::GenerateRange(HInstruction* context, 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 @@ HInstruction* InductionVarRange::GenerateTakenTest(HInstruction* context, 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 @@ bool InductionVarRange::CanGenerateLastValue(HInstruction* instruction) { 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 @@ HInstruction* InductionVarRange::GenerateLastValue(HInstruction* instruction, 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 @@ void InductionVarRange::Replace(HInstruction* instruction, } } +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 @@ InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is 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 @@ bool InductionVarRange::GenerateCode(HInstruction* context, *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 @@ bool InductionVarRange::GenerateCode(HInstruction* context, 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 @@ bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info, // Invariants. switch (info->operation) { case HInductionVarAnalysis::kAdd: + case HInductionVarAnalysis::kXor: case HInductionVarAnalysis::kLT: case HInductionVarAnalysis::kLE: case HInductionVarAnalysis::kGT: @@ -823,6 +885,8 @@ bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info, 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 895130064a..2f70046a27 100644 --- a/compiler/optimizing/induction_var_range.h +++ b/compiler/optimizing/induction_var_range.h @@ -139,6 +139,11 @@ class InductionVarRange { 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 @@ class InductionVarRange { * 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 7347686830..820fa29597 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -168,7 +168,9 @@ class HeapLocation : public ArenaObject<kArenaAllocMisc> { 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 @@ class HeapLocationCollector : public HGraphVisitor { 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 @@ class LSEVisitor : public HGraphVisitor { 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 33fa87d568..703a10402d 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 @@ static bool IsEmptyHeader(HBasicBlock* block, ArenaSet<HInstruction*>* iset) { 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 @@ void HLoopOptimization::TraverseLoopsInnerToOuter(LoopNode* node) { } SimplifyInduction(node); SimplifyBlocks(node); - RemoveIfEmptyLoop(node); + if (node->inner == nullptr) { + RemoveIfEmptyInnerLoop(node); + } } } @@ -233,7 +262,7 @@ void HLoopOptimization::SimplifyBlocks(LoopNode* node) { 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::SimplifyBlocks(LoopNode* node) { } } -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 9c4b462a1f..4113357035 100644 --- a/compiler/optimizing/loop_optimization.h +++ b/compiler/optimizing/loop_optimization.h @@ -62,7 +62,7 @@ class HLoopOptimization : public HOptimization { 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 54e52e5edb..c3321e17b9 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 @@ DEFINE_FUNCTION art_quick_string_compareto 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 @@ DEFINE_FUNCTION art_quick_string_compareto 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 @@ DEFINE_FUNCTION art_quick_string_compareto 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 @@ DEFINE_FUNCTION art_quick_string_compareto 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 @@ DEFINE_FUNCTION art_quick_string_compareto 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 @@ DEFINE_FUNCTION art_quick_string_compareto * 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 dba9b8fb48..126187f092 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -36,7 +36,8 @@ inline mirror::Class* ClassLinker::FindSystemClass(Thread* self, const char* des 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 @@ inline mirror::Class* ClassLinker::FindArrayClass(Thread* self, mirror::Class** 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 d07aa89ee4..63de76ccb7 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1962,7 +1962,7 @@ void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor) { // 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 @@ bool ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& 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 @@ mirror::Class* ClassLinker::FindClass(Thread* self, } } 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 @@ mirror::MethodType* ClassLinker::ResolveMethodType(const DexFile& dex_file, // 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::VisitClassLoaders(ClassLoaderVisitor* visitor) const { } } -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 70cc768686..6437010f3f 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -181,7 +181,7 @@ class ClassLinker { 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 @@ class ClassLinker { 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 @@ class ClassLinker { 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 6279717acb..4fac830d16 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -216,7 +216,7 @@ class ClassLinkerTest : public CommonRuntimeTest { 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 2ae7e8cc30..d43505054e 100644 --- a/runtime/class_table.cc +++ b/runtime/class_table.cc @@ -156,7 +156,7 @@ uint32_t ClassTable::ClassDescriptorHashEquals::operator()(const char* descripto 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 @@ bool ClassTable::InsertStrongRoot(mirror::Object* obj) { 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 acb15c7879..20e434d90b 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 @@ class ClassTable { 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 576c4aa849..e5383341fb 100644 --- a/runtime/dex_file_annotations.cc +++ b/runtime/dex_file_annotations.cc @@ -254,7 +254,7 @@ mirror::Object* ProcessEncodedAnnotation(Handle<mirror::Class> klass, const uint 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 @@ mirror::ObjectArray<mirror::String>* GetSignatureValue(Handle<mirror::Class> kla 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 @@ mirror::ObjectArray<mirror::Class>* GetThrowsValue(Handle<mirror::Class> klass, 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 @@ mirror::ObjectArray<mirror::Object>* ProcessAnnotationSetRefList( 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 @@ bool GetParametersMetadataForMethod(ArtMethod* method, 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 @@ mirror::ObjectArray<mirror::Class>* GetDeclaredClasses(Handle<mirror::Class> kla 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 45bd87b87c..f4a3aeaabc 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -1246,9 +1246,6 @@ Heap::~Heap() { << " 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 00303268ff..2d5d7cbfa6 100644 --- a/runtime/gc/space/large_object_space.cc +++ b/runtime/gc/space/large_object_space.cc @@ -155,11 +155,12 @@ mirror::Object* LargeObjectMapSpace::Alloc(Thread* self, size_t num_bytes, 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 6109ec6758..130c10d322 100644 --- a/runtime/indirect_reference_table.cc +++ b/runtime/indirect_reference_table.cc @@ -58,17 +58,15 @@ void IndirectReferenceTable::AbortIfNoCheckJNI(const std::string& msg) { } } -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 64de7a86ef..1762b10350 100644 --- a/runtime/indirect_reference_table.h +++ b/runtime/indirect_reference_table.h @@ -259,8 +259,7 @@ class IndirectReferenceTable { 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 169911077e..7b28f0bda8 100644 --- a/runtime/indirect_reference_table_test.cc +++ b/runtime/indirect_reference_table_test.cc @@ -48,9 +48,8 @@ TEST_F(IndirectReferenceTableTest, BasicTest) { 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_F(IndirectReferenceTableTest, BasicTest) { // 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 a73970b138..36e860837d 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -647,7 +647,15 @@ void Instrumentation::SetEntrypointsInstrumented(bool instrumented) { } 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 4a3654be3e..4347c37f62 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -1472,13 +1472,17 @@ void UnstartedRuntime::UnstartedJNIVMRuntimeNewUnpaddedArray( 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 @@ void UnstartedRuntime::UnstartedJNIArrayCreateObjectArray( 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 6a4add3bb8..b190c81aff 100644 --- a/runtime/interpreter/unstarted_runtime_test.cc +++ b/runtime/interpreter/unstarted_runtime_test.cc @@ -81,20 +81,21 @@ class UnstartedRuntimeTest : public CommonRuntimeTest { 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 f2bda05b94..99edb7c569 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 @@ JavaVMExt::JavaVMExt(Runtime* runtime, const RuntimeArgumentMap& runtime_options 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 3c749d0471..39f4d97755 100644 --- a/runtime/jni_env_ext.cc +++ b/runtime/jni_env_ext.cc @@ -33,8 +33,6 @@ namespace art { 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 @@ JNIEnvExt::JNIEnvExt(Thread* self_in, JavaVMExt* vm_in) : 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 121f84854b..549f8c56a0 100644 --- a/runtime/jni_env_ext.h +++ b/runtime/jni_env_ext.h @@ -29,9 +29,9 @@ namespace art { 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 8eebe56da7..db2453da5b 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -1904,11 +1904,12 @@ class JNI { // 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 @@ class JNI { 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 fbd670c048..9622a8e9d0 100644 --- a/runtime/jni_internal_test.cc +++ b/runtime/jni_internal_test.cc @@ -865,6 +865,11 @@ TEST_F(JniInternalTest, GetStaticMethodID) { 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 @@ TEST_F(JniInternalTest, FromReflectedField_ToReflectedField) { 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 @@ TEST_F(JniInternalTest, FromReflectedMethod_ToReflectedMethod) { 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 @@ TEST_F(JniInternalTest, IndirectReferenceTableOffsets) { // 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 1aa38dd6b4..8afa4aa744 100644 --- a/runtime/mirror/array.cc +++ b/runtime/mirror/array.cc @@ -60,7 +60,7 @@ static Array* RecursiveCreateMultiArray(Thread* self, 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 @@ Array* Array::CreateMultiArray(Thread* self, Handle<Class> element_class, // 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 @@ Array* Array::CreateMultiArray(Thread* self, Handle<Class> element_class, 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 @@ Array* Array::CreateMultiArray(Thread* self, Handle<Class> element_class, } } // 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 @@ Array* Array::CopyOf(Thread* self, int32_t new_length) { 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 86b5e7a6d1..be849a330c 100644 --- a/runtime/mirror/dex_cache-inl.h +++ b/runtime/mirror/dex_cache-inl.h @@ -44,8 +44,8 @@ inline mirror::String* DexCache::GetResolvedString(uint32_t string_idx) { 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 c3c7ab424a..d728f9052f 100644 --- a/runtime/mirror/dex_cache.h +++ b/runtime/mirror/dex_cache.h @@ -215,7 +215,7 @@ class MANAGED DexCache FINAL : public Object { 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 a968bff84d..03ab93069c 100644 --- a/runtime/mirror/method_type_test.cc +++ b/runtime/mirror/method_type_test.cc @@ -52,7 +52,7 @@ static mirror::MethodType* CreateMethodType(const std::string& return_type, 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 ed1103f46d..d60274fae7 100644 --- a/runtime/mirror/string.cc +++ b/runtime/mirror/string.cc @@ -292,38 +292,41 @@ int32_t String::CompareTo(ObjPtr<String> rhs) { 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 086da60728..df0849a628 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -218,7 +218,7 @@ static jboolean DexFile_closeDexFile(JNIEnv* env, jclass, jobject cookie) { { 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 @@ static jclass DexFile_defineClassNative(JNIEnv* env, 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 e32545bc2e..db245aa0d8 100644 --- a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc +++ b/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc @@ -150,14 +150,18 @@ static jclass InMemoryDexClassLoader_DexData_findClass( 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 e458e2d83a..888fddb4fa 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -74,21 +74,23 @@ static jobject VMRuntime_newNonMovableArray(JNIEnv* env, jobject, jclass javaEle 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 @@ static jobject VMRuntime_newUnpaddedArray(JNIEnv* env, jobject, jclass javaEleme 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 @@ static jlong VMRuntime_addressOf(JNIEnv* env, jobject, jobject javaArray) { 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 @@ static void VMRuntime_runHeapTasks(JNIEnv* env, jobject) { 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 @@ class PreloadDexCachesStringsVisitor : public SingleRootVisitor { 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 @@ class PreloadDexCachesStringsVisitor : public SingleRootVisitor { 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 @@ static void PreloadDexCachesResolveString( } // 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 @@ static void PreloadDexCachesResolveMethod(Handle<mirror::DexCache> dex_cache, ui } 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 @@ static void PreloadDexCachesStatsFilled(DexCacheStats* filled) 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 0dd8cdd2d9..36825cb870 100644 --- a/runtime/native/dalvik_system_VMStack.cc +++ b/runtime/native/dalvik_system_VMStack.cc @@ -87,10 +87,10 @@ static jobject VMStack_getClosestUserClassLoader(JNIEnv* env, jclass) { 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 @@ static jobject VMStack_getClosestUserClassLoader(JNIEnv* env, jclass) { 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 ceb37c488e..ac5dbdabf7 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -497,13 +497,13 @@ static jobjectArray Class_getDeclaredClasses(JNIEnv* env, jobject javaThis) { // 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 @@ static jobject Class_getEnclosingConstructorNative(JNIEnv* env, jobject javaThis 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 @@ static jobject Class_getEnclosingMethodNative(JNIEnv* env, jobject javaThis) { 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 @@ static jobject Class_newInstance(JNIEnv* env, jobject javaThis) { // 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 1fd7ed11e1..71379a51a5 100644 --- a/runtime/native/java_lang_DexCache.cc +++ b/runtime/native/java_lang_DexCache.cc @@ -68,7 +68,7 @@ static void DexCache_setResolvedType(JNIEnv* env, jobject javaDexCache, jint typ 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 @@ static void DexCache_setResolvedString(JNIEnv* env, jobject javaDexCache, jint s 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 5a49c203af..ea266d131d 100644 --- a/runtime/native/java_lang_String.cc +++ b/runtime/native/java_lang_String.cc @@ -57,7 +57,8 @@ static jstring String_concat(JNIEnv* env, jobject java_this, jobject java_string 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 @@ static jstring String_fastSubstring(JNIEnv* env, jobject java_this, jint start, 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 119f2b87ba..e0738a49b9 100644 --- a/runtime/native/java_lang_StringFactory.cc +++ b/runtime/native/java_lang_StringFactory.cc @@ -44,9 +44,12 @@ static jstring StringFactory_newStringFromBytes(JNIEnv* env, jclass, jbyteArray 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 @@ static jstring StringFactory_newStringFromChars(JNIEnv* env, jclass, jint offset 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 @@ static jstring StringFactory_newStringFromString(JNIEnv* env, jclass, jstring to 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 3f5fa73b45..eaf2d65bab 100644 --- a/runtime/native/java_lang_System.cc +++ b/runtime/native/java_lang_System.cc @@ -71,8 +71,8 @@ static void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, 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 @@ static void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, 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 @@ static void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, 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 @@ static void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, // 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 @@ inline void System_arraycopyTUnchecked(JNIEnv* env, jobject javaSrc, jint srcPos 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 73d12f1a59..1fe89bf2f8 100644 --- a/runtime/native/java_lang_VMClassLoader.cc +++ b/runtime/native/java_lang_VMClassLoader.cc @@ -37,24 +37,24 @@ static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoa 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 1f03c7cff6..c7d06f4665 100644 --- a/runtime/native/java_lang_ref_FinalizerReference.cc +++ b/runtime/native/java_lang_ref_FinalizerReference.cc @@ -28,8 +28,7 @@ namespace art { 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 6f2da33291..d827f818c5 100644 --- a/runtime/native/java_lang_reflect_Array.cc +++ b/runtime/native/java_lang_reflect_Array.cc @@ -40,8 +40,9 @@ static jobject Array_createMultiArray( 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 @@ static jobject Array_createObjectArray(JNIEnv* env, jclass, jclass javaElementCl 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 505f85d94c..a81ba7d4fc 100644 --- a/runtime/native/java_lang_reflect_Constructor.cc +++ b/runtime/native/java_lang_reflect_Constructor.cc @@ -39,13 +39,13 @@ static jobjectArray Constructor_getExceptionTypes(JNIEnv* env, jobject javaMetho 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 b5f2f7ca90..a6589bc073 100644 --- a/runtime/native/java_lang_reflect_Method.cc +++ b/runtime/native/java_lang_reflect_Method.cc @@ -44,7 +44,7 @@ static jobjectArray Method_getExceptionTypes(JNIEnv* env, jobject javaMethod) { 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 @@ static jobjectArray Method_getExceptionTypes(JNIEnv* env, jobject javaMethod) { 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 670c4ac19a..cdf4b14dbb 100644 --- a/runtime/native/sun_misc_Unsafe.cc +++ b/runtime/native/sun_misc_Unsafe.cc @@ -305,7 +305,8 @@ static void Unsafe_copyMemory(JNIEnv *env, jobject unsafe ATTRIBUTE_UNUSED, jlon } 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 @@ static void copyToArray(jlong srcAddr, mirror::PrimitiveArray<T>* array, } 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 @@ static void Unsafe_copyMemoryToPrimitiveArray(JNIEnv *env, 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 @@ static void Unsafe_copyMemoryFromPrimitiveArray(JNIEnv *env, 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 450f85e51a..59e01eafa0 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 @@ class JvmtiAllocationListener : public art::gc::AllocationListener { }; 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 @@ jvmtiError EventHandler::SetEvent(ArtJvmTiEnv* env, 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 @@ jvmtiError EventHandler::SetEvent(ArtJvmTiEnv* env, 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 a84668ba02..626d9cf189 100644 --- a/runtime/verifier/reg_type.cc +++ b/runtime/verifier/reg_type.cc @@ -748,7 +748,7 @@ mirror::Class* RegType::ClassJoin(mirror::Class* s, mirror::Class* t) { 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 d1ea0b171a..a848fba6f5 100644 --- a/test/021-string2/src/Main.java +++ b/test/021-string2/src/Main.java @@ -89,5 +89,424 @@ public class Main { 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 89875d7fef..6b0dedfe9d 100644 --- a/test/530-checker-lse/src/Main.java +++ b/test/530-checker-lse/src/Main.java @@ -717,6 +717,33 @@ public class Main { 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 @@ public class Main { 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 5c789cdd84..b5606bd406 100644 --- a/test/618-checker-induction/src/Main.java +++ b/test/618-checker-induction/src/Main.java @@ -31,6 +31,26 @@ public class Main { } } + /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { 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 @@ public class Main { 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 @@ public class Main { /// 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 class Main { public static void main(String[] args) { deadSingleLoop(); + deadSingleLoopN(4); + potentialInfiniteLoop(4); deadNestedLoops(); deadNestedAndFollowingLoops(); @@ -512,7 +604,8 @@ public class Main { } 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 9a089bdd78..fc8a112e49 100644 --- a/test/904-object-allocation/src/Main.java +++ b/test/904-object-allocation/src/Main.java @@ -40,7 +40,11 @@ public class Main { } 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 @@ public class Main { 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 @@ public class Main { 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 @@ public class Main { l.add(new Double(0.0)); if (disableTracking) { - enableAllocationTracking(sameThread ? this : Thread.currentThread(), false); + enableAllocationTracking(sameThread ? this : thisThread, false); } } }; @@ -127,6 +138,6 @@ public class Main { } } - 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 b22fc6c8c0..57bfed544e 100644 --- a/test/904-object-allocation/tracking.cc +++ b/test/904-object-allocation/tracking.cc @@ -58,10 +58,10 @@ static void JNICALL ObjectAllocated(jvmtiEnv* ti_env ATTRIBUTE_UNUSED, } 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 @@ jint OnLoad(JavaVM* vm, 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 34f8838a99..3bf7e4b626 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -491,6 +491,7 @@ TEST_ART_BROKEN_INTERPRETER_RUN_TESTS := # 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 8604ff0cbb..dbc1102095 100644 --- a/tools/ahat/README.txt +++ b/tools/ahat/README.txt @@ -74,7 +74,9 @@ Things to move to perflib: * 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 cac53c5f6b..1993910513 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 0e289a66d7..0000000000 --- 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 01c7f203f9..41faa69c31 100755 --- a/tools/run-libcore-tests.sh +++ b/tools/run-libcore-tests.sh @@ -43,10 +43,6 @@ do 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 |