summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/Android.cpplint.mk4
-rw-r--r--compiler/driver/compiler_driver.cc4
-rw-r--r--compiler/driver/compiler_driver_test.cc34
-rw-r--r--compiler/image_writer.cc4
-rw-r--r--compiler/optimizing/bounds_check_elimination.cc60
-rw-r--r--compiler/optimizing/bounds_check_elimination_test.cc148
-rw-r--r--compiler/optimizing/code_generator_vector_arm64.cc2
-rw-r--r--compiler/optimizing/code_generator_vector_x86.cc2
-rw-r--r--compiler/optimizing/code_generator_vector_x86_64.cc2
-rw-r--r--compiler/optimizing/intrinsics_mips.cc1
-rw-r--r--compiler/optimizing/intrinsics_mips64.cc1
-rw-r--r--compiler/optimizing/load_store_analysis.h21
-rw-r--r--compiler/optimizing/loop_optimization_test.cc40
-rw-r--r--compiler/optimizing/nodes.cc42
-rw-r--r--compiler/optimizing/nodes.h1
-rw-r--r--compiler/optimizing/scheduler_arm.cc1
-rw-r--r--compiler/optimizing/scheduler_arm64.cc1
-rw-r--r--dex2oat/dex2oat.cc39
-rw-r--r--oatdump/oatdump.cc2
-rw-r--r--runtime/arch/arch_test.cc64
-rw-r--r--runtime/arch/arm/asm_support_arm.h2
-rw-r--r--runtime/arch/arm/quick_entrypoints_arm.S22
-rw-r--r--runtime/arch/arm/quick_method_frame_info_arm.h7
-rw-r--r--runtime/arch/arm64/asm_support_arm64.h2
-rw-r--r--runtime/arch/arm64/quick_entrypoints_arm64.S25
-rw-r--r--runtime/arch/arm64/quick_method_frame_info_arm64.h7
-rw-r--r--runtime/arch/mips/asm_support_mips.h2
-rw-r--r--runtime/arch/mips/quick_method_frame_info_mips.h4
-rw-r--r--runtime/arch/mips64/asm_support_mips64.h2
-rw-r--r--runtime/arch/mips64/quick_method_frame_info_mips64.h4
-rw-r--r--runtime/arch/x86/asm_support_x86.h2
-rw-r--r--runtime/arch/x86/quick_entrypoints_x86.S26
-rw-r--r--runtime/arch/x86/quick_method_frame_info_x86.h8
-rw-r--r--runtime/arch/x86_64/asm_support_x86_64.h2
-rw-r--r--runtime/arch/x86_64/quick_entrypoints_x86_64.S26
-rw-r--r--runtime/arch/x86_64/quick_method_frame_info_x86_64.h4
-rw-r--r--runtime/art_method-inl.h4
-rw-r--r--runtime/base/callee_save_type.h10
-rw-r--r--runtime/base/unix_file/fd_file.cc26
-rw-r--r--runtime/base/unix_file/fd_file.h5
-rw-r--r--runtime/base/unix_file/fd_file_test.cc54
-rw-r--r--runtime/class_linker.cc2
-rw-r--r--runtime/class_loader_context.cc4
-rw-r--r--runtime/class_loader_context.h10
-rw-r--r--runtime/entrypoints/quick/quick_dexcache_entrypoints.cc8
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc20
-rw-r--r--runtime/gc/collector/concurrent_copying.cc27
-rw-r--r--runtime/gc/space/image_space.cc10
-rw-r--r--runtime/generated/asm_support_gen.h4
-rw-r--r--runtime/image.h2
-rw-r--r--runtime/mirror/accessible_object.h11
-rw-r--r--runtime/mirror/array-inl.h3
-rw-r--r--runtime/mirror/field-inl.h7
-rw-r--r--runtime/mirror/field.h7
-rw-r--r--runtime/mirror/object-inl.h8
-rw-r--r--runtime/mirror/object.h7
-rw-r--r--runtime/native/java_lang_reflect_Field.cc2
-rw-r--r--runtime/runtime-inl.h4
-rw-r--r--runtime/runtime.h2
-rw-r--r--runtime/stack.cc13
-rw-r--r--runtime/thread.h13
-rw-r--r--test/1338-gc-no-los/expected.txt1
-rw-r--r--test/1338-gc-no-los/info.txt1
-rwxr-xr-xtest/1338-gc-no-los/run16
-rw-r--r--test/1338-gc-no-los/src-art/Main.java39
-rw-r--r--test/449-checker-bce/src/Main.java85
-rw-r--r--test/661-classloader-allocator/expected.txt1
-rw-r--r--test/661-classloader-allocator/info.txt3
-rw-r--r--test/661-classloader-allocator/src-ex/OtherClass.java28
-rw-r--r--test/661-classloader-allocator/src/Main.java62
-rw-r--r--test/662-regression-alias/expected.txt1
-rw-r--r--test/662-regression-alias/info.txt1
-rw-r--r--test/662-regression-alias/src/Main.java80
-rw-r--r--test/common/runtime_state.cc13
-rw-r--r--test/knownfailures.json10
-rw-r--r--test/ti-agent/trace_helper.cc23
-rw-r--r--tools/art17
-rw-r--r--tools/cpp-define-generator/offset_runtime.def4
-rw-r--r--tools/libcore_gcstress_debug_failures.txt1
-rwxr-xr-xtools/run-jdwp-tests.sh3
80 files changed, 1114 insertions, 156 deletions
diff --git a/build/Android.cpplint.mk b/build/Android.cpplint.mk
index 2688c049d5..247f4e3470 100644
--- a/build/Android.cpplint.mk
+++ b/build/Android.cpplint.mk
@@ -18,7 +18,9 @@ include art/build/Android.common_build.mk
ART_CPPLINT := $(LOCAL_PATH)/tools/cpplint.py
ART_CPPLINT_FILTER := --filter=-whitespace/line_length,-build/include,-readability/function,-readability/streams,-readability/todo,-runtime/references,-runtime/sizeof,-runtime/threadsafe_fn,-runtime/printf
-ART_CPPLINT_FLAGS := --root=$(TOP)
+# Use `pwd` instead of $TOP for root, $TOP is always . and --root doesn't seem
+# to work with a relative path (b/34787652).
+ART_CPPLINT_FLAGS := --root=`pwd`
ART_CPPLINT_QUIET := --quiet
ART_CPPLINT_INGORED := \
runtime/elf.h \
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index bd530ac6a6..6e087c5785 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2879,9 +2879,9 @@ void CompilerDriver::AddCompiledMethod(const MethodReference& method_ref,
bool CompilerDriver::GetCompiledClass(ClassReference ref, mirror::Class::Status* status) const {
DCHECK(status != nullptr);
// The table doesn't know if something wasn't inserted. For this case it will return
- // kStatusNotReady. To handle this, just assume anything not verified is not compiled.
+ // kStatusNotReady. To handle this, just assume anything we didn't try to verify is not compiled.
if (!compiled_classes_.Get(DexFileReference(ref.first, ref.second), status) ||
- *status < mirror::Class::kStatusVerified) {
+ *status < mirror::Class::kStatusRetryVerificationAtRuntime) {
return false;
}
return true;
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index fee6afb91f..4da3e0df39 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -366,6 +366,40 @@ TEST_F(CompilerDriverVerifyTest, VerifyCompilation) {
CheckVerifiedClass(class_loader, "LSecond;");
}
+// Test that a class of status kStatusRetryVerificationAtRuntime is indeed recorded that way in the
+// driver.
+TEST_F(CompilerDriverVerifyTest, RetryVerifcationStatus) {
+ Thread* const self = Thread::Current();
+ jobject class_loader;
+ std::vector<const DexFile*> dex_files;
+ const DexFile* dex_file = nullptr;
+ {
+ ScopedObjectAccess soa(self);
+ class_loader = LoadDex("ProfileTestMultiDex");
+ ASSERT_NE(class_loader, nullptr);
+ dex_files = GetDexFiles(class_loader);
+ ASSERT_GT(dex_files.size(), 0u);
+ dex_file = dex_files.front();
+ }
+ compiler_driver_->SetDexFilesForOatFile(dex_files);
+ ClassReference ref(dex_file, 0u);
+ // Test that the status is read from the compiler driver as expected.
+ for (size_t i = mirror::Class::kStatusRetryVerificationAtRuntime;
+ i < mirror::Class::kStatusMax;
+ ++i) {
+ const mirror::Class::Status expected_status = static_cast<mirror::Class::Status>(i);
+ // Skip unsupported status that are not supposed to be ever recorded.
+ if (expected_status == mirror::Class::kStatusVerifyingAtRuntime ||
+ expected_status == mirror::Class::kStatusInitializing) {
+ continue;
+ }
+ compiler_driver_->RecordClassStatus(ref, expected_status);
+ mirror::Class::Status status = {};
+ ASSERT_TRUE(compiler_driver_->GetCompiledClass(ref, &status));
+ EXPECT_EQ(status, expected_status);
+ }
+}
+
// TODO: need check-cast test (when stub complete & we can throw/catch
} // namespace art
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 9e4971ce75..115e722a75 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -1686,6 +1686,10 @@ void ImageWriter::CalculateNewObjectOffsets() {
runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsAndArgs);
image_methods_[ImageHeader::kSaveEverythingMethod] =
runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverything);
+ image_methods_[ImageHeader::kSaveEverythingMethodForClinit] =
+ runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForClinit);
+ image_methods_[ImageHeader::kSaveEverythingMethodForSuspendCheck] =
+ runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForSuspendCheck);
// Visit image methods first to have the main runtime methods in the first image.
for (auto* m : image_methods_) {
CHECK(m != nullptr);
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index c166deb406..2f96cfa382 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -1121,6 +1121,66 @@ class BCEVisitor : public HGraphVisitor {
}
}
+ void VisitRem(HRem* instruction) OVERRIDE {
+ HInstruction* left = instruction->GetLeft();
+ HInstruction* right = instruction->GetRight();
+
+ // Handle 'i % CONST' format expression in array index, e.g:
+ // array[i % 20];
+ if (right->IsIntConstant()) {
+ int32_t right_const = std::abs(right->AsIntConstant()->GetValue());
+ if (right_const == 0) {
+ return;
+ }
+ // The sign of divisor CONST doesn't affect the sign final value range.
+ // For example:
+ // if (i > 0) {
+ // array[i % 10]; // index value range [0, 9]
+ // array[i % -10]; // index value range [0, 9]
+ // }
+ ValueRange* right_range = new (GetGraph()->GetArena()) ValueRange(
+ GetGraph()->GetArena(),
+ ValueBound(nullptr, 1 - right_const),
+ ValueBound(nullptr, right_const - 1));
+
+ ValueRange* left_range = LookupValueRange(left, left->GetBlock());
+ if (left_range != nullptr) {
+ right_range = left_range->Narrow(right_range);
+ }
+ AssignRange(instruction->GetBlock(), instruction, right_range);
+ return;
+ }
+
+ // Handle following pattern:
+ // i0 NullCheck
+ // i1 ArrayLength[i0]
+ // i2 DivByZeroCheck [i1] <-- right
+ // i3 Rem [i5, i2] <-- we are here.
+ // i4 BoundsCheck [i3,i1]
+ if (right->IsDivZeroCheck()) {
+ // if array_length can pass div-by-zero check,
+ // array_length must be > 0.
+ right = right->AsDivZeroCheck()->InputAt(0);
+ }
+
+ // Handle 'i % array.length' format expression in array index, e.g:
+ // array[(i+7) % array.length];
+ if (right->IsArrayLength()) {
+ ValueBound lower = ValueBound::Min(); // ideally, lower should be '1-array_length'.
+ ValueBound upper = ValueBound(right, -1); // array_length - 1
+ ValueRange* right_range = new (GetGraph()->GetArena()) ValueRange(
+ GetGraph()->GetArena(),
+ lower,
+ upper);
+ ValueRange* left_range = LookupValueRange(left, left->GetBlock());
+ if (left_range != nullptr) {
+ right_range = left_range->Narrow(right_range);
+ }
+ AssignRange(instruction->GetBlock(), instruction, right_range);
+ return;
+ }
+ }
+
void VisitNewArray(HNewArray* new_array) OVERRIDE {
HInstruction* len = new_array->GetLength();
if (!len->IsIntConstant()) {
diff --git a/compiler/optimizing/bounds_check_elimination_test.cc b/compiler/optimizing/bounds_check_elimination_test.cc
index 575e2fc24a..2aaf05833c 100644
--- a/compiler/optimizing/bounds_check_elimination_test.cc
+++ b/compiler/optimizing/bounds_check_elimination_test.cc
@@ -951,4 +951,152 @@ TEST_F(BoundsCheckEliminationTest, BubbleSortArrayBoundsElimination) {
ASSERT_TRUE(IsRemoved(bounds_check6));
}
+// int[] array = new int[10];
+// for (int i=0; i<200; i++) {
+// array[i%10] = 10; // Can eliminate
+// array[i%1] = 10; // Can eliminate
+// array[i%200] = 10; // Cannot eliminate
+// array[i%-10] = 10; // Can eliminate
+// array[i%array.length] = 10; // Can eliminate
+// array[param_i%10] = 10; // Can't eliminate, when param_i < 0
+// }
+TEST_F(BoundsCheckEliminationTest, ModArrayBoundsElimination) {
+ HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
+ graph_->AddBlock(entry);
+ graph_->SetEntryBlock(entry);
+ HInstruction* param_i = new (&allocator_)
+ HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
+ entry->AddInstruction(param_i);
+
+ HInstruction* constant_0 = graph_->GetIntConstant(0);
+ HInstruction* constant_1 = graph_->GetIntConstant(1);
+ HInstruction* constant_10 = graph_->GetIntConstant(10);
+ HInstruction* constant_200 = graph_->GetIntConstant(200);
+ HInstruction* constant_minus_10 = graph_->GetIntConstant(-10);
+
+ HBasicBlock* block = new (&allocator_) HBasicBlock(graph_);
+ graph_->AddBlock(block);
+ entry->AddSuccessor(block);
+ // We pass a bogus constant for the class to avoid mocking one.
+ HInstruction* new_array = new (&allocator_) HNewArray(constant_10, constant_10, 0);
+ block->AddInstruction(new_array);
+ block->AddInstruction(new (&allocator_) HGoto());
+
+ HBasicBlock* loop_header = new (&allocator_) HBasicBlock(graph_);
+ HBasicBlock* loop_body = new (&allocator_) HBasicBlock(graph_);
+ HBasicBlock* exit = new (&allocator_) HBasicBlock(graph_);
+
+ graph_->AddBlock(loop_header);
+ graph_->AddBlock(loop_body);
+ graph_->AddBlock(exit);
+ block->AddSuccessor(loop_header);
+ loop_header->AddSuccessor(exit); // true successor
+ loop_header->AddSuccessor(loop_body); // false successor
+ loop_body->AddSuccessor(loop_header);
+
+ HPhi* phi = new (&allocator_) HPhi(&allocator_, 0, 0, Primitive::kPrimInt);
+ HInstruction* cmp = new (&allocator_) HGreaterThanOrEqual(phi, constant_200);
+ HInstruction* if_inst = new (&allocator_) HIf(cmp);
+ loop_header->AddPhi(phi);
+ loop_header->AddInstruction(cmp);
+ loop_header->AddInstruction(if_inst);
+ phi->AddInput(constant_0);
+
+ //////////////////////////////////////////////////////////////////////////////////
+ // LOOP BODY:
+ // array[i % 10] = 10;
+ HRem* i_mod_10 = new (&allocator_) HRem(Primitive::kPrimInt, phi, constant_10, 0);
+ HBoundsCheck* bounds_check_i_mod_10 = new (&allocator_) HBoundsCheck(i_mod_10, constant_10, 0);
+ HInstruction* array_set = new (&allocator_) HArraySet(
+ new_array, bounds_check_i_mod_10, constant_10, Primitive::kPrimInt, 0);
+ loop_body->AddInstruction(i_mod_10);
+ loop_body->AddInstruction(bounds_check_i_mod_10);
+ loop_body->AddInstruction(array_set);
+
+ // array[i % 1] = 10;
+ HRem* i_mod_1 = new (&allocator_) HRem(Primitive::kPrimInt, phi, constant_1, 0);
+ HBoundsCheck* bounds_check_i_mod_1 = new (&allocator_) HBoundsCheck(i_mod_1, constant_10, 0);
+ array_set = new (&allocator_) HArraySet(
+ new_array, bounds_check_i_mod_1, constant_10, Primitive::kPrimInt, 0);
+ loop_body->AddInstruction(i_mod_1);
+ loop_body->AddInstruction(bounds_check_i_mod_1);
+ loop_body->AddInstruction(array_set);
+
+ // array[i % 200] = 10;
+ HRem* i_mod_200 = new (&allocator_) HRem(Primitive::kPrimInt, phi, constant_1, 0);
+ HBoundsCheck* bounds_check_i_mod_200 = new (&allocator_) HBoundsCheck(i_mod_200, constant_10, 0);
+ array_set = new (&allocator_) HArraySet(
+ new_array, bounds_check_i_mod_200, constant_10, Primitive::kPrimInt, 0);
+ loop_body->AddInstruction(i_mod_200);
+ loop_body->AddInstruction(bounds_check_i_mod_200);
+ loop_body->AddInstruction(array_set);
+
+ // array[i % -10] = 10;
+ HRem* i_mod_minus_10 = new (&allocator_) HRem(Primitive::kPrimInt, phi, constant_minus_10, 0);
+ HBoundsCheck* bounds_check_i_mod_minus_10 = new (&allocator_) HBoundsCheck(
+ i_mod_minus_10, constant_10, 0);
+ array_set = new (&allocator_) HArraySet(
+ new_array, bounds_check_i_mod_minus_10, constant_10, Primitive::kPrimInt, 0);
+ loop_body->AddInstruction(i_mod_minus_10);
+ loop_body->AddInstruction(bounds_check_i_mod_minus_10);
+ loop_body->AddInstruction(array_set);
+
+ // array[i%array.length] = 10;
+ HNullCheck* null_check = new (&allocator_) HNullCheck(new_array, 0);
+ HArrayLength* array_length = new (&allocator_) HArrayLength(null_check, 0);
+ HRem* i_mod_array_length = new (&allocator_) HRem(Primitive::kPrimInt, phi, array_length, 0);
+ HBoundsCheck* bounds_check_i_mod_array_len = new (&allocator_) HBoundsCheck(
+ i_mod_array_length, array_length, 0);
+ array_set = new (&allocator_) HArraySet(
+ null_check, bounds_check_i_mod_array_len, constant_10, Primitive::kPrimInt, 0);
+ loop_body->AddInstruction(null_check);
+ loop_body->AddInstruction(array_length);
+ loop_body->AddInstruction(i_mod_array_length);
+ loop_body->AddInstruction(bounds_check_i_mod_array_len);
+ loop_body->AddInstruction(array_set);
+
+ // array[param_i % 10] = 10;
+ HRem* param_i_mod_10 = new (&allocator_) HRem(Primitive::kPrimInt, param_i, constant_10, 0);
+ HBoundsCheck* bounds_check_param_i_mod_10 = new (&allocator_) HBoundsCheck(
+ param_i_mod_10, constant_10, 0);
+ array_set = new (&allocator_) HArraySet(
+ new_array, bounds_check_param_i_mod_10, constant_10, Primitive::kPrimInt, 0);
+ loop_body->AddInstruction(param_i_mod_10);
+ loop_body->AddInstruction(bounds_check_param_i_mod_10);
+ loop_body->AddInstruction(array_set);
+
+ // array[param_i%array.length] = 10;
+ null_check = new (&allocator_) HNullCheck(new_array, 0);
+ array_length = new (&allocator_) HArrayLength(null_check, 0);
+ HRem* param_i_mod_array_length = new (&allocator_) HRem(
+ Primitive::kPrimInt, param_i, array_length, 0);
+ HBoundsCheck* bounds_check_param_i_mod_array_len = new (&allocator_) HBoundsCheck(
+ param_i_mod_array_length, array_length, 0);
+ array_set = new (&allocator_) HArraySet(
+ null_check, bounds_check_param_i_mod_array_len, constant_10, Primitive::kPrimInt, 0);
+ loop_body->AddInstruction(null_check);
+ loop_body->AddInstruction(array_length);
+ loop_body->AddInstruction(param_i_mod_array_length);
+ loop_body->AddInstruction(bounds_check_param_i_mod_array_len);
+ loop_body->AddInstruction(array_set);
+
+ // i++;
+ HInstruction* add = new (&allocator_) HAdd(Primitive::kPrimInt, phi, constant_1);
+ loop_body->AddInstruction(add);
+ loop_body->AddInstruction(new (&allocator_) HGoto());
+ phi->AddInput(add);
+ //////////////////////////////////////////////////////////////////////////////////
+
+ exit->AddInstruction(new (&allocator_) HExit());
+
+ RunBCE();
+
+ ASSERT_TRUE(IsRemoved(bounds_check_i_mod_10));
+ ASSERT_TRUE(IsRemoved(bounds_check_i_mod_1));
+ ASSERT_TRUE(IsRemoved(bounds_check_i_mod_200));
+ ASSERT_TRUE(IsRemoved(bounds_check_i_mod_minus_10));
+ ASSERT_TRUE(IsRemoved(bounds_check_i_mod_array_len));
+ ASSERT_FALSE(IsRemoved(bounds_check_param_i_mod_10));
+}
+
} // namespace art
diff --git a/compiler/optimizing/code_generator_vector_arm64.cc b/compiler/optimizing/code_generator_vector_arm64.cc
index f422b9fc8b..9095ecdf16 100644
--- a/compiler/optimizing/code_generator_vector_arm64.cc
+++ b/compiler/optimizing/code_generator_vector_arm64.cc
@@ -15,7 +15,9 @@
*/
#include "code_generator_arm64.h"
+
#include "mirror/array-inl.h"
+#include "mirror/string.h"
using namespace vixl::aarch64; // NOLINT(build/namespaces)
diff --git a/compiler/optimizing/code_generator_vector_x86.cc b/compiler/optimizing/code_generator_vector_x86.cc
index 14782d70a1..e7aec76aff 100644
--- a/compiler/optimizing/code_generator_vector_x86.cc
+++ b/compiler/optimizing/code_generator_vector_x86.cc
@@ -15,7 +15,9 @@
*/
#include "code_generator_x86.h"
+
#include "mirror/array-inl.h"
+#include "mirror/string.h"
namespace art {
namespace x86 {
diff --git a/compiler/optimizing/code_generator_vector_x86_64.cc b/compiler/optimizing/code_generator_vector_x86_64.cc
index 246044ebb8..c7ee81c60d 100644
--- a/compiler/optimizing/code_generator_vector_x86_64.cc
+++ b/compiler/optimizing/code_generator_vector_x86_64.cc
@@ -15,7 +15,9 @@
*/
#include "code_generator_x86_64.h"
+
#include "mirror/array-inl.h"
+#include "mirror/string.h"
namespace art {
namespace x86_64 {
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 4cea6dfdfb..2669d97d82 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -22,6 +22,7 @@
#include "entrypoints/quick/quick_entrypoints.h"
#include "intrinsics.h"
#include "mirror/array-inl.h"
+#include "mirror/object_array-inl.h"
#include "mirror/string.h"
#include "scoped_thread_state_change-inl.h"
#include "thread.h"
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index d785567e0f..74be954a75 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -22,6 +22,7 @@
#include "entrypoints/quick/quick_entrypoints.h"
#include "intrinsics.h"
#include "mirror/array-inl.h"
+#include "mirror/object_array-inl.h"
#include "mirror/string.h"
#include "scoped_thread_state_change-inl.h"
#include "thread.h"
diff --git a/compiler/optimizing/load_store_analysis.h b/compiler/optimizing/load_store_analysis.h
index 86fb8e0165..a2c17944f2 100644
--- a/compiler/optimizing/load_store_analysis.h
+++ b/compiler/optimizing/load_store_analysis.h
@@ -466,6 +466,11 @@ class HeapLocationCollector : public HGraphVisitor {
CreateReferenceInfoForReferenceType(new_instance);
}
+ void VisitNewArray(HNewArray* new_array) OVERRIDE {
+ // Any references appearing in the ref_info_array_ so far cannot alias with new_array.
+ CreateReferenceInfoForReferenceType(new_array);
+ }
+
void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* instruction) OVERRIDE {
CreateReferenceInfoForReferenceType(instruction);
}
@@ -478,6 +483,22 @@ class HeapLocationCollector : public HGraphVisitor {
CreateReferenceInfoForReferenceType(instruction);
}
+ void VisitInvokeUnresolved(HInvokeUnresolved* instruction) OVERRIDE {
+ CreateReferenceInfoForReferenceType(instruction);
+ }
+
+ void VisitInvokePolymorphic(HInvokePolymorphic* instruction) OVERRIDE {
+ CreateReferenceInfoForReferenceType(instruction);
+ }
+
+ void VisitLoadString(HLoadString* instruction) OVERRIDE {
+ CreateReferenceInfoForReferenceType(instruction);
+ }
+
+ void VisitPhi(HPhi* instruction) OVERRIDE {
+ CreateReferenceInfoForReferenceType(instruction);
+ }
+
void VisitParameterValue(HParameterValue* instruction) OVERRIDE {
CreateReferenceInfoForReferenceType(instruction);
}
diff --git a/compiler/optimizing/loop_optimization_test.cc b/compiler/optimizing/loop_optimization_test.cc
index 5b9350689e..b5b03d8f26 100644
--- a/compiler/optimizing/loop_optimization_test.cc
+++ b/compiler/optimizing/loop_optimization_test.cc
@@ -195,4 +195,44 @@ TEST_F(LoopOptimizationTest, LoopNestWithSequence) {
EXPECT_EQ("[[[[[[[[[[][][][][][][][][][]]]]]]]]]]", LoopStructure());
}
+// Check that SimplifyLoop() doesn't invalidate data flow when ordering loop headers'
+// predecessors.
+TEST_F(LoopOptimizationTest, SimplifyLoop) {
+ // Can't use AddLoop as we want special order for blocks predecessors.
+ HBasicBlock* header = new (&allocator_) HBasicBlock(graph_);
+ HBasicBlock* body = new (&allocator_) HBasicBlock(graph_);
+ graph_->AddBlock(header);
+ graph_->AddBlock(body);
+
+ // Control flow: make a loop back edge first in the list of predecessors.
+ entry_block_->RemoveSuccessor(return_block_);
+ body->AddSuccessor(header);
+ entry_block_->AddSuccessor(header);
+ header->AddSuccessor(body);
+ header->AddSuccessor(return_block_);
+ DCHECK(header->GetSuccessors()[1] == return_block_);
+
+ // Data flow.
+ header->AddInstruction(new (&allocator_) HIf(parameter_));
+ body->AddInstruction(new (&allocator_) HGoto());
+
+ HPhi* phi = new (&allocator_) HPhi(&allocator_, 0, 0, Primitive::kPrimInt);
+ HInstruction* add = new (&allocator_) HAdd(Primitive::kPrimInt, phi, parameter_);
+ header->AddPhi(phi);
+ body->AddInstruction(add);
+
+ phi->AddInput(add);
+ phi->AddInput(parameter_);
+
+ graph_->ClearLoopInformation();
+ graph_->ClearDominanceInformation();
+ graph_->BuildDominatorTree();
+
+ // Check that after optimizations in BuildDominatorTree()/SimplifyCFG() phi inputs
+ // are still mapped correctly to the block predecessors.
+ for (size_t i = 0, e = phi->InputCount(); i < e; i++) {
+ HInstruction* input = phi->InputAt(i);
+ ASSERT_TRUE(input->GetBlock()->Dominates(header->GetPredecessors()[i]));
+ }
+}
} // namespace art
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 3a1864b2ae..ddd798b4a5 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -358,6 +358,35 @@ void HGraph::SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor) {
}
}
+// Reorder phi inputs to match reordering of the block's predecessors.
+static void FixPhisAfterPredecessorsReodering(HBasicBlock* block, size_t first, size_t second) {
+ for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
+ HPhi* phi = it.Current()->AsPhi();
+ HInstruction* first_instr = phi->InputAt(first);
+ HInstruction* second_instr = phi->InputAt(second);
+ phi->ReplaceInput(first_instr, second);
+ phi->ReplaceInput(second_instr, first);
+ }
+}
+
+// Make sure that the first predecessor of a loop header is the incoming block.
+void HGraph::OrderLoopHeaderPredecessors(HBasicBlock* header) {
+ DCHECK(header->IsLoopHeader());
+ HLoopInformation* info = header->GetLoopInformation();
+ if (info->IsBackEdge(*header->GetPredecessors()[0])) {
+ HBasicBlock* to_swap = header->GetPredecessors()[0];
+ for (size_t pred = 1, e = header->GetPredecessors().size(); pred < e; ++pred) {
+ HBasicBlock* predecessor = header->GetPredecessors()[pred];
+ if (!info->IsBackEdge(*predecessor)) {
+ header->predecessors_[pred] = to_swap;
+ header->predecessors_[0] = predecessor;
+ FixPhisAfterPredecessorsReodering(header, 0, pred);
+ break;
+ }
+ }
+ }
+}
+
void HGraph::SimplifyLoop(HBasicBlock* header) {
HLoopInformation* info = header->GetLoopInformation();
@@ -381,18 +410,7 @@ void HGraph::SimplifyLoop(HBasicBlock* header) {
pre_header->AddSuccessor(header);
}
- // Make sure the first predecessor of a loop header is the incoming block.
- if (info->IsBackEdge(*header->GetPredecessors()[0])) {
- HBasicBlock* to_swap = header->GetPredecessors()[0];
- for (size_t pred = 1, e = header->GetPredecessors().size(); pred < e; ++pred) {
- HBasicBlock* predecessor = header->GetPredecessors()[pred];
- if (!info->IsBackEdge(*predecessor)) {
- header->predecessors_[pred] = to_swap;
- header->predecessors_[0] = predecessor;
- break;
- }
- }
- }
+ OrderLoopHeaderPredecessors(header);
HInstruction* first_instruction = header->GetFirstInstruction();
if (first_instruction != nullptr && first_instruction->IsSuspendCheck()) {
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index e4431422b2..488d47269b 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -418,6 +418,7 @@ class HGraph : public ArenaObject<kArenaAllocGraph> {
HBasicBlock* SplitEdge(HBasicBlock* block, HBasicBlock* successor);
void SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor);
+ void OrderLoopHeaderPredecessors(HBasicBlock* header);
void SimplifyLoop(HBasicBlock* header);
int32_t GetNextInstructionId() {
diff --git a/compiler/optimizing/scheduler_arm.cc b/compiler/optimizing/scheduler_arm.cc
index ea15790105..d6eb6e3c52 100644
--- a/compiler/optimizing/scheduler_arm.cc
+++ b/compiler/optimizing/scheduler_arm.cc
@@ -20,6 +20,7 @@
#include "code_generator_utils.h"
#include "common_arm.h"
#include "mirror/array-inl.h"
+#include "mirror/string.h"
namespace art {
namespace arm {
diff --git a/compiler/optimizing/scheduler_arm64.cc b/compiler/optimizing/scheduler_arm64.cc
index f54d3f3de2..510619faf9 100644
--- a/compiler/optimizing/scheduler_arm64.cc
+++ b/compiler/optimizing/scheduler_arm64.cc
@@ -18,6 +18,7 @@
#include "code_generator_utils.h"
#include "mirror/array-inl.h"
+#include "mirror/string.h"
namespace art {
namespace arm64 {
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index e0ad64946e..ff193e933a 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -355,6 +355,9 @@ NO_RETURN static void Usage(const char* fmt, ...) {
UsageError("");
UsageError(" --debuggable: Produce code debuggable with Java debugger.");
UsageError("");
+ UsageError(" --avoid-storing-invocation: Avoid storing the invocation args in the key value");
+ UsageError(" store. Used to test determinism with different args.");
+ UsageError("");
UsageError(" --runtime-arg <argument>: used to specify various arguments for the runtime,");
UsageError(" such as initial heap size, maximum heap size, and verbose output.");
UsageError(" Use a separate --runtime-arg switch for each argument.");
@@ -611,6 +614,7 @@ class Dex2Oat FINAL {
dump_passes_(false),
dump_timing_(false),
dump_slow_timing_(kIsDebugBuild),
+ avoid_storing_invocation_(false),
swap_fd_(kInvalidFd),
app_image_fd_(kInvalidFd),
profile_file_fd_(kInvalidFd),
@@ -1133,14 +1137,16 @@ class Dex2Oat FINAL {
void InsertCompileOptions(int argc, char** argv) {
std::ostringstream oss;
- for (int i = 0; i < argc; ++i) {
- if (i > 0) {
- oss << ' ';
+ if (!avoid_storing_invocation_) {
+ for (int i = 0; i < argc; ++i) {
+ if (i > 0) {
+ oss << ' ';
+ }
+ oss << argv[i];
}
- oss << argv[i];
+ key_value_store_->Put(OatHeader::kDex2OatCmdLineKey, oss.str());
+ oss.str(""); // Reset.
}
- key_value_store_->Put(OatHeader::kDex2OatCmdLineKey, oss.str());
- oss.str(""); // Reset.
oss << kRuntimeISA;
key_value_store_->Put(OatHeader::kDex2OatHostKey, oss.str());
key_value_store_->Put(
@@ -1271,6 +1277,8 @@ class Dex2Oat FINAL {
dump_passes_ = true;
} else if (option == "--dump-stats") {
dump_stats_ = true;
+ } else if (option == "--avoid-storing-invocation") {
+ avoid_storing_invocation_ = true;
} else if (option.starts_with("--swap-file=")) {
swap_file_name_ = option.substr(strlen("--swap-file=")).data();
} else if (option.starts_with("--swap-fd=")) {
@@ -1308,7 +1316,7 @@ class Dex2Oat FINAL {
} else if (option.starts_with("--class-loader-context=")) {
class_loader_context_ = ClassLoaderContext::Create(
option.substr(strlen("--class-loader-context=")).data());
- if (class_loader_context_== nullptr) {
+ if (class_loader_context_ == nullptr) {
Usage("Option --class-loader-context has an incorrect format: %s", option.data());
}
} else if (option.starts_with("--dirty-image-objects=")) {
@@ -1576,20 +1584,12 @@ class Dex2Oat FINAL {
}
// Open dex files for class path.
+
if (class_loader_context_ == nullptr) {
- // TODO(calin): Temporary workaround while we transition to use
- // --class-loader-context instead of --runtime-arg -cp
- if (runtime_->GetClassPathString().empty()) {
- class_loader_context_ = std::unique_ptr<ClassLoaderContext>(
- new ClassLoaderContext());
- } else {
- std::string spec = runtime_->GetClassPathString() == OatFile::kSpecialSharedLibrary
- ? OatFile::kSpecialSharedLibrary
- : "PCL[" + runtime_->GetClassPathString() + "]";
- class_loader_context_ = ClassLoaderContext::Create(spec);
- }
+ // If no context was specified use the default one (which is an empty PathClassLoader).
+ class_loader_context_ = std::unique_ptr<ClassLoaderContext>(ClassLoaderContext::Default());
}
- CHECK(class_loader_context_ != nullptr);
+
DCHECK_EQ(oat_writers_.size(), 1u);
// Note: Ideally we would reject context where the source dex files are also
@@ -2899,6 +2899,7 @@ class Dex2Oat FINAL {
bool dump_passes_;
bool dump_timing_;
bool dump_slow_timing_;
+ bool avoid_storing_invocation_;
std::string swap_file_name_;
int swap_fd_;
size_t min_dex_files_for_swap_ = kDefaultMinDexFilesForSwap;
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 99168c9bc5..f8b1f5375a 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -89,6 +89,8 @@ const char* image_methods_descriptions_[] = {
"kSaveRefsOnlyMethod",
"kSaveRefsAndArgsMethod",
"kSaveEverythingMethod",
+ "kSaveEverythingMethodForClinit",
+ "kSaveEverythingMethodForSuspendCheck",
};
const char* image_roots_descriptions_[] = {
diff --git a/runtime/arch/arch_test.cc b/runtime/arch/arch_test.cc
index bfac8c422d..1ba4070056 100644
--- a/runtime/arch/arch_test.cc
+++ b/runtime/arch/arch_test.cc
@@ -88,6 +88,11 @@ static constexpr size_t kFrameSizeSaveRefsOnly = FRAME_SIZE_SAVE_REFS_ONLY;
#undef FRAME_SIZE_SAVE_REFS_ONLY
static constexpr size_t kFrameSizeSaveRefsAndArgs = FRAME_SIZE_SAVE_REFS_AND_ARGS;
#undef FRAME_SIZE_SAVE_REFS_AND_ARGS
+static constexpr size_t kFrameSizeSaveEverythingForClinit = FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT;
+#undef FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT
+static constexpr size_t kFrameSizeSaveEverythingForSuspendCheck =
+ FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK;
+#undef FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK
static constexpr size_t kFrameSizeSaveEverything = FRAME_SIZE_SAVE_EVERYTHING;
#undef FRAME_SIZE_SAVE_EVERYTHING
#undef BAKER_MARK_INTROSPECTION_FIELD_LDR_NARROW_ENTRYPOINT_OFFSET
@@ -109,6 +114,11 @@ static constexpr size_t kFrameSizeSaveRefsOnly = FRAME_SIZE_SAVE_REFS_ONLY;
#undef FRAME_SIZE_SAVE_REFS_ONLY
static constexpr size_t kFrameSizeSaveRefsAndArgs = FRAME_SIZE_SAVE_REFS_AND_ARGS;
#undef FRAME_SIZE_SAVE_REFS_AND_ARGS
+static constexpr size_t kFrameSizeSaveEverythingForClinit = FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT;
+#undef FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT
+static constexpr size_t kFrameSizeSaveEverythingForSuspendCheck =
+ FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK;
+#undef FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK
static constexpr size_t kFrameSizeSaveEverything = FRAME_SIZE_SAVE_EVERYTHING;
#undef FRAME_SIZE_SAVE_EVERYTHING
#undef BAKER_MARK_INTROSPECTION_ARRAY_SWITCH_OFFSET
@@ -126,6 +136,11 @@ static constexpr size_t kFrameSizeSaveRefsOnly = FRAME_SIZE_SAVE_REFS_ONLY;
#undef FRAME_SIZE_SAVE_REFS_ONLY
static constexpr size_t kFrameSizeSaveRefsAndArgs = FRAME_SIZE_SAVE_REFS_AND_ARGS;
#undef FRAME_SIZE_SAVE_REFS_AND_ARGS
+static constexpr size_t kFrameSizeSaveEverythingForClinit = FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT;
+#undef FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT
+static constexpr size_t kFrameSizeSaveEverythingForSuspendCheck =
+ FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK;
+#undef FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK
static constexpr size_t kFrameSizeSaveEverything = FRAME_SIZE_SAVE_EVERYTHING;
#undef FRAME_SIZE_SAVE_EVERYTHING
#undef BAKER_MARK_INTROSPECTION_REGISTER_COUNT
@@ -142,6 +157,11 @@ static constexpr size_t kFrameSizeSaveRefsOnly = FRAME_SIZE_SAVE_REFS_ONLY;
#undef FRAME_SIZE_SAVE_REFS_ONLY
static constexpr size_t kFrameSizeSaveRefsAndArgs = FRAME_SIZE_SAVE_REFS_AND_ARGS;
#undef FRAME_SIZE_SAVE_REFS_AND_ARGS
+static constexpr size_t kFrameSizeSaveEverythingForClinit = FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT;
+#undef FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT
+static constexpr size_t kFrameSizeSaveEverythingForSuspendCheck =
+ FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK;
+#undef FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK
static constexpr size_t kFrameSizeSaveEverything = FRAME_SIZE_SAVE_EVERYTHING;
#undef FRAME_SIZE_SAVE_EVERYTHING
#undef BAKER_MARK_INTROSPECTION_REGISTER_COUNT
@@ -158,6 +178,11 @@ static constexpr size_t kFrameSizeSaveRefsOnly = FRAME_SIZE_SAVE_REFS_ONLY;
#undef FRAME_SIZE_SAVE_REFS_ONLY
static constexpr size_t kFrameSizeSaveRefsAndArgs = FRAME_SIZE_SAVE_REFS_AND_ARGS;
#undef FRAME_SIZE_SAVE_REFS_AND_ARGS
+static constexpr size_t kFrameSizeSaveEverythingForClinit = FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT;
+#undef FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT
+static constexpr size_t kFrameSizeSaveEverythingForSuspendCheck =
+ FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK;
+#undef FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK
static constexpr size_t kFrameSizeSaveEverything = FRAME_SIZE_SAVE_EVERYTHING;
#undef FRAME_SIZE_SAVE_EVERYTHING
} // namespace x86
@@ -170,25 +195,36 @@ static constexpr size_t kFrameSizeSaveRefsOnly = FRAME_SIZE_SAVE_REFS_ONLY;
#undef FRAME_SIZE_SAVE_REFS_ONLY
static constexpr size_t kFrameSizeSaveRefsAndArgs = FRAME_SIZE_SAVE_REFS_AND_ARGS;
#undef FRAME_SIZE_SAVE_REFS_AND_ARGS
+static constexpr size_t kFrameSizeSaveEverythingForClinit = FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT;
+#undef FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT
+static constexpr size_t kFrameSizeSaveEverythingForSuspendCheck =
+ FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK;
+#undef FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK
static constexpr size_t kFrameSizeSaveEverything = FRAME_SIZE_SAVE_EVERYTHING;
#undef FRAME_SIZE_SAVE_EVERYTHING
} // namespace x86_64
// Check architecture specific constants are sound.
-#define TEST_ARCH(Arch, arch) \
- TEST_F(ArchTest, Arch) { \
- CheckFrameSize(InstructionSet::k##Arch, \
- CalleeSaveType::kSaveAllCalleeSaves, \
- arch::kFrameSizeSaveAllCalleeSaves); \
- CheckFrameSize(InstructionSet::k##Arch, \
- CalleeSaveType::kSaveRefsOnly, \
- arch::kFrameSizeSaveRefsOnly); \
- CheckFrameSize(InstructionSet::k##Arch, \
- CalleeSaveType::kSaveRefsAndArgs, \
- arch::kFrameSizeSaveRefsAndArgs); \
- CheckFrameSize(InstructionSet::k##Arch, \
- CalleeSaveType::kSaveEverything, \
- arch::kFrameSizeSaveEverything); \
+#define TEST_ARCH(Arch, arch) \
+ TEST_F(ArchTest, Arch) { \
+ CheckFrameSize(InstructionSet::k##Arch, \
+ CalleeSaveType::kSaveAllCalleeSaves, \
+ arch::kFrameSizeSaveAllCalleeSaves); \
+ CheckFrameSize(InstructionSet::k##Arch, \
+ CalleeSaveType::kSaveRefsOnly, \
+ arch::kFrameSizeSaveRefsOnly); \
+ CheckFrameSize(InstructionSet::k##Arch, \
+ CalleeSaveType::kSaveRefsAndArgs, \
+ arch::kFrameSizeSaveRefsAndArgs); \
+ CheckFrameSize(InstructionSet::k##Arch, \
+ CalleeSaveType::kSaveEverything, \
+ arch::kFrameSizeSaveEverything); \
+ CheckFrameSize(InstructionSet::k##Arch, \
+ CalleeSaveType::kSaveEverythingForClinit, \
+ arch::kFrameSizeSaveEverythingForClinit); \
+ CheckFrameSize(InstructionSet::k##Arch, \
+ CalleeSaveType::kSaveEverythingForSuspendCheck, \
+ arch::kFrameSizeSaveEverythingForSuspendCheck); \
}
TEST_ARCH(Arm, arm)
TEST_ARCH(Arm64, arm64)
diff --git a/runtime/arch/arm/asm_support_arm.h b/runtime/arch/arm/asm_support_arm.h
index 8f2fd6ecc9..3d85872617 100644
--- a/runtime/arch/arm/asm_support_arm.h
+++ b/runtime/arch/arm/asm_support_arm.h
@@ -23,6 +23,8 @@
#define FRAME_SIZE_SAVE_REFS_ONLY 32
#define FRAME_SIZE_SAVE_REFS_AND_ARGS 112
#define FRAME_SIZE_SAVE_EVERYTHING 192
+#define FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT FRAME_SIZE_SAVE_EVERYTHING
+#define FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK FRAME_SIZE_SAVE_EVERYTHING
// The offset from the art_quick_read_barrier_mark_introspection (used for field
// loads with 32-bit LDR) to the entrypoint for field loads with 16-bit LDR,
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 375768ec3f..cf2bfeeeef 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -182,7 +182,7 @@
* Runtime::CreateCalleeSaveMethod(kSaveEverything)
* when core registers are already saved.
*/
-.macro SETUP_SAVE_EVERYTHING_FRAME_CORE_REGS_SAVED rTemp
+.macro SETUP_SAVE_EVERYTHING_FRAME_CORE_REGS_SAVED rTemp, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
@ 14 words of callee saves and args already saved.
vpush {d0-d15} @ 32 words, 2 for each of the 16 saved doubles.
.cfi_adjust_cfa_offset 128
@@ -190,7 +190,7 @@
.cfi_adjust_cfa_offset 8
RUNTIME_CURRENT1 \rTemp @ Load Runtime::Current into rTemp.
@ Load kSaveEverything Method* into rTemp.
- ldr \rTemp, [\rTemp, #RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET]
+ ldr \rTemp, [\rTemp, #\runtime_method_offset]
str \rTemp, [sp, #0] @ Place Method* at bottom of stack.
str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame.
@@ -204,7 +204,7 @@
* Macro that sets up the callee save frame to conform with
* Runtime::CreateCalleeSaveMethod(kSaveEverything)
*/
-.macro SETUP_SAVE_EVERYTHING_FRAME rTemp
+.macro SETUP_SAVE_EVERYTHING_FRAME rTemp, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
push {r0-r12, lr} @ 14 words of callee saves and args.
.cfi_adjust_cfa_offset 56
.cfi_rel_offset r0, 0
@@ -221,7 +221,7 @@
.cfi_rel_offset r11, 44
.cfi_rel_offset ip, 48
.cfi_rel_offset lr, 52
- SETUP_SAVE_EVERYTHING_FRAME_CORE_REGS_SAVED \rTemp
+ SETUP_SAVE_EVERYTHING_FRAME_CORE_REGS_SAVED \rTemp, \runtime_method_offset
.endm
.macro RESTORE_SAVE_EVERYTHING_FRAME
@@ -1004,10 +1004,10 @@ END \name
.endm
// Macro for string and type resolution and initialization.
-.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL name, entrypoint
+.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL name, entrypoint, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
.extern \entrypoint
ENTRY \name
- SETUP_SAVE_EVERYTHING_FRAME r1 @ save everything in case of GC
+ SETUP_SAVE_EVERYTHING_FRAME r1, \runtime_method_offset @ save everything in case of GC
mov r1, r9 @ pass Thread::Current
bl \entrypoint @ (uint32_t index, Thread*)
cbz r0, 1f @ If result is null, deliver the OOME.
@@ -1021,8 +1021,12 @@ ENTRY \name
END \name
.endm
-ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
-ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode
+.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT name, entrypoint
+ ONE_ARG_SAVE_EVERYTHING_DOWNCALL \name, \entrypoint, RUNTIME_SAVE_EVERYTHING_FOR_CLINIT_METHOD_OFFSET
+.endm
+
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_type, artInitializeTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
@@ -1537,7 +1541,7 @@ ENTRY art_quick_test_suspend
1:
mov rSUSPEND, #SUSPEND_CHECK_INTERVAL @ reset rSUSPEND to SUSPEND_CHECK_INTERVAL
#endif
- SETUP_SAVE_EVERYTHING_FRAME r0 @ save everything for GC stack crawl
+ SETUP_SAVE_EVERYTHING_FRAME r0, RUNTIME_SAVE_EVERYTHING_FOR_SUSPEND_CHECK_METHOD_OFFSET @ save everything for GC stack crawl
mov r0, rSELF
bl artTestSuspendFromCode @ (Thread*)
RESTORE_SAVE_EVERYTHING_FRAME
diff --git a/runtime/arch/arm/quick_method_frame_info_arm.h b/runtime/arch/arm/quick_method_frame_info_arm.h
index 39061f0d4d..5c5b81baae 100644
--- a/runtime/arch/arm/quick_method_frame_info_arm.h
+++ b/runtime/arch/arm/quick_method_frame_info_arm.h
@@ -56,6 +56,7 @@ static constexpr uint32_t kArmCalleeSaveFpEverythingSpills =
kArmCalleeSaveFpArgSpills | kArmCalleeSaveFpAllSpills;
constexpr uint32_t ArmCalleeSaveCoreSpills(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return kArmCalleeSaveAlwaysSpills | kArmCalleeSaveRefSpills |
(type == CalleeSaveType::kSaveRefsAndArgs ? kArmCalleeSaveArgSpills : 0) |
(type == CalleeSaveType::kSaveAllCalleeSaves ? kArmCalleeSaveAllSpills : 0) |
@@ -63,6 +64,7 @@ constexpr uint32_t ArmCalleeSaveCoreSpills(CalleeSaveType type) {
}
constexpr uint32_t ArmCalleeSaveFpSpills(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return kArmCalleeSaveFpAlwaysSpills | kArmCalleeSaveFpRefSpills |
(type == CalleeSaveType::kSaveRefsAndArgs ? kArmCalleeSaveFpArgSpills : 0) |
(type == CalleeSaveType::kSaveAllCalleeSaves ? kArmCalleeSaveFpAllSpills : 0) |
@@ -70,29 +72,34 @@ constexpr uint32_t ArmCalleeSaveFpSpills(CalleeSaveType type) {
}
constexpr uint32_t ArmCalleeSaveFrameSize(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return RoundUp((POPCOUNT(ArmCalleeSaveCoreSpills(type)) /* gprs */ +
POPCOUNT(ArmCalleeSaveFpSpills(type)) /* fprs */ +
1 /* Method* */) * static_cast<size_t>(kArmPointerSize), kStackAlignment);
}
constexpr QuickMethodFrameInfo ArmCalleeSaveMethodFrameInfo(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return QuickMethodFrameInfo(ArmCalleeSaveFrameSize(type),
ArmCalleeSaveCoreSpills(type),
ArmCalleeSaveFpSpills(type));
}
constexpr size_t ArmCalleeSaveFpr1Offset(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return ArmCalleeSaveFrameSize(type) -
(POPCOUNT(ArmCalleeSaveCoreSpills(type)) +
POPCOUNT(ArmCalleeSaveFpSpills(type))) * static_cast<size_t>(kArmPointerSize);
}
constexpr size_t ArmCalleeSaveGpr1Offset(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return ArmCalleeSaveFrameSize(type) -
POPCOUNT(ArmCalleeSaveCoreSpills(type)) * static_cast<size_t>(kArmPointerSize);
}
constexpr size_t ArmCalleeSaveLrOffset(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return ArmCalleeSaveFrameSize(type) -
POPCOUNT(ArmCalleeSaveCoreSpills(type) & (-(1 << LR))) * static_cast<size_t>(kArmPointerSize);
}
diff --git a/runtime/arch/arm64/asm_support_arm64.h b/runtime/arch/arm64/asm_support_arm64.h
index 6b7720023e..57376d0c4f 100644
--- a/runtime/arch/arm64/asm_support_arm64.h
+++ b/runtime/arch/arm64/asm_support_arm64.h
@@ -23,6 +23,8 @@
#define FRAME_SIZE_SAVE_REFS_ONLY 96
#define FRAME_SIZE_SAVE_REFS_AND_ARGS 224
#define FRAME_SIZE_SAVE_EVERYTHING 512
+#define FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT FRAME_SIZE_SAVE_EVERYTHING
+#define FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK FRAME_SIZE_SAVE_EVERYTHING
// The offset from art_quick_read_barrier_mark_introspection to the array switch cases,
// i.e. art_quick_read_barrier_mark_introspection_arrays.
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index d15f5b85ec..3d8ca402cf 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -287,7 +287,7 @@
* when the SP has already been decremented by FRAME_SIZE_SAVE_EVERYTHING
* and saving registers x29 and LR is handled elsewhere.
*/
-.macro SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP_SKIP_X29_LR
+.macro SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP_SKIP_X29_LR runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
// Ugly compile-time check, but we only have the preprocessor.
#if (FRAME_SIZE_SAVE_EVERYTHING != 512)
#error "FRAME_SIZE_SAVE_EVERYTHING(ARM64) size not as expected."
@@ -337,7 +337,7 @@
ldr xIP0, [xIP0] // art::Runtime* xIP0 = art::Runtime::instance_;
// ArtMethod* xIP0 = Runtime::instance_->callee_save_methods_[kSaveEverything];
- ldr xIP0, [xIP0, RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET]
+ ldr xIP0, [xIP0, \runtime_method_offset]
// Store ArtMethod* Runtime::callee_save_methods_[kSaveEverything].
str xIP0, [sp]
@@ -350,10 +350,10 @@
* Macro that sets up the callee save frame to conform with
* Runtime::CreateCalleeSaveMethod(kSaveEverything)
*/
-.macro SETUP_SAVE_EVERYTHING_FRAME
+.macro SETUP_SAVE_EVERYTHING_FRAME runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
INCREASE_FRAME 512
SAVE_TWO_REGS x29, xLR, 496
- SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP_SKIP_X29_LR
+ SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP_SKIP_X29_LR \runtime_method_offset
.endm
.macro RESTORE_SAVE_EVERYTHING_FRAME_KEEP_X0
@@ -398,7 +398,7 @@
.endm
.macro RESTORE_SAVE_EVERYTHING_FRAME
- RESTORE_REG x0, 264
+ RESTORE_REG x0, 264
RESTORE_SAVE_EVERYTHING_FRAME_KEEP_X0
.endm
@@ -1593,10 +1593,10 @@ END \name
.endm
// Macro for string and type resolution and initialization.
-.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL name, entrypoint
+.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL name, entrypoint, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
.extern \entrypoint
ENTRY \name
- SETUP_SAVE_EVERYTHING_FRAME // save everything for stack crawl
+ SETUP_SAVE_EVERYTHING_FRAME \runtime_method_offset // save everything for stack crawl
mov x1, xSELF // pass Thread::Current
bl \entrypoint // (int32_t index, Thread* self)
cbz w0, 1f // If result is null, deliver the OOME.
@@ -1611,6 +1611,10 @@ ENTRY \name
END \name
.endm
+.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT name, entrypoint
+ ONE_ARG_SAVE_EVERYTHING_DOWNCALL \name, \entrypoint, RUNTIME_SAVE_EVERYTHING_FOR_CLINIT_METHOD_OFFSET
+.endm
+
.macro RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
cbz w0, 1f // result zero branch over
ret // return
@@ -1629,9 +1633,8 @@ TWO_ARG_REF_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode,
* initializer and deliver the exception on error. On success the static storage base is
* returned.
*/
-ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
-
-ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_type, artInitializeTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
@@ -2008,7 +2011,7 @@ GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_tlab, artAllocArrayFr
*/
.extern artTestSuspendFromCode
ENTRY art_quick_test_suspend
- SETUP_SAVE_EVERYTHING_FRAME // save callee saves for stack crawl
+ SETUP_SAVE_EVERYTHING_FRAME RUNTIME_SAVE_EVERYTHING_FOR_SUSPEND_CHECK_METHOD_OFFSET // save callee saves for stack crawl
mov x0, xSELF
bl artTestSuspendFromCode // (Thread*)
RESTORE_SAVE_EVERYTHING_FRAME
diff --git a/runtime/arch/arm64/quick_method_frame_info_arm64.h b/runtime/arch/arm64/quick_method_frame_info_arm64.h
index c231d4d3d4..3e6f6c6e3b 100644
--- a/runtime/arch/arm64/quick_method_frame_info_arm64.h
+++ b/runtime/arch/arm64/quick_method_frame_info_arm64.h
@@ -80,6 +80,7 @@ static constexpr uint32_t kArm64CalleeSaveFpEverythingSpills =
(1 << art::arm64::D30) | (1 << art::arm64::D31);
constexpr uint32_t Arm64CalleeSaveCoreSpills(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return kArm64CalleeSaveAlwaysSpills | kArm64CalleeSaveRefSpills |
(type == CalleeSaveType::kSaveRefsAndArgs ? kArm64CalleeSaveArgSpills : 0) |
(type == CalleeSaveType::kSaveAllCalleeSaves ? kArm64CalleeSaveAllSpills : 0) |
@@ -87,6 +88,7 @@ constexpr uint32_t Arm64CalleeSaveCoreSpills(CalleeSaveType type) {
}
constexpr uint32_t Arm64CalleeSaveFpSpills(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return kArm64CalleeSaveFpAlwaysSpills | kArm64CalleeSaveFpRefSpills |
(type == CalleeSaveType::kSaveRefsAndArgs ? kArm64CalleeSaveFpArgSpills : 0) |
(type == CalleeSaveType::kSaveAllCalleeSaves ? kArm64CalleeSaveFpAllSpills : 0) |
@@ -94,29 +96,34 @@ constexpr uint32_t Arm64CalleeSaveFpSpills(CalleeSaveType type) {
}
constexpr uint32_t Arm64CalleeSaveFrameSize(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return RoundUp((POPCOUNT(Arm64CalleeSaveCoreSpills(type)) /* gprs */ +
POPCOUNT(Arm64CalleeSaveFpSpills(type)) /* fprs */ +
1 /* Method* */) * static_cast<size_t>(kArm64PointerSize), kStackAlignment);
}
constexpr QuickMethodFrameInfo Arm64CalleeSaveMethodFrameInfo(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return QuickMethodFrameInfo(Arm64CalleeSaveFrameSize(type),
Arm64CalleeSaveCoreSpills(type),
Arm64CalleeSaveFpSpills(type));
}
constexpr size_t Arm64CalleeSaveFpr1Offset(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return Arm64CalleeSaveFrameSize(type) -
(POPCOUNT(Arm64CalleeSaveCoreSpills(type)) +
POPCOUNT(Arm64CalleeSaveFpSpills(type))) * static_cast<size_t>(kArm64PointerSize);
}
constexpr size_t Arm64CalleeSaveGpr1Offset(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return Arm64CalleeSaveFrameSize(type) -
POPCOUNT(Arm64CalleeSaveCoreSpills(type)) * static_cast<size_t>(kArm64PointerSize);
}
constexpr size_t Arm64CalleeSaveLrOffset(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return Arm64CalleeSaveFrameSize(type) -
POPCOUNT(Arm64CalleeSaveCoreSpills(type) & (-(1 << LR))) *
static_cast<size_t>(kArm64PointerSize);
diff --git a/runtime/arch/mips/asm_support_mips.h b/runtime/arch/mips/asm_support_mips.h
index 9d8572ffb5..2edd63f58a 100644
--- a/runtime/arch/mips/asm_support_mips.h
+++ b/runtime/arch/mips/asm_support_mips.h
@@ -23,6 +23,8 @@
#define FRAME_SIZE_SAVE_REFS_ONLY 48
#define FRAME_SIZE_SAVE_REFS_AND_ARGS 112
#define FRAME_SIZE_SAVE_EVERYTHING 256
+#define FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT FRAME_SIZE_SAVE_EVERYTHING
+#define FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK FRAME_SIZE_SAVE_EVERYTHING
// &art_quick_read_barrier_mark_introspection is the first of many entry points:
// 21 entry points for long field offsets, large array indices and variable array indices
diff --git a/runtime/arch/mips/quick_method_frame_info_mips.h b/runtime/arch/mips/quick_method_frame_info_mips.h
index 01879a5cea..45a21ab942 100644
--- a/runtime/arch/mips/quick_method_frame_info_mips.h
+++ b/runtime/arch/mips/quick_method_frame_info_mips.h
@@ -65,6 +65,7 @@ static constexpr uint32_t kMipsCalleeSaveFpEverythingSpills =
(1 << art::mips::F28) | (1 << art::mips::F29) | (1 << art::mips::F30) | (1u << art::mips::F31);
constexpr uint32_t MipsCalleeSaveCoreSpills(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return kMipsCalleeSaveAlwaysSpills | kMipsCalleeSaveRefSpills |
(type == CalleeSaveType::kSaveRefsAndArgs ? kMipsCalleeSaveArgSpills : 0) |
(type == CalleeSaveType::kSaveAllCalleeSaves ? kMipsCalleeSaveAllSpills : 0) |
@@ -72,6 +73,7 @@ constexpr uint32_t MipsCalleeSaveCoreSpills(CalleeSaveType type) {
}
constexpr uint32_t MipsCalleeSaveFPSpills(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return kMipsCalleeSaveFpAlwaysSpills | kMipsCalleeSaveFpRefSpills |
(type == CalleeSaveType::kSaveRefsAndArgs ? kMipsCalleeSaveFpArgSpills : 0) |
(type == CalleeSaveType::kSaveAllCalleeSaves ? kMipsCalleeSaveAllFPSpills : 0) |
@@ -79,12 +81,14 @@ constexpr uint32_t MipsCalleeSaveFPSpills(CalleeSaveType type) {
}
constexpr uint32_t MipsCalleeSaveFrameSize(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return RoundUp((POPCOUNT(MipsCalleeSaveCoreSpills(type)) /* gprs */ +
POPCOUNT(MipsCalleeSaveFPSpills(type)) /* fprs */ +
1 /* Method* */) * static_cast<size_t>(kMipsPointerSize), kStackAlignment);
}
constexpr QuickMethodFrameInfo MipsCalleeSaveMethodFrameInfo(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return QuickMethodFrameInfo(MipsCalleeSaveFrameSize(type),
MipsCalleeSaveCoreSpills(type),
MipsCalleeSaveFPSpills(type));
diff --git a/runtime/arch/mips64/asm_support_mips64.h b/runtime/arch/mips64/asm_support_mips64.h
index 7185da550c..a8e907eca5 100644
--- a/runtime/arch/mips64/asm_support_mips64.h
+++ b/runtime/arch/mips64/asm_support_mips64.h
@@ -27,6 +27,8 @@
#define FRAME_SIZE_SAVE_REFS_AND_ARGS 208
// $f0-$f31, $at, $v0-$v1, $a0-$a7, $t0-$t3, $s0-$s7, $t8-$t9, $gp, $s8, $ra + padding + method*
#define FRAME_SIZE_SAVE_EVERYTHING 496
+#define FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT FRAME_SIZE_SAVE_EVERYTHING
+#define FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK FRAME_SIZE_SAVE_EVERYTHING
// &art_quick_read_barrier_mark_introspection is the first of many entry points:
// 20 entry points for long field offsets, large array indices and variable array indices
diff --git a/runtime/arch/mips64/quick_method_frame_info_mips64.h b/runtime/arch/mips64/quick_method_frame_info_mips64.h
index a55ab0e196..520f6319d5 100644
--- a/runtime/arch/mips64/quick_method_frame_info_mips64.h
+++ b/runtime/arch/mips64/quick_method_frame_info_mips64.h
@@ -72,6 +72,7 @@ static constexpr uint32_t kMips64CalleeSaveFpEverythingSpills =
(1 << art::mips64::F30) | (1 << art::mips64::F31);
constexpr uint32_t Mips64CalleeSaveCoreSpills(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return kMips64CalleeSaveAlwaysSpills | kMips64CalleeSaveRefSpills |
(type == CalleeSaveType::kSaveRefsAndArgs ? kMips64CalleeSaveArgSpills : 0) |
(type == CalleeSaveType::kSaveAllCalleeSaves ? kMips64CalleeSaveAllSpills : 0) |
@@ -79,6 +80,7 @@ constexpr uint32_t Mips64CalleeSaveCoreSpills(CalleeSaveType type) {
}
constexpr uint32_t Mips64CalleeSaveFpSpills(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return kMips64CalleeSaveFpRefSpills |
(type == CalleeSaveType::kSaveRefsAndArgs ? kMips64CalleeSaveFpArgSpills : 0) |
(type == CalleeSaveType::kSaveAllCalleeSaves ? kMips64CalleeSaveFpAllSpills : 0) |
@@ -86,12 +88,14 @@ constexpr uint32_t Mips64CalleeSaveFpSpills(CalleeSaveType type) {
}
constexpr uint32_t Mips64CalleeSaveFrameSize(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return RoundUp((POPCOUNT(Mips64CalleeSaveCoreSpills(type)) /* gprs */ +
POPCOUNT(Mips64CalleeSaveFpSpills(type)) /* fprs */ +
+ 1 /* Method* */) * static_cast<size_t>(kMips64PointerSize), kStackAlignment);
}
constexpr QuickMethodFrameInfo Mips64CalleeSaveMethodFrameInfo(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return QuickMethodFrameInfo(Mips64CalleeSaveFrameSize(type),
Mips64CalleeSaveCoreSpills(type),
Mips64CalleeSaveFpSpills(type));
diff --git a/runtime/arch/x86/asm_support_x86.h b/runtime/arch/x86/asm_support_x86.h
index 2bba08d571..737d736f01 100644
--- a/runtime/arch/x86/asm_support_x86.h
+++ b/runtime/arch/x86/asm_support_x86.h
@@ -23,5 +23,7 @@
#define FRAME_SIZE_SAVE_REFS_ONLY 32
#define FRAME_SIZE_SAVE_REFS_AND_ARGS (32 + 32)
#define FRAME_SIZE_SAVE_EVERYTHING (48 + 64)
+#define FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT FRAME_SIZE_SAVE_EVERYTHING
+#define FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK FRAME_SIZE_SAVE_EVERYTHING
#endif // ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_H_
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 48d2de9567..4e5e93ac5a 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -226,7 +226,7 @@ END_MACRO
* Runtime::CreateCalleeSaveMethod(kSaveEverything)
* when EDI and ESI are already saved.
*/
-MACRO2(SETUP_SAVE_EVERYTHING_FRAME_EDI_ESI_SAVED, got_reg, temp_reg)
+MACRO3(SETUP_SAVE_EVERYTHING_FRAME_EDI_ESI_SAVED, got_reg, temp_reg, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET)
// Save core registers from highest to lowest to agree with core spills bitmap.
// EDI and ESI, or at least placeholders for them, are already on the stack.
PUSH ebp
@@ -252,7 +252,7 @@ MACRO2(SETUP_SAVE_EVERYTHING_FRAME_EDI_ESI_SAVED, got_reg, temp_reg)
movl SYMBOL(_ZN3art7Runtime9instance_E)@GOT(REG_VAR(got_reg)), REG_VAR(temp_reg)
movl (REG_VAR(temp_reg)), REG_VAR(temp_reg)
// Push save everything callee-save method.
- pushl RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET(REG_VAR(temp_reg))
+ pushl \runtime_method_offset(REG_VAR(temp_reg))
CFI_ADJUST_CFA_OFFSET(4)
// Store esp as the stop quick frame.
movl %esp, %fs:THREAD_TOP_QUICK_FRAME_OFFSET
@@ -269,20 +269,20 @@ END_MACRO
* Runtime::CreateCalleeSaveMethod(kSaveEverything)
* when EDI is already saved.
*/
-MACRO2(SETUP_SAVE_EVERYTHING_FRAME_EDI_SAVED, got_reg, temp_reg)
+MACRO3(SETUP_SAVE_EVERYTHING_FRAME_EDI_SAVED, got_reg, temp_reg, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET)
// Save core registers from highest to lowest to agree with core spills bitmap.
// EDI, or at least a placeholder for it, is already on the stack.
PUSH esi
- SETUP_SAVE_EVERYTHING_FRAME_EDI_ESI_SAVED RAW_VAR(got_reg), RAW_VAR(temp_reg)
+ SETUP_SAVE_EVERYTHING_FRAME_EDI_ESI_SAVED RAW_VAR(got_reg), RAW_VAR(temp_reg), \runtime_method_offset
END_MACRO
/*
* Macro that sets up the callee save frame to conform with
* Runtime::CreateCalleeSaveMethod(kSaveEverything)
*/
-MACRO2(SETUP_SAVE_EVERYTHING_FRAME, got_reg, temp_reg)
+MACRO3(SETUP_SAVE_EVERYTHING_FRAME, got_reg, temp_reg, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET)
PUSH edi
- SETUP_SAVE_EVERYTHING_FRAME_EDI_SAVED RAW_VAR(got_reg), RAW_VAR(temp_reg)
+ SETUP_SAVE_EVERYTHING_FRAME_EDI_SAVED RAW_VAR(got_reg), RAW_VAR(temp_reg), \runtime_method_offset
END_MACRO
MACRO0(RESTORE_SAVE_EVERYTHING_FRAME_FRPS)
@@ -923,9 +923,9 @@ MACRO3(THREE_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
END_MACRO
// Macro for string and type resolution and initialization.
-MACRO2(ONE_ARG_SAVE_EVERYTHING_DOWNCALL, c_name, cxx_name)
+MACRO3(ONE_ARG_SAVE_EVERYTHING_DOWNCALL, c_name, cxx_name, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET)
DEFINE_FUNCTION VAR(c_name)
- SETUP_SAVE_EVERYTHING_FRAME ebx, ebx // save ref containing registers for GC
+ SETUP_SAVE_EVERYTHING_FRAME ebx, ebx, \runtime_method_offset // save ref containing registers for GC
// Outgoing argument set up
subl MACRO_LITERAL(8), %esp // push padding
CFI_ADJUST_CFA_OFFSET(8)
@@ -947,6 +947,10 @@ MACRO2(ONE_ARG_SAVE_EVERYTHING_DOWNCALL, c_name, cxx_name)
END_FUNCTION VAR(c_name)
END_MACRO
+MACRO2(ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT, c_name, cxx_name)
+ ONE_ARG_SAVE_EVERYTHING_DOWNCALL \c_name, \cxx_name, RUNTIME_SAVE_EVERYTHING_FOR_CLINIT_METHOD_OFFSET
+END_MACRO
+
MACRO0(RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER)
testl %eax, %eax // eax == 0 ?
jz 1f // if eax == 0 goto 1
@@ -1270,8 +1274,8 @@ GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved16_tlab, artAllocArrayFr
GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved32_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_32
GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_64
-ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
-ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_type, artInitializeTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
@@ -1598,7 +1602,7 @@ DEFINE_FUNCTION art_quick_memcpy
END_FUNCTION art_quick_memcpy
DEFINE_FUNCTION art_quick_test_suspend
- SETUP_SAVE_EVERYTHING_FRAME ebx, ebx // save everything for GC
+ SETUP_SAVE_EVERYTHING_FRAME ebx, ebx, RUNTIME_SAVE_EVERYTHING_FOR_SUSPEND_CHECK_METHOD_OFFSET // save everything for GC
// Outgoing argument set up
subl MACRO_LITERAL(12), %esp // push padding
CFI_ADJUST_CFA_OFFSET(12)
diff --git a/runtime/arch/x86/quick_method_frame_info_x86.h b/runtime/arch/x86/quick_method_frame_info_x86.h
index 8342c9fe03..9a6633365c 100644
--- a/runtime/arch/x86/quick_method_frame_info_x86.h
+++ b/runtime/arch/x86/quick_method_frame_info_x86.h
@@ -57,23 +57,27 @@ static constexpr uint32_t kX86CalleeSaveFpEverythingSpills =
(1 << art::x86::XMM6) | (1 << art::x86::XMM7);
constexpr uint32_t X86CalleeSaveCoreSpills(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return kX86CalleeSaveAlwaysSpills | kX86CalleeSaveRefSpills |
(type == CalleeSaveType::kSaveRefsAndArgs ? kX86CalleeSaveArgSpills : 0) |
(type == CalleeSaveType::kSaveEverything ? kX86CalleeSaveEverythingSpills : 0);
}
constexpr uint32_t X86CalleeSaveFpSpills(CalleeSaveType type) {
- return (type == CalleeSaveType::kSaveRefsAndArgs ? kX86CalleeSaveFpArgSpills : 0) |
- (type == CalleeSaveType::kSaveEverything ? kX86CalleeSaveFpEverythingSpills : 0);
+ type = GetCanonicalCalleeSaveType(type);
+ return (type == CalleeSaveType::kSaveRefsAndArgs ? kX86CalleeSaveFpArgSpills : 0) |
+ (type == CalleeSaveType::kSaveEverything ? kX86CalleeSaveFpEverythingSpills : 0);
}
constexpr uint32_t X86CalleeSaveFrameSize(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return RoundUp((POPCOUNT(X86CalleeSaveCoreSpills(type)) /* gprs */ +
2 * POPCOUNT(X86CalleeSaveFpSpills(type)) /* fprs */ +
1 /* Method* */) * static_cast<size_t>(kX86PointerSize), kStackAlignment);
}
constexpr QuickMethodFrameInfo X86CalleeSaveMethodFrameInfo(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return QuickMethodFrameInfo(X86CalleeSaveFrameSize(type),
X86CalleeSaveCoreSpills(type),
X86CalleeSaveFpSpills(type));
diff --git a/runtime/arch/x86_64/asm_support_x86_64.h b/runtime/arch/x86_64/asm_support_x86_64.h
index a4446d3345..51befbe7b8 100644
--- a/runtime/arch/x86_64/asm_support_x86_64.h
+++ b/runtime/arch/x86_64/asm_support_x86_64.h
@@ -23,5 +23,7 @@
#define FRAME_SIZE_SAVE_REFS_ONLY (64 + 4*8)
#define FRAME_SIZE_SAVE_REFS_AND_ARGS (112 + 12*8)
#define FRAME_SIZE_SAVE_EVERYTHING (144 + 16*8)
+#define FRAME_SIZE_SAVE_EVERYTHING_FOR_CLINIT FRAME_SIZE_SAVE_EVERYTHING
+#define FRAME_SIZE_SAVE_EVERYTHING_FOR_SUSPEND_CHECK FRAME_SIZE_SAVE_EVERYTHING
#endif // ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_H_
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 0a9199e7e9..73e86100f6 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -272,7 +272,7 @@ END_MACRO
* Runtime::CreateCalleeSaveMethod(kSaveEverything)
* when R14 and R15 are already saved.
*/
-MACRO0(SETUP_SAVE_EVERYTHING_FRAME_R14_R15_SAVED)
+MACRO1(SETUP_SAVE_EVERYTHING_FRAME_R14_R15_SAVED, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET)
#if defined(__APPLE__)
int3
int3
@@ -316,7 +316,7 @@ MACRO0(SETUP_SAVE_EVERYTHING_FRAME_R14_R15_SAVED)
movq %xmm14, 120(%rsp)
movq %xmm15, 128(%rsp)
// Push ArtMethod* for save everything frame method.
- pushq RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET(%r10)
+ pushq \runtime_method_offset(%r10)
CFI_ADJUST_CFA_OFFSET(8)
// Store rsp as the top quick frame.
movq %rsp, %gs:THREAD_TOP_QUICK_FRAME_OFFSET
@@ -334,18 +334,18 @@ END_MACRO
* Runtime::CreateCalleeSaveMethod(kSaveEverything)
* when R15 is already saved.
*/
-MACRO0(SETUP_SAVE_EVERYTHING_FRAME_R15_SAVED)
+MACRO1(SETUP_SAVE_EVERYTHING_FRAME_R15_SAVED, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET)
PUSH r14
- SETUP_SAVE_EVERYTHING_FRAME_R14_R15_SAVED
+ SETUP_SAVE_EVERYTHING_FRAME_R14_R15_SAVED \runtime_method_offset
END_MACRO
/*
* Macro that sets up the callee save frame to conform with
* Runtime::CreateCalleeSaveMethod(kSaveEverything)
*/
-MACRO0(SETUP_SAVE_EVERYTHING_FRAME)
+MACRO1(SETUP_SAVE_EVERYTHING_FRAME, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET)
PUSH r15
- SETUP_SAVE_EVERYTHING_FRAME_R15_SAVED
+ SETUP_SAVE_EVERYTHING_FRAME_R15_SAVED \runtime_method_offset
END_MACRO
MACRO0(RESTORE_SAVE_EVERYTHING_FRAME_FRPS)
@@ -951,9 +951,9 @@ MACRO3(THREE_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
END_MACRO
// Macro for string and type resolution and initialization.
-MACRO2(ONE_ARG_SAVE_EVERYTHING_DOWNCALL, c_name, cxx_name)
+MACRO3(ONE_ARG_SAVE_EVERYTHING_DOWNCALL, c_name, cxx_name, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET)
DEFINE_FUNCTION VAR(c_name)
- SETUP_SAVE_EVERYTHING_FRAME // save everything for GC
+ SETUP_SAVE_EVERYTHING_FRAME \runtime_method_offset // save everything for GC
// Outgoing argument set up
movl %eax, %edi // pass string index
movq %gs:THREAD_SELF_OFFSET, %rsi // pass Thread::Current()
@@ -970,6 +970,10 @@ MACRO2(ONE_ARG_SAVE_EVERYTHING_DOWNCALL, c_name, cxx_name)
END_FUNCTION VAR(c_name)
END_MACRO
+MACRO2(ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT, c_name, cxx_name)
+ ONE_ARG_SAVE_EVERYTHING_DOWNCALL \c_name, \cxx_name, RUNTIME_SAVE_EVERYTHING_FOR_CLINIT_METHOD_OFFSET
+END_MACRO
+
MACRO0(RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER)
testq %rax, %rax // rax == 0 ?
jz 1f // if rax == 0 goto 1
@@ -1290,8 +1294,8 @@ DEFINE_FUNCTION art_quick_alloc_object_initialized_region_tlab
ALLOC_OBJECT_TLAB_SLOW_PATH artAllocObjectFromCodeInitializedRegionTLAB
END_FUNCTION art_quick_alloc_object_initialized_region_tlab
-ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
-ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
+ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_type, artInitializeTypeFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
@@ -1575,7 +1579,7 @@ DEFINE_FUNCTION art_quick_memcpy
END_FUNCTION art_quick_memcpy
DEFINE_FUNCTION art_quick_test_suspend
- SETUP_SAVE_EVERYTHING_FRAME // save everything for GC
+ SETUP_SAVE_EVERYTHING_FRAME RUNTIME_SAVE_EVERYTHING_FOR_SUSPEND_CHECK_METHOD_OFFSET // save everything for GC
// Outgoing argument set up
movq %gs:THREAD_SELF_OFFSET, %rdi // pass Thread::Current()
call SYMBOL(artTestSuspendFromCode) // (Thread*)
diff --git a/runtime/arch/x86_64/quick_method_frame_info_x86_64.h b/runtime/arch/x86_64/quick_method_frame_info_x86_64.h
index 425d616e76..ebf976ef71 100644
--- a/runtime/arch/x86_64/quick_method_frame_info_x86_64.h
+++ b/runtime/arch/x86_64/quick_method_frame_info_x86_64.h
@@ -56,24 +56,28 @@ static constexpr uint32_t kX86_64CalleeSaveFpEverythingSpills =
(1 << art::x86_64::XMM10) | (1 << art::x86_64::XMM11);
constexpr uint32_t X86_64CalleeSaveCoreSpills(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return kX86_64CalleeSaveAlwaysSpills | kX86_64CalleeSaveRefSpills |
(type == CalleeSaveType::kSaveRefsAndArgs ? kX86_64CalleeSaveArgSpills : 0) |
(type == CalleeSaveType::kSaveEverything ? kX86_64CalleeSaveEverythingSpills : 0);
}
constexpr uint32_t X86_64CalleeSaveFpSpills(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return kX86_64CalleeSaveFpSpills |
(type == CalleeSaveType::kSaveRefsAndArgs ? kX86_64CalleeSaveFpArgSpills : 0) |
(type == CalleeSaveType::kSaveEverything ? kX86_64CalleeSaveFpEverythingSpills : 0);
}
constexpr uint32_t X86_64CalleeSaveFrameSize(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return RoundUp((POPCOUNT(X86_64CalleeSaveCoreSpills(type)) /* gprs */ +
POPCOUNT(X86_64CalleeSaveFpSpills(type)) /* fprs */ +
1 /* Method* */) * static_cast<size_t>(kX86_64PointerSize), kStackAlignment);
}
constexpr QuickMethodFrameInfo X86_64CalleeSaveMethodFrameInfo(CalleeSaveType type) {
+ type = GetCanonicalCalleeSaveType(type);
return QuickMethodFrameInfo(X86_64CalleeSaveFrameSize(type),
X86_64CalleeSaveCoreSpills(type),
X86_64CalleeSaveFpSpills(type));
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index fad927804e..50e91447a9 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -285,6 +285,10 @@ inline const char* ArtMethod::GetName() {
return "<runtime internal callee-save reference and argument registers method>";
} else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverything)) {
return "<runtime internal save-every-register method>";
+ } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForClinit)) {
+ return "<runtime internal save-every-register method for clinit>";
+ } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForSuspendCheck)) {
+ return "<runtime internal save-every-register method for suspend check>";
} else {
return "<unknown runtime internal method>";
}
diff --git a/runtime/base/callee_save_type.h b/runtime/base/callee_save_type.h
index 501b296d4f..e9cd63c3a0 100644
--- a/runtime/base/callee_save_type.h
+++ b/runtime/base/callee_save_type.h
@@ -28,10 +28,20 @@ enum class CalleeSaveType : uint32_t {
kSaveRefsOnly, // Only those callee-save registers that can hold references.
kSaveRefsAndArgs, // References (see above) and arguments (usually caller-save registers).
kSaveEverything, // All registers, including both callee-save and caller-save.
+ kSaveEverythingForClinit, // Special kSaveEverything for clinit.
+ kSaveEverythingForSuspendCheck, // Special kSaveEverything for suspend check.
kLastCalleeSaveType // Value used for iteration.
};
std::ostream& operator<<(std::ostream& os, const CalleeSaveType& rhs);
+static inline constexpr CalleeSaveType GetCanonicalCalleeSaveType(CalleeSaveType type) {
+ if (type == CalleeSaveType::kSaveEverythingForClinit ||
+ type == CalleeSaveType::kSaveEverythingForSuspendCheck) {
+ return CalleeSaveType::kSaveEverything;
+ }
+ return type;
+}
+
} // namespace art
#endif // ART_RUNTIME_BASE_CALLEE_SAVE_TYPE_H_
diff --git a/runtime/base/unix_file/fd_file.cc b/runtime/base/unix_file/fd_file.cc
index 0c73ce7ef2..eb8ced00a8 100644
--- a/runtime/base/unix_file/fd_file.cc
+++ b/runtime/base/unix_file/fd_file.cc
@@ -438,4 +438,30 @@ bool FdFile::ResetOffset() {
return true;
}
+int FdFile::Compare(FdFile* other) {
+ int64_t length = GetLength();
+ int64_t length2 = other->GetLength();
+ if (length != length2) {
+ return length < length2 ? -1 : 1;
+ }
+ static const size_t kBufferSize = 4096;
+ std::unique_ptr<uint8_t[]> buffer1(new uint8_t[kBufferSize]);
+ std::unique_ptr<uint8_t[]> buffer2(new uint8_t[kBufferSize]);
+ while (length > 0) {
+ size_t len = std::min(kBufferSize, static_cast<size_t>(length));
+ if (!ReadFully(&buffer1[0], len)) {
+ return -1;
+ }
+ if (!other->ReadFully(&buffer2[0], len)) {
+ return 1;
+ }
+ int result = memcmp(&buffer1[0], &buffer2[0], len);
+ if (result != 0) {
+ return result;
+ }
+ length -= len;
+ }
+ return 0;
+}
+
} // namespace unix_file
diff --git a/runtime/base/unix_file/fd_file.h b/runtime/base/unix_file/fd_file.h
index e07c3fd800..91b08bcb4d 100644
--- a/runtime/base/unix_file/fd_file.h
+++ b/runtime/base/unix_file/fd_file.h
@@ -145,6 +145,11 @@ class FdFile : public RandomAccessFile {
// WARNING: Only use this when you know what you're doing!
void MarkUnchecked();
+ // Compare against another file. Returns 0 if the files are equivalent, otherwise returns -1 or 1
+ // depending on if the lenghts are different. If the lengths are the same, the function returns
+ // the difference of the first byte that differs.
+ int Compare(FdFile* other);
+
protected:
// If the guard state indicates checking (!=kNoCheck), go to the target state "target". Print the
// given warning if the current state is or exceeds warn_threshold.
diff --git a/runtime/base/unix_file/fd_file_test.cc b/runtime/base/unix_file/fd_file_test.cc
index 6aef348433..8b1a115a26 100644
--- a/runtime/base/unix_file/fd_file_test.cc
+++ b/runtime/base/unix_file/fd_file_test.cc
@@ -220,4 +220,58 @@ TEST_F(FdFileTest, EraseWithPathUnlinks) {
EXPECT_FALSE(art::OS::FileExists(filename.c_str())) << filename;
}
+TEST_F(FdFileTest, Compare) {
+ std::vector<uint8_t> buffer;
+ constexpr int64_t length = 17 * art::KB;
+ for (size_t i = 0; i < length; ++i) {
+ buffer.push_back(static_cast<uint8_t>(i));
+ }
+
+ auto reset_compare = [&](art::ScratchFile& a, art::ScratchFile& b) {
+ a.GetFile()->ResetOffset();
+ b.GetFile()->ResetOffset();
+ return a.GetFile()->Compare(b.GetFile());
+ };
+
+ art::ScratchFile tmp;
+ EXPECT_TRUE(tmp.GetFile()->WriteFully(&buffer[0], length));
+ EXPECT_EQ(tmp.GetFile()->GetLength(), length);
+
+ art::ScratchFile tmp2;
+ EXPECT_TRUE(tmp2.GetFile()->WriteFully(&buffer[0], length));
+ EXPECT_EQ(tmp2.GetFile()->GetLength(), length);
+
+ // Basic equality check.
+ tmp.GetFile()->ResetOffset();
+ tmp2.GetFile()->ResetOffset();
+ // Files should be the same.
+ EXPECT_EQ(reset_compare(tmp, tmp2), 0);
+
+ // Change a byte near the start.
+ ++buffer[2];
+ art::ScratchFile tmp3;
+ EXPECT_TRUE(tmp3.GetFile()->WriteFully(&buffer[0], length));
+ --buffer[2];
+ EXPECT_NE(reset_compare(tmp, tmp3), 0);
+
+ // Change a byte near the middle.
+ ++buffer[length / 2];
+ art::ScratchFile tmp4;
+ EXPECT_TRUE(tmp4.GetFile()->WriteFully(&buffer[0], length));
+ --buffer[length / 2];
+ EXPECT_NE(reset_compare(tmp, tmp4), 0);
+
+ // Change a byte near the end.
+ ++buffer[length - 5];
+ art::ScratchFile tmp5;
+ EXPECT_TRUE(tmp5.GetFile()->WriteFully(&buffer[0], length));
+ --buffer[length - 5];
+ EXPECT_NE(reset_compare(tmp, tmp5), 0);
+
+ // Reference check
+ art::ScratchFile tmp6;
+ EXPECT_TRUE(tmp6.GetFile()->WriteFully(&buffer[0], length));
+ EXPECT_EQ(reset_compare(tmp, tmp6), 0);
+}
+
} // namespace unix_file
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 3ac87c5137..fc14da1067 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -7119,7 +7119,7 @@ void ClassLinker::LinkInterfaceMethodsHelper::ReallocMethods() {
method_alignment_);
const size_t old_methods_ptr_size = (old_methods != nullptr) ? old_size : 0;
auto* methods = reinterpret_cast<LengthPrefixedArray<ArtMethod>*>(
- Runtime::Current()->GetLinearAlloc()->Realloc(
+ class_linker_->GetAllocatorForClassLoader(klass_->GetClassLoader())->Realloc(
self_, old_methods, old_methods_ptr_size, new_size));
CHECK(methods != nullptr); // Native allocation failure aborts.
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index b50aec0b63..e7051b35d8 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -68,6 +68,10 @@ ClassLoaderContext::~ClassLoaderContext() {
}
}
+std::unique_ptr<ClassLoaderContext> ClassLoaderContext::Default() {
+ return Create("");
+}
+
std::unique_ptr<ClassLoaderContext> ClassLoaderContext::Create(const std::string& spec) {
std::unique_ptr<ClassLoaderContext> result(new ClassLoaderContext());
if (result->Parse(spec)) {
diff --git a/runtime/class_loader_context.h b/runtime/class_loader_context.h
index 85299d41c0..9afa880da4 100644
--- a/runtime/class_loader_context.h
+++ b/runtime/class_loader_context.h
@@ -34,9 +34,6 @@ class OatFile;
// Utility class which holds the class loader context used during compilation/verification.
class ClassLoaderContext {
public:
- // Creates an empty context (with no class loaders).
- ClassLoaderContext();
-
~ClassLoaderContext();
// Opens requested class path files and appends them to ClassLoaderInfo::opened_dex_files.
@@ -126,6 +123,10 @@ class ClassLoaderContext {
static std::unique_ptr<ClassLoaderContext> CreateContextForClassLoader(jobject class_loader,
jobjectArray dex_elements);
+ // Returns the default class loader context to be used when none is specified.
+ // This will return a context with a single and empty PathClassLoader.
+ static std::unique_ptr<ClassLoaderContext> Default();
+
private:
enum ClassLoaderType {
kInvalidClassLoader = 0,
@@ -151,6 +152,9 @@ class ClassLoaderContext {
explicit ClassLoaderInfo(ClassLoaderType cl_type) : type(cl_type) {}
};
+ // Creates an empty context (with no class loaders).
+ ClassLoaderContext();
+
// Constructs an empty context.
// `owns_the_dex_files` specifies whether or not the context will own the opened dex files
// present in the class loader chain. If `owns_the_dex_files` is true then OpenDexFiles cannot
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index a2a6e085c2..5355267b07 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -65,8 +65,8 @@ extern "C" mirror::Class* artInitializeStaticStorageFromCode(uint32_t type_idx,
// A class may be accessing another class' fields when it doesn't have access, as access has been
// given by inheritance.
ScopedQuickEntrypointChecks sqec(self);
- auto caller_and_outer = GetCalleeSaveMethodCallerAndOuterMethod(self,
- CalleeSaveType::kSaveEverything);
+ auto caller_and_outer = GetCalleeSaveMethodCallerAndOuterMethod(
+ self, CalleeSaveType::kSaveEverythingForClinit);
ArtMethod* caller = caller_and_outer.caller;
mirror::Class* result =
ResolveVerifyAndClinit(dex::TypeIndex(type_idx), caller, self, true, false);
@@ -80,8 +80,8 @@ extern "C" mirror::Class* artInitializeTypeFromCode(uint32_t type_idx, Thread* s
REQUIRES_SHARED(Locks::mutator_lock_) {
// Called when method->dex_cache_resolved_types_[] misses.
ScopedQuickEntrypointChecks sqec(self);
- auto caller_and_outer = GetCalleeSaveMethodCallerAndOuterMethod(self,
- CalleeSaveType::kSaveEverything);
+ auto caller_and_outer = GetCalleeSaveMethodCallerAndOuterMethod(
+ self, CalleeSaveType::kSaveEverythingForClinit);
ArtMethod* caller = caller_and_outer.caller;
mirror::Class* result =
ResolveVerifyAndClinit(dex::TypeIndex(type_idx), caller, self, false, false);
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc
index 7e08b7ace0..b692618740 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc
@@ -90,7 +90,18 @@ TEST_F(QuickTrampolineEntrypointsTest, FrameSize) {
GetCalleeSaveFrameSize(isa, CalleeSaveType::kSaveRefsOnly)); \
CheckFrameSize(isa, \
CalleeSaveType::kSaveAllCalleeSaves, \
- GetCalleeSaveFrameSize(isa, CalleeSaveType::kSaveAllCalleeSaves))
+ GetCalleeSaveFrameSize(isa, CalleeSaveType::kSaveAllCalleeSaves)); \
+ CheckFrameSize(isa, \
+ CalleeSaveType::kSaveEverything, \
+ GetCalleeSaveFrameSize(isa, CalleeSaveType::kSaveEverything)); \
+ CheckFrameSize(isa, \
+ CalleeSaveType::kSaveEverythingForClinit, \
+ GetCalleeSaveFrameSize(isa, \
+ CalleeSaveType::kSaveEverythingForClinit)); \
+ CheckFrameSize(isa, \
+ CalleeSaveType::kSaveEverythingForSuspendCheck, \
+ GetCalleeSaveFrameSize( \
+ isa, CalleeSaveType::kSaveEverythingForSuspendCheck))
CHECK_FRAME_SIZE(kArm);
CHECK_FRAME_SIZE(kArm64);
@@ -123,6 +134,13 @@ TEST_F(QuickTrampolineEntrypointsTest, ReturnPC) {
GetCalleeSaveReturnPcOffset(kRuntimeISA, CalleeSaveType::kSaveRefsOnly));
CheckPCOffset(kRuntimeISA, CalleeSaveType::kSaveAllCalleeSaves,
GetCalleeSaveReturnPcOffset(kRuntimeISA, CalleeSaveType::kSaveAllCalleeSaves));
+ CheckPCOffset(kRuntimeISA, CalleeSaveType::kSaveEverything,
+ GetCalleeSaveReturnPcOffset(kRuntimeISA, CalleeSaveType::kSaveEverything));
+ CheckPCOffset(kRuntimeISA, CalleeSaveType::kSaveEverythingForClinit,
+ GetCalleeSaveReturnPcOffset(kRuntimeISA, CalleeSaveType::kSaveEverythingForClinit));
+ CheckPCOffset(kRuntimeISA, CalleeSaveType::kSaveEverythingForSuspendCheck,
+ GetCalleeSaveReturnPcOffset(kRuntimeISA,
+ CalleeSaveType::kSaveEverythingForSuspendCheck));
}
} // namespace art
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 9d672b1d34..9b24885f53 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -2431,24 +2431,31 @@ mirror::Object* ConcurrentCopying::IsMarked(mirror::Object* from_ref) {
// Non-immune non-moving space. Use the mark bitmap.
accounting::ContinuousSpaceBitmap* mark_bitmap =
heap_mark_bitmap_->GetContinuousSpaceBitmap(from_ref);
- accounting::LargeObjectBitmap* los_bitmap =
- heap_mark_bitmap_->GetLargeObjectBitmap(from_ref);
- CHECK(los_bitmap != nullptr) << "LOS bitmap covers the entire address range";
bool is_los = mark_bitmap == nullptr;
if (!is_los && mark_bitmap->Test(from_ref)) {
// Already marked.
to_ref = from_ref;
- } else if (is_los && los_bitmap->Test(from_ref)) {
- // Already marked in LOS.
- to_ref = from_ref;
} else {
- // Not marked.
- if (IsOnAllocStack(from_ref)) {
- // If on the allocation stack, it's considered marked.
+ accounting::LargeObjectBitmap* los_bitmap =
+ heap_mark_bitmap_->GetLargeObjectBitmap(from_ref);
+ // We may not have a large object space for dex2oat, don't assume it exists.
+ if (los_bitmap == nullptr) {
+ CHECK(heap_->GetLargeObjectsSpace() == nullptr)
+ << "LOS bitmap covers the entire address range " << from_ref
+ << " " << heap_->DumpSpaces();
+ }
+ if (los_bitmap != nullptr && is_los && los_bitmap->Test(from_ref)) {
+ // Already marked in LOS.
to_ref = from_ref;
} else {
// Not marked.
- to_ref = nullptr;
+ if (IsOnAllocStack(from_ref)) {
+ // If on the allocation stack, it's considered marked.
+ to_ref = from_ref;
+ } else {
+ // Not marked.
+ to_ref = nullptr;
+ }
}
}
}
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 148438296f..14e017abd9 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -725,6 +725,10 @@ class ImageSpaceLoader {
image_header->GetImageMethod(ImageHeader::kSaveRefsAndArgsMethod));
CHECK_EQ(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverything),
image_header->GetImageMethod(ImageHeader::kSaveEverythingMethod));
+ CHECK_EQ(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForClinit),
+ image_header->GetImageMethod(ImageHeader::kSaveEverythingMethodForClinit));
+ CHECK_EQ(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForSuspendCheck),
+ image_header->GetImageMethod(ImageHeader::kSaveEverythingMethodForSuspendCheck));
} else if (!runtime->HasResolutionMethod()) {
runtime->SetInstructionSet(space->oat_file_non_owned_->GetOatHeader().GetInstructionSet());
runtime->SetResolutionMethod(image_header->GetImageMethod(ImageHeader::kResolutionMethod));
@@ -743,6 +747,12 @@ class ImageSpaceLoader {
runtime->SetCalleeSaveMethod(
image_header->GetImageMethod(ImageHeader::kSaveEverythingMethod),
CalleeSaveType::kSaveEverything);
+ runtime->SetCalleeSaveMethod(
+ image_header->GetImageMethod(ImageHeader::kSaveEverythingMethodForClinit),
+ CalleeSaveType::kSaveEverythingForClinit);
+ runtime->SetCalleeSaveMethod(
+ image_header->GetImageMethod(ImageHeader::kSaveEverythingMethodForSuspendCheck),
+ CalleeSaveType::kSaveEverythingForSuspendCheck);
}
VLOG(image) << "ImageSpace::Init exiting " << *space.get();
diff --git a/runtime/generated/asm_support_gen.h b/runtime/generated/asm_support_gen.h
index 11b3abb6ed..314c45e117 100644
--- a/runtime/generated/asm_support_gen.h
+++ b/runtime/generated/asm_support_gen.h
@@ -34,6 +34,10 @@ DEFINE_CHECK_EQ(static_cast<size_t>(RUNTIME_SAVE_REFS_ONLY_METHOD_OFFSET), (stat
DEFINE_CHECK_EQ(static_cast<size_t>(RUNTIME_SAVE_REFS_AND_ARGS_METHOD_OFFSET), (static_cast<size_t>(art::Runtime::GetCalleeSaveMethodOffset(art::CalleeSaveType::kSaveRefsAndArgs))))
#define RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET 0x18
DEFINE_CHECK_EQ(static_cast<size_t>(RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET), (static_cast<size_t>(art::Runtime::GetCalleeSaveMethodOffset(art::CalleeSaveType::kSaveEverything))))
+#define RUNTIME_SAVE_EVERYTHING_FOR_CLINIT_METHOD_OFFSET 0x20
+DEFINE_CHECK_EQ(static_cast<size_t>(RUNTIME_SAVE_EVERYTHING_FOR_CLINIT_METHOD_OFFSET), (static_cast<size_t>(art::Runtime::GetCalleeSaveMethodOffset(art::CalleeSaveType::kSaveEverythingForClinit))))
+#define RUNTIME_SAVE_EVERYTHING_FOR_SUSPEND_CHECK_METHOD_OFFSET 0x28
+DEFINE_CHECK_EQ(static_cast<size_t>(RUNTIME_SAVE_EVERYTHING_FOR_SUSPEND_CHECK_METHOD_OFFSET), (static_cast<size_t>(art::Runtime::GetCalleeSaveMethodOffset(art::CalleeSaveType::kSaveEverythingForSuspendCheck))))
#define THREAD_FLAGS_OFFSET 0
DEFINE_CHECK_EQ(static_cast<int32_t>(THREAD_FLAGS_OFFSET), (static_cast<int32_t>(art::Thread:: ThreadFlagsOffset<art::kRuntimePointerSize>().Int32Value())))
#define THREAD_ID_OFFSET 12
diff --git a/runtime/image.h b/runtime/image.h
index 6c76f4915e..7bb796c5a1 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -183,6 +183,8 @@ class PACKED(4) ImageHeader {
kSaveRefsOnlyMethod,
kSaveRefsAndArgsMethod,
kSaveEverythingMethod,
+ kSaveEverythingMethodForClinit,
+ kSaveEverythingMethodForSuspendCheck,
kImageMethodsCount, // Number of elements in enum.
};
diff --git a/runtime/mirror/accessible_object.h b/runtime/mirror/accessible_object.h
index a217193522..d489f14536 100644
--- a/runtime/mirror/accessible_object.h
+++ b/runtime/mirror/accessible_object.h
@@ -17,11 +17,8 @@
#ifndef ART_RUNTIME_MIRROR_ACCESSIBLE_OBJECT_H_
#define ART_RUNTIME_MIRROR_ACCESSIBLE_OBJECT_H_
-#include "class.h"
-#include "gc_root.h"
#include "object.h"
#include "read_barrier_option.h"
-#include "thread.h"
namespace art {
@@ -34,12 +31,6 @@ class MANAGED AccessibleObject : public Object {
return OFFSET_OF_OBJECT_MEMBER(AccessibleObject, flag_);
}
- template<bool kTransactionActive>
- void SetAccessible(bool value) REQUIRES_SHARED(Locks::mutator_lock_) {
- UNUSED(padding_);
- return SetFieldBoolean<kTransactionActive>(FlagOffset(), value ? 1u : 0u);
- }
-
bool IsAccessible() REQUIRES_SHARED(Locks::mutator_lock_) {
return GetFieldBoolean(FlagOffset());
}
@@ -47,7 +38,7 @@ class MANAGED AccessibleObject : public Object {
private:
uint8_t flag_;
// Padding required for correct alignment of subclasses like Executable, Field, etc.
- uint8_t padding_[1];
+ uint8_t padding_[1] ATTRIBUTE_UNUSED;
DISALLOW_IMPLICIT_CONSTRUCTORS(AccessibleObject);
};
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index 63142d5c25..22812454d1 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -27,8 +27,7 @@
#include "class.h"
#include "gc/heap-inl.h"
#include "obj_ptr-inl.h"
-#include "object-inl.h"
-#include "thread.h"
+#include "thread-current-inl.h"
namespace art {
namespace mirror {
diff --git a/runtime/mirror/field-inl.h b/runtime/mirror/field-inl.h
index d33df5c8e7..ad48202514 100644
--- a/runtime/mirror/field-inl.h
+++ b/runtime/mirror/field-inl.h
@@ -20,7 +20,8 @@
#include "field.h"
#include "art_field-inl.h"
-#include "mirror/dex_cache-inl.h"
+#include "class-inl.h"
+#include "dex_cache-inl.h"
namespace art {
@@ -87,6 +88,10 @@ inline void Field::SetType(ObjPtr<mirror::Class> type) {
SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(Field, type_), type);
}
+inline Primitive::Type Field::GetTypeAsPrimitiveType() {
+ return GetType()->GetPrimitiveType();
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/field.h b/runtime/mirror/field.h
index 40186a689b..6845575d18 100644
--- a/runtime/mirror/field.h
+++ b/runtime/mirror/field.h
@@ -20,8 +20,10 @@
#include "accessible_object.h"
#include "base/enums.h"
#include "gc_root.h"
+#include "modifiers.h"
#include "obj_ptr.h"
#include "object.h"
+#include "primitive.h"
#include "read_barrier_option.h"
namespace art {
@@ -69,10 +71,7 @@ class MANAGED Field : public AccessibleObject {
return (GetAccessFlags() & kAccVolatile) != 0;
}
- ALWAYS_INLINE Primitive::Type GetTypeAsPrimitiveType()
- REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetType()->GetPrimitiveType();
- }
+ ALWAYS_INLINE Primitive::Type GetTypeAsPrimitiveType() REQUIRES_SHARED(Locks::mutator_lock_);
mirror::Class* GetType() REQUIRES_SHARED(Locks::mutator_lock_) {
return GetFieldObject<mirror::Class>(OFFSET_OF_OBJECT_MEMBER(Field, type_));
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 086925b9c7..4f8952d8c2 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -393,14 +393,6 @@ inline size_t Object::SizeOf() {
}
template<VerifyObjectFlags kVerifyFlags, bool kIsVolatile>
-inline uint8_t Object::GetFieldBoolean(MemberOffset field_offset) {
- if (kVerifyFlags & kVerifyThis) {
- VerifyObject(this);
- }
- return GetField<uint8_t, kIsVolatile>(field_offset);
-}
-
-template<VerifyObjectFlags kVerifyFlags, bool kIsVolatile>
inline int8_t Object::GetFieldByte(MemberOffset field_offset) {
if (kVerifyFlags & kVerifyThis) {
VerifyObject(this);
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 886780f051..aedcd66082 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -380,7 +380,12 @@ class MANAGED LOCKABLE Object {
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false>
ALWAYS_INLINE uint8_t GetFieldBoolean(MemberOffset field_offset)
- REQUIRES_SHARED(Locks::mutator_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (kVerifyFlags & kVerifyThis) {
+ VerifyObject(this);
+ }
+ return GetField<uint8_t, kIsVolatile>(field_offset);
+ }
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false>
ALWAYS_INLINE int8_t GetFieldByte(MemberOffset field_offset)
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 9f59a1f751..2e4dd8a599 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -27,7 +27,7 @@
#include "dex_file_annotations.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
-#include "mirror/field.h"
+#include "mirror/field-inl.h"
#include "native_util.h"
#include "reflection-inl.h"
#include "scoped_fast_native_object_access-inl.h"
diff --git a/runtime/runtime-inl.h b/runtime/runtime-inl.h
index 609f0d658d..4584351a6a 100644
--- a/runtime/runtime-inl.h
+++ b/runtime/runtime-inl.h
@@ -49,7 +49,9 @@ inline QuickMethodFrameInfo Runtime::GetRuntimeMethodFrameInfo(ArtMethod* method
} else if (method == GetCalleeSaveMethodUnchecked(CalleeSaveType::kSaveRefsOnly)) {
return GetCalleeSaveMethodFrameInfo(CalleeSaveType::kSaveRefsOnly);
} else {
- DCHECK_EQ(method, GetCalleeSaveMethodUnchecked(CalleeSaveType::kSaveEverything));
+ DCHECK(method == GetCalleeSaveMethodUnchecked(CalleeSaveType::kSaveEverything) ||
+ method == GetCalleeSaveMethodUnchecked(CalleeSaveType::kSaveEverythingForClinit) ||
+ method == GetCalleeSaveMethodUnchecked(CalleeSaveType::kSaveEverythingForSuspendCheck));
return GetCalleeSaveMethodFrameInfo(CalleeSaveType::kSaveEverything);
}
}
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 0c1344e11a..4e84468744 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -714,7 +714,7 @@ class Runtime {
static constexpr int kProfileForground = 0;
static constexpr int kProfileBackground = 1;
- static constexpr uint32_t kCalleeSaveSize = 4u;
+ static constexpr uint32_t kCalleeSaveSize = 6u;
// 64 bit so that we can share the same asm offsets for both 32 and 64 bits.
uint64_t callee_save_methods_[kCalleeSaveSize];
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 19df0d26a1..2e0653666f 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -634,7 +634,7 @@ static void AssertPcIsWithinQuickCode(ArtMethod* method, uintptr_t pc)
void StackVisitor::SanityCheckFrame() const {
if (kIsDebugBuild) {
ArtMethod* method = GetMethod();
- auto* declaring_class = method->GetDeclaringClass();
+ mirror::Class* declaring_class = method->GetDeclaringClass();
// Runtime methods have null declaring class.
if (!method->IsRuntimeMethod()) {
CHECK(declaring_class != nullptr);
@@ -647,11 +647,14 @@ void StackVisitor::SanityCheckFrame() const {
LinearAlloc* const linear_alloc = runtime->GetLinearAlloc();
if (!linear_alloc->Contains(method)) {
// Check class linker linear allocs.
- mirror::Class* klass = method->GetDeclaringClass();
+ // We get the canonical method as copied methods may have their declaring
+ // class from another class loader.
+ ArtMethod* canonical = method->GetCanonicalMethod();
+ mirror::Class* klass = canonical->GetDeclaringClass();
LinearAlloc* const class_linear_alloc = (klass != nullptr)
? runtime->GetClassLinker()->GetAllocatorForClassLoader(klass->GetClassLoader())
: linear_alloc;
- if (!class_linear_alloc->Contains(method)) {
+ if (!class_linear_alloc->Contains(canonical)) {
// Check image space.
bool in_image = false;
for (auto& space : runtime->GetHeap()->GetContinuousSpaces()) {
@@ -660,14 +663,14 @@ void StackVisitor::SanityCheckFrame() const {
const auto& header = image_space->GetImageHeader();
const ImageSection& methods = header.GetMethodsSection();
const ImageSection& runtime_methods = header.GetRuntimeMethodsSection();
- const size_t offset = reinterpret_cast<const uint8_t*>(method) - image_space->Begin();
+ const size_t offset = reinterpret_cast<const uint8_t*>(canonical) - image_space->Begin();
if (methods.Contains(offset) || runtime_methods.Contains(offset)) {
in_image = true;
break;
}
}
}
- CHECK(in_image) << method->PrettyMethod() << " not in linear alloc or image";
+ CHECK(in_image) << canonical->PrettyMethod() << " not in linear alloc or image";
}
}
if (cur_quick_frame_ != nullptr) {
diff --git a/runtime/thread.h b/runtime/thread.h
index 776096a7bb..7540fd2563 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -1705,8 +1705,13 @@ class Thread {
class SCOPED_CAPABILITY ScopedAssertNoThreadSuspension {
public:
- ALWAYS_INLINE explicit ScopedAssertNoThreadSuspension(const char* cause)
- ACQUIRE(Roles::uninterruptible_) {
+ ALWAYS_INLINE ScopedAssertNoThreadSuspension(const char* cause,
+ bool enabled = true)
+ ACQUIRE(Roles::uninterruptible_)
+ : enabled_(enabled) {
+ if (!enabled_) {
+ return;
+ }
if (kIsDebugBuild) {
self_ = Thread::Current();
old_cause_ = self_->StartAssertNoThreadSuspension(cause);
@@ -1715,6 +1720,9 @@ class SCOPED_CAPABILITY ScopedAssertNoThreadSuspension {
}
}
ALWAYS_INLINE ~ScopedAssertNoThreadSuspension() RELEASE(Roles::uninterruptible_) {
+ if (!enabled_) {
+ return;
+ }
if (kIsDebugBuild) {
self_->EndAssertNoThreadSuspension(old_cause_);
} else {
@@ -1724,6 +1732,7 @@ class SCOPED_CAPABILITY ScopedAssertNoThreadSuspension {
private:
Thread* self_;
+ const bool enabled_;
const char* old_cause_;
};
diff --git a/test/1338-gc-no-los/expected.txt b/test/1338-gc-no-los/expected.txt
new file mode 100644
index 0000000000..36bec43b8b
--- /dev/null
+++ b/test/1338-gc-no-los/expected.txt
@@ -0,0 +1 @@
+131072 200 true
diff --git a/test/1338-gc-no-los/info.txt b/test/1338-gc-no-los/info.txt
new file mode 100644
index 0000000000..2e27357b80
--- /dev/null
+++ b/test/1338-gc-no-los/info.txt
@@ -0,0 +1 @@
+Test that the GC works with no large object space. Regression test for b/64393515. \ No newline at end of file
diff --git a/test/1338-gc-no-los/run b/test/1338-gc-no-los/run
new file mode 100755
index 0000000000..f3c43fbce6
--- /dev/null
+++ b/test/1338-gc-no-los/run
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# Copyright 2017 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.
+./default-run "$@" --runtime-option -XX:LargeObjectSpace=disabled
diff --git a/test/1338-gc-no-los/src-art/Main.java b/test/1338-gc-no-los/src-art/Main.java
new file mode 100644
index 0000000000..662fa7e610
--- /dev/null
+++ b/test/1338-gc-no-los/src-art/Main.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+import dalvik.system.VMRuntime;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+
+public class Main {
+ public static void main(String[] args) {
+ try {
+ // Allocate a large object.
+ byte[] arr = new byte[128 * 1024];
+ // Allocate a non movable object.
+ byte[] arr2 = (byte[])VMRuntime.getRuntime().newNonMovableArray(Byte.TYPE, 200);
+ // Put the array in a weak reference so that IsMarked is called by the GC.
+ WeakReference weakRef = new WeakReference(arr2);
+ // Do a GC.
+ Runtime.getRuntime().gc();
+ arr[0] = 1;
+ arr2[0] = 1;
+ System.out.println(arr.length + " " + arr2.length + " " + (weakRef.get() != null));
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ }
+}
diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java
index 510354073a..f466eea97b 100644
--- a/test/449-checker-bce/src/Main.java
+++ b/test/449-checker-bce/src/Main.java
@@ -876,6 +876,91 @@ public class Main {
return true;
}
+ /// CHECK-START: void Main.modArrayIndex1(int[]) BCE (before)
+ /// CHECK-DAG: BoundsCheck
+ /// CHECK-DAG: ArraySet
+ /// CHECK-DAG: BoundsCheck
+ /// CHECK-DAG: ArraySet
+
+ /// CHECK-START: void Main.modArrayIndex1(int[]) BCE (after)
+ /// CHECK-NOT: Deoptimize
+ /// CHECK-DAG: BoundsCheck
+ /// CHECK-DAG: ArraySet
+ /// CHECK-NOT: BoundsCheck
+ /// CHECK-DAG: ArraySet
+ public static void modArrayIndex1(int[] array) {
+ for(int i = 0; i < 100; i++) {
+ // Cannot statically eliminate, for example, when array.length == 5.
+ // Currently dynamic BCE isn't applied for this case.
+ array[i % 10] = i;
+ // Can be eliminated by BCE.
+ array[i % array.length] = i;
+ }
+ }
+
+ /// CHECK-START: void Main.modArrayIndex2(int[], int) BCE (before)
+ /// CHECK-DAG: BoundsCheck
+ /// CHECK-DAG: ArraySet
+ /// CHECK-DAG: BoundsCheck
+ /// CHECK-DAG: ArraySet
+
+ /// CHECK-START: void Main.modArrayIndex2(int[], int) BCE (after)
+ /// CHECK-NOT: Deoptimize
+ /// CHECK-DAG: BoundsCheck
+ /// CHECK-DAG: ArraySet
+ /// CHECK-DAG: BoundsCheck
+ /// CHECK-DAG: ArraySet
+ public static void modArrayIndex2(int array[], int index) {
+ for(int i = 0; i < 100; i++) {
+ // Both bounds checks cannot be statically eliminated, because index can be < 0.
+ // Currently dynamic BCE isn't applied for this case.
+ array[(index+i) % 10] = i;
+ array[(index+i) % array.length] = i;
+ }
+ }
+
+ static final int[] staticArray = new int[10];
+
+ /// CHECK-START: void Main.modArrayIndex3() BCE (before)
+ /// CHECK-DAG: BoundsCheck
+ /// CHECK-DAG: ArraySet
+ /// CHECK-DAG: BoundsCheck
+ /// CHECK-DAG: ArraySet
+
+ /// CHECK-START: void Main.modArrayIndex3() BCE (after)
+ /// CHECK-NOT: Deoptimize
+ /// CHECK-DAG: BoundsCheck
+ /// CHECK-DAG: ArraySet
+ /// CHECK-NOT: BoundsCheck
+ /// CHECK-DAG: ArraySet
+ public static void modArrayIndex3() {
+ for(int i = 0; i < 100; i++) {
+ // Currently dynamic BCE isn't applied for this case.
+ staticArray[i % 10] = i;
+ // Can be eliminated by BCE.
+ staticArray[i % staticArray.length] = i;
+ }
+ }
+
+ /// CHECK-START: void Main.modArrayIndex4() BCE (before)
+ /// CHECK-DAG: BoundsCheck
+ /// CHECK-DAG: ArraySet
+ /// CHECK-DAG: BoundsCheck
+ /// CHECK-DAG: ArraySet
+
+ /// CHECK-START: void Main.modArrayIndex4() BCE (after)
+ /// CHECK-NOT: BoundsCheck
+ /// CHECK-DAG: ArraySet
+ /// CHECK-NOT: BoundsCheck
+ /// CHECK-DAG: ArraySet
+ public static void modArrayIndex4() {
+ int[] array = new int[20];
+ for(int i = 0; i < 100; i++) {
+ // The local array length is statically know. Both can be eliminated by BCE.
+ array[i % 10] = i;
+ array[i % array.length] = i;
+ }
+ }
/// CHECK-START: void Main.bubbleSort(int[]) GVN (before)
/// CHECK: BoundsCheck
diff --git a/test/661-classloader-allocator/expected.txt b/test/661-classloader-allocator/expected.txt
new file mode 100644
index 0000000000..6a5618ebc6
--- /dev/null
+++ b/test/661-classloader-allocator/expected.txt
@@ -0,0 +1 @@
+JNI_OnLoad called
diff --git a/test/661-classloader-allocator/info.txt b/test/661-classloader-allocator/info.txt
new file mode 100644
index 0000000000..872b5e0a5a
--- /dev/null
+++ b/test/661-classloader-allocator/info.txt
@@ -0,0 +1,3 @@
+Regression test for copied methods which used to not
+be (re-)allocated with the right class loader allocator,
+which crashed the JIT profiler.
diff --git a/test/661-classloader-allocator/src-ex/OtherClass.java b/test/661-classloader-allocator/src-ex/OtherClass.java
new file mode 100644
index 0000000000..e59cb953fc
--- /dev/null
+++ b/test/661-classloader-allocator/src-ex/OtherClass.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package p1;
+
+interface Itf {
+ public default int defaultMethod() {
+ return 42;
+ }
+}
+
+public class OtherClass implements Itf {
+ public void foo() {
+ }
+}
diff --git a/test/661-classloader-allocator/src/Main.java b/test/661-classloader-allocator/src/Main.java
new file mode 100644
index 0000000000..40f8f7a4bf
--- /dev/null
+++ b/test/661-classloader-allocator/src/Main.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+import java.lang.reflect.Constructor;
+
+public class Main {
+ static final String DEX_FILE =
+ System.getenv("DEX_LOCATION") + "/661-classloader-allocator-ex.jar";
+ static final String LIBRARY_SEARCH_PATH = System.getProperty("java.library.path");
+
+ private static void doUnloading() {
+ // Stop the JIT to ensure its threads and work queue are not keeping classes
+ // artifically alive.
+ stopJit();
+ // Do multiple GCs to prevent rare flakiness if some other thread is keeping the
+ // classloader live.
+ for (int i = 0; i < 5; ++i) {
+ Runtime.getRuntime().gc();
+ }
+ startJit();
+ }
+
+ public static void main(String[] args) throws Exception {
+ System.loadLibrary(args[0]);
+ loadClass();
+ doUnloading();
+ // fetchProfiles iterate over the ProfilingInfo, we used to crash in the presence
+ // of unloaded copied methods.
+ fetchProfiles();
+ }
+
+ public static void loadClass() throws Exception {
+ Class<?> pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
+ if (pathClassLoader == null) {
+ throw new AssertionError("Couldn't find path class loader class");
+ }
+ Constructor<?> constructor =
+ pathClassLoader.getDeclaredConstructor(String.class, String.class, ClassLoader.class);
+ ClassLoader loader = (ClassLoader) constructor.newInstance(
+ DEX_FILE, LIBRARY_SEARCH_PATH, ClassLoader.getSystemClassLoader());
+ Class<?> otherClass = loader.loadClass("p1.OtherClass");
+ ensureJitCompiled(otherClass, "foo");
+ }
+
+ public static native void ensureJitCompiled(Class<?> cls, String methodName);
+ public static native void fetchProfiles();
+ public static native void stopJit();
+ public static native void startJit();
+}
diff --git a/test/662-regression-alias/expected.txt b/test/662-regression-alias/expected.txt
new file mode 100644
index 0000000000..7250211df8
--- /dev/null
+++ b/test/662-regression-alias/expected.txt
@@ -0,0 +1 @@
+passed 127 4
diff --git a/test/662-regression-alias/info.txt b/test/662-regression-alias/info.txt
new file mode 100644
index 0000000000..584d3ee3d3
--- /dev/null
+++ b/test/662-regression-alias/info.txt
@@ -0,0 +1 @@
+Regression test on missed array element aliasing.
diff --git a/test/662-regression-alias/src/Main.java b/test/662-regression-alias/src/Main.java
new file mode 100644
index 0000000000..aad61e254d
--- /dev/null
+++ b/test/662-regression-alias/src/Main.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/**
+ * Regression test on ARM-scheduling/array-aliasing bug (b/64018485).
+ */
+public class Main {
+
+ //
+ // Mimic original bug.
+ //
+
+ static void setFields(int[] fields) {
+ if (fields == null || fields.length < 6)
+ fields = new int[6]; // creates phi
+ fields[5] = 127;
+ }
+
+ static void processFieldValues(int field0, int field1, int field2,
+ int field3, int field4, int field5) {
+ if (field5 != 127) {
+ throw new Error("field = " + field5);
+ } else if (field0 != 0) {
+ processFieldValues(0, 0, 0, 0, 0, 0); // disable inlining
+ }
+ }
+
+ static int doit(int pass) {
+ int[] fields = new int[6];
+ for (; ; pass++) {
+ setFields(fields);
+ processFieldValues(fields[0], fields[1], fields[2],
+ fields[3], fields[4], fields[5]);
+ if (pass == 0)
+ break;
+ }
+ return fields[5];
+ }
+
+ //
+ // Similar situation.
+ //
+
+ private static int aliasing(boolean f) {
+ int[] array = new int[6];
+ int[] array2 = null;
+ int s = 0;
+ for (int i = 0; i < 1; i++) {
+ if (f) {
+ array2 = array;
+ }
+ array2[1] = 4;
+ s = array[1];
+ }
+ return s;
+ }
+
+ //
+ // Main driver.
+ //
+
+ static public void main(String[] args) {
+ int r = doit(0);
+ int s = aliasing(true);
+ System.out.println("passed " + r + " " + s);
+ }
+}
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index 7c0ed691b6..60c7315b6f 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -254,4 +254,17 @@ extern "C" JNIEXPORT int JNICALL Java_Main_numberOfDeoptimizations(JNIEnv*, jcla
return Runtime::Current()->GetNumberOfDeoptimizations();
}
+extern "C" JNIEXPORT void JNICALL Java_Main_fetchProfiles(JNIEnv*, jclass) {
+ jit::Jit* jit = GetJitIfEnabled();
+ if (jit == nullptr) {
+ return;
+ }
+ jit::JitCodeCache* code_cache = jit->GetCodeCache();
+ std::vector<ProfileMethodInfo> unused_vector;
+ std::set<std::string> unused_locations;
+ unused_locations.insert("fake_location");
+ ScopedObjectAccess soa(Thread::Current());
+ code_cache->GetProfiledMethods(unused_locations, unused_vector);
+}
+
} // namespace art
diff --git a/test/knownfailures.json b/test/knownfailures.json
index bd9591a8a8..a8191bbb23 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -713,8 +713,16 @@
"--no-dex2oat do not create"]
},
{
- "tests": "961-default-iface-resolution-gen",
+ "tests": ["961-default-iface-resolution-gen",
+ "964-default-iface-init-gen",
+ "968-default-partial-compile-gen"],
"env_vars": {"SANITIZE_HOST": "address"},
"description": ["Test hits dex2oat watchdog timeout (60sec) on art-asan"]
+ },
+ {
+ "tests": "662-regression-alias",
+ "variant": "target",
+ "description": ["disable until ARM scheduling/aliasing bug is fixed."],
+ "bug": "b/64018485"
}
]
diff --git a/test/ti-agent/trace_helper.cc b/test/ti-agent/trace_helper.cc
index 7a9d1e0d92..1f8ceff91c 100644
--- a/test/ti-agent/trace_helper.cc
+++ b/test/ti-agent/trace_helper.cc
@@ -388,10 +388,12 @@ extern "C" JNIEXPORT void JNICALL Java_art_Trace_enableTracing(
data->single_step = single_step != nullptr ? env->FromReflectedMethod(single_step) : nullptr;
data->in_callback = false;
- void* old_data = nullptr;
- if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(&old_data))) {
+ TraceData* old_data = nullptr;
+ if (JvmtiErrorToException(env, jvmti_env,
+ jvmti_env->GetEnvironmentLocalStorage(
+ reinterpret_cast<void**>(&old_data)))) {
return;
- } else if (old_data != nullptr) {
+ } else if (old_data != nullptr && old_data->test_klass != nullptr) {
ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
env->ThrowNew(rt_exception.get(), "Environment already has local storage set!");
return;
@@ -455,6 +457,21 @@ extern "C" JNIEXPORT void JNICALL Java_art_Trace_enableTracing(
extern "C" JNIEXPORT void JNICALL Java_art_Trace_disableTracing(
JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
+ TraceData* data = nullptr;
+ if (JvmtiErrorToException(
+ env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
+ return;
+ }
+ // If data is null then we haven't ever enabled tracing so we don't need to do anything.
+ if (data == nullptr || data->test_klass == nullptr) {
+ return;
+ }
+ env->DeleteGlobalRef(data->test_klass);
+ if (env->ExceptionCheck()) {
+ return;
+ }
+ // Clear test_klass so we know this isn't being used
+ data->test_klass = nullptr;
if (JvmtiErrorToException(env, jvmti_env,
jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
JVMTI_EVENT_FIELD_ACCESS,
diff --git a/tools/art b/tools/art
index dea7ebdc3c..15993ddaa2 100644
--- a/tools/art
+++ b/tools/art
@@ -23,6 +23,7 @@ LAUNCH_WRAPPER=
LIBART=libart.so
JIT_PROFILE="no"
VERBOSE="no"
+CLEAN_OAT_FILES="yes"
EXTRA_OPTIONS=()
# Follow all sym links to get the program name.
@@ -87,6 +88,7 @@ Supported OPTIONS include:
report upon completion.
--profile Run with profiling, then run using profile data.
--verbose Run script verbosely.
+ --no-clean Don't cleanup oat directories.
The ART_OPTIONS are passed directly to the Android Runtime.
@@ -176,12 +178,14 @@ cleanup_oat_directory() {
# Input: Command line arguments to the art script.
# e.g. -cp foo/classes.dex:bar/classes.dex would delete (foo/oat bar/oat) directories.
cleanup_oat_directory_for_classpath() {
- # First try: Use $CLASSPATH environment variable.
- parse_classpath "$CLASSPATH"
- # Second try: Look for latest -cp or -classpath arg which will take precedence.
- find_cp_in_args "$@"
+ if [ "$CLEAN_OAT_FILES" = "yes" ]; then
+ # First try: Use $CLASSPATH environment variable.
+ parse_classpath "$CLASSPATH"
+ # Second try: Look for latest -cp or -classpath arg which will take precedence.
+ find_cp_in_args "$@"
- cleanup_oat_directory "${PARSE_CLASSPATH_RESULT[@]}"
+ cleanup_oat_directory "${PARSE_CLASSPATH_RESULT[@]}"
+ fi
}
# Attempt to find $ANDROID_ROOT/framework/<isa>/core.art' without knowing what <isa> is.
@@ -291,6 +295,9 @@ while [[ "$1" = "-"* ]]; do
--verbose)
VERBOSE="yes"
;;
+ --no-clean)
+ CLEAN_OAT_FILES="no"
+ ;;
--*)
echo "unknown option: $1" 1>&2
usage
diff --git a/tools/cpp-define-generator/offset_runtime.def b/tools/cpp-define-generator/offset_runtime.def
index 41e7e40af5..1d5ce7dd49 100644
--- a/tools/cpp-define-generator/offset_runtime.def
+++ b/tools/cpp-define-generator/offset_runtime.def
@@ -40,6 +40,10 @@ DEFINE_RUNTIME_CALLEE_SAVE_OFFSET(SAVE_REFS_ONLY, art::CalleeSaveType::kSaveRefs
DEFINE_RUNTIME_CALLEE_SAVE_OFFSET(SAVE_REFS_AND_ARGS, art::CalleeSaveType::kSaveRefsAndArgs)
// Offset of field Runtime::callee_save_methods_[kSaveEverything]
DEFINE_RUNTIME_CALLEE_SAVE_OFFSET(SAVE_EVERYTHING, art::CalleeSaveType::kSaveEverything)
+// Offset of field Runtime::callee_save_methods_[kSaveEverythingForClinit]
+DEFINE_RUNTIME_CALLEE_SAVE_OFFSET(SAVE_EVERYTHING_FOR_CLINIT, art::CalleeSaveType::kSaveEverythingForClinit)
+// Offset of field Runtime::callee_save_methods_[kSaveEverythingForSuspendCheck]
+DEFINE_RUNTIME_CALLEE_SAVE_OFFSET(SAVE_EVERYTHING_FOR_SUSPEND_CHECK, art::CalleeSaveType::kSaveEverythingForSuspendCheck)
#undef DEFINE_RUNTIME_CALLEE_SAVE_OFFSET
#include "common_undef.def" // undef DEFINE_OFFSET_EXPR
diff --git a/tools/libcore_gcstress_debug_failures.txt b/tools/libcore_gcstress_debug_failures.txt
index 66bc252055..d4a0423eac 100644
--- a/tools/libcore_gcstress_debug_failures.txt
+++ b/tools/libcore_gcstress_debug_failures.txt
@@ -11,6 +11,7 @@
names: ["libcore.icu.TransliteratorTest#testAll",
"libcore.icu.RelativeDateTimeFormatterTest#test_bug25821045",
"libcore.java.lang.ref.ReferenceQueueTest#testRemoveWithDelayedResultAndTimeout",
+ "libcore.java.lang.ref.ReferenceQueueTest#testRemoveWithDelayedResultAndNoTimeout",
"libcore.java.util.TimeZoneTest#testSetDefaultDeadlock",
"org.apache.harmony.tests.java.util.TimerTest#testThrowingTaskKillsTimerThread"]
}
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index d2322bb3a9..355646b713 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -122,6 +122,9 @@ while true; do
fi
done
+# Make sure the debuggee doesn't clean up what the debugger has generated.
+art_debugee="$art_debugee --no-clean"
+
# For the host:
#
# If, on the other hand, there is a variant set, use it to modify the art_debugee parameter to