diff options
| -rw-r--r-- | compiler/oat_writer.h | 2 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 3 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 3 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_mips64.cc | 3 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 3 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 3 | ||||
| -rw-r--r-- | compiler/optimizing/induction_var_analysis_test.cc | 31 | ||||
| -rw-r--r-- | compiler/optimizing/induction_var_range.cc | 167 | ||||
| -rw-r--r-- | compiler/optimizing/induction_var_range.h | 48 | ||||
| -rw-r--r-- | compiler/optimizing/induction_var_range_test.cc | 138 | ||||
| -rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 13 | ||||
| -rw-r--r-- | runtime/class_linker.cc | 17 | ||||
| -rw-r--r-- | runtime/class_linker.h | 12 | ||||
| -rw-r--r-- | runtime/class_table-inl.h | 3 | ||||
| -rw-r--r-- | runtime/class_table.cc | 11 | ||||
| -rw-r--r-- | runtime/class_table.h | 34 | ||||
| -rw-r--r-- | runtime/native/dalvik_system_DexFile.cc | 16 | ||||
| -rw-r--r-- | runtime/oat_file.cc | 147 | ||||
| -rw-r--r-- | runtime/oat_file.h | 10 | ||||
| -rw-r--r-- | test/087-gc-after-link/src/Main.java | 1 |
20 files changed, 534 insertions, 131 deletions
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index a82d09eedd..d6cb65bd64 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -281,7 +281,7 @@ class OatWriter { // Offsets of the dex cache arrays for each app dex file. For the // boot image, this information is provided by the ImageWriter. - SafeMap<const DexFile*, size_t> dex_cache_arrays_offsets_; + SafeMap<const DexFile*, size_t> dex_cache_arrays_offsets_; // DexFiles not owned. // Offset of the oat data from the start of the mmapped region of the elf file. size_t oat_data_offset_; diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 3e6cad83fa..92a5878476 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -1376,8 +1376,7 @@ void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath); HInstruction* cond = deoptimize->InputAt(0); - DCHECK(cond->IsCondition()); - if (cond->AsCondition()->NeedsMaterialization()) { + if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { locations->SetInAt(0, Location::RequiresRegister()); } } diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index ffb9b794fc..f68b11b504 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -2353,8 +2353,7 @@ void LocationsBuilderARM64::VisitDeoptimize(HDeoptimize* deoptimize) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath); HInstruction* cond = deoptimize->InputAt(0); - DCHECK(cond->IsCondition()); - if (cond->AsCondition()->NeedsMaterialization()) { + if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { locations->SetInAt(0, Location::RequiresRegister()); } } diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index eb20291e20..f561c97eb0 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -2223,8 +2223,7 @@ void LocationsBuilderMIPS64::VisitDeoptimize(HDeoptimize* deoptimize) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath); HInstruction* cond = deoptimize->InputAt(0); - DCHECK(cond->IsCondition()); - if (cond->AsCondition()->NeedsMaterialization()) { + if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { locations->SetInAt(0, Location::RequiresRegister()); } } diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 2aea859b7d..963eec2529 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1306,8 +1306,7 @@ void LocationsBuilderX86::VisitDeoptimize(HDeoptimize* deoptimize) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath); HInstruction* cond = deoptimize->InputAt(0); - DCHECK(cond->IsCondition()); - if (cond->AsCondition()->NeedsMaterialization()) { + if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { locations->SetInAt(0, Location::Any()); } } diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index bf570f581b..ed2e4ca87c 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1252,8 +1252,7 @@ void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath); HInstruction* cond = deoptimize->InputAt(0); - DCHECK(cond->IsCondition()); - if (cond->AsCondition()->NeedsMaterialization()) { + if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { locations->SetInAt(0, Location::Any()); } } diff --git a/compiler/optimizing/induction_var_analysis_test.cc b/compiler/optimizing/induction_var_analysis_test.cc index 20492e7152..fd1e334bb6 100644 --- a/compiler/optimizing/induction_var_analysis_test.cc +++ b/compiler/optimizing/induction_var_analysis_test.cc @@ -20,7 +20,6 @@ #include "builder.h" #include "gtest/gtest.h" #include "induction_var_analysis.h" -#include "induction_var_range.h" #include "nodes.h" #include "optimizing_unit_test.h" @@ -522,36 +521,6 @@ TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) { EXPECT_STREQ("periodic(( - (1)), (0))", GetInductionInfo(neg, 0).c_str()); } -TEST_F(InductionVarAnalysisTest, FindRange) { - // Setup: - // for (int i = 0; i < 100; i++) { - // k = i << 1; - // k = k + 1; - // a[k] = 0; - // } - BuildLoopNest(1); - HInstruction *shl = InsertInstruction( - new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0); - InsertLocalStore(induc_, shl, 0); - HInstruction *add = InsertInstruction( - new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0); - InsertLocalStore(induc_, add, 0); - HInstruction* store = InsertArrayStore(induc_, 0); - PerformInductionVarAnalysis(); - - EXPECT_STREQ("((2) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str()); - - InductionVarRange range(iva_); - InductionVarRange::Value v_min = range.GetMinInduction(store, store->InputAt(1)); - InductionVarRange::Value v_max = range.GetMaxInduction(store, store->InputAt(1)); - ASSERT_TRUE(v_min.is_known); - EXPECT_EQ(0, v_min.a_constant); - EXPECT_EQ(1, v_min.b_constant); - ASSERT_TRUE(v_max.is_known); - EXPECT_EQ(0, v_max.a_constant); - EXPECT_EQ(199, v_max.b_constant); -} - TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) { // Setup: // k = 0; diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc index db12819060..f4842f9696 100644 --- a/compiler/optimizing/induction_var_range.cc +++ b/compiler/optimizing/induction_var_range.cc @@ -75,6 +75,13 @@ static InductionVarRange::Value SimplifyMax(InductionVarRange::Value v) { return v; } +static HInstruction* Insert(HBasicBlock* preheader, HInstruction* instruction) { + DCHECK(preheader != nullptr); + DCHECK(instruction != nullptr); + preheader->InsertInstructionBefore(instruction, preheader->GetLastInstruction()); + return instruction; +} + // // Public class methods. // @@ -94,6 +101,21 @@ InductionVarRange::Value InductionVarRange::GetMaxInduction(HInstruction* contex return SimplifyMax(GetInduction(context, instruction, /* is_min */ false)); } +bool InductionVarRange::CanGenerateCode(HInstruction* context, + HInstruction* instruction, + /*out*/bool* top_test) { + return GenerateCode(context, instruction, nullptr, nullptr, nullptr, nullptr, top_test); +} + +bool InductionVarRange::GenerateCode(HInstruction* context, + HInstruction* instruction, + HGraph* graph, + HBasicBlock* block, + /*out*/HInstruction** lower, + /*out*/HInstruction** upper) { + return GenerateCode(context, instruction, graph, block, lower, upper, nullptr); +} + // // Private class methods. // @@ -162,15 +184,15 @@ InductionVarRange::Value InductionVarRange::GetVal(HInductionVarAnalysis::Induct case HInductionVarAnalysis::kFetch: return GetFetch(info->fetch, trip, in_body, is_min); case HInductionVarAnalysis::kTripCountInLoop: - if (!in_body) { - return is_min ? Value(0) - : GetVal(info->op_b, trip, in_body, is_min); // one extra! + if (!in_body && !is_min) { // one extra! + return GetVal(info->op_b, trip, in_body, is_min); } FALLTHROUGH_INTENDED; case HInductionVarAnalysis::kTripCountInBody: - if (in_body) { - return is_min ? Value(0) - : SubValue(GetVal(info->op_b, trip, in_body, is_min), Value(1)); + if (is_min) { + return Value(0); + } else if (in_body) { + return SubValue(GetVal(info->op_b, trip, in_body, is_min), Value(1)); } break; default: @@ -256,9 +278,11 @@ InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::Induct bool InductionVarRange::GetConstant(HInductionVarAnalysis::InductionInfo* info, int32_t *value) { Value v_min = GetVal(info, nullptr, false, /* is_min */ true); Value v_max = GetVal(info, nullptr, false, /* is_min */ false); - if (v_min.a_constant == 0 && v_max.a_constant == 0 && v_min.b_constant == v_max.b_constant) { - *value = v_min.b_constant; - return true; + if (v_min.is_known && v_max.is_known) { + if (v_min.a_constant == 0 && v_max.a_constant == 0 && v_min.b_constant == v_max.b_constant) { + *value = v_min.b_constant; + return true; + } } return false; } @@ -326,4 +350,129 @@ InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is return Value(); } +bool InductionVarRange::GenerateCode(HInstruction* context, + HInstruction* instruction, + HGraph* graph, + HBasicBlock* block, + /*out*/HInstruction** lower, + /*out*/HInstruction** upper, + /*out*/bool* top_test) { + HLoopInformation* loop = context->GetBlock()->GetLoopInformation(); // closest enveloping loop + if (loop != nullptr) { + HBasicBlock* header = loop->GetHeader(); + bool in_body = context->GetBlock() != header; + HInductionVarAnalysis::InductionInfo* info = induction_analysis_->LookupInfo(loop, instruction); + HInductionVarAnalysis::InductionInfo* trip = + induction_analysis_->LookupInfo(loop, header->GetLastInstruction()); + if (info != nullptr && trip != nullptr) { + if (top_test != nullptr) { + *top_test = trip->operation != HInductionVarAnalysis::kTripCountInLoop; + } + return + // Success on lower if invariant (not set), or code can be generated. + ((info->induction_class == HInductionVarAnalysis::kInvariant) || + GenerateCode(info, trip, graph, block, lower, in_body, /* is_min */ true)) && + // And success on upper. + GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false); + } + } + return false; +} + +bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info, + HInductionVarAnalysis::InductionInfo* trip, + HGraph* graph, // when set, code is generated + HBasicBlock* block, + /*out*/HInstruction** result, + bool in_body, + bool is_min) { + if (info != nullptr) { + Primitive::Type type = Primitive::kPrimInt; + HInstruction* opa = nullptr; + HInstruction* opb = nullptr; + int32_t value = 0; + switch (info->induction_class) { + case HInductionVarAnalysis::kInvariant: + // Invariants. + switch (info->operation) { + case HInductionVarAnalysis::kAdd: + if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) && + GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) { + if (graph != nullptr) { + *result = Insert(block, new (graph->GetArena()) HAdd(type, opa, opb)); + } + return true; + } + break; + case HInductionVarAnalysis::kSub: // second reversed! + if (GenerateCode(info->op_a, trip, graph, block, &opa, in_body, is_min) && + GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) { + if (graph != nullptr) { + *result = Insert(block, new (graph->GetArena()) HSub(type, opa, opb)); + } + return true; + } + break; + case HInductionVarAnalysis::kNeg: // reversed! + if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, !is_min)) { + if (graph != nullptr) { + *result = Insert(block, new (graph->GetArena()) HNeg(type, opb)); + } + return true; + } + break; + case HInductionVarAnalysis::kFetch: + if (graph != nullptr) { + *result = info->fetch; // already in HIR + } + return true; + case HInductionVarAnalysis::kTripCountInLoop: + if (!in_body && !is_min) { // one extra! + return GenerateCode(info->op_b, trip, graph, block, result, in_body, is_min); + } + FALLTHROUGH_INTENDED; + case HInductionVarAnalysis::kTripCountInBody: + if (is_min) { + if (graph != nullptr) { + *result = graph->GetIntConstant(0); + } + return true; + } else if (in_body) { + if (GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) { + if (graph != nullptr) { + *result = Insert(block, + new (graph->GetArena()) + HSub(type, opb, graph->GetIntConstant(1))); + } + return true; + } + } + break; + default: + break; + } + break; + case HInductionVarAnalysis::kLinear: + // Linear induction a * i + b, for normalized 0 <= i < TC. Restrict to unit stride only + // to avoid arithmetic wrap-around situations that are hard to guard against. + if (GetConstant(info->op_a, &value)) { + if (value == 1 || value == -1) { + const bool is_min_a = value == 1 ? is_min : !is_min; + if (GenerateCode(trip, trip, graph, block, &opa, in_body, is_min_a) && + GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) { + if (graph != nullptr) { + *result = Insert(block, new (graph->GetArena()) HAdd(type, opa, opb)); + } + return true; + } + } + } + break; + default: // TODO(ajcbik): add more cases + break; + } + } + return false; +} + } // namespace art diff --git a/compiler/optimizing/induction_var_range.h b/compiler/optimizing/induction_var_range.h index dbdd2eedac..7fa5a26dce 100644 --- a/compiler/optimizing/induction_var_range.h +++ b/compiler/optimizing/induction_var_range.h @@ -68,6 +68,33 @@ class InductionVarRange { */ Value GetMaxInduction(HInstruction* context, HInstruction* instruction); + /** + * Returns true if range analysis is able to generate code for the lower and upper bound + * expressions on the instruction in the given context. Output parameter top_test denotes + * whether a top test is needed to protect the trip-count expression evaluation. + */ + bool CanGenerateCode(HInstruction* context, HInstruction* instruction, /*out*/bool* top_test); + + /** + * Generates the actual code in the HIR for the lower and upper bound expressions on the + * instruction in the given context. Code for the lower and upper bound expression are + * generated in given block and graph and are returned in lower and upper, respectively. + * For a loop invariant, lower is not set. + * + * For example, given expression x+i with range [0, 5] for i, calling this method + * will generate the following sequence: + * + * block: + * lower: add x, 0 + * upper: add x, 5 + */ + bool GenerateCode(HInstruction* context, + HInstruction* instruction, + HGraph* graph, + HBasicBlock* block, + /*out*/HInstruction** lower, + /*out*/HInstruction** upper); + private: // // Private helper methods. @@ -102,6 +129,27 @@ class InductionVarRange { static Value DivValue(Value v1, Value v2); static Value MergeVal(Value v1, Value v2, bool is_min); + /** + * Generates code for lower/upper expression in the HIR. Returns true on success. + * With graph == 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, + HGraph* graph, + HBasicBlock* block, + /*out*/HInstruction** lower, + /*out*/HInstruction** upper, + bool* top_test); + + static bool GenerateCode(HInductionVarAnalysis::InductionInfo* info, + HInductionVarAnalysis::InductionInfo* trip, + HGraph* graph, + HBasicBlock* block, + /*out*/HInstruction** result, + bool in_body, + bool is_min); + /** Results of prior induction variable analysis. */ HInductionVarAnalysis *induction_analysis_; diff --git a/compiler/optimizing/induction_var_range_test.cc b/compiler/optimizing/induction_var_range_test.cc index 4497a884d9..56f661ed46 100644 --- a/compiler/optimizing/induction_var_range_test.cc +++ b/compiler/optimizing/induction_var_range_test.cc @@ -49,12 +49,52 @@ class InductionVarRangeTest : public testing::Test { /** Constructs bare minimum graph. */ void BuildGraph() { graph_->SetNumberOfVRegs(1); - HBasicBlock* entry_block = new (&allocator_) HBasicBlock(graph_); - HBasicBlock* exit_block = new (&allocator_) HBasicBlock(graph_); - graph_->AddBlock(entry_block); - graph_->AddBlock(exit_block); - graph_->SetEntryBlock(entry_block); - graph_->SetExitBlock(exit_block); + entry_block_ = new (&allocator_) HBasicBlock(graph_); + exit_block_ = new (&allocator_) HBasicBlock(graph_); + graph_->AddBlock(entry_block_); + graph_->AddBlock(exit_block_); + graph_->SetEntryBlock(entry_block_); + graph_->SetExitBlock(exit_block_); + } + + /** Constructs loop with given upper bound. */ + void BuildLoop(HInstruction* upper) { + // Control flow. + loop_preheader_ = new (&allocator_) HBasicBlock(graph_); + graph_->AddBlock(loop_preheader_); + HBasicBlock* loop_header = new (&allocator_) HBasicBlock(graph_); + graph_->AddBlock(loop_header); + HBasicBlock* loop_body = new (&allocator_) HBasicBlock(graph_); + graph_->AddBlock(loop_body); + entry_block_->AddSuccessor(loop_preheader_); + loop_preheader_->AddSuccessor(loop_header); + loop_header->AddSuccessor(loop_body); + loop_header->AddSuccessor(exit_block_); + loop_body->AddSuccessor(loop_header); + // Instructions. + HLocal* induc = new (&allocator_) HLocal(0); + entry_block_->AddInstruction(induc); + loop_preheader_->AddInstruction( + new (&allocator_) HStoreLocal(induc, graph_->GetIntConstant(0))); // i = 0 + loop_preheader_->AddInstruction(new (&allocator_) HGoto()); + HInstruction* load = new (&allocator_) HLoadLocal(induc, Primitive::kPrimInt); + loop_header->AddInstruction(load); + condition_ = new (&allocator_) HLessThan(load, upper); + loop_header->AddInstruction(condition_); + loop_header->AddInstruction(new (&allocator_) HIf(condition_)); // i < u + load = new (&allocator_) HLoadLocal(induc, Primitive::kPrimInt); + loop_body->AddInstruction(load); + increment_ = new (&allocator_) HAdd(Primitive::kPrimInt, load, graph_->GetIntConstant(1)); + loop_body->AddInstruction(increment_); + loop_body->AddInstruction(new (&allocator_) HStoreLocal(induc, increment_)); // i++ + loop_body->AddInstruction(new (&allocator_) HGoto()); + exit_block_->AddInstruction(new (&allocator_) HReturnVoid()); + } + + /** Performs induction variable analysis. */ + void PerformInductionVarAnalysis() { + ASSERT_TRUE(graph_->TryBuildingSsa()); + iva_->Run(); } /** Constructs an invariant. */ @@ -146,15 +186,20 @@ class InductionVarRangeTest : public testing::Test { ArenaPool pool_; ArenaAllocator allocator_; HGraph* graph_; + HBasicBlock* entry_block_; + HBasicBlock* exit_block_; + HBasicBlock* loop_preheader_; HInductionVarAnalysis* iva_; - // Two dummy instructions. + // Instructions. + HInstruction* condition_; + HInstruction* increment_; HReturnVoid x_; HReturnVoid y_; }; // -// The actual InductionVarRange tests. +// Tests on static methods. // TEST_F(InductionVarRangeTest, GetMinMaxNull) { @@ -349,4 +394,81 @@ TEST_F(InductionVarRangeTest, MaxValue) { ExpectEqual(Value(), MaxValue(Value(55), Value(&y_, 1, -50))); } +// +// Tests on instance methods. +// + +TEST_F(InductionVarRangeTest, FindRangeConstantTripCount) { + BuildLoop(graph_->GetIntConstant(1000)); + PerformInductionVarAnalysis(); + InductionVarRange range(iva_); + + // In context of header: known. + ExpectEqual(Value(0), range.GetMinInduction(condition_, condition_->InputAt(0))); + ExpectEqual(Value(1000), range.GetMaxInduction(condition_, condition_->InputAt(0))); + + // In context of loop-body: known. + ExpectEqual(Value(0), range.GetMinInduction(increment_, condition_->InputAt(0))); + ExpectEqual(Value(999), range.GetMaxInduction(increment_, condition_->InputAt(0))); + ExpectEqual(Value(1), range.GetMinInduction(increment_, increment_)); + ExpectEqual(Value(1000), range.GetMaxInduction(increment_, increment_)); +} + +TEST_F(InductionVarRangeTest, FindRangeSymbolicTripCount) { + HInstruction* parameter = new (&allocator_) HParameterValue(0, Primitive::kPrimInt); + entry_block_->AddInstruction(parameter); + BuildLoop(parameter); + PerformInductionVarAnalysis(); + InductionVarRange range(iva_); + + // In context of header: full range unknown. + ExpectEqual(Value(0), range.GetMinInduction(condition_, condition_->InputAt(0))); + ExpectEqual(Value(), range.GetMaxInduction(condition_, condition_->InputAt(0))); + + // In context of loop-body: known. + ExpectEqual(Value(0), range.GetMinInduction(increment_, condition_->InputAt(0))); + ExpectEqual(Value(parameter, 1, -1), range.GetMaxInduction(increment_, condition_->InputAt(0))); + ExpectEqual(Value(1), range.GetMinInduction(increment_, increment_)); + ExpectEqual(Value(parameter, 1, 0), range.GetMaxInduction(increment_, increment_)); +} + +TEST_F(InductionVarRangeTest, CodeGeneration) { + HInstruction* parameter = new (&allocator_) HParameterValue(0, Primitive::kPrimInt); + entry_block_->AddInstruction(parameter); + BuildLoop(parameter); + PerformInductionVarAnalysis(); + InductionVarRange range(iva_); + + HInstruction* lower = nullptr; + HInstruction* upper = nullptr; + bool top_test = false; + + // Can generate code in context of loop-body only. + EXPECT_FALSE(range.CanGenerateCode(condition_, condition_->InputAt(0), &top_test)); + ASSERT_TRUE(range.CanGenerateCode(increment_, condition_->InputAt(0), &top_test)); + EXPECT_TRUE(top_test); + + // Generates code. + EXPECT_TRUE(range.GenerateCode( + increment_, condition_->InputAt(0), graph_, loop_preheader_, &lower, &upper)); + + // Verify lower is 0+0. + ASSERT_TRUE(lower != nullptr); + ASSERT_TRUE(lower->IsAdd()); + ASSERT_TRUE(lower->InputAt(0)->IsIntConstant()); + EXPECT_EQ(0, lower->InputAt(0)->AsIntConstant()->GetValue()); + ASSERT_TRUE(lower->InputAt(1)->IsIntConstant()); + EXPECT_EQ(0, lower->InputAt(1)->AsIntConstant()->GetValue()); + + // Verify upper is (V-1)+0 + ASSERT_TRUE(upper != nullptr); + ASSERT_TRUE(upper->IsAdd()); + ASSERT_TRUE(upper->InputAt(0)->IsSub()); + EXPECT_TRUE(upper->InputAt(0)->InputAt(0)->IsParameterValue()); + ASSERT_TRUE(upper->InputAt(0)->InputAt(1)->IsIntConstant()); + EXPECT_EQ(1, upper->InputAt(0)->InputAt(1)->AsIntConstant()->GetValue()); + ASSERT_TRUE(upper->InputAt(1)->IsIntConstant()); + EXPECT_EQ(0, upper->InputAt(1)->AsIntConstant()->GetValue()); +} + } // namespace art diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index d468540091..7814eb9c11 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -73,6 +73,7 @@ class InstructionSimplifierVisitor : public HGraphDelegateVisitor { void VisitInstanceOf(HInstanceOf* instruction) OVERRIDE; void VisitFakeString(HFakeString* fake_string) OVERRIDE; void VisitInvoke(HInvoke* invoke) OVERRIDE; + void VisitDeoptimize(HDeoptimize* deoptimize) OVERRIDE; bool CanEnsureNotNullAt(HInstruction* instr, HInstruction* at) const; @@ -1151,4 +1152,16 @@ void InstructionSimplifierVisitor::VisitInvoke(HInvoke* instruction) { } } +void InstructionSimplifierVisitor::VisitDeoptimize(HDeoptimize* deoptimize) { + HInstruction* cond = deoptimize->InputAt(0); + if (cond->IsConstant()) { + if (cond->AsIntConstant()->IsZero()) { + // Never deopt: instruction can be removed. + deoptimize->GetBlock()->RemoveInstruction(deoptimize); + } else { + // Always deopt. + } + } +} + } // namespace art diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 395649ed74..81622e14ed 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1208,7 +1208,7 @@ mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, uint8_t* raw_arrays = nullptr; if (dex_file.GetOatDexFile() != nullptr && dex_file.GetOatDexFile()->GetDexCacheArrays() != nullptr) { - raw_arrays = const_cast<uint8_t*>(dex_file.GetOatDexFile()->GetDexCacheArrays()); + raw_arrays = dex_file.GetOatDexFile()->GetDexCacheArrays(); } else if (dex_file.NumStringIds() != 0u || dex_file.NumTypeIds() != 0u || dex_file.NumMethodIds() != 0u || dex_file.NumFieldIds() != 0u) { // NOTE: We "leak" the raw_arrays because we never destroy the dex cache. @@ -6369,6 +6369,21 @@ void ClassLinker::VisitClassLoaders(ClassLoaderVisitor* visitor) const { } } +void ClassLinker::InsertDexFileInToClassLoader(mirror::Object* dex_file, + mirror::ClassLoader* class_loader) { + DCHECK(dex_file != nullptr); + DCHECK(class_loader != nullptr); + Thread* const self = Thread::Current(); + WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); + ClassTable* const table = class_loader->GetClassTable(); + DCHECK(table != nullptr); + if (table->InsertDexFile(dex_file)) { + // It was not already inserted, perform the write barrier to let the GC know the class loader's + // class table was modified. + Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader); + } +} + void ClassLinker::CleanupClassLoaders() { Thread* const self = Thread::Current(); WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); diff --git a/runtime/class_linker.h b/runtime/class_linker.h index fd30a46a1b..a2d38ac620 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -526,8 +526,8 @@ class ClassLinker { // Clean up class loaders, this needs to happen after JNI weak globals are cleared. void CleanupClassLoaders() - SHARED_REQUIRES(Locks::mutator_lock_) - REQUIRES(!Locks::classlinker_classes_lock_); + REQUIRES(!Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); // Unlike GetOrCreateAllocatorForClassLoader, GetAllocatorForClassLoader asserts that the // allocator for this class loader is already created. @@ -537,8 +537,12 @@ class ClassLinker { // Return the linear alloc for a class loader if it is already allocated, otherwise allocate and // set it. TODO: Consider using a lock other than classlinker_classes_lock_. static LinearAlloc* GetOrCreateAllocatorForClassLoader(mirror::ClassLoader* class_loader) - SHARED_REQUIRES(Locks::mutator_lock_) - REQUIRES(!Locks::classlinker_classes_lock_); + REQUIRES(!Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); + + void InsertDexFileInToClassLoader(mirror::Object* dex_file, mirror::ClassLoader* class_loader) + REQUIRES(!Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); private: struct ClassLoaderData { diff --git a/runtime/class_table-inl.h b/runtime/class_table-inl.h index dc60a2c239..aef02b6d5d 100644 --- a/runtime/class_table-inl.h +++ b/runtime/class_table-inl.h @@ -37,6 +37,9 @@ void ClassTable::VisitRoots(const Visitor& visitor) { visitor.VisitRoot(root.AddressWithoutBarrier()); } } + for (GcRoot<mirror::Object>& root : dex_files_) { + visitor.VisitRoot(root.AddressWithoutBarrier()); + } } } // namespace art diff --git a/runtime/class_table.cc b/runtime/class_table.cc index 4b0cbc836c..3ed1c9540d 100644 --- a/runtime/class_table.cc +++ b/runtime/class_table.cc @@ -137,4 +137,15 @@ std::size_t ClassTable::ClassDescriptorHashEquals::operator()(const char* descri return ComputeModifiedUtf8Hash(descriptor); } +bool ClassTable::InsertDexFile(mirror::Object* dex_file) { + DCHECK(dex_file != nullptr); + for (GcRoot<mirror::Object>& root : dex_files_) { + if (root.Read() == dex_file) { + return false; + } + } + dex_files_.push_back(GcRoot<mirror::Object>(dex_file)); + return true; +} + } // namespace art diff --git a/runtime/class_table.h b/runtime/class_table.h index 727392eb6f..002bb564ab 100644 --- a/runtime/class_table.h +++ b/runtime/class_table.h @@ -50,12 +50,14 @@ class ClassTable { // Used by image writer for checking. bool Contains(mirror::Class* klass) - REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES(Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); // Freeze the current class tables by allocating a new table and never updating or modifying the // existing table. This helps prevents dirty pages after caused by inserting after zygote fork. void FreezeSnapshot() - REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES(Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); // Returns the number of classes in previous snapshots. size_t NumZygoteClasses() const SHARED_REQUIRES(Locks::classlinker_classes_lock_); @@ -65,17 +67,18 @@ class ClassTable { // Update a class in the table with the new class. Returns the existing class which was replaced. mirror::Class* UpdateClass(const char* descriptor, mirror::Class* new_klass, size_t hash) - REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES(Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); // NO_THREAD_SAFETY_ANALYSIS for object marking requiring heap bitmap lock. template<class Visitor> void VisitRoots(Visitor& visitor) - SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_) - NO_THREAD_SAFETY_ANALYSIS; + NO_THREAD_SAFETY_ANALYSIS + SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_); template<class Visitor> void VisitRoots(const Visitor& visitor) - SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_) - NO_THREAD_SAFETY_ANALYSIS; + NO_THREAD_SAFETY_ANALYSIS + SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_); // Return false if the callback told us to exit. bool Visit(ClassVisitor* visitor) @@ -85,13 +88,21 @@ class ClassTable { SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_); void Insert(mirror::Class* klass) - REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES(Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); void InsertWithHash(mirror::Class* klass, size_t hash) - REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES(Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); // Returns true if the class was found and removed, false otherwise. bool Remove(const char* descriptor) - REQUIRES(Locks::classlinker_classes_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + REQUIRES(Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); + + // Return true if we inserted the dex file, false if it already exists. + bool InsertDexFile(mirror::Object* dex_file) + REQUIRES(Locks::classlinker_classes_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); private: class ClassDescriptorHashEquals { @@ -123,6 +134,9 @@ class ClassTable { // TODO: shard lock to have one per class loader. // We have a vector to help prevent dirty pages after the zygote forks by calling FreezeSnapshot. std::vector<ClassSet> classes_ GUARDED_BY(Locks::classlinker_classes_lock_); + // Dex files used by the class loader which may not be owned by the class loader. We keep these + // live so that we do not have issues closing any of the dex files. + std::vector<GcRoot<mirror::Object>> dex_files_ GUARDED_BY(Locks::classlinker_classes_lock_); }; } // namespace art diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 4eea3f39f7..8b2f4d8d24 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -243,7 +243,8 @@ static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, jobject javaLoader, - jobject cookie) { + jobject cookie, + jobject dexFile) { std::vector<const DexFile*> dex_files; const OatFile* oat_file; if (!ConvertJavaArrayToDexFiles(env, cookie, /*out*/ dex_files, /*out*/ oat_file)) { @@ -276,6 +277,10 @@ static jclass DexFile_defineClassNative(JNIEnv* env, 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), + class_loader.Get()); if (result != nullptr) { VLOG(class_linker) << "DexFile_defineClassNative returning " << result << " for " << class_name.c_str(); @@ -424,8 +429,13 @@ static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename static JNINativeMethod gMethods[] = { NATIVE_METHOD(DexFile, closeDexFile, "(Ljava/lang/Object;)Z"), - NATIVE_METHOD(DexFile, defineClassNative, - "(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/Object;)Ljava/lang/Class;"), + NATIVE_METHOD(DexFile, + defineClassNative, + "(Ljava/lang/String;" + "Ljava/lang/ClassLoader;" + "Ljava/lang/Object;" + "Ldalvik/system/DexFile;" + ")Ljava/lang/Class;"), NATIVE_METHOD(DexFile, getClassNameList, "(Ljava/lang/Object;)[Ljava/lang/String;"), NATIVE_METHOD(DexFile, isDexOptNeeded, "(Ljava/lang/String;)Z"), NATIVE_METHOD(DexFile, getDexOptNeeded, diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index e861921130..a162a4ea72 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -18,6 +18,7 @@ #include <dlfcn.h> #include <string.h> +#include <type_traits> #include <unistd.h> #include <cstdlib> @@ -388,13 +389,13 @@ bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file // Readjust to be non-inclusive upper bound. end_ += sizeof(uint32_t); - bss_begin_ = elf_file_->FindDynamicSymbolAddress("oatbss"); + bss_begin_ = const_cast<uint8_t*>(elf_file_->FindDynamicSymbolAddress("oatbss")); if (bss_begin_ == nullptr) { // No .bss section. Clear dlerror(). bss_end_ = nullptr; dlerror(); } else { - bss_end_ = elf_file_->FindDynamicSymbolAddress("oatbsslastword"); + bss_end_ = const_cast<uint8_t*>(elf_file_->FindDynamicSymbolAddress("oatbsslastword")); if (bss_end_ == nullptr) { *error_msg = StringPrintf("Failed to find oatbasslastword symbol in '%s'", file->GetPath().c_str()); @@ -407,10 +408,31 @@ bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file return Setup(abs_dex_location, error_msg); } +// Read an unaligned entry from the OatDexFile data in OatFile and advance the read +// position by the number of bytes read, i.e. sizeof(T). +// Return true on success, false if the read would go beyond the end of the OatFile. +template <typename T> +inline static bool ReadOatDexFileData(const OatFile& oat_file, + /*inout*/const uint8_t** oat, + /*out*/T* value) { + DCHECK(oat != nullptr); + DCHECK(value != nullptr); + DCHECK_LE(*oat, oat_file.End()); + if (UNLIKELY(static_cast<size_t>(oat_file.End() - *oat) < sizeof(T))) { + return false; + } + static_assert(std::is_trivial<T>::value, "T must be a trivial type"); + typedef __attribute__((__aligned__(1))) T unaligned_type; + *value = *reinterpret_cast<const unaligned_type*>(*oat); + *oat += sizeof(T); + return true; +} + bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) { if (!GetOatHeader().IsValid()) { std::string cause = GetOatHeader().GetValidationErrorMessage(); - *error_msg = StringPrintf("Invalid oat header for '%s': %s", GetLocation().c_str(), + *error_msg = StringPrintf("Invalid oat header for '%s': %s", + GetLocation().c_str(), cause.c_str()); return false; } @@ -424,35 +446,42 @@ bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) { oat += GetOatHeader().GetKeyValueStoreSize(); if (oat > End()) { *error_msg = StringPrintf("In oat file '%s' found truncated variable-size data: " - "%p + %zd + %ud <= %p", GetLocation().c_str(), - Begin(), sizeof(OatHeader), GetOatHeader().GetKeyValueStoreSize(), + "%p + %zu + %u <= %p", + GetLocation().c_str(), + Begin(), + sizeof(OatHeader), + GetOatHeader().GetKeyValueStoreSize(), End()); return false; } size_t pointer_size = GetInstructionSetPointerSize(GetOatHeader().GetInstructionSet()); - const uint8_t* dex_cache_arrays = bss_begin_; + uint8_t* dex_cache_arrays = bss_begin_; uint32_t dex_file_count = GetOatHeader().GetDexFileCount(); oat_dex_files_storage_.reserve(dex_file_count); for (size_t i = 0; i < dex_file_count; i++) { - uint32_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat); - if (UNLIKELY(dex_file_location_size == 0U)) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with empty location name", - GetLocation().c_str(), i); + uint32_t dex_file_location_size; + if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &dex_file_location_size))) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu truncated after dex file " + "location size", + GetLocation().c_str(), + i); return false; } - oat += sizeof(dex_file_location_size); - if (UNLIKELY(oat > End())) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd truncated after dex file " - "location size", GetLocation().c_str(), i); + if (UNLIKELY(dex_file_location_size == 0U)) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu with empty location name", + GetLocation().c_str(), + i); return false; } const char* dex_file_location_data = reinterpret_cast<const char*>(oat); oat += dex_file_location_size; if (UNLIKELY(oat > End())) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with truncated dex file " - "location", GetLocation().c_str(), i); + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu with truncated dex file " + "location", + GetLocation().c_str(), + i); return false; } @@ -460,46 +489,61 @@ bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) { abs_dex_location, std::string(dex_file_location_data, dex_file_location_size)); - uint32_t dex_file_checksum = *reinterpret_cast<const uint32_t*>(oat); - oat += sizeof(dex_file_checksum); - if (UNLIKELY(oat > End())) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated after " - "dex file checksum", GetLocation().c_str(), i, + uint32_t dex_file_checksum; + if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &dex_file_checksum))) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' truncated after " + "dex file checksum", + GetLocation().c_str(), + i, dex_file_location.c_str()); return false; } - uint32_t dex_file_offset = *reinterpret_cast<const uint32_t*>(oat); - if (UNLIKELY(dex_file_offset == 0U)) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with zero dex " - "file offset", GetLocation().c_str(), i, dex_file_location.c_str()); + uint32_t dex_file_offset; + if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &dex_file_offset))) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' truncated " + "after dex file offsets", + GetLocation().c_str(), + i, + dex_file_location.c_str()); return false; } - if (UNLIKELY(dex_file_offset > Size())) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with dex file " - "offset %ud > %zd", GetLocation().c_str(), i, - dex_file_location.c_str(), dex_file_offset, Size()); + if (UNLIKELY(dex_file_offset == 0U)) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with zero dex " + "file offset", + GetLocation().c_str(), + i, + dex_file_location.c_str()); return false; } - oat += sizeof(dex_file_offset); - if (UNLIKELY(oat > End())) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated " - "after dex file offsets", GetLocation().c_str(), i, - dex_file_location.c_str()); + if (UNLIKELY(dex_file_offset > Size())) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with dex file " + "offset %u > %zu", + GetLocation().c_str(), + i, + dex_file_location.c_str(), + dex_file_offset, + Size()); return false; } const uint8_t* dex_file_pointer = Begin() + dex_file_offset; if (UNLIKELY(!DexFile::IsMagicValid(dex_file_pointer))) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with invalid " - "dex file magic '%s'", GetLocation().c_str(), i, - dex_file_location.c_str(), dex_file_pointer); + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with invalid " + "dex file magic '%s'", + GetLocation().c_str(), + i, + dex_file_location.c_str(), + dex_file_pointer); return false; } if (UNLIKELY(!DexFile::IsVersionValid(dex_file_pointer))) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with invalid " - "dex file version '%s'", GetLocation().c_str(), i, - dex_file_location.c_str(), dex_file_pointer); + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with invalid " + "dex file version '%s'", + GetLocation().c_str(), + i, + dex_file_location.c_str(), + dex_file_pointer); return false; } const DexFile::Header* header = reinterpret_cast<const DexFile::Header*>(dex_file_pointer); @@ -507,21 +551,26 @@ bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) { oat += (sizeof(*methods_offsets_pointer) * header->class_defs_size_); if (UNLIKELY(oat > End())) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with truncated " - "method offsets", GetLocation().c_str(), i, + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with truncated " + "method offsets", + GetLocation().c_str(), + i, dex_file_location.c_str()); return false; } - const uint8_t* current_dex_cache_arrays = nullptr; + uint8_t* current_dex_cache_arrays = nullptr; if (dex_cache_arrays != nullptr) { DexCacheArraysLayout layout(pointer_size, *header); if (layout.Size() != 0u) { if (static_cast<size_t>(bss_end_ - dex_cache_arrays) < layout.Size()) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with " - "truncated dex cache arrays, %zd < %zd.", - GetLocation().c_str(), i, dex_file_location.c_str(), - static_cast<size_t>(bss_end_ - dex_cache_arrays), layout.Size()); + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with " + "truncated dex cache arrays, %zu < %zu.", + GetLocation().c_str(), + i, + dex_file_location.c_str(), + static_cast<size_t>(bss_end_ - dex_cache_arrays), + layout.Size()); return false; } current_dex_cache_arrays = dex_cache_arrays; @@ -553,7 +602,7 @@ bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) { if (dex_cache_arrays != bss_end_) { // We expect the bss section to be either empty (dex_cache_arrays and bss_end_ // both null) or contain just the dex cache arrays and nothing else. - *error_msg = StringPrintf("In oat file '%s' found unexpected bss size bigger by %zd bytes.", + *error_msg = StringPrintf("In oat file '%s' found unexpected bss size bigger by %zu bytes.", GetLocation().c_str(), static_cast<size_t>(bss_end_ - dex_cache_arrays)); return false; @@ -661,7 +710,7 @@ OatFile::OatDexFile::OatDexFile(const OatFile* oat_file, uint32_t dex_file_location_checksum, const uint8_t* dex_file_pointer, const uint32_t* oat_class_offsets_pointer, - const uint8_t* dex_cache_arrays) + uint8_t* dex_cache_arrays) : oat_file_(oat_file), dex_file_location_(dex_file_location), canonical_dex_file_location_(canonical_dex_file_location), diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 34f014123b..6acdf86208 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -301,10 +301,10 @@ class OatFile FINAL { const uint8_t* end_; // Pointer to the .bss section, if present, otherwise null. - const uint8_t* bss_begin_; + uint8_t* bss_begin_; // Pointer to the end of the .bss section, if present, otherwise null. - const uint8_t* bss_end_; + uint8_t* bss_end_; // Was this oat_file loaded executable? const bool is_executable_; @@ -396,7 +396,7 @@ class OatDexFile FINAL { // Returns the offset to the OatClass information. Most callers should use GetOatClass. uint32_t GetOatClassOffset(uint16_t class_def_index) const; - const uint8_t* GetDexCacheArrays() const { + uint8_t* GetDexCacheArrays() const { return dex_cache_arrays_; } @@ -409,7 +409,7 @@ class OatDexFile FINAL { uint32_t dex_file_checksum, const uint8_t* dex_file_pointer, const uint32_t* oat_class_offsets_pointer, - const uint8_t* dex_cache_arrays); + uint8_t* dex_cache_arrays); const OatFile* const oat_file_; const std::string dex_file_location_; @@ -417,7 +417,7 @@ class OatDexFile FINAL { const uint32_t dex_file_location_checksum_; const uint8_t* const dex_file_pointer_; const uint32_t* const oat_class_offsets_pointer_; - const uint8_t* const dex_cache_arrays_; + uint8_t* const dex_cache_arrays_; friend class OatFile; DISALLOW_COPY_AND_ASSIGN(OatDexFile); diff --git a/test/087-gc-after-link/src/Main.java b/test/087-gc-after-link/src/Main.java index 2f6d496f44..7c47e9976f 100644 --- a/test/087-gc-after-link/src/Main.java +++ b/test/087-gc-after-link/src/Main.java @@ -91,6 +91,7 @@ public class Main { * is an error we can't recover from. */ meth.invoke(dexFile, name, this); + System.out.println("Unreachable"); } finally { if (dexFile != null) { /* close the DexFile to make CloseGuard happy */ |