Merge "ARM64: Use macros for saving/restoring registers in assembly."
diff --git a/build/art.go b/build/art.go
index f305c07..d41b407 100644
--- a/build/art.go
+++ b/build/art.go
@@ -137,12 +137,42 @@
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 @@
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 2ef1802..5301a6b 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -247,35 +247,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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::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 ac10e23..ce9d7e6 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -271,11 +271,12 @@
//
// 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 ceceedd..36f7b4d 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -4044,17 +4044,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 78db803..f0d7910 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -294,7 +294,8 @@
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 8858def..4689ccb 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -5961,17 +5961,6 @@
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 @@
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 @@
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 @@
// /* 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 @@
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 @@
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 @@
__ 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::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 df65fa2..e225098 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -263,7 +263,8 @@
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 5230269..a21a09e 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -5408,17 +5408,6 @@
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 @@
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 @@
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 @@
// /* 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 @@
// /* 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 @@
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 @@
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::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 f23bff5..d939083 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -257,7 +257,8 @@
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 1e5f0b6..ce53134 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -452,7 +452,8 @@
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 32dcc28..d7e4c53 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -935,7 +935,8 @@
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 @@
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 @@
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 @@
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 @@
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 19e499b..149a71d 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -5461,7 +5461,8 @@
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 @@
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 @@
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 @@
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 @@
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 81163e2..8d4d143 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -176,6 +176,7 @@
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 @@
// 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 @@
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 3095866..de02580 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 0ed040e..0000000
--- 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 fcd3ab0..cbb4404 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 @@
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 @@
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 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 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 @@
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 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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 AnnotationItem {
+ public:
+ AnnotationItem(uint8_t visibility, ArrayItem* item) : visibility_(visibility), item_(item) { }
+
+ 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);
+};
+
+using AnnotationItemVector = std::vector<std::unique_ptr<AnnotationItem>>;
+
class AnnotationSetItem : public Item {
public:
- class AnnotationItem {
- public:
- AnnotationItem(uint8_t visibility, ArrayItem* item) :
- visibility_(visibility), item_(item) { }
-
- 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);
- };
-
- AnnotationSetItem(const DexFile::AnnotationSetItem& disk_annotations_item, Header& header);
+ 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);
};
+using AnnotationSetItemVector = std::vector<std::unique_ptr<AnnotationSetItem>>;
+
+class FieldAnnotation {
+ public:
+ 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(); }
+
+ private:
+ FieldId* field_id_;
+ std::unique_ptr<AnnotationSetItem> annotation_set_item_;
+ DISALLOW_COPY_AND_ASSIGN(FieldAnnotation);
+};
+
+using FieldAnnotationVector = std::vector<std::unique_ptr<FieldAnnotation>>;
+
+class MethodAnnotation {
+ public:
+ MethodAnnotation(MethodId* method_id, AnnotationSetItem* annotation_set_item)
+ : method_id_(method_id), annotation_set_item_(annotation_set_item) { }
+
+ MethodId* GetMethodId() const { return method_id_; }
+ AnnotationSetItem* GetAnnotationSetItem() const { return annotation_set_item_.get(); }
+
+ private:
+ MethodId* method_id_;
+ std::unique_ptr<AnnotationSetItem> annotation_set_item_;
+ DISALLOW_COPY_AND_ASSIGN(MethodAnnotation);
+};
+
+using MethodAnnotationVector = std::vector<std::unique_ptr<MethodAnnotation>>;
+
+class ParameterAnnotation {
+ public:
+ ParameterAnnotation(MethodId* method_id, AnnotationSetItemVector* annotations)
+ : method_id_(method_id), annotations_(annotations) { }
+
+ MethodId* GetMethodId() const { return method_id_; }
+ AnnotationSetItemVector* GetAnnotations() { return annotations_.get(); }
+
+ private:
+ MethodId* method_id_;
+ std::unique_ptr<AnnotationSetItemVector> annotations_;
+ DISALLOW_COPY_AND_ASSIGN(ParameterAnnotation);
+};
+
+using ParameterAnnotationVector = std::vector<std::unique_ptr<ParameterAnnotation>>;
+
class AnnotationsDirectoryItem : public Item {
public:
- class FieldAnnotation {
- public:
- 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(); }
-
- 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) { }
-
- MethodId* GetMethodId() const { return method_id_; }
- AnnotationSetItem* GetAnnotationSetItem() const { return annotation_set_item_.get(); }
-
- private:
- MethodId* method_id_;
- std::unique_ptr<AnnotationSetItem> annotation_set_item_;
- DISALLOW_COPY_AND_ASSIGN(MethodAnnotation);
- };
-
- 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::vector<std::unique_ptr<AnnotationSetItem>> annotations_;
- DISALLOW_COPY_AND_ASSIGN(ParameterAnnotation);
- };
-
- AnnotationsDirectoryItem(const DexFile::AnnotationsDirectoryItem* disk_annotations_item,
- Header& header);
+ 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(); }
-
- std::vector<std::unique_ptr<FieldAnnotation>>& GetFieldAnnotations() {
- return field_annotations_;
- }
-
- std::vector<std::unique_ptr<MethodAnnotation>>& GetMethodAnnotations() {
- return method_annotations_;
- }
-
- std::vector<std::unique_ptr<ParameterAnnotation>>& GetParameterAnnotations() {
- return parameter_annotations_;
- }
+ 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 0000000..30f57d9
--- /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 0000000..c53157b
--- /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 0b31614..3a3f417 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 @@
}
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 @@
* 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 @@
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 @@
}
// 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 @@
/*
* 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 @@
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 @@
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 @@
}
while (it.HasNextVirtualMethod()) {
DumpCFG(dex_file,
- it.GetMemberIndex(),
- it.GetMethodCodeItem());
+ it.GetMemberIndex(),
+ it.GetMethodCodeItem());
it.Next();
}
}
@@ -1274,7 +1289,10 @@
* 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 @@
}
if (options_.show_cfg_) {
- DumpCFG(&header->GetDexFile(), idx);
+ DumpCFG(dex_file, idx);
return;
}
@@ -1368,10 +1386,12 @@
}
// 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 @@
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 @@
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 @@
// 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 857c930..a7485c2 100644
--- a/tools/bisection-search/README.md
+++ b/tools/bisection-search/README.md
@@ -15,29 +15,29 @@
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 d6c1749..110ef82 100755
--- a/tools/bisection-search/bisection_search.py
+++ b/tools/bisection-search/bisection_search.py
@@ -22,15 +22,20 @@
./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 @@
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 @@
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 @@
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 @@
"""
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 @@
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 @@
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 @@
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 @@
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 8361fc9..d5029bb 100755
--- a/tools/bisection-search/common.py
+++ b/tools/bisection-search/common.py
@@ -23,6 +23,7 @@
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 @@
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 @@
"""
@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 @@
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 @@
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 @@
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 @@
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 @@
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)