Merge "ART: Implement support for instruction inlining"
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index 97fe587..e8912b3 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -807,7 +807,8 @@
}
static void CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator* arena,
- HInvoke* invoke) {
+ HInvoke* invoke,
+ Primitive::Type type) {
LocationSummary* locations = new (arena) LocationSummary(invoke,
LocationSummary::kNoCall,
kIntrinsified);
@@ -817,11 +818,15 @@
locations->SetInAt(3, Location::RequiresRegister());
locations->SetInAt(4, Location::RequiresRegister());
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ // If heap poisoning is enabled, we don't want the unpoisoning
+ // operations to potentially clobber the output.
+ Location::OutputOverlap overlaps = (kPoisonHeapReferences && type == Primitive::kPrimNot)
+ ? Location::kOutputOverlap
+ : Location::kNoOutputOverlap;
+ locations->SetOut(Location::RequiresRegister(), overlaps);
locations->AddTemp(Location::RequiresRegister()); // Pointer.
locations->AddTemp(Location::RequiresRegister()); // Temp 1.
- locations->AddTemp(Location::RequiresRegister()); // Temp 2.
}
static void GenCas(LocationSummary* locations, Primitive::Type type, CodeGeneratorARM* codegen) {
@@ -856,7 +861,12 @@
if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
codegen->GetAssembler()->PoisonHeapReference(expected_lo);
- codegen->GetAssembler()->PoisonHeapReference(value_lo);
+ if (value_lo == expected_lo) {
+ // Do not poison `value_lo`, as it is the same register as
+ // `expected_lo`, which has just been poisoned.
+ } else {
+ codegen->GetAssembler()->PoisonHeapReference(value_lo);
+ }
}
// do {
@@ -892,13 +902,18 @@
__ mov(out, ShifterOperand(0), CC);
if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
- codegen->GetAssembler()->UnpoisonHeapReference(value_lo);
codegen->GetAssembler()->UnpoisonHeapReference(expected_lo);
+ if (value_lo == expected_lo) {
+ // Do not unpoison `value_lo`, as it is the same register as
+ // `expected_lo`, which has just been unpoisoned.
+ } else {
+ codegen->GetAssembler()->UnpoisonHeapReference(value_lo);
+ }
}
}
void IntrinsicLocationsBuilderARM::VisitUnsafeCASInt(HInvoke* invoke) {
- CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke);
+ CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke, Primitive::kPrimInt);
}
void IntrinsicLocationsBuilderARM::VisitUnsafeCASObject(HInvoke* invoke) {
// The UnsafeCASObject intrinsic is missing a read barrier, and
@@ -906,16 +921,12 @@
// Turn it off temporarily as a quick fix, until the read barrier is
// implemented (see TODO in GenCAS below).
//
- // Also, the UnsafeCASObject intrinsic does not always work when heap
- // poisoning is enabled (it breaks run-test 004-UnsafeTest); turn it
- // off temporarily as a quick fix (b/26204023).
- //
- // TODO(rpl): Fix these two issues and re-enable this intrinsic.
- if (kEmitCompilerReadBarrier || kPoisonHeapReferences) {
+ // TODO(rpl): Fix this issue and re-enable this intrinsic with read barriers.
+ if (kEmitCompilerReadBarrier) {
return;
}
- CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke);
+ CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke, Primitive::kPrimNot);
}
void IntrinsicCodeGeneratorARM::VisitUnsafeCASInt(HInvoke* invoke) {
GenCas(invoke->GetLocations(), Primitive::kPrimInt, codegen_);
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index c888f01..d5ed585 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -986,7 +986,9 @@
codegen_);
}
-static void CreateIntIntIntIntIntToInt(ArenaAllocator* arena, HInvoke* invoke) {
+static void CreateIntIntIntIntIntToInt(ArenaAllocator* arena,
+ HInvoke* invoke,
+ Primitive::Type type) {
LocationSummary* locations = new (arena) LocationSummary(invoke,
LocationSummary::kNoCall,
kIntrinsified);
@@ -996,7 +998,12 @@
locations->SetInAt(3, Location::RequiresRegister());
locations->SetInAt(4, Location::RequiresRegister());
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+ // If heap poisoning is enabled, we don't want the unpoisoning
+ // operations to potentially clobber the output.
+ Location::OutputOverlap overlaps = (kPoisonHeapReferences && type == Primitive::kPrimNot)
+ ? Location::kOutputOverlap
+ : Location::kNoOutputOverlap;
+ locations->SetOut(Location::RequiresRegister(), overlaps);
}
static void GenCas(LocationSummary* locations, Primitive::Type type, CodeGeneratorARM64* codegen) {
@@ -1027,7 +1034,12 @@
if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
codegen->GetAssembler()->PoisonHeapReference(expected);
- codegen->GetAssembler()->PoisonHeapReference(value);
+ if (value.Is(expected)) {
+ // Do not poison `value`, as it is the same register as
+ // `expected`, which has just been poisoned.
+ } else {
+ codegen->GetAssembler()->PoisonHeapReference(value);
+ }
}
// do {
@@ -1077,16 +1089,21 @@
__ Cset(out, eq);
if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
- codegen->GetAssembler()->UnpoisonHeapReference(value);
codegen->GetAssembler()->UnpoisonHeapReference(expected);
+ if (value.Is(expected)) {
+ // Do not unpoison `value`, as it is the same register as
+ // `expected`, which has just been unpoisoned.
+ } else {
+ codegen->GetAssembler()->UnpoisonHeapReference(value);
+ }
}
}
void IntrinsicLocationsBuilderARM64::VisitUnsafeCASInt(HInvoke* invoke) {
- CreateIntIntIntIntIntToInt(arena_, invoke);
+ CreateIntIntIntIntIntToInt(arena_, invoke, Primitive::kPrimInt);
}
void IntrinsicLocationsBuilderARM64::VisitUnsafeCASLong(HInvoke* invoke) {
- CreateIntIntIntIntIntToInt(arena_, invoke);
+ CreateIntIntIntIntIntToInt(arena_, invoke, Primitive::kPrimLong);
}
void IntrinsicLocationsBuilderARM64::VisitUnsafeCASObject(HInvoke* invoke) {
// The UnsafeCASObject intrinsic is missing a read barrier, and
@@ -1094,16 +1111,12 @@
// Turn it off temporarily as a quick fix, until the read barrier is
// implemented (see TODO in GenCAS below).
//
- // Also, the UnsafeCASObject intrinsic does not always work when heap
- // poisoning is enabled (it breaks run-test 004-UnsafeTest); turn it
- // off temporarily as a quick fix (b/26204023).
- //
- // TODO(rpl): Fix these two issues and re-enable this intrinsic.
- if (kEmitCompilerReadBarrier || kPoisonHeapReferences) {
+ // TODO(rpl): Fix this issue and re-enable this intrinsic with read barriers.
+ if (kEmitCompilerReadBarrier) {
return;
}
- CreateIntIntIntIntIntToInt(arena_, invoke);
+ CreateIntIntIntIntIntToInt(arena_, invoke, Primitive::kPrimNot);
}
void IntrinsicCodeGeneratorARM64::VisitUnsafeCASInt(HInvoke* invoke) {
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index a1f6eee..5d06919 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -153,6 +153,7 @@
strtab->Start();
strtab->Write(""); // strtab should start with empty string.
+ AddTrampolineSymbols();
Walk(&art::OatSymbolizer::AddSymbol);
strtab->End();
@@ -165,6 +166,33 @@
return builder_->Good();
}
+ void AddTrampolineSymbol(const char* name, uint32_t code_offset) {
+ if (code_offset != 0) {
+ uint32_t name_offset = builder_->GetStrTab()->Write(name);
+ uint64_t symbol_value = code_offset - oat_file_->GetOatHeader().GetExecutableOffset();
+ builder_->GetSymTab()->Add(name_offset, builder_->GetText(), symbol_value,
+ /* is_relative */ true, /* size */ 0, STB_GLOBAL, STT_FUNC);
+ }
+ }
+
+ void AddTrampolineSymbols() {
+ const OatHeader& oat_header = oat_file_->GetOatHeader();
+ AddTrampolineSymbol("interpreterToInterpreterBridge",
+ oat_header.GetInterpreterToInterpreterBridgeOffset());
+ AddTrampolineSymbol("interpreterToCompiledCodeBridge",
+ oat_header.GetInterpreterToCompiledCodeBridgeOffset());
+ AddTrampolineSymbol("jniDlsymLookup",
+ oat_header.GetJniDlsymLookupOffset());
+ AddTrampolineSymbol("quickGenericJniTrampoline",
+ oat_header.GetQuickGenericJniTrampolineOffset());
+ AddTrampolineSymbol("quickImtConflictTrampoline",
+ oat_header.GetQuickImtConflictTrampolineOffset());
+ AddTrampolineSymbol("quickResolutionTrampoline",
+ oat_header.GetQuickResolutionTrampolineOffset());
+ AddTrampolineSymbol("quickToInterpreterBridge",
+ oat_header.GetQuickToInterpreterBridgeOffset());
+ }
+
void Walk(Callback callback) {
std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file_->GetOatDexFiles();
for (size_t i = 0; i < oat_dex_files.size(); i++) {
diff --git a/test/004-UnsafeTest/src/Main.java b/test/004-UnsafeTest/src/Main.java
index 5b22e88..a9a7a05 100644
--- a/test/004-UnsafeTest/src/Main.java
+++ b/test/004-UnsafeTest/src/Main.java
@@ -110,23 +110,35 @@
check(unsafe.getObject(t, objectOffset), objectValue, "Unsafe.getObject(Object, long)");
if (unsafe.compareAndSwapInt(t, intOffset, 0, 1)) {
- System.out.println("Unexpectedly succeeding compareAndSwap...");
+ System.out.println("Unexpectedly succeeding compareAndSwapInt(t, intOffset, 0, 1)");
}
if (!unsafe.compareAndSwapInt(t, intOffset, intValue, 0)) {
- System.out.println("Unexpectedly not succeeding compareAndSwap...");
+ System.out.println(
+ "Unexpectedly not succeeding compareAndSwapInt(t, intOffset, intValue, 0)");
}
if (!unsafe.compareAndSwapInt(t, intOffset, 0, 1)) {
- System.out.println("Unexpectedly not succeeding compareAndSwap...");
+ System.out.println("Unexpectedly not succeeding compareAndSwapInt(t, intOffset, 0, 1)");
+ }
+ // Exercise sun.misc.Unsafe.compareAndSwapInt using the same
+ // integer (1) for the `expectedValue` and `newValue` arguments.
+ if (!unsafe.compareAndSwapInt(t, intOffset, 1, 1)) {
+ System.out.println("Unexpectedly not succeeding compareAndSwapInt(t, intOffset, 1, 1)");
}
if (unsafe.compareAndSwapLong(t, longOffset, 0, 1)) {
- System.out.println("Unexpectedly succeeding compareAndSwapLong...");
+ System.out.println("Unexpectedly succeeding compareAndSwapLong(t, longOffset, 0, 1)");
}
if (!unsafe.compareAndSwapLong(t, longOffset, longValue, 0)) {
- System.out.println("Unexpectedly not succeeding compareAndSwapLong...");
+ System.out.println(
+ "Unexpectedly not succeeding compareAndSwapLong(t, longOffset, longValue, 0)");
}
if (!unsafe.compareAndSwapLong(t, longOffset, 0, 1)) {
- System.out.println("Unexpectedly not succeeding compareAndSwapLong...");
+ System.out.println("Unexpectedly not succeeding compareAndSwapLong(t, longOffset, 0, 1)");
+ }
+ // Exercise sun.misc.Unsafe.compareAndSwapLong using the same
+ // integer (1) for the `expectedValue` and `newValue` arguments.
+ if (!unsafe.compareAndSwapLong(t, longOffset, 1, 1)) {
+ System.out.println("Unexpectedly not succeeding compareAndSwapLong(t, longOffset, 1, 1)");
}
// We do not use `null` as argument to sun.misc.Unsafe.compareAndSwapObject
@@ -135,31 +147,41 @@
// references). This way, when heap poisoning is enabled, we can
// better exercise its implementation within that method.
if (unsafe.compareAndSwapObject(t, objectOffset, new Object(), new Object())) {
- System.out.println("Unexpectedly succeeding compareAndSwapObject...");
+ System.out.println("Unexpectedly succeeding " +
+ "compareAndSwapObject(t, objectOffset, new Object(), new Object())");
}
Object objectValue2 = new Object();
if (!unsafe.compareAndSwapObject(t, objectOffset, objectValue, objectValue2)) {
- System.out.println("Unexpectedly not succeeding compareAndSwapObject...");
+ System.out.println("Unexpectedly not succeeding " +
+ "compareAndSwapObject(t, objectOffset, objectValue, objectValue2)");
}
Object objectValue3 = new Object();
if (!unsafe.compareAndSwapObject(t, objectOffset, objectValue2, objectValue3)) {
- System.out.println("Unexpectedly not succeeding compareAndSwapObject...");
+ System.out.println("Unexpectedly not succeeding " +
+ "compareAndSwapObject(t, objectOffset, objectValue2, objectValue3)");
}
-
+ // Exercise sun.misc.Unsafe.compareAndSwapObject using the same
+ // object (`objectValue3`) for the `expectedValue` and `newValue` arguments.
+ if (!unsafe.compareAndSwapObject(t, objectOffset, objectValue3, objectValue3)) {
+ System.out.println("Unexpectedly not succeeding " +
+ "compareAndSwapObject(t, objectOffset, objectValue3, objectValue3)");
+ }
// Exercise sun.misc.Unsafe.compareAndSwapObject using the same
// object (`t`) for the `obj` and `newValue` arguments.
if (!unsafe.compareAndSwapObject(t, objectOffset, objectValue3, t)) {
- System.out.println("Unexpectedly not succeeding compareAndSwapObject...");
+ System.out.println(
+ "Unexpectedly not succeeding compareAndSwapObject(t, objectOffset, objectValue3, t)");
}
// Exercise sun.misc.Unsafe.compareAndSwapObject using the same
// object (`t`) for the `obj`, `expectedValue` and `newValue` arguments.
if (!unsafe.compareAndSwapObject(t, objectOffset, t, t)) {
- System.out.println("Unexpectedly not succeeding compareAndSwapObject...");
+ System.out.println("Unexpectedly not succeeding compareAndSwapObject(t, objectOffset, t, t)");
}
// Exercise sun.misc.Unsafe.compareAndSwapObject using the same
// object (`t`) for the `obj` and `expectedValue` arguments.
if (!unsafe.compareAndSwapObject(t, objectOffset, t, new Object())) {
- System.out.println("Unexpectedly not succeeding compareAndSwapObject...");
+ System.out.println(
+ "Unexpectedly not succeeding compareAndSwapObject(t, objectOffset, t, new Object())");
}
}