diff options
22 files changed, 1410 insertions, 1016 deletions
diff --git a/build/art.go b/build/art.go index f305c0784a..d41b40704f 100644 --- a/build/art.go +++ b/build/art.go @@ -137,12 +137,42 @@ func (a *artGlobalDefaults) CustomizeProperties(ctx android.CustomizePropertiesC p.Target.Android.Cflags = deviceFlags(ctx) p.Target.Host.Cflags = hostFlags(ctx) ctx.AppendProperties(p) + + if envTrue(ctx, "HOST_PREFER_32_BIT") { + type props struct { + Target struct { + Host struct { + Compile_multilib string + } + } + } + + p := &props{} + p.Target.Host.Compile_multilib = "prefer32" + ctx.AppendProperties(p) + } } type artGlobalDefaults struct{} +func (a *artLinkerCustomizer) CustomizeProperties(ctx android.CustomizePropertiesContext) { + linker := envDefault(ctx, "CUSTOM_TARGET_LINKER", "") + if linker != "" { + type props struct { + DynamicLinker string + } + + p := &props{} + p.DynamicLinker = linker + ctx.AppendProperties(p) + } +} + +type artLinkerCustomizer struct{} + func init() { soong.RegisterModuleType("art_cc_library", artLibrary) + soong.RegisterModuleType("art_cc_binary", artBinary) soong.RegisterModuleType("art_cc_defaults", artDefaultsFactory) soong.RegisterModuleType("art_global_defaults", artGlobalDefaultsFactory) } @@ -173,6 +203,14 @@ func artLibrary() (blueprint.Module, []interface{}) { return module, props } +func artBinary() (blueprint.Module, []interface{}) { + binary, _ := cc.NewBinary(android.HostAndDeviceSupported) + module, props := binary.Init() + + android.AddCustomizer(binary, &artLinkerCustomizer{}) + return module, props +} + func envDefault(ctx android.BaseContext, key string, defaultValue string) string { ret := ctx.AConfig().Getenv(key) if ret == "" { diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 2ef1802522..5301a6bb3e 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -247,35 +247,6 @@ class LoadClassSlowPathARM : public SlowPathCode { DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM); }; -class LoadStringSlowPathARM : public SlowPathCode { - public: - explicit LoadStringSlowPathARM(HLoadString* instruction) : SlowPathCode(instruction) {} - - void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { - LocationSummary* locations = instruction_->GetLocations(); - DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); - - CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); - __ Bind(GetEntryLabel()); - SaveLiveRegisters(codegen, locations); - - InvokeRuntimeCallingConvention calling_convention; - const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex(); - __ LoadImmediate(calling_convention.GetRegisterAt(0), string_index); - arm_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this); - CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>(); - arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0)); - - RestoreLiveRegisters(codegen, locations); - __ b(GetExitLabel()); - } - - const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; } - - private: - DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM); -}; - class TypeCheckSlowPathARM : public SlowPathCode { public: TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal) @@ -5337,17 +5308,6 @@ void ParallelMoveResolverARM::RestoreScratch(int reg) { HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind( HLoadClass::LoadKind desired_class_load_kind) { - if (kEmitCompilerReadBarrier) { - switch (desired_class_load_kind) { - case HLoadClass::LoadKind::kBootImageLinkTimeAddress: - case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: - case HLoadClass::LoadKind::kBootImageAddress: - // TODO: Implement for read barrier. - return HLoadClass::LoadKind::kDexCacheViaMethod; - default: - break; - } - } switch (desired_class_load_kind) { case HLoadClass::LoadKind::kReferrersClass: break; @@ -5389,11 +5349,12 @@ void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) { return; } - LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || kEmitCompilerReadBarrier) + const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage(); + LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier) ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall; LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); - if (kUseBakerReadBarrier && !cls->NeedsEnvironment()) { + if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) { locations->SetCustomSlowPathCallerSaves(RegisterSet()); // No caller-save registers. } @@ -5418,6 +5379,7 @@ void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) { Location out_loc = locations->Out(); Register out = out_loc.AsRegister<Register>(); + const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage(); bool generate_null_check = false; switch (cls->GetLoadKind()) { case HLoadClass::LoadKind::kReferrersClass: { @@ -5425,18 +5387,21 @@ void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) { DCHECK(!cls->MustGenerateClinitCheck()); // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_ Register current_method = locations->InAt(0).AsRegister<Register>(); - GenerateGcRootFieldLoad( - cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value()); + GenerateGcRootFieldLoad(cls, + out_loc, + current_method, + ArtMethod::DeclaringClassOffset().Int32Value(), + requires_read_barrier); break; } case HLoadClass::LoadKind::kBootImageLinkTimeAddress: { - DCHECK(!kEmitCompilerReadBarrier); + DCHECK(!requires_read_barrier); __ LoadLiteral(out, codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(), cls->GetTypeIndex())); break; } case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: { - DCHECK(!kEmitCompilerReadBarrier); + DCHECK(!requires_read_barrier); CodeGeneratorARM::PcRelativePatchInfo* labels = codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex()); __ BindTrackedLabel(&labels->movw_label); @@ -5448,7 +5413,7 @@ void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) { break; } case HLoadClass::LoadKind::kBootImageAddress: { - DCHECK(!kEmitCompilerReadBarrier); + DCHECK(!requires_read_barrier); DCHECK_NE(cls->GetAddress(), 0u); uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress()); __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address)); @@ -5468,7 +5433,7 @@ void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) { uint32_t offset = address & MaxInt<uint32_t>(offset_bits); __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address)); // /* GcRoot<mirror::Class> */ out = *(base_address + offset) - GenerateGcRootFieldLoad(cls, out_loc, out, offset); + GenerateGcRootFieldLoad(cls, out_loc, out, offset, requires_read_barrier); generate_null_check = !cls->IsInDexCache(); break; } @@ -5477,7 +5442,7 @@ void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) { HArmDexCacheArraysBase* base = cls->InputAt(0)->AsArmDexCacheArraysBase(); int32_t offset = cls->GetDexCacheElementOffset() - base->GetElementOffset(); // /* GcRoot<mirror::Class> */ out = *(dex_cache_arrays_base + offset) - GenerateGcRootFieldLoad(cls, out_loc, base_reg, offset); + GenerateGcRootFieldLoad(cls, out_loc, base_reg, offset, requires_read_barrier); generate_null_check = !cls->IsInDexCache(); break; } @@ -5491,7 +5456,7 @@ void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) { ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value()); // /* GcRoot<mirror::Class> */ out = out[type_index] size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex()); - GenerateGcRootFieldLoad(cls, out_loc, out, offset); + GenerateGcRootFieldLoad(cls, out_loc, out, offset, requires_read_barrier); generate_null_check = !cls->IsInDexCache(); } } @@ -5583,28 +5548,28 @@ HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind( } void LocationsBuilderARM::VisitLoadString(HLoadString* load) { - LocationSummary::CallKind call_kind = (load->NeedsEnvironment() || kEmitCompilerReadBarrier) - ? LocationSummary::kCallOnSlowPath + LocationSummary::CallKind call_kind = load->NeedsEnvironment() + ? LocationSummary::kCallOnMainOnly : LocationSummary::kNoCall; LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind); - if (kUseBakerReadBarrier && !load->NeedsEnvironment()) { - locations->SetCustomSlowPathCallerSaves(RegisterSet()); // No caller-save registers. - } HLoadString::LoadKind load_kind = load->GetLoadKind(); - if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod || - load_kind == HLoadString::LoadKind::kDexCachePcRelative) { + DCHECK(load_kind != HLoadString::LoadKind::kDexCachePcRelative) << "Not supported"; + if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) { locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RegisterLocation(R0)); + } else { + locations->SetOut(Location::RequiresRegister()); } - locations->SetOut(Location::RequiresRegister()); } void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) { LocationSummary* locations = load->GetLocations(); Location out_loc = locations->Out(); Register out = out_loc.AsRegister<Register>(); + HLoadString::LoadKind load_kind = load->GetLoadKind(); - switch (load->GetLoadKind()) { + switch (load_kind) { case HLoadString::LoadKind::kBootImageLinkTimeAddress: { DCHECK(!kEmitCompilerReadBarrier); __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(), @@ -5634,11 +5599,12 @@ void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) { break; } - // TODO: Re-add the compiler code to do string dex cache lookup again. - SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load); - codegen_->AddSlowPath(slow_path); - __ b(slow_path->GetEntryLabel()); - __ Bind(slow_path->GetExitLabel()); + // TODO: Consider re-adding the compiler code to do string dex cache lookup again. + DCHECK(load_kind == HLoadString::LoadKind::kDexCacheViaMethod); + InvokeRuntimeCallingConvention calling_convention; + __ LoadImmediate(calling_convention.GetRegisterAt(0), load->GetStringIndex()); + codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc()); + CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>(); } static int32_t GetExceptionTlsOffset() { @@ -6403,9 +6369,11 @@ void InstructionCodeGeneratorARM::GenerateReferenceLoadTwoRegisters(HInstruction void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction, Location root, Register obj, - uint32_t offset) { + uint32_t offset, + bool requires_read_barrier) { Register root_reg = root.AsRegister<Register>(); - if (kEmitCompilerReadBarrier) { + if (requires_read_barrier) { + DCHECK(kEmitCompilerReadBarrier); if (kUseBakerReadBarrier) { // Fast path implementation of art::ReadBarrier::BarrierForRoot when // Baker's read barrier are used: diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index ac10e2364a..ce9d7e6056 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -271,11 +271,12 @@ class InstructionCodeGeneratorARM : public InstructionCodeGenerator { // // root <- *(obj + offset) // - // while honoring read barriers (if any). + // while honoring read barriers if requires_read_barrier is true. void GenerateGcRootFieldLoad(HInstruction* instruction, Location root, Register obj, - uint32_t offset); + uint32_t offset, + bool requires_read_barrier = kEmitCompilerReadBarrier); void GenerateTestAndBranch(HInstruction* instruction, size_t condition_input_index, Label* true_target, diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index ceceedd793..36f7b4d914 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -4044,17 +4044,6 @@ void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) { HLoadClass::LoadKind CodeGeneratorARM64::GetSupportedLoadClassKind( HLoadClass::LoadKind desired_class_load_kind) { - if (kEmitCompilerReadBarrier) { - switch (desired_class_load_kind) { - case HLoadClass::LoadKind::kBootImageLinkTimeAddress: - case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: - case HLoadClass::LoadKind::kBootImageAddress: - // TODO: Implement for read barrier. - return HLoadClass::LoadKind::kDexCacheViaMethod; - default: - break; - } - } switch (desired_class_load_kind) { case HLoadClass::LoadKind::kReferrersClass: break; @@ -4089,11 +4078,12 @@ void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) { return; } - LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || kEmitCompilerReadBarrier) + const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage(); + LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier) ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall; LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); - if (kUseBakerReadBarrier && !cls->NeedsEnvironment()) { + if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) { locations->SetCustomSlowPathCallerSaves(RegisterSet()); // No caller-save registers. } @@ -4116,6 +4106,7 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) { Location out_loc = cls->GetLocations()->Out(); Register out = OutputRegister(cls); + const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage(); bool generate_null_check = false; switch (cls->GetLoadKind()) { case HLoadClass::LoadKind::kReferrersClass: { @@ -4123,17 +4114,21 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) { DCHECK(!cls->MustGenerateClinitCheck()); // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_ Register current_method = InputRegisterAt(cls, 0); - GenerateGcRootFieldLoad( - cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value()); + GenerateGcRootFieldLoad(cls, + out_loc, + current_method, + ArtMethod::DeclaringClassOffset().Int32Value(), + /*fixup_label*/ nullptr, + requires_read_barrier); break; } case HLoadClass::LoadKind::kBootImageLinkTimeAddress: - DCHECK(!kEmitCompilerReadBarrier); + DCHECK(!requires_read_barrier); __ Ldr(out, codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(), cls->GetTypeIndex())); break; case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: { - DCHECK(!kEmitCompilerReadBarrier); + DCHECK(!requires_read_barrier); // Add ADRP with its PC-relative type patch. const DexFile& dex_file = cls->GetDexFile(); uint32_t type_index = cls->GetTypeIndex(); @@ -4154,7 +4149,7 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) { break; } case HLoadClass::LoadKind::kBootImageAddress: { - DCHECK(!kEmitCompilerReadBarrier); + DCHECK(!requires_read_barrier); DCHECK(cls->GetAddress() != 0u && IsUint<32>(cls->GetAddress())); __ Ldr(out.W(), codegen_->DeduplicateBootImageAddressLiteral(cls->GetAddress())); break; @@ -4172,7 +4167,12 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) { uint32_t offset = cls->GetAddress() & MaxInt<uint64_t>(offset_bits); __ Ldr(out.X(), codegen_->DeduplicateDexCacheAddressLiteral(base_address)); // /* GcRoot<mirror::Class> */ out = *(base_address + offset) - GenerateGcRootFieldLoad(cls, out_loc, out.X(), offset); + GenerateGcRootFieldLoad(cls, + out_loc, + out.X(), + offset, + /*fixup_label*/ nullptr, + requires_read_barrier); generate_null_check = !cls->IsInDexCache(); break; } @@ -4191,7 +4191,12 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) { vixl::aarch64::Label* ldr_label = codegen_->NewPcRelativeDexCacheArrayPatch(dex_file, element_offset, adrp_label); // /* GcRoot<mirror::Class> */ out = *(base_address + offset) /* PC-relative */ - GenerateGcRootFieldLoad(cls, out_loc, out.X(), /* offset placeholder */ 0, ldr_label); + GenerateGcRootFieldLoad(cls, + out_loc, + out.X(), + /* offset placeholder */ 0, + ldr_label, + requires_read_barrier); generate_null_check = !cls->IsInDexCache(); break; } @@ -4203,8 +4208,12 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) { Register current_method = InputRegisterAt(cls, 0); __ Ldr(out.X(), MemOperand(current_method, resolved_types_offset.Int32Value())); // /* GcRoot<mirror::Class> */ out = out[type_index] - GenerateGcRootFieldLoad( - cls, out_loc, out.X(), CodeGenerator::GetCacheOffset(cls->GetTypeIndex())); + GenerateGcRootFieldLoad(cls, + out_loc, + out.X(), + CodeGenerator::GetCacheOffset(cls->GetTypeIndex()), + /*fixup_label*/ nullptr, + requires_read_barrier); generate_null_check = !cls->IsInDexCache(); break; } @@ -5106,9 +5115,11 @@ void InstructionCodeGeneratorARM64::GenerateGcRootFieldLoad(HInstruction* instru Location root, Register obj, uint32_t offset, - vixl::aarch64::Label* fixup_label) { + vixl::aarch64::Label* fixup_label, + bool requires_read_barrier) { Register root_reg = RegisterFrom(root, Primitive::kPrimNot); - if (kEmitCompilerReadBarrier) { + if (requires_read_barrier) { + DCHECK(kEmitCompilerReadBarrier); if (kUseBakerReadBarrier) { // Fast path implementation of art::ReadBarrier::BarrierForRoot when // Baker's read barrier are used: diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index 78db80307c..f0d79106dc 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -294,7 +294,8 @@ class InstructionCodeGeneratorARM64 : public InstructionCodeGenerator { Location root, vixl::aarch64::Register obj, uint32_t offset, - vixl::aarch64::Label* fixup_label = nullptr); + vixl::aarch64::Label* fixup_label = nullptr, + bool requires_read_barrier = kEmitCompilerReadBarrier); // Generate a floating-point comparison. void GenerateFcmp(HInstruction* instruction); diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 8858def40a..4689ccb05c 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -5961,17 +5961,6 @@ void ParallelMoveResolverX86::RestoreScratch(int reg) { HLoadClass::LoadKind CodeGeneratorX86::GetSupportedLoadClassKind( HLoadClass::LoadKind desired_class_load_kind) { - if (kEmitCompilerReadBarrier) { - switch (desired_class_load_kind) { - case HLoadClass::LoadKind::kBootImageLinkTimeAddress: - case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: - case HLoadClass::LoadKind::kBootImageAddress: - // TODO: Implement for read barrier. - return HLoadClass::LoadKind::kDexCacheViaMethod; - default: - break; - } - } switch (desired_class_load_kind) { case HLoadClass::LoadKind::kReferrersClass: break; @@ -6013,11 +6002,12 @@ void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) { return; } - LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || kEmitCompilerReadBarrier) + const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage(); + LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier) ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall; LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); - if (kUseBakerReadBarrier && !cls->NeedsEnvironment()) { + if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) { locations->SetCustomSlowPathCallerSaves(RegisterSet()); // No caller-save registers. } @@ -6044,6 +6034,7 @@ void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) { Register out = out_loc.AsRegister<Register>(); bool generate_null_check = false; + const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage(); switch (cls->GetLoadKind()) { case HLoadClass::LoadKind::kReferrersClass: { DCHECK(!cls->CanCallRuntime()); @@ -6051,24 +6042,28 @@ void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) { // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_ Register current_method = locations->InAt(0).AsRegister<Register>(); GenerateGcRootFieldLoad( - cls, out_loc, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value())); + cls, + out_loc, + Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()), + /*fixup_label*/ nullptr, + requires_read_barrier); break; } case HLoadClass::LoadKind::kBootImageLinkTimeAddress: { - DCHECK(!kEmitCompilerReadBarrier); + DCHECK(!requires_read_barrier); __ movl(out, Immediate(/* placeholder */ 0)); codegen_->RecordTypePatch(cls); break; } case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: { - DCHECK(!kEmitCompilerReadBarrier); + DCHECK(!requires_read_barrier); Register method_address = locations->InAt(0).AsRegister<Register>(); __ leal(out, Address(method_address, CodeGeneratorX86::kDummy32BitOffset)); codegen_->RecordTypePatch(cls); break; } case HLoadClass::LoadKind::kBootImageAddress: { - DCHECK(!kEmitCompilerReadBarrier); + DCHECK(!requires_read_barrier); DCHECK_NE(cls->GetAddress(), 0u); uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress()); __ movl(out, Immediate(address)); @@ -6079,7 +6074,11 @@ void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) { DCHECK_NE(cls->GetAddress(), 0u); uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress()); // /* GcRoot<mirror::Class> */ out = *address - GenerateGcRootFieldLoad(cls, out_loc, Address::Absolute(address)); + GenerateGcRootFieldLoad(cls, + out_loc, + Address::Absolute(address), + /*fixup_label*/ nullptr, + requires_read_barrier); generate_null_check = !cls->IsInDexCache(); break; } @@ -6088,8 +6087,11 @@ void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) { uint32_t offset = cls->GetDexCacheElementOffset(); Label* fixup_label = codegen_->NewPcRelativeDexCacheArrayPatch(cls->GetDexFile(), offset); // /* GcRoot<mirror::Class> */ out = *(base + offset) /* PC-relative */ - GenerateGcRootFieldLoad( - cls, out_loc, Address(base_reg, CodeGeneratorX86::kDummy32BitOffset), fixup_label); + GenerateGcRootFieldLoad(cls, + out_loc, + Address(base_reg, CodeGeneratorX86::kDummy32BitOffset), + fixup_label, + requires_read_barrier); generate_null_check = !cls->IsInDexCache(); break; } @@ -6100,8 +6102,11 @@ void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) { __ movl(out, Address(current_method, ArtMethod::DexCacheResolvedTypesOffset(kX86PointerSize).Int32Value())); // /* GcRoot<mirror::Class> */ out = out[type_index] - GenerateGcRootFieldLoad( - cls, out_loc, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()))); + GenerateGcRootFieldLoad(cls, + out_loc, + Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())), + /*fixup_label*/ nullptr, + requires_read_barrier); generate_null_check = !cls->IsInDexCache(); break; } @@ -6938,9 +6943,11 @@ void InstructionCodeGeneratorX86::GenerateReferenceLoadTwoRegisters(HInstruction void InstructionCodeGeneratorX86::GenerateGcRootFieldLoad(HInstruction* instruction, Location root, const Address& address, - Label* fixup_label) { + Label* fixup_label, + bool requires_read_barrier) { Register root_reg = root.AsRegister<Register>(); - if (kEmitCompilerReadBarrier) { + if (requires_read_barrier) { + DCHECK(kEmitCompilerReadBarrier); if (kUseBakerReadBarrier) { // Fast path implementation of art::ReadBarrier::BarrierForRoot when // Baker's read barrier are used: diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index df65fa2f4a..e2250981bb 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -263,7 +263,8 @@ class InstructionCodeGeneratorX86 : public InstructionCodeGenerator { void GenerateGcRootFieldLoad(HInstruction* instruction, Location root, const Address& address, - Label* fixup_label = nullptr); + Label* fixup_label = nullptr, + bool requires_read_barrier = kEmitCompilerReadBarrier); // Push value to FPU stack. `is_fp` specifies whether the value is floating point or not. // `is_wide` specifies whether it is long/double or not. diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 5230269730..a21a09ee8a 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -5408,17 +5408,6 @@ void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck( HLoadClass::LoadKind CodeGeneratorX86_64::GetSupportedLoadClassKind( HLoadClass::LoadKind desired_class_load_kind) { - if (kEmitCompilerReadBarrier) { - switch (desired_class_load_kind) { - case HLoadClass::LoadKind::kBootImageLinkTimeAddress: - case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: - case HLoadClass::LoadKind::kBootImageAddress: - // TODO: Implement for read barrier. - return HLoadClass::LoadKind::kDexCacheViaMethod; - default: - break; - } - } switch (desired_class_load_kind) { case HLoadClass::LoadKind::kReferrersClass: break; @@ -5454,11 +5443,12 @@ void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) { return; } - LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || kEmitCompilerReadBarrier) + const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage(); + LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier) ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall; LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); - if (kUseBakerReadBarrier && !cls->NeedsEnvironment()) { + if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) { locations->SetCustomSlowPathCallerSaves(RegisterSet()); // No caller-save registers. } @@ -5482,6 +5472,7 @@ void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) { Location out_loc = locations->Out(); CpuRegister out = out_loc.AsRegister<CpuRegister>(); + const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage(); bool generate_null_check = false; switch (cls->GetLoadKind()) { case HLoadClass::LoadKind::kReferrersClass: { @@ -5490,16 +5481,20 @@ void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) { // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_ CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>(); GenerateGcRootFieldLoad( - cls, out_loc, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value())); + cls, + out_loc, + Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()), + /*fixup_label*/nullptr, + requires_read_barrier); break; } case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: - DCHECK(!kEmitCompilerReadBarrier); + DCHECK(!requires_read_barrier); __ leal(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false)); codegen_->RecordTypePatch(cls); break; case HLoadClass::LoadKind::kBootImageAddress: { - DCHECK(!kEmitCompilerReadBarrier); + DCHECK(!requires_read_barrier); DCHECK_NE(cls->GetAddress(), 0u); uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress()); __ movl(out, Immediate(address)); // Zero-extended. @@ -5511,11 +5506,19 @@ void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) { // /* GcRoot<mirror::Class> */ out = *address if (IsUint<32>(cls->GetAddress())) { Address address = Address::Absolute(cls->GetAddress(), /* no_rip */ true); - GenerateGcRootFieldLoad(cls, out_loc, address); + GenerateGcRootFieldLoad(cls, + out_loc, + address, + /*fixup_label*/nullptr, + requires_read_barrier); } else { // TODO: Consider using opcode A1, i.e. movl eax, moff32 (with 64-bit address). __ movq(out, Immediate(cls->GetAddress())); - GenerateGcRootFieldLoad(cls, out_loc, Address(out, 0)); + GenerateGcRootFieldLoad(cls, + out_loc, + Address(out, 0), + /*fixup_label*/nullptr, + requires_read_barrier); } generate_null_check = !cls->IsInDexCache(); break; @@ -5526,7 +5529,7 @@ void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) { Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false); // /* GcRoot<mirror::Class> */ out = *address /* PC-relative */ - GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label); + GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, requires_read_barrier); generate_null_check = !cls->IsInDexCache(); break; } @@ -5539,7 +5542,11 @@ void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) { ArtMethod::DexCacheResolvedTypesOffset(kX86_64PointerSize).Int32Value())); // /* GcRoot<mirror::Class> */ out = out[type_index] GenerateGcRootFieldLoad( - cls, out_loc, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()))); + cls, + out_loc, + Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())), + /*fixup_label*/nullptr, + requires_read_barrier); generate_null_check = !cls->IsInDexCache(); break; } @@ -6387,9 +6394,11 @@ void InstructionCodeGeneratorX86_64::GenerateReferenceLoadTwoRegisters(HInstruct void InstructionCodeGeneratorX86_64::GenerateGcRootFieldLoad(HInstruction* instruction, Location root, const Address& address, - Label* fixup_label) { + Label* fixup_label, + bool requires_read_barrier) { CpuRegister root_reg = root.AsRegister<CpuRegister>(); - if (kEmitCompilerReadBarrier) { + if (requires_read_barrier) { + DCHECK(kEmitCompilerReadBarrier); if (kUseBakerReadBarrier) { // Fast path implementation of art::ReadBarrier::BarrierForRoot when // Baker's read barrier are used: diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index f23bff5e1f..d93908343d 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -257,7 +257,8 @@ class InstructionCodeGeneratorX86_64 : public InstructionCodeGenerator { void GenerateGcRootFieldLoad(HInstruction* instruction, Location root, const Address& address, - Label* fixup_label = nullptr); + Label* fixup_label = nullptr, + bool requires_read_barrier = kEmitCompilerReadBarrier); void PushOntoFPStack(Location source, uint32_t temp_offset, uint32_t stack_adjustment, bool is_float); diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 1e5f0b6c75..ce53134235 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -452,7 +452,8 @@ HInstruction* HInliner::AddTypeGuard(HInstruction* receiver, is_referrer, invoke_instruction->GetDexPc(), /* needs_access_check */ false, - /* is_in_dex_cache */ true); + /* is_in_dex_cache */ true, + /* is_in_boot_image */ false); HNotEqual* compare = new (graph_->GetArena()) HNotEqual(load_class, receiver_class); // TODO: Extend reference type propagation to understand the guard. diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index 32dcc2814b..d7e4c53df0 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -935,7 +935,8 @@ bool HInstructionBuilder::BuildNewInstance(uint16_t type_index, uint32_t dex_pc) IsOutermostCompilingClass(type_index), dex_pc, needs_access_check, - /* is_in_dex_cache */ false); + /* is_in_dex_cache */ false, + /* is_in_boot_image */ false); AppendInstruction(load_class); HInstruction* cls = load_class; @@ -1026,7 +1027,8 @@ HClinitCheck* HInstructionBuilder::ProcessClinitCheckForInvoke( is_outer_class, dex_pc, /*needs_access_check*/ false, - /* is_in_dex_cache */ false); + /* is_in_dex_cache */ false, + /* is_in_boot_image */ false); AppendInstruction(load_class); clinit_check = new (arena_) HClinitCheck(load_class, dex_pc); AppendInstruction(clinit_check); @@ -1384,7 +1386,8 @@ bool HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction, is_outer_class, dex_pc, /*needs_access_check*/ false, - /* is_in_dex_cache */ false); + /* is_in_dex_cache */ false, + /* is_in_boot_image */ false); AppendInstruction(constant); HInstruction* cls = constant; @@ -1659,7 +1662,8 @@ void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction, IsOutermostCompilingClass(type_index), dex_pc, !can_access, - /* is_in_dex_cache */ false); + /* is_in_dex_cache */ false, + /* is_in_boot_image */ false); AppendInstruction(cls); TypeCheckKind check_kind = ComputeTypeCheckKind(resolved_class); @@ -2634,7 +2638,8 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction, IsOutermostCompilingClass(type_index), dex_pc, !can_access, - /* is_in_dex_cache */ false)); + /* is_in_dex_cache */ false, + /* is_in_boot_image */ false)); UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction()); break; } diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 19e499ba8c..149a71d1b9 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -5461,7 +5461,8 @@ class HLoadClass FINAL : public HInstruction { bool is_referrers_class, uint32_t dex_pc, bool needs_access_check, - bool is_in_dex_cache) + bool is_in_dex_cache, + bool is_in_boot_image) : HInstruction(SideEffectsForArchRuntimeCalls(), dex_pc), special_input_(HUserRecord<HInstruction*>(current_method)), type_index_(type_index), @@ -5475,6 +5476,7 @@ class HLoadClass FINAL : public HInstruction { is_referrers_class ? LoadKind::kReferrersClass : LoadKind::kDexCacheViaMethod); SetPackedFlag<kFlagNeedsAccessCheck>(needs_access_check); SetPackedFlag<kFlagIsInDexCache>(is_in_dex_cache); + SetPackedFlag<kFlagIsInBootImage>(is_in_boot_image); SetPackedFlag<kFlagGenerateClInitCheck>(false); } @@ -5565,6 +5567,7 @@ class HLoadClass FINAL : public HInstruction { bool IsReferrersClass() const { return GetLoadKind() == LoadKind::kReferrersClass; } bool NeedsAccessCheck() const { return GetPackedFlag<kFlagNeedsAccessCheck>(); } bool IsInDexCache() const { return GetPackedFlag<kFlagIsInDexCache>(); } + bool IsInBootImage() const { return GetPackedFlag<kFlagIsInBootImage>(); } bool MustGenerateClinitCheck() const { return GetPackedFlag<kFlagGenerateClInitCheck>(); } void MarkInDexCache() { @@ -5574,6 +5577,10 @@ class HLoadClass FINAL : public HInstruction { SetSideEffects(SideEffects::None()); } + void MarkInBootImage() { + SetPackedFlag<kFlagIsInBootImage>(true); + } + void AddSpecialInput(HInstruction* special_input); using HInstruction::GetInputRecords; // Keep the const version visible. @@ -5591,9 +5598,10 @@ class HLoadClass FINAL : public HInstruction { private: static constexpr size_t kFlagNeedsAccessCheck = kNumberOfGenericPackedBits; static constexpr size_t kFlagIsInDexCache = kFlagNeedsAccessCheck + 1; + static constexpr size_t kFlagIsInBootImage = kFlagIsInDexCache + 1; // Whether this instruction must generate the initialization check. // Used for code generation. - static constexpr size_t kFlagGenerateClInitCheck = kFlagIsInDexCache + 1; + static constexpr size_t kFlagGenerateClInitCheck = kFlagIsInBootImage + 1; static constexpr size_t kFieldLoadKind = kFlagGenerateClInitCheck + 1; static constexpr size_t kFieldLoadKindSize = MinimumBitsToStore(static_cast<size_t>(LoadKind::kLast)); diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc index 81163e296e..8d4d143696 100644 --- a/compiler/optimizing/sharpening.cc +++ b/compiler/optimizing/sharpening.cc @@ -176,6 +176,7 @@ void HSharpening::ProcessLoadClass(HLoadClass* load_class) { uint32_t type_index = load_class->GetTypeIndex(); bool is_in_dex_cache = false; + bool is_in_boot_image = false; HLoadClass::LoadKind desired_load_kind; uint64_t address = 0u; // Class or dex cache element address. { @@ -192,45 +193,42 @@ void HSharpening::ProcessLoadClass(HLoadClass* load_class) { // Compiling boot image. Check if the class is a boot image class. DCHECK(!runtime->UseJitCompilation()); if (!compiler_driver_->GetSupportBootImageFixup()) { - // MIPS/MIPS64 or compiler_driver_test. Do not sharpen. + // MIPS64 or compiler_driver_test. Do not sharpen. desired_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod; + } else if ((klass != nullptr) && compiler_driver_->IsImageClass( + dex_file.StringDataByIdx(dex_file.GetTypeId(type_index).descriptor_idx_))) { + is_in_boot_image = true; + is_in_dex_cache = true; + desired_load_kind = codegen_->GetCompilerOptions().GetCompilePic() + ? HLoadClass::LoadKind::kBootImageLinkTimePcRelative + : HLoadClass::LoadKind::kBootImageLinkTimeAddress; } else { - if (klass != nullptr && - compiler_driver_->IsImageClass( - dex_file.StringDataByIdx(dex_file.GetTypeId(type_index).descriptor_idx_))) { - is_in_dex_cache = true; - desired_load_kind = codegen_->GetCompilerOptions().GetCompilePic() - ? HLoadClass::LoadKind::kBootImageLinkTimePcRelative - : HLoadClass::LoadKind::kBootImageLinkTimeAddress; - } else { - // Not a boot image class. We must go through the dex cache. - DCHECK(ContainsElement(compiler_driver_->GetDexFilesForOatFile(), &dex_file)); - desired_load_kind = HLoadClass::LoadKind::kDexCachePcRelative; - } - } - } else if (runtime->UseJitCompilation()) { - // TODO: Make sure we don't set the "compile PIC" flag for JIT as that's bogus. - // DCHECK(!codegen_->GetCompilerOptions().GetCompilePic()); - is_in_dex_cache = (klass != nullptr); - if (klass != nullptr && runtime->GetHeap()->ObjectIsInBootImageSpace(klass)) { - // TODO: Use direct pointers for all non-moving spaces, not just boot image. Bug: 29530787 - desired_load_kind = HLoadClass::LoadKind::kBootImageAddress; - address = reinterpret_cast64<uint64_t>(klass); - } else { - // Note: If the class is not in the dex cache or isn't initialized, the - // instruction needs environment and will not be inlined across dex files. - // Within a dex file, the slow-path helper loads the correct class and - // inlined frames are used correctly for OOM stack trace. - // TODO: Write a test for this. Bug: 29416588 - desired_load_kind = HLoadClass::LoadKind::kDexCacheAddress; - void* dex_cache_element_address = &dex_cache->GetResolvedTypes()[type_index]; - address = reinterpret_cast64<uint64_t>(dex_cache_element_address); + // Not a boot image class. We must go through the dex cache. + DCHECK(ContainsElement(compiler_driver_->GetDexFilesForOatFile(), &dex_file)); + desired_load_kind = HLoadClass::LoadKind::kDexCachePcRelative; } } else { - // AOT app compilation. Check if the class is in the boot image. - if ((klass != nullptr) && - runtime->GetHeap()->ObjectIsInBootImageSpace(klass) && - !codegen_->GetCompilerOptions().GetCompilePic()) { + is_in_boot_image = (klass != nullptr) && runtime->GetHeap()->ObjectIsInBootImageSpace(klass); + if (runtime->UseJitCompilation()) { + // TODO: Make sure we don't set the "compile PIC" flag for JIT as that's bogus. + // DCHECK(!codegen_->GetCompilerOptions().GetCompilePic()); + is_in_dex_cache = (klass != nullptr); + if (is_in_boot_image) { + // TODO: Use direct pointers for all non-moving spaces, not just boot image. Bug: 29530787 + desired_load_kind = HLoadClass::LoadKind::kBootImageAddress; + address = reinterpret_cast64<uint64_t>(klass); + } else { + // Note: If the class is not in the dex cache or isn't initialized, the + // instruction needs environment and will not be inlined across dex files. + // Within a dex file, the slow-path helper loads the correct class and + // inlined frames are used correctly for OOM stack trace. + // TODO: Write a test for this. Bug: 29416588 + desired_load_kind = HLoadClass::LoadKind::kDexCacheAddress; + void* dex_cache_element_address = &dex_cache->GetResolvedTypes()[type_index]; + address = reinterpret_cast64<uint64_t>(dex_cache_element_address); + } + // AOT app compilation. Check if the class is in the boot image. + } else if (is_in_boot_image && !codegen_->GetCompilerOptions().GetCompilePic()) { desired_load_kind = HLoadClass::LoadKind::kBootImageAddress; address = reinterpret_cast64<uint64_t>(klass); } else { @@ -247,6 +245,9 @@ void HSharpening::ProcessLoadClass(HLoadClass* load_class) { if (is_in_dex_cache) { load_class->MarkInDexCache(); } + if (is_in_boot_image) { + load_class->MarkInBootImage(); + } HLoadClass::LoadKind load_kind = codegen_->GetSupportedLoadClassKind(desired_load_kind); switch (load_kind) { diff --git a/dexlayout/Android.mk b/dexlayout/Android.mk index 3095866cf0..de02580bf6 100755 --- a/dexlayout/Android.mk +++ b/dexlayout/Android.mk @@ -16,7 +16,7 @@ LOCAL_PATH:= $(call my-dir) -dexlayout_src_files := dexlayout_main.cc dexlayout.cc dex_ir.cc +dexlayout_src_files := dexlayout_main.cc dexlayout.cc dex_ir_builder.cc dexlayout_c_includes := art/runtime dexlayout_libraries := libart diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc deleted file mode 100644 index 0ed040eba5..0000000000 --- a/dexlayout/dex_ir.cc +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Implementation file of the dex file intermediate representation. - * - * Utilities for reading dex files into an internal representation, - * manipulating them, and writing them out. - */ - -#include "dex_ir.h" - -#include <map> -#include <vector> - -#include "dex_file.h" -#include "dex_file-inl.h" -#include "utils.h" - -namespace art { -namespace dex_ir { - -namespace { -static uint64_t ReadVarWidth(const uint8_t** data, uint8_t length, bool sign_extend) { - uint64_t value = 0; - for (uint32_t i = 0; i <= length; i++) { - value |= static_cast<uint64_t>(*(*data)++) << (i * 8); - } - if (sign_extend) { - int shift = (7 - length) * 8; - return (static_cast<int64_t>(value) << shift) >> shift; - } - return value; -} - -static bool GetPositionsCb(void* context, const DexFile::PositionInfo& entry) { - DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context); - std::vector<std::unique_ptr<PositionInfo>>& positions = debug_info->GetPositionInfo(); - positions.push_back(std::unique_ptr<PositionInfo>(new PositionInfo(entry.address_, entry.line_))); - return false; -} - -static void GetLocalsCb(void* context, const DexFile::LocalInfo& entry) { - DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context); - std::vector<std::unique_ptr<LocalInfo>>& locals = debug_info->GetLocalInfo(); - const char* name = entry.name_ != nullptr ? entry.name_ : "(null)"; - const char* signature = entry.signature_ != nullptr ? entry.signature_ : ""; - locals.push_back(std::unique_ptr<LocalInfo>( - new LocalInfo(name, entry.descriptor_, signature, entry.start_address_, - entry.end_address_, entry.reg_))); -} -} // namespace - -Header::Header(const DexFile& dex_file) : dex_file_(dex_file) { - const DexFile::Header& disk_header = dex_file.GetHeader(); - memcpy(magic_, disk_header.magic_, sizeof(magic_)); - checksum_ = disk_header.checksum_; - // TODO(sehr): clearly the signature will need to be recomputed before dumping. - memcpy(signature_, disk_header.signature_, sizeof(signature_)); - endian_tag_ = disk_header.endian_tag_; - file_size_ = disk_header.file_size_; - header_size_ = disk_header.header_size_; - link_size_ = disk_header.link_size_; - link_offset_ = disk_header.link_off_; - data_size_ = disk_header.data_size_; - data_offset_ = disk_header.data_off_; - // Walk the rest of the header fields. - string_ids_.SetOffset(disk_header.string_ids_off_); - for (uint32_t i = 0; i < dex_file_.NumStringIds(); ++i) { - string_ids_.AddWithPosition(i, new StringId(dex_file_.GetStringId(i), *this)); - } - type_ids_.SetOffset(disk_header.type_ids_off_); - for (uint32_t i = 0; i < dex_file_.NumTypeIds(); ++i) { - type_ids_.AddWithPosition(i, new TypeId(dex_file_.GetTypeId(i), *this)); - } - proto_ids_.SetOffset(disk_header.proto_ids_off_); - for (uint32_t i = 0; i < dex_file_.NumProtoIds(); ++i) { - proto_ids_.AddWithPosition(i, new ProtoId(dex_file_.GetProtoId(i), *this)); - } - field_ids_.SetOffset(disk_header.field_ids_off_); - for (uint32_t i = 0; i < dex_file_.NumFieldIds(); ++i) { - field_ids_.AddWithPosition(i, new FieldId(dex_file_.GetFieldId(i), *this)); - } - method_ids_.SetOffset(disk_header.method_ids_off_); - for (uint32_t i = 0; i < dex_file_.NumMethodIds(); ++i) { - method_ids_.AddWithPosition(i, new MethodId(dex_file_.GetMethodId(i), *this)); - } - class_defs_.SetOffset(disk_header.class_defs_off_); - for (uint32_t i = 0; i < dex_file_.NumClassDefs(); ++i) { - class_defs_.AddWithPosition(i, new ClassDef(dex_file_.GetClassDef(i), *this)); - } -} - -ArrayItem::ArrayItem(Header& header, const uint8_t** data, uint8_t type, uint8_t length) { - Read(header, data, type, length); -} - -ArrayItem::ArrayItem(Header& header, const uint8_t** data) { - const uint8_t encoded_value = *(*data)++; - Read(header, data, encoded_value & 0x1f, encoded_value >> 5); -} - -void ArrayItem::Read(Header& header, const uint8_t** data, uint8_t type, uint8_t length) { - type_ = type; - switch (type_) { - case DexFile::kDexAnnotationByte: - item_.byte_val_ = static_cast<int8_t>(ReadVarWidth(data, length, false)); - break; - case DexFile::kDexAnnotationShort: - item_.short_val_ = static_cast<int16_t>(ReadVarWidth(data, length, true)); - break; - case DexFile::kDexAnnotationChar: - item_.char_val_ = static_cast<uint16_t>(ReadVarWidth(data, length, false)); - break; - case DexFile::kDexAnnotationInt: - item_.int_val_ = static_cast<int32_t>(ReadVarWidth(data, length, true)); - break; - case DexFile::kDexAnnotationLong: - item_.long_val_ = static_cast<int64_t>(ReadVarWidth(data, length, true)); - break; - case DexFile::kDexAnnotationFloat: { - // Fill on right. - union { - float f; - uint32_t data; - } conv; - conv.data = static_cast<uint32_t>(ReadVarWidth(data, length, false)) << (3 - length) * 8; - item_.float_val_ = conv.f; - break; - } - case DexFile::kDexAnnotationDouble: { - // Fill on right. - union { - double d; - uint64_t data; - } conv; - conv.data = ReadVarWidth(data, length, false) << (7 - length) * 8; - item_.double_val_ = conv.d; - break; - } - case DexFile::kDexAnnotationString: { - const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false)); - item_.string_val_ = header.StringIds()[string_index].get(); - break; - } - case DexFile::kDexAnnotationType: { - const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false)); - item_.string_val_ = header.TypeIds()[string_index]->GetStringId(); - break; - } - case DexFile::kDexAnnotationField: - case DexFile::kDexAnnotationEnum: { - const uint32_t field_index = static_cast<uint32_t>(ReadVarWidth(data, length, false)); - item_.field_val_ = header.FieldIds()[field_index].get(); - break; - } - case DexFile::kDexAnnotationMethod: { - const uint32_t method_index = static_cast<uint32_t>(ReadVarWidth(data, length, false)); - item_.method_val_ = header.MethodIds()[method_index].get(); - break; - } - case DexFile::kDexAnnotationArray: { - item_.annotation_array_val_ = new std::vector<std::unique_ptr<ArrayItem>>(); - // Decode all elements. - const uint32_t size = DecodeUnsignedLeb128(data); - for (uint32_t i = 0; i < size; i++) { - item_.annotation_array_val_->push_back( - std::unique_ptr<ArrayItem>(new ArrayItem(header, data))); - } - break; - } - case DexFile::kDexAnnotationAnnotation: { - const uint32_t type_idx = DecodeUnsignedLeb128(data); - item_.annotation_annotation_val_.string_ = header.TypeIds()[type_idx]->GetStringId(); - item_.annotation_annotation_val_.array_ = new std::vector<std::unique_ptr<NameValuePair>>(); - // Decode all name=value pairs. - const uint32_t size = DecodeUnsignedLeb128(data); - for (uint32_t i = 0; i < size; i++) { - const uint32_t name_index = DecodeUnsignedLeb128(data); - item_.annotation_annotation_val_.array_->push_back(std::unique_ptr<NameValuePair>( - new NameValuePair(header.StringIds()[name_index].get(), new ArrayItem(header, data)))); - } - break; - } - case DexFile::kDexAnnotationNull: - break; - case DexFile::kDexAnnotationBoolean: - item_.bool_val_ = (length != 0); - break; - default: - break; - } -} - -ClassDef::ClassDef(const DexFile::ClassDef& disk_class_def, Header& header) { - class_type_ = header.TypeIds()[disk_class_def.class_idx_].get(); - access_flags_ = disk_class_def.access_flags_; - superclass_ = header.GetTypeIdOrNullPtr(disk_class_def.superclass_idx_); - - const DexFile::TypeList* type_list = header.GetDexFile().GetInterfacesList(disk_class_def); - interfaces_offset_ = disk_class_def.interfaces_off_; - if (type_list != nullptr) { - for (uint32_t index = 0; index < type_list->Size(); ++index) { - interfaces_.push_back(header.TypeIds()[type_list->GetTypeItem(index).type_idx_].get()); - } - } - source_file_ = header.GetStringIdOrNullPtr(disk_class_def.source_file_idx_); - // Annotations. - const DexFile::AnnotationsDirectoryItem* disk_annotations_directory_item = - header.GetDexFile().GetAnnotationsDirectory(disk_class_def); - if (disk_annotations_directory_item == nullptr) { - annotations_.reset(nullptr); - } else { - annotations_.reset(new AnnotationsDirectoryItem(disk_annotations_directory_item, header)); - annotations_->SetOffset(disk_class_def.annotations_off_); - } - // Static field initializers. - static_values_ = nullptr; - const uint8_t* static_data = header.GetDexFile().GetEncodedStaticFieldValuesArray(disk_class_def); - if (static_data != nullptr) { - uint32_t static_value_count = static_data == nullptr ? 0 : DecodeUnsignedLeb128(&static_data); - if (static_value_count > 0) { - static_values_ = new std::vector<std::unique_ptr<ArrayItem>>(); - for (uint32_t i = 0; i < static_value_count; ++i) { - static_values_->push_back(std::unique_ptr<ArrayItem>(new ArrayItem(header, &static_data))); - } - } - } - // Read the fields and methods defined by the class, resolving the circular reference from those - // to classes by setting class at the same time. - const uint8_t* encoded_data = header.GetDexFile().GetClassData(disk_class_def); - class_data_.SetOffset(disk_class_def.class_data_off_); - if (encoded_data != nullptr) { - ClassDataItemIterator cdii(header.GetDexFile(), encoded_data); - // Static fields. - for (uint32_t i = 0; cdii.HasNextStaticField(); i++, cdii.Next()) { - FieldId* field_item = header.FieldIds()[cdii.GetMemberIndex()].get(); - uint32_t access_flags = cdii.GetRawMemberAccessFlags(); - class_data_.StaticFields().push_back( - std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item))); - } - // Instance fields. - for (uint32_t i = 0; cdii.HasNextInstanceField(); i++, cdii.Next()) { - FieldId* field_item = header.FieldIds()[cdii.GetMemberIndex()].get(); - uint32_t access_flags = cdii.GetRawMemberAccessFlags(); - class_data_.InstanceFields().push_back( - std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item))); - } - // Direct methods. - for (uint32_t i = 0; cdii.HasNextDirectMethod(); i++, cdii.Next()) { - class_data_.DirectMethods().push_back( - std::unique_ptr<MethodItem>(GenerateMethodItem(header, cdii))); - } - // Virtual methods. - for (uint32_t i = 0; cdii.HasNextVirtualMethod(); i++, cdii.Next()) { - class_data_.VirtualMethods().push_back( - std::unique_ptr<MethodItem>(GenerateMethodItem(header, cdii))); - } - } -} - -MethodItem* ClassDef::GenerateMethodItem(Header& header, ClassDataItemIterator& cdii) { - MethodId* method_item = header.MethodIds()[cdii.GetMemberIndex()].get(); - uint32_t access_flags = cdii.GetRawMemberAccessFlags(); - const DexFile::CodeItem* disk_code_item = cdii.GetMethodCodeItem(); - CodeItem* code_item = nullptr; - DebugInfoItem* debug_info = nullptr; - if (disk_code_item != nullptr) { - code_item = new CodeItem(*disk_code_item, header); - code_item->SetOffset(cdii.GetMethodCodeItemOffset()); - debug_info = code_item->DebugInfo(); - } - if (debug_info != nullptr) { - bool is_static = (access_flags & kAccStatic) != 0; - header.GetDexFile().DecodeDebugLocalInfo( - disk_code_item, is_static, cdii.GetMemberIndex(), GetLocalsCb, debug_info); - header.GetDexFile().DecodeDebugPositionInfo(disk_code_item, GetPositionsCb, debug_info); - } - return new MethodItem(access_flags, method_item, code_item); -} - -CodeItem::CodeItem(const DexFile::CodeItem& disk_code_item, Header& header) { - registers_size_ = disk_code_item.registers_size_; - ins_size_ = disk_code_item.ins_size_; - outs_size_ = disk_code_item.outs_size_; - tries_size_ = disk_code_item.tries_size_; - - const uint8_t* debug_info_stream = header.GetDexFile().GetDebugInfoStream(&disk_code_item); - if (debug_info_stream != nullptr) { - debug_info_.reset(new DebugInfoItem()); - } else { - debug_info_.reset(nullptr); - } - - insns_size_ = disk_code_item.insns_size_in_code_units_; - insns_.reset(new uint16_t[insns_size_]); - memcpy(insns_.get(), disk_code_item.insns_, insns_size_ * sizeof(uint16_t)); - - if (tries_size_ > 0) { - tries_ = new std::vector<std::unique_ptr<const TryItem>>(); - for (uint32_t i = 0; i < tries_size_; ++i) { - const DexFile::TryItem* disk_try_item = header.GetDexFile().GetTryItems(disk_code_item, i); - tries_->push_back(std::unique_ptr<const TryItem>( - new TryItem(*disk_try_item, disk_code_item, header))); - } - } else { - tries_ = nullptr; - } -} - -AnnotationSetItem::AnnotationSetItem(const DexFile::AnnotationSetItem& disk_annotations_item, - Header& header) { - if (disk_annotations_item.size_ == 0) { - return; - } - for (uint32_t i = 0; i < disk_annotations_item.size_; ++i) { - const DexFile::AnnotationItem* annotation = - header.GetDexFile().GetAnnotationItem(&disk_annotations_item, i); - if (annotation == nullptr) { - continue; - } - uint8_t visibility = annotation->visibility_; - const uint8_t* annotation_data = annotation->annotation_; - ArrayItem* array_item = - new ArrayItem(header, &annotation_data, DexFile::kDexAnnotationAnnotation, 0); - items_.push_back(std::unique_ptr<AnnotationItem>(new AnnotationItem(visibility, array_item))); - } -} - -AnnotationsDirectoryItem::AnnotationsDirectoryItem( - const DexFile::AnnotationsDirectoryItem* disk_annotations_item, Header& header) { - const DexFile::AnnotationSetItem* class_set_item = - header.GetDexFile().GetClassAnnotationSet(disk_annotations_item); - if (class_set_item == nullptr) { - class_annotation_.reset(nullptr); - } else { - class_annotation_.reset(new AnnotationSetItem(*class_set_item, header)); - } - const DexFile::FieldAnnotationsItem* fields = - header.GetDexFile().GetFieldAnnotations(disk_annotations_item); - if (fields != nullptr) { - for (uint32_t i = 0; i < disk_annotations_item->fields_size_; ++i) { - FieldId* field_id = header.FieldIds()[fields[i].field_idx_].get(); - const DexFile::AnnotationSetItem* field_set_item = - header.GetDexFile().GetFieldAnnotationSetItem(fields[i]); - dex_ir::AnnotationSetItem* annotation_set_item = - new AnnotationSetItem(*field_set_item, header); - field_annotations_.push_back(std::unique_ptr<FieldAnnotation>( - new FieldAnnotation(field_id, annotation_set_item))); - } - } - const DexFile::MethodAnnotationsItem* methods = - header.GetDexFile().GetMethodAnnotations(disk_annotations_item); - if (methods != nullptr) { - for (uint32_t i = 0; i < disk_annotations_item->methods_size_; ++i) { - MethodId* method_id = header.MethodIds()[methods[i].method_idx_].get(); - const DexFile::AnnotationSetItem* method_set_item = - header.GetDexFile().GetMethodAnnotationSetItem(methods[i]); - dex_ir::AnnotationSetItem* annotation_set_item = - new AnnotationSetItem(*method_set_item, header); - method_annotations_.push_back(std::unique_ptr<MethodAnnotation>( - new MethodAnnotation(method_id, annotation_set_item))); - } - } - const DexFile::ParameterAnnotationsItem* parameters = - header.GetDexFile().GetParameterAnnotations(disk_annotations_item); - if (parameters != nullptr) { - for (uint32_t i = 0; i < disk_annotations_item->parameters_size_; ++i) { - MethodId* method_id = header.MethodIds()[parameters[i].method_idx_].get(); - const DexFile::AnnotationSetRefList* list = - header.GetDexFile().GetParameterAnnotationSetRefList(¶meters[i]); - parameter_annotations_.push_back(std::unique_ptr<ParameterAnnotation>( - new ParameterAnnotation(method_id, list, header))); - } - } -} - -} // namespace dex_ir -} // namespace art diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h index fcd3ab0c1e..cbb4404234 100644 --- a/dexlayout/dex_ir.h +++ b/dexlayout/dex_ir.h @@ -19,12 +19,10 @@ #ifndef ART_DEXLAYOUT_DEX_IR_H_ #define ART_DEXLAYOUT_DEX_IR_H_ -#include <iostream> -#include <map> #include <vector> #include <stdint.h> -#include "dex_file.h" +#include "dex_file-inl.h" namespace art { namespace dex_ir { @@ -106,19 +104,39 @@ template<class T> class CollectionWithOffset { class Item { public: virtual ~Item() { } + uint32_t GetOffset() const { return offset_; } void SetOffset(uint32_t offset) { offset_ = offset; } + protected: uint32_t offset_ = 0; }; class Header : public Item { public: - explicit Header(const DexFile& dex_file); + Header(const uint8_t* magic, + uint32_t checksum, + const uint8_t* signature, + uint32_t endian_tag, + uint32_t file_size, + uint32_t header_size, + uint32_t link_size, + uint32_t link_offset, + uint32_t data_size, + uint32_t data_offset) + : checksum_(checksum), + endian_tag_(endian_tag), + file_size_(file_size), + header_size_(header_size), + link_size_(link_size), + link_offset_(link_offset), + data_size_(data_size), + data_offset_(data_offset) { + memcpy(magic_, magic, sizeof(magic_)); + memcpy(signature_, signature, sizeof(signature_)); + } ~Header() OVERRIDE { } - const DexFile& GetDexFile() const { return dex_file_; } - const uint8_t* Magic() const { return magic_; } uint32_t Checksum() const { return checksum_; } const uint8_t* Signature() const { return signature_; } @@ -178,7 +196,6 @@ class Header : public Item { void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } private: - const DexFile& dex_file_; uint8_t magic_[8]; uint32_t checksum_; uint8_t signature_[DexFile::kSha1DigestSize]; @@ -201,9 +218,7 @@ class Header : public Item { class StringId : public Item { public: - StringId(const DexFile::StringId& disk_string_id, Header& header) : - data_(strdup(header.GetDexFile().GetStringData(disk_string_id))) { - } + explicit StringId(const char* data) : data_(strdup(data)) { } ~StringId() OVERRIDE { } const char* Data() const { return data_.get(); } @@ -217,9 +232,7 @@ class StringId : public Item { class TypeId : public Item { public: - TypeId(const DexFile::TypeId& disk_type_id, Header& header) : - string_id_(header.StringIds()[disk_type_id.descriptor_idx_].get()) { - } + explicit TypeId(StringId* string_id) : string_id_(string_id) { } ~TypeId() OVERRIDE { } StringId* GetStringId() const { return string_id_; } @@ -231,39 +244,31 @@ class TypeId : public Item { DISALLOW_COPY_AND_ASSIGN(TypeId); }; +using TypeIdVector = std::vector<const TypeId*>; + class ProtoId : public Item { public: - ProtoId(const DexFile::ProtoId& disk_proto_id, Header& header) { - shorty_ = header.StringIds()[disk_proto_id.shorty_idx_].get(); - return_type_ = header.TypeIds()[disk_proto_id.return_type_idx_].get(); - DexFileParameterIterator dfpi(header.GetDexFile(), disk_proto_id); - while (dfpi.HasNext()) { - parameters_.push_back(header.TypeIds()[dfpi.GetTypeIdx()].get()); - dfpi.Next(); - } - } + ProtoId(const StringId* shorty, const TypeId* return_type, TypeIdVector* parameters) + : shorty_(shorty), return_type_(return_type), parameters_(parameters) { } ~ProtoId() OVERRIDE { } const StringId* Shorty() const { return shorty_; } const TypeId* ReturnType() const { return return_type_; } - const std::vector<const TypeId*>& Parameters() const { return parameters_; } + const std::vector<const TypeId*>& Parameters() const { return *parameters_; } void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); } private: const StringId* shorty_; const TypeId* return_type_; - std::vector<const TypeId*> parameters_; + std::unique_ptr<TypeIdVector> parameters_; DISALLOW_COPY_AND_ASSIGN(ProtoId); }; class FieldId : public Item { public: - FieldId(const DexFile::FieldId& disk_field_id, Header& header) { - class_ = header.TypeIds()[disk_field_id.class_idx_].get(); - type_ = header.TypeIds()[disk_field_id.type_idx_].get(); - name_ = header.StringIds()[disk_field_id.name_idx_].get(); - } + FieldId(const TypeId* klass, const TypeId* type, const StringId* name) + : class_(klass), type_(type), name_(name) { } ~FieldId() OVERRIDE { } const TypeId* Class() const { return class_; } @@ -281,11 +286,8 @@ class FieldId : public Item { class MethodId : public Item { public: - MethodId(const DexFile::MethodId& disk_method_id, Header& header) { - class_ = header.TypeIds()[disk_method_id.class_idx_].get(); - proto_ = header.ProtoIds()[disk_method_id.proto_idx_].get(); - name_ = header.StringIds()[disk_method_id.name_idx_].get(); - } + MethodId(const TypeId* klass, const ProtoId* proto, const StringId* name) + : class_(klass), proto_(proto), name_(name) { } ~MethodId() OVERRIDE { } const TypeId* Class() const { return class_; } @@ -303,8 +305,8 @@ class MethodId : public Item { class FieldItem : public Item { public: - FieldItem(uint32_t access_flags, const FieldId* field_id) : - access_flags_(access_flags), field_id_(field_id) { } + FieldItem(uint32_t access_flags, const FieldId* field_id) + : access_flags_(access_flags), field_id_(field_id) { } ~FieldItem() OVERRIDE { } uint32_t GetAccessFlags() const { return access_flags_; } @@ -318,10 +320,12 @@ class FieldItem : public Item { DISALLOW_COPY_AND_ASSIGN(FieldItem); }; +using FieldItemVector = std::vector<std::unique_ptr<FieldItem>>; + class MethodItem : public Item { public: - MethodItem(uint32_t access_flags, const MethodId* method_id, const CodeItem* code) : - access_flags_(access_flags), method_id_(method_id), code_(code) { } + MethodItem(uint32_t access_flags, const MethodId* method_id, const CodeItem* code) + : access_flags_(access_flags), method_id_(method_id), code_(code) { } ~MethodItem() OVERRIDE { } uint32_t GetAccessFlags() const { return access_flags_; } @@ -337,12 +341,14 @@ class MethodItem : public Item { DISALLOW_COPY_AND_ASSIGN(MethodItem); }; +using MethodItemVector = std::vector<std::unique_ptr<MethodItem>>; + class ArrayItem : public Item { public: class NameValuePair { public: - NameValuePair(StringId* name, ArrayItem* value) : - name_(name), value_(value) { } + NameValuePair(StringId* name, ArrayItem* value) + : name_(name), value_(value) { } StringId* Name() const { return name_; } ArrayItem* Value() const { return value_.get(); } @@ -353,92 +359,125 @@ class ArrayItem : public Item { DISALLOW_COPY_AND_ASSIGN(NameValuePair); }; - ArrayItem(Header& header, const uint8_t** data, uint8_t type, uint8_t length); - ArrayItem(Header& header, const uint8_t** data); + struct ArrayItemVariant { + public: + union { + bool bool_val_; + int8_t byte_val_; + int16_t short_val_; + uint16_t char_val_; + int32_t int_val_; + int64_t long_val_; + float float_val_; + double double_val_; + StringId* string_val_; + FieldId* field_val_; + MethodId* method_val_; + } u_; + std::unique_ptr<std::vector<std::unique_ptr<ArrayItem>>> annotation_array_val_; + struct { + StringId* string_; + std::unique_ptr<std::vector<std::unique_ptr<NameValuePair>>> array_; + } annotation_annotation_val_; + }; + + explicit ArrayItem(uint8_t type) : type_(type) { } ~ArrayItem() OVERRIDE { } int8_t Type() const { return type_; } - bool GetBoolean() const { return item_.bool_val_; } - int8_t GetByte() const { return item_.byte_val_; } - int16_t GetShort() const { return item_.short_val_; } - uint16_t GetChar() const { return item_.char_val_; } - int32_t GetInt() const { return item_.int_val_; } - int64_t GetLong() const { return item_.long_val_; } - float GetFloat() const { return item_.float_val_; } - double GetDouble() const { return item_.double_val_; } - StringId* GetStringId() const { return item_.string_val_; } - FieldId* GetFieldId() const { return item_.field_val_; } - MethodId* GetMethodId() const { return item_.method_val_; } + bool GetBoolean() const { return item_.u_.bool_val_; } + int8_t GetByte() const { return item_.u_.byte_val_; } + int16_t GetShort() const { return item_.u_.short_val_; } + uint16_t GetChar() const { return item_.u_.char_val_; } + int32_t GetInt() const { return item_.u_.int_val_; } + int64_t GetLong() const { return item_.u_.long_val_; } + float GetFloat() const { return item_.u_.float_val_; } + double GetDouble() const { return item_.u_.double_val_; } + StringId* GetStringId() const { return item_.u_.string_val_; } + FieldId* GetFieldId() const { return item_.u_.field_val_; } + MethodId* GetMethodId() const { return item_.u_.method_val_; } std::vector<std::unique_ptr<ArrayItem>>* GetAnnotationArray() const { - return item_.annotation_array_val_; + return item_.annotation_array_val_.get(); } StringId* GetAnnotationAnnotationString() const { return item_.annotation_annotation_val_.string_; } std::vector<std::unique_ptr<NameValuePair>>* GetAnnotationAnnotationNameValuePairArray() const { - return item_.annotation_annotation_val_.array_; + return item_.annotation_annotation_val_.array_.get(); } + // Used to construct the item union. Ugly, but necessary. + ArrayItemVariant* GetArrayItemVariant() { return &item_; } void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } private: - void Read(Header& header, const uint8_t** data, uint8_t type, uint8_t length); uint8_t type_; - union { - bool bool_val_; - int8_t byte_val_; - int16_t short_val_; - uint16_t char_val_; - int32_t int_val_; - int64_t long_val_; - float float_val_; - double double_val_; - StringId* string_val_; - FieldId* field_val_; - MethodId* method_val_; - std::vector<std::unique_ptr<ArrayItem>>* annotation_array_val_; - struct { - StringId* string_; - std::vector<std::unique_ptr<NameValuePair>>* array_; - } annotation_annotation_val_; - } item_; + ArrayItemVariant item_; DISALLOW_COPY_AND_ASSIGN(ArrayItem); }; +using ArrayItemVector = std::vector<std::unique_ptr<ArrayItem>>; + class ClassData : public Item { public: - ClassData() = default; + ClassData(FieldItemVector* static_fields, + FieldItemVector* instance_fields, + MethodItemVector* direct_methods, + MethodItemVector* virtual_methods) + : static_fields_(static_fields), + instance_fields_(instance_fields), + direct_methods_(direct_methods), + virtual_methods_(virtual_methods) { } + ~ClassData() OVERRIDE = default; - std::vector<std::unique_ptr<FieldItem>>& StaticFields() { return static_fields_; } - std::vector<std::unique_ptr<FieldItem>>& InstanceFields() { return instance_fields_; } - std::vector<std::unique_ptr<MethodItem>>& DirectMethods() { return direct_methods_; } - std::vector<std::unique_ptr<MethodItem>>& VirtualMethods() { return virtual_methods_; } + FieldItemVector* StaticFields() { return static_fields_.get(); } + FieldItemVector* InstanceFields() { return instance_fields_.get(); } + MethodItemVector* DirectMethods() { return direct_methods_.get(); } + MethodItemVector* VirtualMethods() { return virtual_methods_.get(); } void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } private: - std::vector<std::unique_ptr<FieldItem>> static_fields_; - std::vector<std::unique_ptr<FieldItem>> instance_fields_; - std::vector<std::unique_ptr<MethodItem>> direct_methods_; - std::vector<std::unique_ptr<MethodItem>> virtual_methods_; + std::unique_ptr<FieldItemVector> static_fields_; + std::unique_ptr<FieldItemVector> instance_fields_; + std::unique_ptr<MethodItemVector> direct_methods_; + std::unique_ptr<MethodItemVector> virtual_methods_; DISALLOW_COPY_AND_ASSIGN(ClassData); }; class ClassDef : public Item { public: - ClassDef(const DexFile::ClassDef& disk_class_def, Header& header); + ClassDef(const TypeId* class_type, + uint32_t access_flags, + const TypeId* superclass, + TypeIdVector* interfaces, + uint32_t interfaces_offset, + const StringId* source_file, + AnnotationsDirectoryItem* annotations, + ArrayItemVector* static_values, + ClassData* class_data) + : class_type_(class_type), + access_flags_(access_flags), + superclass_(superclass), + interfaces_(interfaces), + interfaces_offset_(interfaces_offset), + source_file_(source_file), + annotations_(annotations), + static_values_(static_values), + class_data_(class_data) { } + ~ClassDef() OVERRIDE { } const TypeId* ClassType() const { return class_type_; } uint32_t GetAccessFlags() const { return access_flags_; } const TypeId* Superclass() const { return superclass_; } - std::vector<TypeId*>* Interfaces() { return &interfaces_; } + TypeIdVector* Interfaces() { return interfaces_.get(); } uint32_t InterfacesOffset() const { return interfaces_offset_; } void SetInterfacesOffset(uint32_t new_offset) { interfaces_offset_ = new_offset; } const StringId* SourceFile() const { return source_file_; } AnnotationsDirectoryItem* Annotations() const { return annotations_.get(); } - std::vector<std::unique_ptr<ArrayItem>>* StaticValues() { return static_values_; } - ClassData* GetClassData() { return &class_data_; } + ArrayItemVector* StaticValues() { return static_values_.get(); } + ClassData* GetClassData() { return class_data_.get(); } MethodItem* GenerateMethodItem(Header& header, ClassDataItemIterator& cdii); @@ -448,28 +487,78 @@ class ClassDef : public Item { const TypeId* class_type_; uint32_t access_flags_; const TypeId* superclass_; - std::vector<TypeId*> interfaces_; + std::unique_ptr<TypeIdVector> interfaces_; uint32_t interfaces_offset_; const StringId* source_file_; std::unique_ptr<AnnotationsDirectoryItem> annotations_; - std::vector<std::unique_ptr<ArrayItem>>* static_values_; - ClassData class_data_; + std::unique_ptr<ArrayItemVector> static_values_; + std::unique_ptr<ClassData> class_data_; DISALLOW_COPY_AND_ASSIGN(ClassDef); }; +class CatchHandler { + public: + CatchHandler(const TypeId* type_id, uint32_t address) : type_id_(type_id), address_(address) { } + + const TypeId* GetTypeId() const { return type_id_; } + uint32_t GetAddress() const { return address_; } + + private: + const TypeId* type_id_; + uint32_t address_; + DISALLOW_COPY_AND_ASSIGN(CatchHandler); +}; + +using CatchHandlerVector = std::vector<std::unique_ptr<const CatchHandler>>; + +class TryItem : public Item { + public: + TryItem(uint32_t start_addr, uint16_t insn_count, CatchHandlerVector* handlers) + : start_addr_(start_addr), insn_count_(insn_count), handlers_(handlers) { } + ~TryItem() OVERRIDE { } + + uint32_t StartAddr() const { return start_addr_; } + uint16_t InsnCount() const { return insn_count_; } + const CatchHandlerVector& GetHandlers() const { return *handlers_.get(); } + + void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } + + private: + uint32_t start_addr_; + uint16_t insn_count_; + std::unique_ptr<CatchHandlerVector> handlers_; + DISALLOW_COPY_AND_ASSIGN(TryItem); +}; + +using TryItemVector = std::vector<std::unique_ptr<const TryItem>>; + class CodeItem : public Item { public: - CodeItem(const DexFile::CodeItem& disk_code_item, Header& header); + CodeItem(uint16_t registers_size, + uint16_t ins_size, + uint16_t outs_size, + DebugInfoItem* debug_info, + uint32_t insns_size, + uint16_t* insns, + TryItemVector* tries) + : registers_size_(registers_size), + ins_size_(ins_size), + outs_size_(outs_size), + debug_info_(debug_info), + insns_size_(insns_size), + insns_(insns), + tries_(tries) { } + ~CodeItem() OVERRIDE { } uint16_t RegistersSize() const { return registers_size_; } uint16_t InsSize() const { return ins_size_; } uint16_t OutsSize() const { return outs_size_; } - uint16_t TriesSize() const { return tries_size_; } + uint16_t TriesSize() const { return tries_ == nullptr ? 0 : tries_->size(); } DebugInfoItem* DebugInfo() const { return debug_info_.get(); } uint32_t InsnsSize() const { return insns_size_; } uint16_t* Insns() const { return insns_.get(); } - std::vector<std::unique_ptr<const TryItem>>* Tries() const { return tries_; } + TryItemVector* Tries() const { return tries_.get(); } void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } @@ -477,56 +566,13 @@ class CodeItem : public Item { uint16_t registers_size_; uint16_t ins_size_; uint16_t outs_size_; - uint16_t tries_size_; std::unique_ptr<DebugInfoItem> debug_info_; uint32_t insns_size_; std::unique_ptr<uint16_t[]> insns_; - std::vector<std::unique_ptr<const TryItem>>* tries_; + std::unique_ptr<TryItemVector> tries_; DISALLOW_COPY_AND_ASSIGN(CodeItem); }; -class TryItem : public Item { - public: - class CatchHandler { - public: - CatchHandler(const TypeId* type_id, uint32_t address) : type_id_(type_id), address_(address) { } - - const TypeId* GetTypeId() const { return type_id_; } - uint32_t GetAddress() const { return address_; } - - private: - const TypeId* type_id_; - uint32_t address_; - DISALLOW_COPY_AND_ASSIGN(CatchHandler); - }; - - TryItem(const DexFile::TryItem& disk_try_item, - const DexFile::CodeItem& disk_code_item, - Header& header) { - start_addr_ = disk_try_item.start_addr_; - insn_count_ = disk_try_item.insn_count_; - for (CatchHandlerIterator it(disk_code_item, disk_try_item); it.HasNext(); it.Next()) { - const uint16_t type_index = it.GetHandlerTypeIndex(); - const TypeId* type_id = header.GetTypeIdOrNullPtr(type_index); - handlers_.push_back(std::unique_ptr<const CatchHandler>( - new CatchHandler(type_id, it.GetHandlerAddress()))); - } - } - ~TryItem() OVERRIDE { } - - uint32_t StartAddr() const { return start_addr_; } - uint16_t InsnCount() const { return insn_count_; } - const std::vector<std::unique_ptr<const CatchHandler>>& GetHandlers() const { return handlers_; } - - void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } - - private: - uint32_t start_addr_; - uint16_t insn_count_; - std::vector<std::unique_ptr<const CatchHandler>> handlers_; - DISALLOW_COPY_AND_ASSIGN(TryItem); -}; - struct PositionInfo { PositionInfo(uint32_t address, uint32_t line) : address_(address), line_(line) { } @@ -535,11 +581,21 @@ struct PositionInfo { uint32_t line_; }; +using PositionInfoVector = std::vector<std::unique_ptr<PositionInfo>>; + struct LocalInfo { - LocalInfo(const char* name, const char* descriptor, const char* signature, uint32_t start_address, - uint32_t end_address, uint16_t reg) : - name_(name), descriptor_(descriptor), signature_(signature), start_address_(start_address), - end_address_(end_address), reg_(reg) { } + LocalInfo(const char* name, + const char* descriptor, + const char* signature, + uint32_t start_address, + uint32_t end_address, + uint16_t reg) + : name_(name), + descriptor_(descriptor), + signature_(signature), + start_address_(start_address), + end_address_(end_address), + reg_(reg) { } std::string name_; std::string descriptor_; @@ -549,124 +605,123 @@ struct LocalInfo { uint16_t reg_; }; +using LocalInfoVector = std::vector<std::unique_ptr<LocalInfo>>; + class DebugInfoItem : public Item { public: DebugInfoItem() = default; - std::vector<std::unique_ptr<PositionInfo>>& GetPositionInfo() { return positions_; } - std::vector<std::unique_ptr<LocalInfo>>& GetLocalInfo() { return locals_; } + PositionInfoVector& GetPositionInfo() { return positions_; } + LocalInfoVector& GetLocalInfo() { return locals_; } private: - std::vector<std::unique_ptr<PositionInfo>> positions_; - std::vector<std::unique_ptr<LocalInfo>> locals_; + PositionInfoVector positions_; + LocalInfoVector locals_; DISALLOW_COPY_AND_ASSIGN(DebugInfoItem); }; -class AnnotationSetItem : public Item { +class AnnotationItem { public: - class AnnotationItem { - public: - AnnotationItem(uint8_t visibility, ArrayItem* item) : - visibility_(visibility), item_(item) { } + AnnotationItem(uint8_t visibility, ArrayItem* item) : visibility_(visibility), item_(item) { } - uint8_t GetVisibility() const { return visibility_; } - ArrayItem* GetItem() const { return item_.get(); } + uint8_t GetVisibility() const { return visibility_; } + ArrayItem* GetItem() const { return item_.get(); } - private: - uint8_t visibility_; - std::unique_ptr<ArrayItem> item_; - DISALLOW_COPY_AND_ASSIGN(AnnotationItem); - }; + private: + uint8_t visibility_; + std::unique_ptr<ArrayItem> item_; + DISALLOW_COPY_AND_ASSIGN(AnnotationItem); +}; - AnnotationSetItem(const DexFile::AnnotationSetItem& disk_annotations_item, Header& header); +using AnnotationItemVector = std::vector<std::unique_ptr<AnnotationItem>>; + +class AnnotationSetItem : public Item { + public: + explicit AnnotationSetItem(AnnotationItemVector* items) : items_(items) { } ~AnnotationSetItem() OVERRIDE { } - std::vector<std::unique_ptr<AnnotationItem>>& GetItems() { return items_; } + AnnotationItemVector* GetItems() { return items_.get(); } void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } private: - std::vector<std::unique_ptr<AnnotationItem>> items_; + std::unique_ptr<AnnotationItemVector> items_; DISALLOW_COPY_AND_ASSIGN(AnnotationSetItem); }; -class AnnotationsDirectoryItem : public Item { +using AnnotationSetItemVector = std::vector<std::unique_ptr<AnnotationSetItem>>; + +class FieldAnnotation { public: - class FieldAnnotation { - public: - FieldAnnotation(FieldId* field_id, AnnotationSetItem* annotation_set_item) : - field_id_(field_id), annotation_set_item_(annotation_set_item) { } + FieldAnnotation(FieldId* field_id, AnnotationSetItem* annotation_set_item) + : field_id_(field_id), annotation_set_item_(annotation_set_item) { } - FieldId* GetFieldId() const { return field_id_; } - AnnotationSetItem* GetAnnotationSetItem() const { return annotation_set_item_.get(); } + FieldId* GetFieldId() const { return field_id_; } + AnnotationSetItem* GetAnnotationSetItem() const { return annotation_set_item_.get(); } - private: - FieldId* field_id_; - std::unique_ptr<AnnotationSetItem> annotation_set_item_; - DISALLOW_COPY_AND_ASSIGN(FieldAnnotation); - }; + private: + FieldId* field_id_; + std::unique_ptr<AnnotationSetItem> annotation_set_item_; + DISALLOW_COPY_AND_ASSIGN(FieldAnnotation); +}; - class MethodAnnotation { - public: - MethodAnnotation(MethodId* method_id, AnnotationSetItem* annotation_set_item) : - method_id_(method_id), annotation_set_item_(annotation_set_item) { } +using FieldAnnotationVector = std::vector<std::unique_ptr<FieldAnnotation>>; - MethodId* GetMethodId() const { return method_id_; } - AnnotationSetItem* GetAnnotationSetItem() const { return annotation_set_item_.get(); } +class MethodAnnotation { + public: + MethodAnnotation(MethodId* method_id, AnnotationSetItem* annotation_set_item) + : method_id_(method_id), annotation_set_item_(annotation_set_item) { } - private: - MethodId* method_id_; - std::unique_ptr<AnnotationSetItem> annotation_set_item_; - DISALLOW_COPY_AND_ASSIGN(MethodAnnotation); - }; + MethodId* GetMethodId() const { return method_id_; } + AnnotationSetItem* GetAnnotationSetItem() const { return annotation_set_item_.get(); } - class ParameterAnnotation { - public: - ParameterAnnotation(MethodId* method_id, - const DexFile::AnnotationSetRefList* annotation_set_ref_list, - Header& header) : - method_id_(method_id) { - for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) { - const DexFile::AnnotationSetItem* annotation_set_item = - header.GetDexFile().GetSetRefItemItem(&annotation_set_ref_list->list_[i]); - annotations_.push_back(std::unique_ptr<AnnotationSetItem>( - new AnnotationSetItem(*annotation_set_item, header))); - } - } - - MethodId* GetMethodId() const { return method_id_; } - std::vector<std::unique_ptr<AnnotationSetItem>>& GetAnnotations() { return annotations_; } + private: + MethodId* method_id_; + std::unique_ptr<AnnotationSetItem> annotation_set_item_; + DISALLOW_COPY_AND_ASSIGN(MethodAnnotation); +}; - private: - MethodId* method_id_; - std::vector<std::unique_ptr<AnnotationSetItem>> annotations_; - DISALLOW_COPY_AND_ASSIGN(ParameterAnnotation); - }; +using MethodAnnotationVector = std::vector<std::unique_ptr<MethodAnnotation>>; - AnnotationsDirectoryItem(const DexFile::AnnotationsDirectoryItem* disk_annotations_item, - Header& header); +class ParameterAnnotation { + public: + ParameterAnnotation(MethodId* method_id, AnnotationSetItemVector* annotations) + : method_id_(method_id), annotations_(annotations) { } - AnnotationSetItem* GetClassAnnotation() const { return class_annotation_.get(); } + MethodId* GetMethodId() const { return method_id_; } + AnnotationSetItemVector* GetAnnotations() { return annotations_.get(); } - std::vector<std::unique_ptr<FieldAnnotation>>& GetFieldAnnotations() { - return field_annotations_; - } + private: + MethodId* method_id_; + std::unique_ptr<AnnotationSetItemVector> annotations_; + DISALLOW_COPY_AND_ASSIGN(ParameterAnnotation); +}; - std::vector<std::unique_ptr<MethodAnnotation>>& GetMethodAnnotations() { - return method_annotations_; - } +using ParameterAnnotationVector = std::vector<std::unique_ptr<ParameterAnnotation>>; - std::vector<std::unique_ptr<ParameterAnnotation>>& GetParameterAnnotations() { - return parameter_annotations_; - } +class AnnotationsDirectoryItem : public Item { + public: + AnnotationsDirectoryItem(AnnotationSetItem* class_annotation, + FieldAnnotationVector* field_annotations, + MethodAnnotationVector* method_annotations, + ParameterAnnotationVector* parameter_annotations) + : class_annotation_(class_annotation), + field_annotations_(field_annotations), + method_annotations_(method_annotations), + parameter_annotations_(parameter_annotations) { } + + AnnotationSetItem* GetClassAnnotation() const { return class_annotation_.get(); } + FieldAnnotationVector* GetFieldAnnotations() { return field_annotations_.get(); } + MethodAnnotationVector* GetMethodAnnotations() { return method_annotations_.get(); } + ParameterAnnotationVector* GetParameterAnnotations() { return parameter_annotations_.get(); } void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } private: std::unique_ptr<AnnotationSetItem> class_annotation_; - std::vector<std::unique_ptr<FieldAnnotation>> field_annotations_; - std::vector<std::unique_ptr<MethodAnnotation>> method_annotations_; - std::vector<std::unique_ptr<ParameterAnnotation>> parameter_annotations_; + std::unique_ptr<FieldAnnotationVector> field_annotations_; + std::unique_ptr<MethodAnnotationVector> method_annotations_; + std::unique_ptr<ParameterAnnotationVector> parameter_annotations_; DISALLOW_COPY_AND_ASSIGN(AnnotationsDirectoryItem); }; diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc new file mode 100644 index 0000000000..30f57d95a4 --- /dev/null +++ b/dexlayout/dex_ir_builder.cc @@ -0,0 +1,507 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Header file of an in-memory representation of DEX files. + */ + +#include <stdint.h> +#include <vector> + +#include "dex_ir_builder.h" + +namespace art { +namespace dex_ir { + +namespace { + +static uint64_t ReadVarWidth(const uint8_t** data, uint8_t length, bool sign_extend) { + uint64_t value = 0; + for (uint32_t i = 0; i <= length; i++) { + value |= static_cast<uint64_t>(*(*data)++) << (i * 8); + } + if (sign_extend) { + int shift = (7 - length) * 8; + return (static_cast<int64_t>(value) << shift) >> shift; + } + return value; +} + +// Prototype to break cyclic dependency. +void ReadArrayItemVariant(Header& header, + const uint8_t** data, + uint8_t type, + uint8_t length, + ArrayItem::ArrayItemVariant* item); + +ArrayItem* ReadArrayItem(Header& header, const uint8_t** data, uint8_t type, uint8_t length) { + ArrayItem* item = new ArrayItem(type); + ReadArrayItemVariant(header, data, type, length, item->GetArrayItemVariant()); + return item; +} + +ArrayItem* ReadArrayItem(Header& header, const uint8_t** data) { + const uint8_t encoded_value = *(*data)++; + const uint8_t type = encoded_value & 0x1f; + ArrayItem* item = new ArrayItem(type); + ReadArrayItemVariant(header, data, type, encoded_value >> 5, item->GetArrayItemVariant()); + return item; +} + +void ReadArrayItemVariant(Header& header, + const uint8_t** data, + uint8_t type, + uint8_t length, + ArrayItem::ArrayItemVariant* item) { + switch (type) { + case DexFile::kDexAnnotationByte: + item->u_.byte_val_ = static_cast<int8_t>(ReadVarWidth(data, length, false)); + break; + case DexFile::kDexAnnotationShort: + item->u_.short_val_ = static_cast<int16_t>(ReadVarWidth(data, length, true)); + break; + case DexFile::kDexAnnotationChar: + item->u_.char_val_ = static_cast<uint16_t>(ReadVarWidth(data, length, false)); + break; + case DexFile::kDexAnnotationInt: + item->u_.int_val_ = static_cast<int32_t>(ReadVarWidth(data, length, true)); + break; + case DexFile::kDexAnnotationLong: + item->u_.long_val_ = static_cast<int64_t>(ReadVarWidth(data, length, true)); + break; + case DexFile::kDexAnnotationFloat: { + // Fill on right. + union { + float f; + uint32_t data; + } conv; + conv.data = static_cast<uint32_t>(ReadVarWidth(data, length, false)) << (3 - length) * 8; + item->u_.float_val_ = conv.f; + break; + } + case DexFile::kDexAnnotationDouble: { + // Fill on right. + union { + double d; + uint64_t data; + } conv; + conv.data = ReadVarWidth(data, length, false) << (7 - length) * 8; + item->u_.double_val_ = conv.d; + break; + } + case DexFile::kDexAnnotationString: { + const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false)); + item->u_.string_val_ = header.StringIds()[string_index].get(); + break; + } + case DexFile::kDexAnnotationType: { + const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false)); + item->u_.string_val_ = header.TypeIds()[string_index]->GetStringId(); + break; + } + case DexFile::kDexAnnotationField: + case DexFile::kDexAnnotationEnum: { + const uint32_t field_index = static_cast<uint32_t>(ReadVarWidth(data, length, false)); + item->u_.field_val_ = header.FieldIds()[field_index].get(); + break; + } + case DexFile::kDexAnnotationMethod: { + const uint32_t method_index = static_cast<uint32_t>(ReadVarWidth(data, length, false)); + item->u_.method_val_ = header.MethodIds()[method_index].get(); + break; + } + case DexFile::kDexAnnotationArray: { + item->annotation_array_val_.reset(new ArrayItemVector()); + // Decode all elements. + const uint32_t size = DecodeUnsignedLeb128(data); + for (uint32_t i = 0; i < size; i++) { + item->annotation_array_val_->push_back( + std::unique_ptr<ArrayItem>(ReadArrayItem(header, data))); + } + break; + } + case DexFile::kDexAnnotationAnnotation: { + const uint32_t type_idx = DecodeUnsignedLeb128(data); + item->annotation_annotation_val_.string_ = header.TypeIds()[type_idx]->GetStringId(); + item->annotation_annotation_val_.array_.reset( + new std::vector<std::unique_ptr<ArrayItem::NameValuePair>>()); + // Decode all name=value pairs. + const uint32_t size = DecodeUnsignedLeb128(data); + for (uint32_t i = 0; i < size; i++) { + const uint32_t name_index = DecodeUnsignedLeb128(data); + item->annotation_annotation_val_.array_->push_back( + std::unique_ptr<ArrayItem::NameValuePair>( + new ArrayItem::NameValuePair(header.StringIds()[name_index].get(), + ReadArrayItem(header, data)))); + } + break; + } + case DexFile::kDexAnnotationNull: + break; + case DexFile::kDexAnnotationBoolean: + item->u_.bool_val_ = (length != 0); + break; + default: + break; + } +} + +static bool GetPositionsCb(void* context, const DexFile::PositionInfo& entry) { + DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context); + PositionInfoVector& positions = debug_info->GetPositionInfo(); + positions.push_back(std::unique_ptr<PositionInfo>(new PositionInfo(entry.address_, entry.line_))); + return false; +} + +static void GetLocalsCb(void* context, const DexFile::LocalInfo& entry) { + DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context); + LocalInfoVector& locals = debug_info->GetLocalInfo(); + const char* name = entry.name_ != nullptr ? entry.name_ : "(null)"; + const char* signature = entry.signature_ != nullptr ? entry.signature_ : ""; + locals.push_back(std::unique_ptr<LocalInfo>( + new LocalInfo(name, entry.descriptor_, signature, entry.start_address_, + entry.end_address_, entry.reg_))); +} + +CodeItem* ReadCodeItem(const DexFile& dex_file, + const DexFile::CodeItem& disk_code_item, + Header& header) { + uint16_t registers_size = disk_code_item.registers_size_; + uint16_t ins_size = disk_code_item.ins_size_; + uint16_t outs_size = disk_code_item.outs_size_; + uint32_t tries_size = disk_code_item.tries_size_; + + const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(&disk_code_item); + DebugInfoItem* debug_info = nullptr; + if (debug_info_stream != nullptr) { + debug_info = new DebugInfoItem(); + } + + uint32_t insns_size = disk_code_item.insns_size_in_code_units_; + uint16_t* insns = new uint16_t[insns_size]; + memcpy(insns, disk_code_item.insns_, insns_size * sizeof(uint16_t)); + + TryItemVector* tries = nullptr; + if (tries_size > 0) { + tries = new TryItemVector(); + for (uint32_t i = 0; i < tries_size; ++i) { + const DexFile::TryItem* disk_try_item = dex_file.GetTryItems(disk_code_item, i); + uint32_t start_addr = disk_try_item->start_addr_; + uint16_t insn_count = disk_try_item->insn_count_; + CatchHandlerVector* handlers = new CatchHandlerVector(); + for (CatchHandlerIterator it(disk_code_item, *disk_try_item); it.HasNext(); it.Next()) { + const uint16_t type_index = it.GetHandlerTypeIndex(); + const TypeId* type_id = header.GetTypeIdOrNullPtr(type_index); + handlers->push_back(std::unique_ptr<const CatchHandler>( + new CatchHandler(type_id, it.GetHandlerAddress()))); + } + TryItem* try_item = new TryItem(start_addr, insn_count, handlers); + tries->push_back(std::unique_ptr<const TryItem>(try_item)); + } + } + return new CodeItem(registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries); +} + +MethodItem* GenerateMethodItem(const DexFile& dex_file, + dex_ir::Header& header, + ClassDataItemIterator& cdii) { + MethodId* method_item = header.MethodIds()[cdii.GetMemberIndex()].get(); + uint32_t access_flags = cdii.GetRawMemberAccessFlags(); + const DexFile::CodeItem* disk_code_item = cdii.GetMethodCodeItem(); + CodeItem* code_item = nullptr; + DebugInfoItem* debug_info = nullptr; + if (disk_code_item != nullptr) { + code_item = ReadCodeItem(dex_file, *disk_code_item, header); + code_item->SetOffset(cdii.GetMethodCodeItemOffset()); + debug_info = code_item->DebugInfo(); + } + if (debug_info != nullptr) { + bool is_static = (access_flags & kAccStatic) != 0; + dex_file.DecodeDebugLocalInfo( + disk_code_item, is_static, cdii.GetMemberIndex(), GetLocalsCb, debug_info); + dex_file.DecodeDebugPositionInfo(disk_code_item, GetPositionsCb, debug_info); + } + return new MethodItem(access_flags, method_item, code_item); +} + +AnnotationSetItem* ReadAnnotationSetItem(const DexFile& dex_file, + const DexFile::AnnotationSetItem& disk_annotations_item, + Header& header) { + if (disk_annotations_item.size_ == 0) { + return nullptr; + } + AnnotationItemVector* items = new AnnotationItemVector(); + for (uint32_t i = 0; i < disk_annotations_item.size_; ++i) { + const DexFile::AnnotationItem* annotation = + dex_file.GetAnnotationItem(&disk_annotations_item, i); + if (annotation == nullptr) { + continue; + } + uint8_t visibility = annotation->visibility_; + const uint8_t* annotation_data = annotation->annotation_; + ArrayItem* array_item = + ReadArrayItem(header, &annotation_data, DexFile::kDexAnnotationAnnotation, 0); + items->push_back(std::unique_ptr<AnnotationItem>(new AnnotationItem(visibility, array_item))); + } + return new AnnotationSetItem(items); +} + +ParameterAnnotation* ReadParameterAnnotation( + const DexFile& dex_file, + MethodId* method_id, + const DexFile::AnnotationSetRefList* annotation_set_ref_list, + Header& header) { + AnnotationSetItemVector* annotations = new AnnotationSetItemVector(); + for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) { + const DexFile::AnnotationSetItem* annotation_set_item = + dex_file.GetSetRefItemItem(&annotation_set_ref_list->list_[i]); + annotations->push_back(std::unique_ptr<AnnotationSetItem>( + ReadAnnotationSetItem(dex_file, *annotation_set_item, header))); + } + return new ParameterAnnotation(method_id, annotations); +} + +AnnotationsDirectoryItem* ReadAnnotationsDirectoryItem( + const DexFile& dex_file, + const DexFile::AnnotationsDirectoryItem* disk_annotations_item, + Header& header) { + const DexFile::AnnotationSetItem* class_set_item = + dex_file.GetClassAnnotationSet(disk_annotations_item); + AnnotationSetItem* class_annotation = nullptr; + if (class_set_item != nullptr) { + class_annotation = ReadAnnotationSetItem(dex_file, *class_set_item, header); + } + const DexFile::FieldAnnotationsItem* fields = + dex_file.GetFieldAnnotations(disk_annotations_item); + FieldAnnotationVector* field_annotations = nullptr; + if (fields != nullptr) { + field_annotations = new FieldAnnotationVector(); + for (uint32_t i = 0; i < disk_annotations_item->fields_size_; ++i) { + FieldId* field_id = header.FieldIds()[fields[i].field_idx_].get(); + const DexFile::AnnotationSetItem* field_set_item = + dex_file.GetFieldAnnotationSetItem(fields[i]); + AnnotationSetItem* annotation_set_item = + ReadAnnotationSetItem(dex_file, *field_set_item, header); + field_annotations->push_back(std::unique_ptr<FieldAnnotation>( + new FieldAnnotation(field_id, annotation_set_item))); + } + } + const DexFile::MethodAnnotationsItem* methods = + dex_file.GetMethodAnnotations(disk_annotations_item); + MethodAnnotationVector* method_annotations = nullptr; + if (methods != nullptr) { + method_annotations = new MethodAnnotationVector(); + for (uint32_t i = 0; i < disk_annotations_item->methods_size_; ++i) { + MethodId* method_id = header.MethodIds()[methods[i].method_idx_].get(); + const DexFile::AnnotationSetItem* method_set_item = + dex_file.GetMethodAnnotationSetItem(methods[i]); + AnnotationSetItem* annotation_set_item = + ReadAnnotationSetItem(dex_file, *method_set_item, header); + method_annotations->push_back(std::unique_ptr<MethodAnnotation>( + new MethodAnnotation(method_id, annotation_set_item))); + } + } + const DexFile::ParameterAnnotationsItem* parameters = + dex_file.GetParameterAnnotations(disk_annotations_item); + ParameterAnnotationVector* parameter_annotations = nullptr; + if (parameters != nullptr) { + parameter_annotations = new ParameterAnnotationVector(); + for (uint32_t i = 0; i < disk_annotations_item->parameters_size_; ++i) { + MethodId* method_id = header.MethodIds()[parameters[i].method_idx_].get(); + const DexFile::AnnotationSetRefList* list = + dex_file.GetParameterAnnotationSetRefList(¶meters[i]); + parameter_annotations->push_back(std::unique_ptr<ParameterAnnotation>( + ReadParameterAnnotation(dex_file, method_id, list, header))); + } + } + + return new AnnotationsDirectoryItem(class_annotation, + field_annotations, + method_annotations, + parameter_annotations); +} + +ClassDef* ReadClassDef(const DexFile& dex_file, + const DexFile::ClassDef& disk_class_def, + Header& header) { + const TypeId* class_type = header.TypeIds()[disk_class_def.class_idx_].get(); + uint32_t access_flags = disk_class_def.access_flags_; + const TypeId* superclass = header.GetTypeIdOrNullPtr(disk_class_def.superclass_idx_); + + TypeIdVector* interfaces = nullptr; + const DexFile::TypeList* type_list = dex_file.GetInterfacesList(disk_class_def); + uint32_t interfaces_offset = disk_class_def.interfaces_off_; + if (type_list != nullptr) { + interfaces = new TypeIdVector(); + for (uint32_t index = 0; index < type_list->Size(); ++index) { + interfaces->push_back(header.TypeIds()[type_list->GetTypeItem(index).type_idx_].get()); + } + } + const StringId* source_file = header.GetStringIdOrNullPtr(disk_class_def.source_file_idx_); + // Annotations. + AnnotationsDirectoryItem* annotations = nullptr; + const DexFile::AnnotationsDirectoryItem* disk_annotations_directory_item = + dex_file.GetAnnotationsDirectory(disk_class_def); + if (disk_annotations_directory_item != nullptr) { + annotations = ReadAnnotationsDirectoryItem(dex_file, disk_annotations_directory_item, header); + annotations->SetOffset(disk_class_def.annotations_off_); + } + // Static field initializers. + ArrayItemVector* static_values = nullptr; + const uint8_t* static_data = dex_file.GetEncodedStaticFieldValuesArray(disk_class_def); + if (static_data != nullptr) { + uint32_t static_value_count = static_data == nullptr ? 0 : DecodeUnsignedLeb128(&static_data); + if (static_value_count > 0) { + static_values = new ArrayItemVector(); + for (uint32_t i = 0; i < static_value_count; ++i) { + static_values->push_back(std::unique_ptr<ArrayItem>(ReadArrayItem(header, &static_data))); + } + } + } + // Read the fields and methods defined by the class, resolving the circular reference from those + // to classes by setting class at the same time. + const uint8_t* encoded_data = dex_file.GetClassData(disk_class_def); + ClassData* class_data = nullptr; + if (encoded_data != nullptr) { + uint32_t offset = disk_class_def.class_data_off_; + ClassDataItemIterator cdii(dex_file, encoded_data); + // Static fields. + FieldItemVector* static_fields = new FieldItemVector(); + for (uint32_t i = 0; cdii.HasNextStaticField(); i++, cdii.Next()) { + FieldId* field_item = header.FieldIds()[cdii.GetMemberIndex()].get(); + uint32_t access_flags = cdii.GetRawMemberAccessFlags(); + static_fields->push_back(std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item))); + } + // Instance fields. + FieldItemVector* instance_fields = new FieldItemVector(); + for (uint32_t i = 0; cdii.HasNextInstanceField(); i++, cdii.Next()) { + FieldId* field_item = header.FieldIds()[cdii.GetMemberIndex()].get(); + uint32_t access_flags = cdii.GetRawMemberAccessFlags(); + instance_fields->push_back( + std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item))); + } + // Direct methods. + MethodItemVector* direct_methods = new MethodItemVector(); + for (uint32_t i = 0; cdii.HasNextDirectMethod(); i++, cdii.Next()) { + direct_methods->push_back( + std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, header, cdii))); + } + // Virtual methods. + MethodItemVector* virtual_methods = new MethodItemVector(); + for (uint32_t i = 0; cdii.HasNextVirtualMethod(); i++, cdii.Next()) { + virtual_methods->push_back( + std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, header, cdii))); + } + class_data = new ClassData(static_fields, instance_fields, direct_methods, virtual_methods); + class_data->SetOffset(offset); + } + return new ClassDef(class_type, + access_flags, + superclass, + interfaces, + interfaces_offset, + source_file, + annotations, + static_values, + class_data); +} + +} // namespace + +Header* DexIrBuilder(const DexFile& dex_file) { + const DexFile::Header& disk_header = dex_file.GetHeader(); + Header* header = new Header(disk_header.magic_, + disk_header.checksum_, + disk_header.signature_, + disk_header.endian_tag_, + disk_header.file_size_, + disk_header.header_size_, + disk_header.link_size_, + disk_header.link_off_, + disk_header.data_size_, + disk_header.data_off_); + // Walk the rest of the header fields. + // StringId table. + std::vector<std::unique_ptr<StringId>>& string_ids = header->StringIds(); + header->SetStringIdsOffset(disk_header.string_ids_off_); + for (uint32_t i = 0; i < dex_file.NumStringIds(); ++i) { + const DexFile::StringId& disk_string_id = dex_file.GetStringId(i); + StringId* string_id = new StringId(dex_file.GetStringData(disk_string_id)); + string_id->SetOffset(i); + string_ids.push_back(std::unique_ptr<StringId>(string_id)); + } + // TypeId table. + std::vector<std::unique_ptr<TypeId>>& type_ids = header->TypeIds(); + header->SetTypeIdsOffset(disk_header.type_ids_off_); + for (uint32_t i = 0; i < dex_file.NumTypeIds(); ++i) { + const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(i); + TypeId* type_id = new TypeId(header->StringIds()[disk_type_id.descriptor_idx_].get()); + type_id->SetOffset(i); + type_ids.push_back(std::unique_ptr<TypeId>(type_id)); + } + // ProtoId table. + std::vector<std::unique_ptr<ProtoId>>& proto_ids = header->ProtoIds(); + header->SetProtoIdsOffset(disk_header.proto_ids_off_); + for (uint32_t i = 0; i < dex_file.NumProtoIds(); ++i) { + const DexFile::ProtoId& disk_proto_id = dex_file.GetProtoId(i); + // Build the parameter type vector. + TypeIdVector* parameters = new TypeIdVector(); + DexFileParameterIterator dfpi(dex_file, disk_proto_id); + while (dfpi.HasNext()) { + parameters->push_back(header->TypeIds()[dfpi.GetTypeIdx()].get()); + dfpi.Next(); + } + ProtoId* proto_id = new ProtoId(header->StringIds()[disk_proto_id.shorty_idx_].get(), + header->TypeIds()[disk_proto_id.return_type_idx_].get(), + parameters); + proto_id->SetOffset(i); + proto_ids.push_back(std::unique_ptr<ProtoId>(proto_id)); + } + // FieldId table. + std::vector<std::unique_ptr<FieldId>>& field_ids = header->FieldIds(); + header->SetFieldIdsOffset(disk_header.field_ids_off_); + for (uint32_t i = 0; i < dex_file.NumFieldIds(); ++i) { + const DexFile::FieldId& disk_field_id = dex_file.GetFieldId(i); + FieldId* field_id = new FieldId(header->TypeIds()[disk_field_id.class_idx_].get(), + header->TypeIds()[disk_field_id.type_idx_].get(), + header->StringIds()[disk_field_id.name_idx_].get()); + field_id->SetOffset(i); + field_ids.push_back(std::unique_ptr<FieldId>(field_id)); + } + // MethodId table. + std::vector<std::unique_ptr<MethodId>>& method_ids = header->MethodIds(); + header->SetMethodIdsOffset(disk_header.method_ids_off_); + for (uint32_t i = 0; i < dex_file.NumMethodIds(); ++i) { + const DexFile::MethodId& disk_method_id = dex_file.GetMethodId(i); + MethodId* method_id = new MethodId(header->TypeIds()[disk_method_id.class_idx_].get(), + header->ProtoIds()[disk_method_id.proto_idx_].get(), + header->StringIds()[disk_method_id.name_idx_].get()); + method_id->SetOffset(i); + method_ids.push_back(std::unique_ptr<MethodId>(method_id)); + } + // ClassDef table. + std::vector<std::unique_ptr<ClassDef>>& class_defs = header->ClassDefs(); + header->SetClassDefsOffset(disk_header.class_defs_off_); + for (uint32_t i = 0; i < dex_file.NumClassDefs(); ++i) { + const DexFile::ClassDef& disk_class_def = dex_file.GetClassDef(i); + ClassDef* class_def = ReadClassDef(dex_file, disk_class_def, *header); + class_def->SetOffset(i); + class_defs.push_back(std::unique_ptr<ClassDef>(class_def)); + } + + return header; +} + +} // namespace dex_ir +} // namespace art diff --git a/dexlayout/dex_ir_builder.h b/dexlayout/dex_ir_builder.h new file mode 100644 index 0000000000..c53157b5fc --- /dev/null +++ b/dexlayout/dex_ir_builder.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Header file of an in-memory representation of DEX files. + */ + +#ifndef ART_DEXLAYOUT_DEX_IR_BUILDER_H_ +#define ART_DEXLAYOUT_DEX_IR_BUILDER_H_ + +#include "dex_ir.h" + +namespace art { +namespace dex_ir { + +dex_ir::Header* DexIrBuilder(const DexFile& dex_file); + +} // namespace dex_ir +} // namespace art + +#endif // ART_DEXLAYOUT_DEX_IR_BUILDER_H_ diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc index 0b3161426a..3a3f417825 100644 --- a/dexlayout/dexlayout.cc +++ b/dexlayout/dexlayout.cc @@ -30,7 +30,7 @@ #include <sstream> #include <vector> -#include "dex_ir.h" +#include "dex_ir_builder.h" #include "dex_file-inl.h" #include "dex_instruction-inl.h" #include "utils.h" @@ -501,20 +501,33 @@ static void DumpClassDef(dex_ir::Header* header, int idx) { } fprintf(out_file_, "annotations_off : %d (0x%06x)\n", annotations_offset, annotations_offset); - fprintf(out_file_, "class_data_off : %d (0x%06x)\n", - class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset()); + if (class_def->GetClassData() == nullptr) { + fprintf(out_file_, "class_data_off : %d (0x%06x)\n", 0, 0); + } else { + fprintf(out_file_, "class_data_off : %d (0x%06x)\n", + class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset()); + } // Fields and methods. dex_ir::ClassData* class_data = class_def->GetClassData(); - if (class_data != nullptr) { - fprintf(out_file_, "static_fields_size : %zu\n", class_data->StaticFields().size()); - fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields().size()); - fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods().size()); - fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods().size()); + if (class_data != nullptr && class_data->StaticFields() != nullptr) { + fprintf(out_file_, "static_fields_size : %zu\n", class_data->StaticFields()->size()); } else { fprintf(out_file_, "static_fields_size : 0\n"); + } + if (class_data != nullptr && class_data->InstanceFields() != nullptr) { + fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size()); + } else { fprintf(out_file_, "instance_fields_size: 0\n"); + } + if (class_data != nullptr && class_data->DirectMethods() != nullptr) { + fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size()); + } else { fprintf(out_file_, "direct_methods_size : 0\n"); + } + if (class_data != nullptr && class_data->VirtualMethods() != nullptr) { + fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size()); + } else { fprintf(out_file_, "virtual_methods_size: 0\n"); } fprintf(out_file_, "\n"); @@ -524,12 +537,11 @@ static void DumpClassDef(dex_ir::Header* header, int idx) { * Dumps an annotation set item. */ static void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) { - if (set_item == nullptr || set_item->GetItems().size() == 0) { + if (set_item == nullptr || set_item->GetItems()->size() == 0) { fputs(" empty-annotation-set\n", out_file_); return; } - for (std::unique_ptr<dex_ir::AnnotationSetItem::AnnotationItem>& annotation : - set_item->GetItems()) { + for (std::unique_ptr<dex_ir::AnnotationItem>& annotation : *set_item->GetItems()) { if (annotation == nullptr) { continue; } @@ -561,12 +573,9 @@ static void DumpClassAnnotations(dex_ir::Header* header, int idx) { fprintf(out_file_, "Class #%d annotations:\n", idx); dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation(); - std::vector<std::unique_ptr<dex_ir::AnnotationsDirectoryItem::FieldAnnotation>>& fields = - annotations_directory->GetFieldAnnotations(); - std::vector<std::unique_ptr<dex_ir::AnnotationsDirectoryItem::MethodAnnotation>>& methods = - annotations_directory->GetMethodAnnotations(); - std::vector<std::unique_ptr<dex_ir::AnnotationsDirectoryItem::ParameterAnnotation>>& parameters = - annotations_directory->GetParameterAnnotations(); + dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations(); + dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations(); + dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations(); // Annotations on the class itself. if (class_set_item != nullptr) { @@ -575,34 +584,40 @@ static void DumpClassAnnotations(dex_ir::Header* header, int idx) { } // Annotations on fields. - for (auto& field : fields) { - const dex_ir::FieldId* field_id = field->GetFieldId(); - const uint32_t field_idx = field_id->GetOffset(); - const char* field_name = field_id->Name()->Data(); - fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name); - DumpAnnotationSetItem(field->GetAnnotationSetItem()); + if (fields != nullptr) { + for (auto& field : *fields) { + const dex_ir::FieldId* field_id = field->GetFieldId(); + const uint32_t field_idx = field_id->GetOffset(); + const char* field_name = field_id->Name()->Data(); + fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name); + DumpAnnotationSetItem(field->GetAnnotationSetItem()); + } } // Annotations on methods. - for (auto& method : methods) { - const dex_ir::MethodId* method_id = method->GetMethodId(); - const uint32_t method_idx = method_id->GetOffset(); - const char* method_name = method_id->Name()->Data(); - fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name); - DumpAnnotationSetItem(method->GetAnnotationSetItem()); + if (methods != nullptr) { + for (auto& method : *methods) { + const dex_ir::MethodId* method_id = method->GetMethodId(); + const uint32_t method_idx = method_id->GetOffset(); + const char* method_name = method_id->Name()->Data(); + fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name); + DumpAnnotationSetItem(method->GetAnnotationSetItem()); + } } // Annotations on method parameters. - for (auto& parameter : parameters) { - const dex_ir::MethodId* method_id = parameter->GetMethodId(); - const uint32_t method_idx = method_id->GetOffset(); - const char* method_name = method_id->Name()->Data(); - fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name); - uint32_t j = 0; - for (auto& annotation : parameter->GetAnnotations()) { - fprintf(out_file_, "#%u\n", j); - DumpAnnotationSetItem(annotation.get()); - ++j; + if (parameters != nullptr) { + for (auto& parameter : *parameters) { + const dex_ir::MethodId* method_id = parameter->GetMethodId(); + const uint32_t method_idx = method_id->GetOffset(); + const char* method_name = method_id->Name()->Data(); + fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name); + uint32_t j = 0; + for (auto& annotation : *parameter->GetAnnotations()) { + fprintf(out_file_, "#%u\n", j); + DumpAnnotationSetItem(annotation.get()); + ++j; + } } } @@ -612,7 +627,7 @@ static void DumpClassAnnotations(dex_ir::Header* header, int idx) { /* * Dumps an interface that a class declares to implement. */ -static void DumpInterface(dex_ir::TypeId* type_item, int i) { +static void DumpInterface(const dex_ir::TypeId* type_item, int i) { const char* interface_name = type_item->GetStringId()->Data(); if (options_.output_format_ == kOutputPlain) { fprintf(out_file_, " #%d : '%s'\n", i, interface_name); @@ -752,10 +767,10 @@ static std::unique_ptr<char[]> IndexString(dex_ir::Header* header, if (index < header->MethodIdsSize()) { dex_ir::MethodId* method_id = header->MethodIds()[index].get(); const char* name = method_id->Name()->Data(); - char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str()); + std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); const char* back_descriptor = method_id->Class()->GetStringId()->Data(); outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x", - back_descriptor, name, type_descriptor, width, index); + back_descriptor, name, type_descriptor.c_str(), width, index); } else { outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index); } @@ -1015,13 +1030,13 @@ static void DumpBytecodes(dex_ir::Header* header, uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) { dex_ir::MethodId* method_id = header->MethodIds()[idx].get(); const char* name = method_id->Name()->Data(); - const char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str()); + std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); const char* back_descriptor = method_id->Class()->GetStringId()->Data(); // Generate header. std::string dot(DescriptorToDotWrapper(back_descriptor)); fprintf(out_file_, "%06x: |[%06x] %s.%s:%s\n", - code_offset, code_offset, dot.c_str(), name, type_descriptor); + code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str()); // Iterate over all instructions. const uint16_t* insns = code->Insns(); @@ -1260,8 +1275,8 @@ static void DumpCFG(const DexFile* dex_file, int idx) { } while (it.HasNextVirtualMethod()) { DumpCFG(dex_file, - it.GetMemberIndex(), - it.GetMethodCodeItem()); + it.GetMemberIndex(), + it.GetMethodCodeItem()); it.Next(); } } @@ -1274,7 +1289,10 @@ static void DumpCFG(const DexFile* dex_file, int idx) { * If "*last_package" is nullptr or does not match the current class' package, * the value will be replaced with a newly-allocated string. */ -static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { +static void DumpClass(const DexFile* dex_file, + dex_ir::Header* header, + int idx, + char** last_package) { dex_ir::ClassDef* class_def = header->ClassDefs()[idx].get(); // Omitting non-public class. if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) { @@ -1290,7 +1308,7 @@ static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { } if (options_.show_cfg_) { - DumpCFG(&header->GetDexFile(), idx); + DumpCFG(dex_file, idx); return; } @@ -1368,10 +1386,12 @@ static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { } // Interfaces. - std::vector<dex_ir::TypeId*>* interfaces = class_def->Interfaces(); - for (uint32_t i = 0; i < interfaces->size(); i++) { - DumpInterface((*interfaces)[i], i); - } // for + dex_ir::TypeIdVector* interfaces = class_def->Interfaces(); + if (interfaces != nullptr) { + for (uint32_t i = 0; i < interfaces->size(); i++) { + DumpInterface((*interfaces)[i], i); + } // for + } // Fields and methods. dex_ir::ClassData* class_data = class_def->GetClassData(); @@ -1383,52 +1403,68 @@ static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { if (options_.output_format_ == kOutputPlain) { fprintf(out_file_, " Static fields -\n"); } - std::vector<std::unique_ptr<dex_ir::FieldItem>>& static_fields = class_data->StaticFields(); - for (uint32_t i = 0; i < static_fields.size(); i++) { - DumpSField(header, - static_fields[i]->GetFieldId()->GetOffset(), - static_fields[i]->GetAccessFlags(), - i, - i < static_values_size ? (*static_values)[i].get() : nullptr); - } // for + if (class_data != nullptr) { + dex_ir::FieldItemVector* static_fields = class_data->StaticFields(); + if (static_fields != nullptr) { + for (uint32_t i = 0; i < static_fields->size(); i++) { + DumpSField(header, + (*static_fields)[i]->GetFieldId()->GetOffset(), + (*static_fields)[i]->GetAccessFlags(), + i, + i < static_values_size ? (*static_values)[i].get() : nullptr); + } // for + } + } // Instance fields. if (options_.output_format_ == kOutputPlain) { fprintf(out_file_, " Instance fields -\n"); } - std::vector<std::unique_ptr<dex_ir::FieldItem>>& instance_fields = class_data->InstanceFields(); - for (uint32_t i = 0; i < instance_fields.size(); i++) { - DumpIField(header, - instance_fields[i]->GetFieldId()->GetOffset(), - instance_fields[i]->GetAccessFlags(), - i); - } // for + if (class_data != nullptr) { + dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields(); + if (instance_fields != nullptr) { + for (uint32_t i = 0; i < instance_fields->size(); i++) { + DumpIField(header, + (*instance_fields)[i]->GetFieldId()->GetOffset(), + (*instance_fields)[i]->GetAccessFlags(), + i); + } // for + } + } // Direct methods. if (options_.output_format_ == kOutputPlain) { fprintf(out_file_, " Direct methods -\n"); } - std::vector<std::unique_ptr<dex_ir::MethodItem>>& direct_methods = class_data->DirectMethods(); - for (uint32_t i = 0; i < direct_methods.size(); i++) { - DumpMethod(header, - direct_methods[i]->GetMethodId()->GetOffset(), - direct_methods[i]->GetAccessFlags(), - direct_methods[i]->GetCodeItem(), - i); - } // for + if (class_data != nullptr) { + dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods(); + if (direct_methods != nullptr) { + for (uint32_t i = 0; i < direct_methods->size(); i++) { + DumpMethod(header, + (*direct_methods)[i]->GetMethodId()->GetOffset(), + (*direct_methods)[i]->GetAccessFlags(), + (*direct_methods)[i]->GetCodeItem(), + i); + } // for + } + } // Virtual methods. if (options_.output_format_ == kOutputPlain) { fprintf(out_file_, " Virtual methods -\n"); } - std::vector<std::unique_ptr<dex_ir::MethodItem>>& virtual_methods = class_data->VirtualMethods(); - for (uint32_t i = 0; i < virtual_methods.size(); i++) { - DumpMethod(header, - virtual_methods[i]->GetMethodId()->GetOffset(), - virtual_methods[i]->GetAccessFlags(), - virtual_methods[i]->GetCodeItem(), - i); - } // for + if (class_data != nullptr) { + dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods(); + if (virtual_methods != nullptr) { + for (uint32_t i = 0; i < virtual_methods->size(); i++) { + DumpMethod(header, + (*virtual_methods)[i]->GetMethodId()->GetOffset(), + (*virtual_methods)[i]->GetAccessFlags(), + (*virtual_methods)[i]->GetCodeItem(), + i); + } // for + } + } // End of class. if (options_.output_format_ == kOutputPlain) { @@ -1454,11 +1490,11 @@ static void ProcessDexFile(const char* file_name, const DexFile* dex_file) { fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n", file_name, dex_file->GetHeader().magic_ + 4); } - dex_ir::Header header(*dex_file); + std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file)); // Headers. if (options_.show_file_headers_) { - DumpFileHeader(&header); + DumpFileHeader(header.get()); } // Open XML context. @@ -1468,9 +1504,9 @@ static void ProcessDexFile(const char* file_name, const DexFile* dex_file) { // Iterate over all classes. char* package = nullptr; - const uint32_t class_defs_size = header.ClassDefsSize(); + const uint32_t class_defs_size = header->ClassDefsSize(); for (uint32_t i = 0; i < class_defs_size; i++) { - DumpClass(&header, i, &package); + DumpClass(dex_file, header.get(), i, &package); } // for // Free the last package allocated. diff --git a/tools/bisection-search/README.md b/tools/bisection-search/README.md index 857c93075e..a7485c2bb5 100644 --- a/tools/bisection-search/README.md +++ b/tools/bisection-search/README.md @@ -15,29 +15,29 @@ incorrect output. Prints Mi and Pj. How to run Bisection Bug Search =============================== - bisection_search.py [-h] -cp CLASSPATH - [--expected-output EXPECTED_OUTPUT] [--device] - [--lib LIB] [--64] - [--dalvikvm-option [OPTION [OPTION ...]]] - [--arg [TEST_ARGS [TEST_ARGS ...]]] [--image IMAGE] - [--verbose] - classname + bisection_search.py [-h] [-cp CLASSPATH] [--class CLASSNAME] [--lib LIB] + [--dalvikvm-option [OPT [OPT ...]]] [--arg [ARG [ARG ...]]] + [--image IMAGE] [--raw-cmd RAW_CMD] + [--64] [--device] [--expected-output EXPECTED_OUTPUT] + [--check-script CHECK_SCRIPT] [--verbose] - positional arguments: - classname name of class to run + Tool for finding compiler bugs. Either --raw-cmd or both -cp and --class are required. optional arguments: - -h, --help show this help message and exit - -cp CLASSPATH, --classpath CLASSPATH - classpath - --expected-output EXPECTED_OUTPUT - file containing expected output - --device run on device - --lib LIB lib to use, default: libart.so - --64 x64 mode - --dalvikvm-option [OPTION [OPTION ...]] - additional dalvikvm option - --arg [TEST_ARGS [TEST_ARGS ...]] - argument to pass to program - --image IMAGE path to image - --verbose enable verbose output + -h, --help show this help message and exit + + dalvikvm command options: + -cp CLASSPATH, --classpath CLASSPATH classpath + --class CLASSNAME name of main class + --lib LIB lib to use, default: libart.so + --dalvikvm-option [OPT [OPT ...]] additional dalvikvm option + --arg [ARG [ARG ...]] argument passed to test + --image IMAGE path to image + --raw-cmd RAW_CMD bisect with this command, ignore other command options + + bisection options: + --64 x64 mode + --device run on device + --expected-output EXPECTED_OUTPUT file containing expected output + --check-script CHECK_SCRIPT script comparing output and expected output + --verbose enable verbose output diff --git a/tools/bisection-search/bisection_search.py b/tools/bisection-search/bisection_search.py index d6c1749b60..110ef82433 100755 --- a/tools/bisection-search/bisection_search.py +++ b/tools/bisection-search/bisection_search.py @@ -22,15 +22,20 @@ Example usage: ./bisection-search.py -cp classes.dex --expected-output output Test """ +import abc import argparse import re +import shlex +from subprocess import call import sys +from tempfile import NamedTemporaryFile from common import DeviceTestEnv from common import FatalError from common import GetEnvVariableOrError from common import HostTestEnv + # Passes that are never disabled during search process because disabling them # would compromise correctness. MANDATORY_PASSES = ['dex_cache_array_fixups_arm', @@ -53,23 +58,18 @@ class Dex2OatWrapperTestable(object): Accepts filters on compiled methods and optimization passes. """ - def __init__(self, base_cmd, test_env, class_name, args, - expected_output=None, verbose=False): + def __init__(self, base_cmd, test_env, output_checker=None, verbose=False): """Constructor. Args: base_cmd: list of strings, base command to run. test_env: ITestEnv. - class_name: string, name of class to run. - args: list of strings, program arguments to pass. - expected_output: string, expected output to compare against or None. + output_checker: IOutputCheck, output checker. verbose: bool, enable verbose output. """ self._base_cmd = base_cmd self._test_env = test_env - self._class_name = class_name - self._args = args - self._expected_output = expected_output + self._output_checker = output_checker self._compiled_methods_path = self._test_env.CreateFile('compiled_methods') self._passes_to_run_path = self._test_env.CreateFile('run_passes') self._verbose = verbose @@ -88,14 +88,15 @@ class Dex2OatWrapperTestable(object): True if test passes with given settings. False otherwise. """ if self._verbose: - print('Testing methods: {0} passes:{1}.'.format( + print('Testing methods: {0} passes: {1}.'.format( compiled_methods, passes_to_run)) cmd = self._PrepareCmd(compiled_methods=compiled_methods, passes_to_run=passes_to_run, - verbose_compiler=True) - (output, _, ret_code) = self._test_env.RunCommand(cmd) - res = ret_code == 0 and (self._expected_output is None - or output == self._expected_output) + verbose_compiler=False) + (output, ret_code) = self._test_env.RunCommand( + cmd, {'ANDROID_LOG_TAGS': '*:e'}) + res = ((self._output_checker is None and ret_code == 0) + or self._output_checker.Check(output)) if self._verbose: print('Test passed: {0}.'.format(res)) return res @@ -110,8 +111,8 @@ class Dex2OatWrapperTestable(object): FatalError: An error occurred when retrieving methods list. """ cmd = self._PrepareCmd(verbose_compiler=True) - (_, err_output, _) = self._test_env.RunCommand(cmd) - match_methods = re.findall(r'Building ([^\n]+)\n', err_output) + (output, _) = self._test_env.RunCommand(cmd, {'ANDROID_LOG_TAGS': '*:i'}) + match_methods = re.findall(r'Building ([^\n]+)\n', output) if not match_methods: raise FatalError('Failed to retrieve methods list. ' 'Not recognized output format.') @@ -131,8 +132,8 @@ class Dex2OatWrapperTestable(object): """ cmd = self._PrepareCmd(compiled_methods=[compiled_method], verbose_compiler=True) - (_, err_output, _) = self._test_env.RunCommand(cmd) - match_passes = re.findall(r'Starting pass: ([^\n]+)\n', err_output) + (output, _) = self._test_env.RunCommand(cmd, {'ANDROID_LOG_TAGS': '*:i'}) + match_passes = re.findall(r'Starting pass: ([^\n]+)\n', output) if not match_passes: raise FatalError('Failed to retrieve passes list. ' 'Not recognized output format.') @@ -141,7 +142,8 @@ class Dex2OatWrapperTestable(object): def _PrepareCmd(self, compiled_methods=None, passes_to_run=None, verbose_compiler=False): """Prepare command to run.""" - cmd = list(self._base_cmd) + cmd = [self._base_cmd[0]] + # insert additional arguments if compiled_methods is not None: self._test_env.WriteLines(self._compiled_methods_path, compiled_methods) cmd += ['-Xcompiler-option', '--compiled-methods={0}'.format( @@ -152,12 +154,78 @@ class Dex2OatWrapperTestable(object): self._passes_to_run_path)] if verbose_compiler: cmd += ['-Xcompiler-option', '--runtime-arg', '-Xcompiler-option', - '-verbose:compiler'] - cmd += ['-classpath', self._test_env.classpath, self._class_name] - cmd += self._args + '-verbose:compiler', '-Xcompiler-option', '-j1'] + cmd += self._base_cmd[1:] return cmd +class IOutputCheck(object): + """Abstract output checking class. + + Checks if output is correct. + """ + __meta_class__ = abc.ABCMeta + + @abc.abstractmethod + def Check(self, output): + """Check if output is correct. + + Args: + output: string, output to check. + + Returns: + boolean, True if output is correct, False otherwise. + """ + + +class EqualsOutputCheck(IOutputCheck): + """Concrete output checking class checking for equality to expected output.""" + + def __init__(self, expected_output): + """Constructor. + + Args: + expected_output: string, expected output. + """ + self._expected_output = expected_output + + def Check(self, output): + """See base class.""" + return self._expected_output == output + + +class ExternalScriptOutputCheck(IOutputCheck): + """Concrete output checking class calling an external script. + + The script should accept two arguments, path to expected output and path to + program output. It should exit with 0 return code if outputs are equivalent + and with different return code otherwise. + """ + + def __init__(self, script_path, expected_output_path, logfile): + """Constructor. + + Args: + script_path: string, path to checking script. + expected_output_path: string, path to file with expected output. + logfile: file handle, logfile. + """ + self._script_path = script_path + self._expected_output_path = expected_output_path + self._logfile = logfile + + def Check(self, output): + """See base class.""" + ret_code = None + with NamedTemporaryFile(mode='w', delete=False) as temp_file: + temp_file.write(output) + temp_file.flush() + ret_code = call( + [self._script_path, self._expected_output_path, temp_file.name], + stdout=self._logfile, stderr=self._logfile, universal_newlines=True) + return ret_code == 0 + + def BinarySearch(start, end, test): """Binary search integers using test function to guide the process.""" while start < end: @@ -200,9 +268,9 @@ def BugSearch(testable): all_methods = testable.GetAllMethods() faulty_method_idx = BinarySearch( 0, - len(all_methods), + len(all_methods) + 1, lambda mid: testable.Test(all_methods[0:mid])) - if faulty_method_idx == len(all_methods): + if faulty_method_idx == len(all_methods) + 1: return (None, None) if faulty_method_idx == 0: raise FatalError('Testable fails with no methods compiled. ' @@ -211,72 +279,100 @@ def BugSearch(testable): all_passes = testable.GetAllPassesForMethod(faulty_method) faulty_pass_idx = BinarySearch( 0, - len(all_passes), + len(all_passes) + 1, lambda mid: testable.Test([faulty_method], FilterPasses(all_passes, mid))) if faulty_pass_idx == 0: return (faulty_method, None) - assert faulty_pass_idx != len(all_passes), 'Method must fail for some passes.' + assert faulty_pass_idx != len(all_passes) + 1, ('Method must fail for some ' + 'passes.') faulty_pass = all_passes[faulty_pass_idx - 1] return (faulty_method, faulty_pass) def PrepareParser(): """Prepares argument parser.""" - parser = argparse.ArgumentParser() - parser.add_argument( - '-cp', '--classpath', required=True, type=str, help='classpath') - parser.add_argument('--expected-output', type=str, - help='file containing expected output') - parser.add_argument( + parser = argparse.ArgumentParser( + description='Tool for finding compiler bugs. Either --raw-cmd or both ' + '-cp and --class are required.') + command_opts = parser.add_argument_group('dalvikvm command options') + command_opts.add_argument('-cp', '--classpath', type=str, help='classpath') + command_opts.add_argument('--class', dest='classname', type=str, + help='name of main class') + command_opts.add_argument('--lib', dest='lib', type=str, default='libart.so', + help='lib to use, default: libart.so') + command_opts.add_argument('--dalvikvm-option', dest='dalvikvm_opts', + metavar='OPT', nargs='*', default=[], + help='additional dalvikvm option') + command_opts.add_argument('--arg', dest='test_args', nargs='*', default=[], + metavar='ARG', help='argument passed to test') + command_opts.add_argument('--image', type=str, help='path to image') + command_opts.add_argument('--raw-cmd', dest='raw_cmd', type=str, + help='bisect with this command, ignore other ' + 'command options') + bisection_opts = parser.add_argument_group('bisection options') + bisection_opts.add_argument('--64', dest='x64', action='store_true', + default=False, help='x64 mode') + bisection_opts.add_argument( '--device', action='store_true', default=False, help='run on device') - parser.add_argument('classname', type=str, help='name of class to run') - parser.add_argument('--lib', dest='lib', type=str, default='libart.so', - help='lib to use, default: libart.so') - parser.add_argument('--64', dest='x64', action='store_true', - default=False, help='x64 mode') - parser.add_argument('--dalvikvm-option', dest='dalvikvm_opts', - metavar='OPTION', nargs='*', default=[], - help='additional dalvikvm option') - parser.add_argument('--arg', dest='test_args', nargs='*', default=[], - help='argument to pass to program') - parser.add_argument('--image', type=str, help='path to image') - parser.add_argument('--verbose', action='store_true', - default=False, help='enable verbose output') + bisection_opts.add_argument('--expected-output', type=str, + help='file containing expected output') + bisection_opts.add_argument( + '--check-script', dest='check_script', type=str, + help='script comparing output and expected output') + bisection_opts.add_argument('--verbose', action='store_true', + default=False, help='enable verbose output') return parser +def PrepareBaseCommand(args, classpath): + """Prepares base command used to run test.""" + if args.raw_cmd: + return shlex.split(args.raw_cmd) + else: + base_cmd = ['dalvikvm64'] if args.x64 else ['dalvikvm32'] + if not args.device: + base_cmd += ['-XXlib:{0}'.format(args.lib)] + if not args.image: + image_path = '{0}/framework/core-optimizing-pic.art'.format( + GetEnvVariableOrError('ANDROID_HOST_OUT')) + else: + image_path = args.image + base_cmd += ['-Ximage:{0}'.format(image_path)] + if args.dalvikvm_opts: + base_cmd += args.dalvikvm_opts + base_cmd += ['-cp', classpath, args.classname] + args.test_args + return base_cmd + + def main(): # Parse arguments parser = PrepareParser() args = parser.parse_args() + if not args.raw_cmd and (not args.classpath or not args.classname): + parser.error('Either --raw-cmd or both -cp and --class are required') # Prepare environment - if args.expected_output is not None: - with open(args.expected_output, 'r') as f: - expected_output = f.read() - else: - expected_output = None + classpath = args.classpath if args.device: - run_cmd = ['dalvikvm64'] if args.x64 else ['dalvikvm32'] - test_env = DeviceTestEnv(args.classpath) + test_env = DeviceTestEnv() + if classpath: + classpath = test_env.PushClasspath(classpath) else: - run_cmd = ['dalvikvm64'] if args.x64 else ['dalvikvm32'] - run_cmd += ['-XXlib:{0}'.format(args.lib)] - if not args.image: - image_path = '{0}/framework/core-optimizing-pic.art'.format( - GetEnvVariableOrError('ANDROID_HOST_OUT')) + test_env = HostTestEnv(args.x64) + base_cmd = PrepareBaseCommand(args, classpath) + output_checker = None + if args.expected_output: + if args.check_script: + output_checker = ExternalScriptOutputCheck( + args.check_script, args.expected_output, test_env.logfile) else: - image_path = args.image - run_cmd += ['-Ximage:{0}'.format(image_path)] - if args.dalvikvm_opts: - run_cmd += args.dalvikvm_opts - test_env = HostTestEnv(args.classpath, args.x64) + with open(args.expected_output, 'r') as expected_output_file: + output_checker = EqualsOutputCheck(expected_output_file.read()) # Perform the search try: - testable = Dex2OatWrapperTestable(run_cmd, test_env, args.classname, - args.test_args, expected_output, + testable = Dex2OatWrapperTestable(base_cmd, test_env, output_checker, args.verbose) (method, opt_pass) = BugSearch(testable) except Exception as e: diff --git a/tools/bisection-search/common.py b/tools/bisection-search/common.py index 8361fc9e94..d5029bb970 100755 --- a/tools/bisection-search/common.py +++ b/tools/bisection-search/common.py @@ -23,6 +23,7 @@ import shlex from subprocess import check_call from subprocess import PIPE from subprocess import Popen +from subprocess import STDOUT from subprocess import TimeoutExpired from tempfile import mkdtemp @@ -81,19 +82,20 @@ def _RunCommandForOutputAndLog(cmd, env, logfile, timeout=60): Returns: tuple (string, string, int) stdout output, stderr output, return code. """ - proc = Popen(cmd, stderr=PIPE, stdout=PIPE, env=env, universal_newlines=True) + proc = Popen(cmd, stderr=STDOUT, stdout=PIPE, env=env, + universal_newlines=True) timeouted = False try: - (output, err_output) = proc.communicate(timeout=timeout) + (output, _) = proc.communicate(timeout=timeout) except TimeoutExpired: timeouted = True proc.kill() - (output, err_output) = proc.communicate() - logfile.write('Command:\n{0}\n{1}{2}\nReturn code: {3}\n'.format( - _CommandListToCommandString(cmd), err_output, output, + (output, _) = proc.communicate() + logfile.write('Command:\n{0}\n{1}\nReturn code: {2}\n'.format( + _CommandListToCommandString(cmd), output, 'TIMEOUT' if timeouted else proc.returncode)) ret_code = 1 if timeouted else proc.returncode - return (output, err_output, ret_code) + return (output, ret_code) def _CommandListToCommandString(cmd): @@ -148,21 +150,18 @@ class ITestEnv(object): """ @abc.abstractmethod - def RunCommand(self, cmd): - """Runs command in environment. + def RunCommand(self, cmd, env_updates=None): + """Runs command in environment with updated environmental variables. Args: - cmd: string, command to run. - + cmd: list of strings, command to run. + env_updates: dict, string to string, maps names of variables to their + updated values. Returns: tuple (string, string, int) stdout output, stderr output, return code. """ @abc.abstractproperty - def classpath(self): - """Gets environment specific classpath with test class.""" - - @abc.abstractproperty def logfile(self): """Gets file handle to logfile residing on host.""" @@ -176,14 +175,12 @@ class HostTestEnv(ITestEnv): For methods documentation see base class. """ - def __init__(self, classpath, x64): + def __init__(self, x64): """Constructor. Args: - classpath: string, classpath with test class. x64: boolean, whether to setup in x64 mode. """ - self._classpath = classpath self._env_path = mkdtemp(dir='/tmp/', prefix='bisection_search_') self._logfile = open('{0}/log'.format(self._env_path), 'w+') os.mkdir('{0}/dalvik-cache'.format(self._env_path)) @@ -197,6 +194,7 @@ class HostTestEnv(ITestEnv): self._shell_env['ANDROID_DATA'] = self._env_path self._shell_env['ANDROID_ROOT'] = android_root self._shell_env['LD_LIBRARY_PATH'] = library_path + self._shell_env['DYLD_LIBRARY_PATH'] = library_path self._shell_env['PATH'] = (path + ':' + self._shell_env['PATH']) # Using dlopen requires load bias on the host. self._shell_env['LD_USE_LOAD_BIAS'] = '1' @@ -213,13 +211,13 @@ class HostTestEnv(ITestEnv): f.writelines('{0}\n'.format(line) for line in lines) return - def RunCommand(self, cmd): + def RunCommand(self, cmd, env_updates=None): + if not env_updates: + env_updates = {} self._EmptyDexCache() - return _RunCommandForOutputAndLog(cmd, self._shell_env, self._logfile) - - @property - def classpath(self): - return self._classpath + env = self._shell_env.copy() + env.update(env_updates) + return _RunCommandForOutputAndLog(cmd, env, self._logfile) @property def logfile(self): @@ -247,32 +245,18 @@ class DeviceTestEnv(ITestEnv): For methods documentation see base class. """ - def __init__(self, classpath): - """Constructor. - - Args: - classpath: string, classpath with test class. - """ + def __init__(self): + """Constructor.""" self._host_env_path = mkdtemp(dir='/tmp/', prefix='bisection_search_') self._logfile = open('{0}/log'.format(self._host_env_path), 'w+') self._device_env_path = '{0}/{1}'.format( DEVICE_TMP_PATH, os.path.basename(self._host_env_path)) - self._classpath = os.path.join( - self._device_env_path, os.path.basename(classpath)) - self._shell_env = os.environ + self._shell_env = os.environ.copy() self._AdbMkdir('{0}/dalvik-cache'.format(self._device_env_path)) for arch_cache_path in _DexArchCachePaths(self._device_env_path): self._AdbMkdir(arch_cache_path) - paths = classpath.split(':') - device_paths = [] - for path in paths: - device_paths.append('{0}/{1}'.format( - self._device_env_path, os.path.basename(path))) - self._AdbPush(path, self._device_env_path) - self._classpath = ':'.join(device_paths) - def CreateFile(self, name=None): with NamedTemporaryFile(mode='w') as temp_file: self._AdbPush(temp_file.name, self._device_env_path) @@ -283,25 +267,47 @@ class DeviceTestEnv(ITestEnv): def WriteLines(self, file_path, lines): with NamedTemporaryFile(mode='w') as temp_file: temp_file.writelines('{0}\n'.format(line) for line in lines) + temp_file.flush() self._AdbPush(temp_file.name, file_path) return - def RunCommand(self, cmd): + def RunCommand(self, cmd, env_updates=None): + if not env_updates: + env_updates = {} self._EmptyDexCache() + if 'ANDROID_DATA' not in env_updates: + env_updates['ANDROID_DATA'] = self._device_env_path + env_updates_cmd = ' '.join(['{0}={1}'.format(var, val) for var, val + in env_updates.items()]) cmd = _CommandListToCommandString(cmd) - cmd = ('adb shell "logcat -c && ANDROID_DATA={0} {1} && ' - 'logcat -d dex2oat:* *:S 1>&2"').format(self._device_env_path, cmd) - return _RunCommandForOutputAndLog(shlex.split(cmd), self._shell_env, - self._logfile) - - @property - def classpath(self): - return self._classpath + cmd = ('adb shell "logcat -c && {0} {1} ; logcat -d -s dex2oat:* dex2oatd:*' + '| grep -v "^---------" 1>&2"').format(env_updates_cmd, cmd) + return _RunCommandForOutputAndLog( + shlex.split(cmd), self._shell_env, self._logfile) @property def logfile(self): return self._logfile + def PushClasspath(self, classpath): + """Push classpath to on-device test directory. + + Classpath can contain multiple colon separated file paths, each file is + pushed. Returns analogous classpath with paths valid on device. + + Args: + classpath: string, classpath in format 'a/b/c:d/e/f'. + Returns: + string, classpath valid on device. + """ + paths = classpath.split(':') + device_paths = [] + for path in paths: + device_paths.append('{0}/{1}'.format( + self._device_env_path, os.path.basename(path))) + self._AdbPush(path, self._device_env_path) + return ':'.join(device_paths) + def _AdbPush(self, what, where): check_call(shlex.split('adb push "{0}" "{1}"'.format(what, where)), stdout=self._logfile, stderr=self._logfile) |