summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbuild/apex/art_apex_test.py5
-rw-r--r--compiler/optimizing/codegen_test_utils.h15
-rw-r--r--runtime/Android.bp4
-rw-r--r--runtime/art_method.cc21
-rw-r--r--runtime/art_method.h2
-rw-r--r--runtime/class_linker.cc19
-rw-r--r--runtime/elf_file.cc5
-rw-r--r--runtime/entrypoints_order_test.cc6
-rw-r--r--runtime/interpreter/mterp/mterp.cc3
-rw-r--r--runtime/native/java_lang_VMClassLoader.cc6
-rw-r--r--runtime/oat_file_assistant.cc4
-rw-r--r--runtime/oat_file_manager.cc8
-rw-r--r--runtime/parsed_options.cc5
-rw-r--r--runtime/parsed_options_test.cc15
-rw-r--r--runtime/runtime.cc49
-rw-r--r--runtime/runtime.h28
-rw-r--r--runtime/runtime_options.def2
-rw-r--r--runtime/thread.cc26
-rw-r--r--runtime/thread.h10
-rw-r--r--simulator/Android.bp28
-rw-r--r--simulator/code_simulator_arm64.cc378
-rw-r--r--simulator/code_simulator_arm64.h18
-rw-r--r--simulator/include/code_simulator.h13
-rwxr-xr-xtest.py1
-rw-r--r--test/README.simulator.md98
-rwxr-xr-xtest/etc/run-test-jar23
-rw-r--r--test/knownfailures.json631
-rwxr-xr-xtest/run-test15
-rwxr-xr-xtest/testrunner/testrunner.py5
29 files changed, 1395 insertions, 48 deletions
diff --git a/build/apex/art_apex_test.py b/build/apex/art_apex_test.py
index 1a337cbe3e..021fd5af81 100755
--- a/build/apex/art_apex_test.py
+++ b/build/apex/art_apex_test.py
@@ -546,6 +546,8 @@ class ReleaseChecker:
self._checker.check_native_library('libopenjdkjvmti')
self._checker.check_native_library('libprofile')
self._checker.check_native_library('libsigchain')
+ # Only on ARM/ARM64
+ self._checker.check_optional_native_library('libart-simulator-container')
# Check java libraries for Managed Core Library.
self._checker.check_java_library('apache-xml')
@@ -688,6 +690,8 @@ class DebugChecker:
self._checker.check_native_library('libopenjdkjvmd')
self._checker.check_native_library('libopenjdkjvmtid')
self._checker.check_native_library('libprofiled')
+ # Only on ARM/ARM64
+ self._checker.check_optional_native_library('libartd-simulator-container')
# Check internal libraries for Managed Core Library.
self._checker.check_native_library('libopenjdkd')
@@ -759,7 +763,6 @@ class TestingTargetChecker:
# Check ART test (internal) libraries.
self._checker.check_native_library('libart-gtest')
- self._checker.check_native_library('libartd-simulator-container')
# Check ART test tools.
self._checker.check_executable('signal_dumper')
diff --git a/compiler/optimizing/codegen_test_utils.h b/compiler/optimizing/codegen_test_utils.h
index 9d15f1f294..f873e7514e 100644
--- a/compiler/optimizing/codegen_test_utils.h
+++ b/compiler/optimizing/codegen_test_utils.h
@@ -223,12 +223,15 @@ static void VerifyGeneratedCode(InstructionSet target_isa,
Expected expected) {
ASSERT_TRUE(CanExecute(target_isa)) << "Target isa is not executable.";
- // Verify on simulator.
- CodeSimulatorContainer simulator(target_isa);
- if (simulator.CanSimulate()) {
- Expected result = SimulatorExecute<Expected>(simulator.Get(), f);
- if (has_result) {
- ASSERT_EQ(expected, result);
+ // Simulator cannot run without runtime, because it needs quick entrypoints.
+ if (Runtime::Current() != nullptr) {
+ // Verify on simulator.
+ CodeSimulatorContainer simulator(target_isa);
+ if (simulator.CanSimulate()) {
+ Expected result = SimulatorExecute<Expected>(simulator.Get(), f);
+ if (has_result) {
+ ASSERT_EQ(expected, result);
+ }
}
}
diff --git a/runtime/Android.bp b/runtime/Android.bp
index e3200c4394..f82a623c71 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -410,6 +410,7 @@ libart_cc_defaults {
export_generated_headers: ["cpp-define-generator-asm-support"],
header_libs: [
"art_cmdlineparser_headers",
+ "libart_simulator_headers",
"cpp-define-generator-definitions",
"jni_platform_headers",
"libnativehelper_header_only",
@@ -436,6 +437,7 @@ libart_static_cc_defaults {
name: "libart_static_base_defaults",
static_libs: [
"libartpalette",
+ "libart-simulator-container",
"libbacktrace",
"libbase",
"liblog",
@@ -529,6 +531,7 @@ art_cc_library {
],
shared_libs: [
"libartbase",
+ "libart-simulator-container",
"libdexfile",
// We need to eagerly load it so libdexfile_support used from libunwindstack can find it.
"libdexfile_external",
@@ -563,6 +566,7 @@ art_cc_library {
],
shared_libs: [
"libartbased",
+ "libartd-simulator-container",
"libdexfiled",
// We need to eagerly preload it, so that libunwindstack can find it.
// Otherwise, it would try to load the non-debug version with dlopen.
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 2db2faa408..3c70a92612 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -20,13 +20,14 @@
#include <cstddef>
#include "android-base/stringprintf.h"
-
#include "arch/context.h"
#include "art_method-inl.h"
#include "base/enums.h"
#include "base/stl_util.h"
#include "class_linker-inl.h"
#include "class_root-inl.h"
+#include "code_simulator.h"
+#include "code_simulator_container.h"
#include "debugger.h"
#include "dex/class_accessor-inl.h"
#include "dex/descriptors_names.h"
@@ -101,6 +102,11 @@ ArtMethod* ArtMethod::GetSingleImplementation(PointerSize pointer_size) {
return reinterpret_cast<ArtMethod*>(GetDataPtrSize(pointer_size));
}
+bool ArtMethod::CanBeSimulated() REQUIRES_SHARED(Locks::mutator_lock_) {
+ CodeSimulatorContainer* simulator = Thread::Current()->GetSimulator();
+ return simulator->Get()->CanSimulate(this);
+}
+
ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa,
jobject jlr_method) {
ObjPtr<mirror::Executable> executable = soa.Decode<mirror::Executable>(jlr_method);
@@ -355,7 +361,9 @@ void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue*
}
// Ensure that we won't be accidentally calling quick compiled code when -Xint.
- if (kIsDebugBuild && runtime->GetInstrumentation()->IsForcedInterpretOnly()) {
+ if (kIsDebugBuild &&
+ runtime->GetInstrumentation()->IsForcedInterpretOnly() &&
+ !Runtime::SimulatorMode()) {
CHECK(!runtime->UseJitCompilation());
const void* oat_quick_code =
(IsNative() || !IsInvokable() || IsProxyMethod() || IsObsolete())
@@ -365,7 +373,10 @@ void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue*
<< "Don't call compiled code when -Xint " << PrettyMethod();
}
- if (!IsStatic()) {
+ if (Runtime::SimulatorMode() && CanBeSimulated()) {
+ CodeSimulatorContainer* simulator = Thread::Current()->GetSimulator();
+ simulator->Get()->Invoke(this, args, args_size, self, result, shorty, IsStatic());
+ } else if (!IsStatic()) {
(*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);
} else {
(*art_quick_invoke_static_stub)(this, args, args_size, self, result, shorty);
@@ -570,6 +581,10 @@ const OatQuickMethodHeader* ArtMethod::GetOatQuickMethodHeader(uintptr_t pc) {
return nullptr;
}
+ if (Runtime::SimulatorMode()) {
+ return nullptr;
+ }
+
Runtime* runtime = Runtime::Current();
const void* existing_entry_point = GetEntryPointFromQuickCompiledCode();
CHECK(existing_entry_point != nullptr) << PrettyMethod() << "@" << this;
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 16b4648821..7f6004ace7 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -384,6 +384,8 @@ class ArtMethod final {
ClearAccessFlags(kAccSkipAccessChecks);
}
+ bool CanBeSimulated() REQUIRES_SHARED(Locks::mutator_lock_);
+
// Returns true if this method could be overridden by a default method.
bool IsOverridableByDefaultMethod() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 8bf38d35b2..3ea4a8d06f 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2185,9 +2185,14 @@ bool ClassLinker::AddImageSpace(
header.VisitPackedArtMethods([&](ArtMethod& method) REQUIRES_SHARED(Locks::mutator_lock_) {
if (!method.IsRuntimeMethod()) {
DCHECK(method.GetDeclaringClass() != nullptr);
- if (!method.IsNative() && !method.IsResolutionMethod()) {
- method.SetEntryPointFromQuickCompiledCodePtrSize(GetQuickToInterpreterBridge(),
- image_pointer_size_);
+ if (!method.IsResolutionMethod()) {
+ if (!method.IsNative()) {
+ method.SetEntryPointFromQuickCompiledCodePtrSize(GetQuickToInterpreterBridge(),
+ image_pointer_size_);
+ } else if (Runtime::SimulatorMode()) {
+ method.SetEntryPointFromQuickCompiledCodePtrSize(GetQuickGenericJniStub(),
+ image_pointer_size_);
+ }
}
}
}, space->Begin(), image_pointer_size_);
@@ -3554,6 +3559,10 @@ bool ClassLinker::ShouldUseInterpreterEntrypoint(ArtMethod* method, const void*
return true;
}
+ if (Runtime::SimulatorMode()) {
+ return !method->CanBeSimulated();
+ }
+
Runtime* runtime = Runtime::Current();
instrumentation::Instrumentation* instr = runtime->GetInstrumentation();
if (instr->InterpretOnly()) {
@@ -3671,7 +3680,7 @@ void ClassLinker::FixupStaticTrampolines(Thread* self, ObjPtr<mirror::Class> kla
}
// Check whether the method is native, in which case it's generic JNI.
- if (quick_code == nullptr && method->IsNative()) {
+ if ((Runtime::SimulatorMode() || quick_code == nullptr) && method->IsNative()) {
quick_code = GetQuickGenericJniStub();
} else if (ShouldUseInterpreterEntrypoint(method, quick_code)) {
// Use interpreter entry point.
@@ -3731,7 +3740,7 @@ static void LinkCode(ClassLinker* class_linker,
// Note: this mimics the logic in image_writer.cc that installs the resolution
// stub only if we have compiled code and the method needs a class initialization
// check.
- if (quick_code == nullptr) {
+ if (quick_code == nullptr || Runtime::SimulatorMode()) {
method->SetEntryPointFromQuickCompiledCode(
method->IsNative() ? GetQuickGenericJniStub() : GetQuickToInterpreterBridge());
} else if (enter_interpreter) {
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 6bd1c8f933..88992f126a 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -31,6 +31,7 @@
#include "base/utils.h"
#include "elf/elf_utils.h"
#include "elf_file_impl.h"
+#include "runtime.h"
namespace art {
@@ -1101,9 +1102,9 @@ bool ElfFileImpl<ElfTypes>::Load(File* file,
if (executable) {
InstructionSet elf_ISA = GetInstructionSetFromELF(GetHeader().e_machine, GetHeader().e_flags);
- if (elf_ISA != kRuntimeISA) {
+ if (elf_ISA != Runtime::GetQuickCodeISA()) {
std::ostringstream oss;
- oss << "Expected ISA " << kRuntimeISA << " but found " << elf_ISA;
+ oss << "Expected ISA " << Runtime::GetQuickCodeISA() << " but found " << elf_ISA;
*error_msg = oss.str();
return false;
}
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index 52c4142712..e3f0d00440 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -136,12 +136,12 @@ class EntrypointsOrderTest : public CommonRuntimeTest {
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_mark_stack, async_exception, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, async_exception, top_reflective_handle_scope,
sizeof(void*));
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, top_reflective_handle_scope, simulator, sizeof(void*));
// The first field after tlsPtr_ is forced to a 16 byte alignment so it might have some space.
auto offset_tlsptr_end = OFFSETOF_MEMBER(Thread, tlsPtr_) +
sizeof(decltype(reinterpret_cast<Thread*>(16)->tlsPtr_));
- CHECKED(offset_tlsptr_end - OFFSETOF_MEMBER(Thread, tlsPtr_.top_reflective_handle_scope) ==
- sizeof(void*),
- "async_exception last field");
+ CHECKED(offset_tlsptr_end - OFFSETOF_MEMBER(Thread, tlsPtr_.simulator) == sizeof(void*),
+ "simulator last field");
}
void CheckJniEntryPoints() {
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index c6d3258766..01a6213a26 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -150,6 +150,9 @@ bool CanUseMterp()
runtime->IsStarted() &&
!runtime->IsAotCompiler() &&
!runtime->GetInstrumentation()->IsActive() &&
+ // In simulator mode, mterp and its fast path are avoided to ensure every
+ // called method can go through ArtMethod::Invoke().
+ !Runtime::SimulatorMode() &&
// mterp only knows how to deal with the normal exits. It cannot handle any of the
// non-standard force-returns.
!runtime->AreNonStandardExitsEnabled() &&
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index 11e02a2ce4..27dd9709bd 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -143,8 +143,10 @@ static jobjectArray VMClassLoader_getBootClassPathEntries(JNIEnv* env, jclass) {
const DexFile* dex_file = path[i];
// For multidex locations, e.g., x.jar!classes2.dex, we want to look into x.jar.
- const std::string location(DexFileLoader::GetBaseLocation(dex_file->GetLocation()));
-
+ std::string location(DexFileLoader::GetBaseLocation(dex_file->GetLocation()));
+ if (Runtime::SimulatorMode()) {
+ location = getenv("ANDROID_PRODUCT_OUT") + location;
+ }
ScopedLocalRef<jstring> javaPath(env, env->NewStringUTF(location.c_str()));
if (javaPath.get() == nullptr) {
DCHECK(env->ExceptionCheck());
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 9c169e6c63..de3d878302 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -111,9 +111,9 @@ OatFileAssistant::OatFileAssistant(const char* dex_location,
dex_location_.assign(dex_location);
- if (load_executable_ && isa != kRuntimeISA) {
+ if (load_executable_ && isa != Runtime::GetQuickCodeISA()) {
LOG(WARNING) << "OatFileAssistant: Load executable specified, "
- << "but isa is not kRuntimeISA. Will not attempt to load executable.";
+ << "but isa is not executable isa. Will not attempt to load executable.";
load_executable_ = false;
}
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 85992ea191..1480c1db6f 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -236,10 +236,10 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
std::unique_ptr<ClassLoaderContext> context(
ClassLoaderContext::CreateContextForClassLoader(class_loader, dex_elements));
- OatFileAssistant oat_file_assistant(dex_location,
- kRuntimeISA,
- runtime->GetOatFilesExecutable(),
- only_use_system_oat_files_);
+ OatFileAssistant oat_file_assistant(dex_location,
+ Runtime::GetQuickCodeISA(),
+ runtime->GetOatFilesExecutable(),
+ only_use_system_oat_files_);
// Get the oat file on disk.
std::unique_ptr<const OatFile> oat_file(oat_file_assistant.GetBestOatFile().release());
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 0a52e7e861..dab0f55df8 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -422,6 +422,11 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize
.WithType<bool>()
.WithValueMap({{"false", false}, {"true", true}})
.IntoKey(M::PerfettoHprof)
+ .Define("--simulate-isa=_")
+ .WithType<InstructionSet>()
+ .WithValueMap({{"none", InstructionSet::kNone},
+ {"arm64", InstructionSet::kArm64}})
+ .IntoKey(M::SimulateInstructionSet)
.Ignore({
"-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa",
"-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:_",
diff --git a/runtime/parsed_options_test.cc b/runtime/parsed_options_test.cc
index 8873eb9c60..60a0837819 100644
--- a/runtime/parsed_options_test.cc
+++ b/runtime/parsed_options_test.cc
@@ -109,6 +109,7 @@ TEST_F(ParsedOptionsTest, ParsedOptions) {
EXPECT_FALSE(VLOG_IS_ON(startup));
EXPECT_FALSE(VLOG_IS_ON(third_party_jni));
EXPECT_FALSE(VLOG_IS_ON(threads));
+ EXPECT_PARSED_EQ(InstructionSet::kNone, Opt::SimulateInstructionSet);
auto&& properties_list = map.GetOrDefault(Opt::PropertiesList);
ASSERT_EQ(2U, properties_list.size());
@@ -181,4 +182,18 @@ TEST_F(ParsedOptionsTest, ParsedOptionsInstructionSet) {
}
}
+TEST_F(ParsedOptionsTest, ParsedOptionSimulateInstructionSet) {
+ RuntimeOptions options;
+ options.push_back(std::make_pair("--simulate-isa=arm64", nullptr));
+
+ RuntimeArgumentMap map;
+ bool parsed = ParsedOptions::Parse(options, false, &map);
+ ASSERT_TRUE(parsed);
+ ASSERT_NE(0u, map.Size());
+
+ using Opt = RuntimeArgumentMap;
+
+ EXPECT_PARSED_EQ(InstructionSet::kArm64, Opt::SimulateInstructionSet);
+}
+
} // namespace art
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index fc1a3c8031..79b51daff7 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -69,6 +69,7 @@
#include "base/utils.h"
#include "class_linker-inl.h"
#include "class_root-inl.h"
+#include "code_simulator_container.h"
#include "compiler_callbacks.h"
#include "debugger.h"
#include "dex/art_dex_file_loader.h"
@@ -230,6 +231,7 @@ Runtime::Runtime()
imt_conflict_method_(nullptr),
imt_unimplemented_method_(nullptr),
instruction_set_(InstructionSet::kNone),
+ simulate_isa_(InstructionSet::kNone),
compiler_callbacks_(nullptr),
is_zygote_(false),
is_primary_zygote_(false),
@@ -1340,7 +1342,9 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
fingerprint_ = runtime_options.ReleaseOrDefault(Opt::Fingerprint);
- if (runtime_options.GetOrDefault(Opt::Interpret)) {
+ if (runtime_options.GetOrDefault(Opt::Interpret) ||
+ runtime_options.GetOrDefault(Opt::SimulateInstructionSet) != InstructionSet::kNone) {
+ // Both -Xint and --simulate-isa options force interpreter only.
GetInstrumentation()->ForceInterpretOnly();
}
@@ -1376,6 +1380,12 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
image_space_loading_order_ = runtime_options.GetOrDefault(Opt::ImageSpaceLoadingOrder);
+ instruction_set_ = runtime_options.GetOrDefault(Opt::ImageInstructionSet);
+ SetInstructionSet(instruction_set_);
+
+ InstructionSet simulate_isa = runtime_options.GetOrDefault(Opt::SimulateInstructionSet);
+ SetSimulateISA(simulate_isa);
+
heap_ = new gc::Heap(runtime_options.GetOrDefault(Opt::MemoryInitialSize),
runtime_options.GetOrDefault(Opt::HeapGrowthLimit),
runtime_options.GetOrDefault(Opt::HeapMinFree),
@@ -1388,7 +1398,7 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
GetBootClassPath(),
GetBootClassPathLocations(),
image_location_,
- instruction_set_,
+ GetQuickCodeISA(),
// Override the collector type to CC if the read barrier config.
kUseReadBarrier ? gc::kCollectorTypeCC : xgc_option.collector_type_,
kUseReadBarrier ? BackgroundGcOption(gc::kCollectorTypeCCBackground)
@@ -1616,7 +1626,6 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
}
// TODO: Should we move the following to InitWithoutImage?
- SetInstructionSet(instruction_set_);
for (uint32_t i = 0; i < kCalleeSaveSize; i++) {
CalleeSaveType type = CalleeSaveType(i);
if (!HasCalleeSaveMethod(type)) {
@@ -2367,6 +2376,24 @@ void Runtime::BroadcastForNewSystemWeaks(bool broadcast_for_checkpoint) {
}
}
+InstructionSet Runtime::GetQuickCodeISA() {
+ Runtime* runtime = Runtime::Current();
+ if (runtime == nullptr) {
+ return kRuntimeISA;
+ }
+
+ // In simulator mode, image ISA should align with simulator.
+ if (SimulatorMode()) {
+ return runtime->GetSimulateISA();
+ }
+
+ // Otherwise, image ISA should align with runtime.
+ if (runtime->GetInstructionSet() == InstructionSet::kNone) {
+ return kRuntimeISA;
+ }
+ return runtime->GetInstructionSet();
+}
+
void Runtime::SetInstructionSet(InstructionSet instruction_set) {
instruction_set_ = instruction_set;
switch (instruction_set) {
@@ -2389,6 +2416,16 @@ void Runtime::ClearInstructionSet() {
instruction_set_ = InstructionSet::kNone;
}
+void Runtime::SetSimulateISA(InstructionSet instruction_set) {
+ DCHECK(GetInstructionSet() != InstructionSet::kNone) << "Simulator ISA set before runtime ISA.";
+ if (instruction_set == InstructionSet::kNone) {
+ return;
+ }
+ CodeSimulatorContainer simulator(instruction_set);
+ DCHECK(simulator.CanSimulate()) << "Fail to set simulator isa: " << instruction_set;
+ simulate_isa_ = instruction_set;
+}
+
void Runtime::SetCalleeSaveMethod(ArtMethod* method, CalleeSaveType type) {
DCHECK_LT(static_cast<uint32_t>(type), kCalleeSaveSize);
CHECK(method != nullptr);
@@ -2625,8 +2662,12 @@ void Runtime::AddCurrentRuntimeFeaturesAsDex2OatArguments(std::vector<std::strin
// Make the dex2oat instruction set match that of the launching runtime. If we have multiple
// architecture support, dex2oat may be compiled as a different instruction-set than that
// currently being executed.
+ // In simulator mode, the dex2oat instruction set should match the simulator, so that we can
+ // compile for simulating ISA.
+ InstructionSet target_isa =
+ (simulate_isa_ == InstructionSet::kNone) ? kRuntimeISA : simulate_isa_;
std::string instruction_set("--instruction-set=");
- instruction_set += GetInstructionSetString(kRuntimeISA);
+ instruction_set += GetInstructionSetString(target_isa);
argv->push_back(instruction_set);
if (InstructionSetFeatures::IsRuntimeDetectionSupported()) {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 594edaae39..0ee280c359 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -461,6 +461,10 @@ class Runtime {
return OFFSETOF_MEMBER(Runtime, callee_save_methods_[static_cast<size_t>(type)]);
}
+ // There are different kinds of ISAs in runtime:
+ // 1) Runtime ISA: for compiler, frame information
+ // 2) Quick code ISA: for image loading
+ // 3) Simulate ISA: for simulator
InstructionSet GetInstructionSet() const {
return instruction_set_;
}
@@ -468,6 +472,26 @@ class Runtime {
void SetInstructionSet(InstructionSet instruction_set);
void ClearInstructionSet();
+ static InstructionSet GetQuickCodeISA();
+
+ void SetSimulateISA(InstructionSet instruction_set);
+
+ InstructionSet GetSimulateISA() const {
+ return simulate_isa_;
+ }
+
+ static inline bool SimulatorMode() {
+ if (kIsDebugBuild) {
+ Runtime* runtime = Current();
+ // Disable simulator for compiler.
+ if (runtime == nullptr || runtime->IsCompiler()) {
+ return false;
+ }
+ return runtime->GetSimulateISA() != InstructionSet::kNone;
+ }
+ return false;
+ }
+
void SetCalleeSaveMethod(ArtMethod* method, CalleeSaveType type);
void ClearCalleeSaveMethods();
@@ -1046,6 +1070,10 @@ class Runtime {
InstructionSet instruction_set_;
+ // The ISA of code we are simulating. If it is not kNone, we will run the code with that ISA and
+ // run with a simulator. The code might come from JIT compiler or a pre-built image.
+ InstructionSet simulate_isa_;
+
CompilerCallbacks* compiler_callbacks_;
bool is_zygote_;
bool is_primary_zygote_;
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index a3429732f3..ce5a16b125 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -139,6 +139,8 @@ RUNTIME_OPTIONS_KEY (ExperimentalFlags, Experimental, ExperimentalFlags::k
RUNTIME_OPTIONS_KEY (std::list<ti::AgentSpec>, AgentLib) // -agentlib:<libname>=<options>
RUNTIME_OPTIONS_KEY (std::list<ti::AgentSpec>, AgentPath) // -agentpath:<libname>=<options>
RUNTIME_OPTIONS_KEY (std::vector<Plugin>, Plugins) // -Xplugin:<library>
+// Simulator is disabled by default.
+RUNTIME_OPTIONS_KEY (InstructionSet, SimulateInstructionSet, InstructionSet::kNone) // --simulate-isa=_
// Not parse-able from command line, but can be provided explicitly.
// (Do not add anything here that is defined in ParsedOptions::MakeParser)
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 21b8d05087..b71c41e48e 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -57,6 +57,8 @@
#include "base/utils.h"
#include "class_linker-inl.h"
#include "class_root-inl.h"
+#include "code_simulator.h"
+#include "code_simulator_container.h"
#include "debugger.h"
#include "dex/descriptors_names.h"
#include "dex/dex_file-inl.h"
@@ -164,6 +166,15 @@ void Thread::SetIsGcMarkingAndUpdateEntrypoints(bool is_marking) {
UpdateReadBarrierEntrypoints(&tlsPtr_.quick_entrypoints, /* is_active= */ is_marking);
}
+void Thread::InitSimulator() {
+ tlsPtr_.simulator = new CodeSimulatorContainer(Runtime::Current()->GetSimulateISA());
+}
+
+CodeSimulatorContainer* Thread::GetSimulator() {
+ DCHECK(tlsPtr_.simulator != nullptr);
+ return tlsPtr_.simulator;
+}
+
void Thread::InitTlsEntryPoints() {
ScopedTrace trace("InitTlsEntryPoints");
// Insert a placeholder so we can easily tell if we call an unimplemented entry point.
@@ -174,6 +185,14 @@ void Thread::InitTlsEntryPoints() {
*it = reinterpret_cast<uintptr_t>(UnimplementedEntryPoint);
}
InitEntryPoints(&tlsPtr_.jni_entrypoints, &tlsPtr_.quick_entrypoints);
+
+ // Initialize entry points for simulator because some entry points are not needed in normal run,
+ // but required in simulator mode.
+ if (Runtime::SimulatorMode()) {
+ CodeSimulatorContainer *simulator = GetSimulator();
+ DCHECK(simulator->CanSimulate());
+ simulator->Get()->InitEntryPoints(&tlsPtr_.quick_entrypoints);
+ }
}
void Thread::ResetQuickAllocEntryPointsForThread() {
@@ -934,6 +953,9 @@ bool Thread::Init(ThreadList* thread_list, JavaVMExt* java_vm, JNIEnvExt* jni_en
return false;
}
InitCpu();
+ if (Runtime::SimulatorMode()) {
+ InitSimulator();
+ }
InitTlsEntryPoints();
RemoveSuspendTrigger();
InitCardTable();
@@ -2488,6 +2510,10 @@ Thread::~Thread() {
CleanupCpu();
}
+ if (tlsPtr_.simulator != nullptr) {
+ delete tlsPtr_.simulator;
+ }
+
delete tlsPtr_.instrumentation_stack;
delete tlsPtr_.name;
delete tlsPtr_.deps_or_stack_trace_sample.stack_trace_sample;
diff --git a/runtime/thread.h b/runtime/thread.h
index d2833b0372..c2416e61f9 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -49,6 +49,8 @@ class BacktraceMap;
namespace art {
+class CodeSimulatorContainer;
+
namespace gc {
namespace accounting {
template<class T> class AtomicStack;
@@ -192,6 +194,8 @@ class Thread {
// TODO: mark as PURE so the compiler may coalesce and remove?
static Thread* Current();
+ CodeSimulatorContainer* GetSimulator();
+
// On a runnable thread, check for pending thread suspension request and handle if pending.
void AllowThreadSuspension() REQUIRES_SHARED(Locks::mutator_lock_);
@@ -1419,6 +1423,7 @@ class Thread {
REQUIRES(Locks::runtime_shutdown_lock_);
void InitCardTable();
void InitCpu();
+ void InitSimulator();
void CleanupCpu();
void InitTlsEntryPoints();
void InitTid();
@@ -1683,7 +1688,7 @@ class Thread {
thread_local_objects(0), mterp_current_ibase(nullptr), thread_local_alloc_stack_top(nullptr),
thread_local_alloc_stack_end(nullptr),
flip_function(nullptr), method_verifier(nullptr), thread_local_mark_stack(nullptr),
- async_exception(nullptr), top_reflective_handle_scope(nullptr) {
+ async_exception(nullptr), top_reflective_handle_scope(nullptr), simulator(nullptr) {
std::fill(held_mutexes, held_mutexes + kLockLevelCount, nullptr);
}
@@ -1842,6 +1847,9 @@ class Thread {
// Top of the linked-list for reflective-handle scopes or null if none.
BaseReflectiveHandleScope* top_reflective_handle_scope;
+
+ // A pointer to the simulator container.
+ CodeSimulatorContainer* simulator;
} tlsPtr_;
// Small thread-local cache to be used from the interpreter.
diff --git a/simulator/Android.bp b/simulator/Android.bp
index 1410444a3d..d71e56578c 100644
--- a/simulator/Android.bp
+++ b/simulator/Android.bp
@@ -18,12 +18,15 @@ cc_library_headers {
name: "libart_simulator_headers",
host_supported: true,
export_include_dirs: ["include"],
+ apex_available: [
+ "com.android.art.release",
+ "com.android.art.debug",
+ ],
}
cc_defaults {
name: "libart_simulator_defaults",
host_supported: true,
- device_supported: false,
defaults: ["art_defaults"],
srcs: [
@@ -36,7 +39,12 @@ cc_defaults {
],
cflags: ["-DVIXL_INCLUDE_SIMULATOR_AARCH64"],
- header_libs: ["libart_simulator_headers"],
+ header_libs: [
+ "jni_platform_headers",
+ "libdexfile_all_headers",
+ "libart_runtime_headers_ndk",
+ "libart_simulator_headers",
+ ],
}
art_cc_library {
@@ -47,6 +55,7 @@ art_cc_library {
"libartbase",
"libvixl",
],
+ device_supported: false,
}
art_cc_library {
@@ -60,6 +69,7 @@ art_cc_library {
"libartbased",
"libvixld",
],
+ device_supported: false,
}
cc_defaults {
@@ -73,8 +83,12 @@ cc_defaults {
shared_libs: [
"libbase",
],
-
- header_libs: ["libart_simulator_headers"],
+ header_libs: [
+ "jni_platform_headers",
+ "libdexfile_all_headers",
+ "libart_runtime_headers_ndk",
+ "libart_simulator_headers",
+ ],
export_include_dirs: ["."], // TODO: Consider a proper separation.
}
@@ -83,7 +97,10 @@ art_cc_library {
defaults: ["libart_simulator_container_defaults"],
shared_libs: [
"libartbase",
- "libart",
+ ],
+ apex_available: [
+ "com.android.art.release",
+ "com.android.art.debug",
],
}
@@ -95,7 +112,6 @@ art_cc_library {
],
shared_libs: [
"libartbased",
- "libartd",
],
apex_available: [
"com.android.art.debug",
diff --git a/simulator/code_simulator_arm64.cc b/simulator/code_simulator_arm64.cc
index a64bd0bc0b..7521d183b8 100644
--- a/simulator/code_simulator_arm64.cc
+++ b/simulator/code_simulator_arm64.cc
@@ -16,13 +16,178 @@
#include "code_simulator_arm64.h"
-#include <android-base/logging.h>
+#include "art_method.h"
+#include "base/logging.h"
+#include "class_linker.h"
+#include "thread.h"
+
+#include <string>
+#include <cstring>
+#include <math.h>
+
+static constexpr bool kEnableSimulateMethodAllowList = false;
+
+static const std::vector<std::string> simulate_method_allow_list = {
+ // Add any run test method you want to simulate here, for example:
+ // test/684-checker-simd-dotprod
+ "other.TestByte.testDotProdComplex",
+ "other.TestByte.testDotProdComplexSignedCastedToUnsigned",
+ "other.TestByte.testDotProdComplexUnsigned",
+ "other.TestByte.testDotProdComplexUnsignedCastedToSigned",
+};
+static const std::vector<std::string> avoid_simulation_method_list = {
+ // For now, we can focus on simulating run test methods called by main().
+ "main",
+ "<clinit>",
+ // Currently, we don't simulate Java library methods.
+ "java.",
+ "sun.",
+ "dalvik.",
+ "android.",
+ "libcore.",
+};
using namespace vixl::aarch64; // NOLINT(build/namespaces)
namespace art {
namespace arm64 {
+ // Special registers defined in asm_support_arm64.s.
+ // Register holding Thread::current().
+ static const unsigned kSelf = 19;
+ // Marking register.
+ static const unsigned kMR = 20;
+ // Frame Pointer.
+ static const unsigned kFp = 29;
+ // Stack Pointer.
+ static const unsigned kSp = 31;
+
+class CustomSimulator final: public Simulator {
+ public:
+ explicit CustomSimulator(Decoder* decoder) : Simulator(decoder), qpoints_(nullptr) {}
+ virtual ~CustomSimulator() {}
+
+ void SetEntryPoints(QuickEntryPoints* qpoints) {
+ DCHECK(qpoints_ == nullptr);
+ qpoints_ = qpoints;
+ }
+
+ template <typename R, typename... P>
+ struct RuntimeCallHelper {
+ static void Execute(Simulator* simulator, R (*f)(P...)) {
+ simulator->RuntimeCallNonVoid(f);
+ }
+ };
+
+ // Partial specialization when the return type is `void`.
+ template <typename... P>
+ struct RuntimeCallHelper<void, P...> {
+ static void Execute(Simulator* simulator, void (*f)(P...)) {
+ simulator->RuntimeCallVoid(f);
+ }
+ };
+
+ // Override Simulator::VisitUnconditionalBranchToRegister to handle any runtime invokes
+ // which can be simulated.
+ void VisitUnconditionalBranchToRegister(const vixl::aarch64::Instruction* instr) override
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(qpoints_ != nullptr);
+ if (instr->Mask(UnconditionalBranchToRegisterMask) == BR) {
+ // The thunk mechansim code (LDR, BR) is generated by
+ // CodeGeneratorARM64::InvokeRuntime()
+
+ // Conceptually, the control flow works as if:
+ // #########################################################################
+ // Compiled Method (arm64) | THUNK (arm64) | Runtime Function (x86_64)
+ // #########################################################################
+ // BL kQuickTestSuspend@thunk -> LDR x16, [...]
+ // BR x16 -------> art_quick_test_suspend
+ // ^ (x86 ret)
+ // | |
+ // +---------------------------------------------------+
+
+ // Actual control flow: arm64 code <-> x86_64 runtime, intercepted by simulator.
+ // ##########################################################################
+ // arm64 code in simulator | | ART Runtime (x86_64)
+ // ##########################################################################
+ // BL kQuickTestSuspend@thunk -> LDR x16, [...]
+ // BR x16 ---> simulator ---> art_quick_test_suspend
+ // ^ (x86 call) (x86 ret)
+ // | |
+ // +------------------------------------- simulator <-------------+
+ // (ARM ret)
+ //
+
+ const void* target = reinterpret_cast<const void*>(ReadXRegister(instr->GetRn()));
+ auto lr = vixl::aarch64::Instruction::Cast(get_lr());
+ if (target == reinterpret_cast<const void*>(qpoints_->pTestSuspend)) {
+ RuntimeCallHelper<void>::Execute(this, qpoints_->pTestSuspend);
+ } else {
+ // For branching to fixed addresses or labels, nothing has changed.
+ Simulator::VisitUnconditionalBranchToRegister(instr);
+ return;
+ }
+ WritePc(lr); // aarch64 return
+ return;
+ } else if (instr->Mask(UnconditionalBranchToRegisterMask) == BLR) {
+ const void* target = reinterpret_cast<const void*>(ReadXRegister(instr->GetRn()));
+ auto lr = instr->GetNextInstruction();
+ if (target == reinterpret_cast<const void*>(qpoints_->pAllocObjectInitialized)) {
+ RuntimeCallHelper<void *, mirror::Class *>::Execute(this, qpoints_->pAllocObjectInitialized);
+ } else if (target == reinterpret_cast<const void*>(qpoints_->pAllocArrayResolved8) ||
+ target == reinterpret_cast<const void*>(qpoints_->pAllocArrayResolved16) ||
+ target == reinterpret_cast<const void*>(qpoints_->pAllocArrayResolved32) ||
+ target == reinterpret_cast<const void*>(qpoints_->pAllocArrayResolved64)) {
+ RuntimeCallHelper<void *, mirror::Class *, int32_t>::Execute(this,
+ reinterpret_cast<void *(*)(art::mirror::Class *, int)>(const_cast<void*>(target)));
+ } else {
+ // For branching to fixed addresses or labels, nothing has changed.
+ Simulator::VisitUnconditionalBranchToRegister(instr);
+ return;
+ }
+ WritePc(lr); // aarch64 return
+ return;
+ }
+ Simulator::VisitUnconditionalBranchToRegister(instr);
+ return;
+ }
+
+ // TODO(simulator): Maybe integrate these into vixl?
+ int64_t get_sp() const {
+ return ReadRegister<int64_t>(kSp, Reg31IsStackPointer);
+ }
+
+ int64_t get_x(int32_t n) const {
+ return ReadRegister<int64_t>(n, Reg31IsStackPointer);
+ }
+
+ int64_t get_lr() const {
+ return ReadRegister<int64_t>(kLinkRegCode);
+ }
+
+ int64_t get_fp() const {
+ return ReadXRegister(kFp);
+ }
+
+ private:
+ QuickEntryPoints* qpoints_;
+};
+
+static const void* GetQuickCodeFromArtMethod(ArtMethod* method)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(!method->IsAbstract());
+ DCHECK(!method->IsNative());
+ DCHECK(Runtime::SimulatorMode());
+ DCHECK(method->CanBeSimulated());
+
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
+ const void* code = method->GetOatMethodQuickCode(linker->GetImagePointerSize());
+ if (code != nullptr) {
+ return code;
+ }
+ return nullptr;
+}
+
// VIXL has not been tested on 32bit architectures, so Simulator is not always
// available. To avoid linker error on these architectures, we check if we can simulate
// in the beginning of following methods, with compile time constant `kCanSimulate`.
@@ -40,7 +205,11 @@ CodeSimulatorArm64::CodeSimulatorArm64()
: CodeSimulator(), decoder_(nullptr), simulator_(nullptr) {
DCHECK(kCanSimulate);
decoder_ = new Decoder();
- simulator_ = new Simulator(decoder_);
+ simulator_ = new CustomSimulator(decoder_);
+ if (VLOG_IS_ON(simulator)) {
+ simulator_->SetColouredTrace(true);
+ simulator_->SetTraceParameters(LOG_DISASM | LOG_WRITE);
+ }
}
CodeSimulatorArm64::~CodeSimulatorArm64() {
@@ -51,7 +220,7 @@ CodeSimulatorArm64::~CodeSimulatorArm64() {
void CodeSimulatorArm64::RunFrom(intptr_t code_buffer) {
DCHECK(kCanSimulate);
- simulator_->RunFrom(reinterpret_cast<const Instruction*>(code_buffer));
+ simulator_->RunFrom(reinterpret_cast<const vixl::aarch64::Instruction*>(code_buffer));
}
bool CodeSimulatorArm64::GetCReturnBool() const {
@@ -69,5 +238,208 @@ int64_t CodeSimulatorArm64::GetCReturnInt64() const {
return simulator_->ReadXRegister(0);
}
+void CodeSimulatorArm64::Invoke(ArtMethod* method, uint32_t* args, uint32_t args_size_in_bytes,
+ Thread* self, JValue* result, const char* shorty, bool isStatic)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(kCanSimulate);
+ // ARM64 simulator only supports 64-bit host machines. Because:
+ // 1) vixl simulator is not tested on 32-bit host machines.
+ // 2) Data structures in ART have different representations for 32/64-bit machines.
+ DCHECK(sizeof(args) == sizeof(int64_t));
+
+ if (VLOG_IS_ON(simulator)) {
+ VLOG(simulator) << "\nVIXL_SIMULATOR simulate: " << method->PrettyMethod();
+ }
+
+ InitRegistersForInvokeStub(method, args, args_size_in_bytes, self, result, shorty, isStatic);
+
+ int64_t quick_code = reinterpret_cast<int64_t>(GetQuickCodeFromArtMethod(method));
+ RunFrom(quick_code);
+
+ GetResultFromShorty(result, shorty);
+
+ // Ensure simulation state is not carried over from one method to another.
+ simulator_->ResetState();
+
+ // Reset stack pointer.
+ simulator_->WriteSp(saved_sp_);
+}
+
+void CodeSimulatorArm64::GetResultFromShorty(JValue* result, const char* shorty) {
+ switch (shorty[0]) {
+ case 'V':
+ return;
+ case 'D':
+ result->SetD(simulator_->ReadDRegister(0));
+ return;
+ case 'F':
+ result->SetF(simulator_->ReadSRegister(0));
+ return;
+ default:
+ // Just store x0. Doesn't matter if it is 64 or 32 bits.
+ result->SetJ(simulator_->ReadXRegister(0));
+ return;
+ }
+}
+
+// Init registers for invoking art_quick_invoke_stub:
+//
+// extern"C" void art_quick_invoke_stub(ArtMethod *method, x0
+// uint32_t *args, x1
+// uint32_t argsize, w2
+// Thread *self, x3
+// JValue *result, x4
+// char *shorty); x5
+//
+// See art/runtime/arch/arm64/quick_entrypoints_arm64.S
+//
+// +----------------------+
+// | |
+// | C/C++ frame |
+// | LR'' |
+// | FP'' | <- SP'
+// +----------------------+
+// +----------------------+
+// | X28 |
+// | : |
+// | X19 (*self) |
+// | SP' | Saved registers
+// | X5 (*shorty) |
+// | X4 (*result) |
+// | LR' |
+// | FP' | <- FP
+// +----------------------+
+// | uint32_t out[n-1] |
+// | : : | Outs
+// | uint32_t out[0] |
+// | ArtMethod* | <- SP value=null
+// +----------------------+
+//
+// Outgoing registers:
+// x0 - Current ArtMethod*
+// x1-x7 - integer parameters.
+// d0-d7 - Floating point parameters.
+// xSELF = self
+// SP = & of ArtMethod*
+// x1 - "this" pointer (for non-static method)
+void CodeSimulatorArm64::InitRegistersForInvokeStub(ArtMethod* method, uint32_t* args,
+ uint32_t args_size_in_bytes, Thread* self,
+ JValue* result, const char* shorty,
+ bool isStatic)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(kCanSimulate);
+
+ // Set registers x0, x4, x5, and x19.
+ simulator_->WriteXRegister(0, reinterpret_cast<int64_t>(method));
+ simulator_->WriteXRegister(kSelf, reinterpret_cast<int64_t>(self));
+ simulator_->WriteXRegister(4, reinterpret_cast<int64_t>(result));
+ simulator_->WriteXRegister(5, reinterpret_cast<int64_t>(shorty));
+
+ // Stack Pointer here is not the real one in hardware. This will break stack overflow check.
+ // Also note that the simulator stack is limited.
+ saved_sp_ = simulator_->get_sp();
+ // x4, x5, x19, x20 .. x28, SP, LR, FP saved (15 in total).
+ const int64_t regs_save_size_in_bytes = kXRegSizeInBytes * 15;
+ const int64_t frame_save_size = regs_save_size_in_bytes +
+ kXRegSizeInBytes + // ArtMethod*
+ static_cast<int64_t>(args_size_in_bytes);
+ // Comply with 16-byte alignment requirement for SP.
+ void** new_sp = reinterpret_cast<void**>((saved_sp_ - frame_save_size) & (~0xfUL));
+
+ simulator_->WriteSp(new_sp);
+
+ // Store null into ArtMethod* at bottom of frame.
+ *new_sp++ = nullptr;
+ // Copy arguments into stack frame.
+ std::memcpy(new_sp, args, args_size_in_bytes * sizeof(uint32_t));
+
+ // Callee-saved registers.
+ int64_t* save_registers = reinterpret_cast<int64_t*>(saved_sp_) + 3;
+ save_registers[0] = simulator_->get_fp();
+ save_registers[1] = simulator_->get_lr();
+ save_registers[2] = simulator_->get_x(4); // X4 (*result)
+ save_registers[3] = simulator_->get_x(5); // X5 (*shorty)
+ save_registers[4] = saved_sp_;
+ save_registers[5] = simulator_->get_x(kSelf); // X19 (*self)
+ for (unsigned int i = 6; i < 15; i++) {
+ save_registers[i] = simulator_->get_x(i + 14); // X20 .. X28
+ }
+
+ // Use xFP (Frame Pointer) now, as it's callee-saved.
+ simulator_->WriteXRegister(kFp, saved_sp_ - regs_save_size_in_bytes);
+
+ // Fill registers from args, according to shorty.
+ static const unsigned kRegisterIndexLimit = 8;
+ unsigned fpr_index = 0;
+ unsigned gpr_index = 1; // x1 ~ x7 integer parameters.
+ shorty++; // Skip the return value.
+ // For non-static method, load "this" parameter, and increment args pointer.
+ if (!isStatic) {
+ simulator_->WriteWRegister(gpr_index++, *args++);
+ }
+ // Loop to fill registers.
+ for (const char* s = shorty; *s != '\0'; s++) {
+ switch (*s) {
+ case 'D':
+ simulator_->WriteDRegister(fpr_index++, *reinterpret_cast<double*>(args));
+ args += 2;
+ break;
+ case 'J':
+ simulator_->WriteXRegister(gpr_index++, *reinterpret_cast<int64_t*>(args));
+ args += 2;
+ break;
+ case 'F':
+ simulator_->WriteSRegister(fpr_index++, *reinterpret_cast<float*>(args));
+ args++;
+ break;
+ default:
+ // Everything else takes one vReg.
+ simulator_->WriteWRegister(gpr_index++, *reinterpret_cast<int32_t*>(args));
+ args++;
+ break;
+ }
+ if (gpr_index > kRegisterIndexLimit || fpr_index < kRegisterIndexLimit) {
+ // TODO: Handle register spill.
+ UNREACHABLE();
+ }
+ }
+
+ // REFRESH_MARKING_REGISTER
+ if (kUseReadBarrier) {
+ simulator_->WriteWRegister(kMR, self->GetIsGcMarking());
+ }
+}
+
+void CodeSimulatorArm64::InitEntryPoints(QuickEntryPoints* qpoints) {
+ simulator_->SetEntryPoints(qpoints);
+}
+
+bool CodeSimulatorArm64::CanSimulate(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
+ std::string name = method->PrettyMethod();
+
+ // Make sure simulate methods with $simulate$ in their names.
+ if (name.find("$simulate$") != std::string::npos) {
+ return true;
+ }
+ // Simulation allow list mode, only simulate method on the allow list.
+ if (kEnableSimulateMethodAllowList) {
+ for (auto& s : simulate_method_allow_list) {
+ if (name.find(s) != std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+ }
+ // Avoid simulating following methods.
+ for (auto& s : avoid_simulation_method_list) {
+ if (name.find(s) != std::string::npos) {
+ return false;
+ }
+ }
+
+ // Try to simulate as much as we can.
+ return true;
+}
+
} // namespace arm64
} // namespace art
diff --git a/simulator/code_simulator_arm64.h b/simulator/code_simulator_arm64.h
index e726500452..ea5c95a3cc 100644
--- a/simulator/code_simulator_arm64.h
+++ b/simulator/code_simulator_arm64.h
@@ -27,10 +27,13 @@
#include "arch/instruction_set.h"
#include "code_simulator.h"
+#include "entrypoints/quick/quick_entrypoints.h"
namespace art {
namespace arm64 {
+class CustomSimulator;
+
class CodeSimulatorArm64 : public CodeSimulator {
public:
static CodeSimulatorArm64* CreateCodeSimulatorArm64();
@@ -42,11 +45,24 @@ class CodeSimulatorArm64 : public CodeSimulator {
int32_t GetCReturnInt32() const override;
int64_t GetCReturnInt64() const override;
+ bool CanSimulate(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) override;
+ void Invoke(ArtMethod* method, uint32_t* args, uint32_t args_size, Thread* self, JValue* result,
+ const char* shorty, bool isStatic) override REQUIRES_SHARED(Locks::mutator_lock_);
+
+ void InitEntryPoints(QuickEntryPoints* qpoints) override;
+
private:
CodeSimulatorArm64();
+ void InitRegistersForInvokeStub(ArtMethod* method, uint32_t* args, uint32_t args_size,
+ Thread* self, JValue* result, const char* shorty, bool isStatic)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ void GetResultFromShorty(JValue* result, const char* shorty);
+
vixl::aarch64::Decoder* decoder_;
- vixl::aarch64::Simulator* simulator_;
+ CustomSimulator* simulator_;
+ int64_t saved_sp_;
// TODO: Enable CodeSimulatorArm64 for more host ISAs once Simulator supports them.
static constexpr bool kCanSimulate = (kRuntimeISA == InstructionSet::kX86_64);
diff --git a/simulator/include/code_simulator.h b/simulator/include/code_simulator.h
index 256ab23aa4..22bac1e83f 100644
--- a/simulator/include/code_simulator.h
+++ b/simulator/include/code_simulator.h
@@ -18,9 +18,15 @@
#define ART_SIMULATOR_INCLUDE_CODE_SIMULATOR_H_
#include "arch/instruction_set.h"
+#include "runtime.h"
namespace art {
+class ArtMethod;
+union JValue;
+class Thread;
+struct QuickEntryPoints;
+
class CodeSimulator {
public:
CodeSimulator() {}
@@ -35,6 +41,13 @@ class CodeSimulator {
virtual int32_t GetCReturnInt32() const = 0;
virtual int64_t GetCReturnInt64() const = 0;
+ virtual bool CanSimulate(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+ virtual void Invoke(ArtMethod* method, uint32_t* args, uint32_t args_size, Thread* self,
+ JValue* result, const char* shorty, bool isStatic)
+ REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+
+ virtual void InitEntryPoints(QuickEntryPoints* qpoints) = 0;
+
private:
DISALLOW_COPY_AND_ASSIGN(CodeSimulator);
};
diff --git a/test.py b/test.py
index 9e54363d50..1cbad72529 100755
--- a/test.py
+++ b/test.py
@@ -33,6 +33,7 @@ parser.add_argument('--run-test', '-r', action='store_true', dest='run_test', he
parser.add_argument('--gtest', '-g', action='store_true', dest='gtest', help='execute gtest tests')
parser.add_argument('--target', action='store_true', dest='target', help='test on target system')
parser.add_argument('--host', action='store_true', dest='host', help='test on build host system')
+parser.add_argument('--simulate-arm64', action='store_true', dest='simulate_arm64', help='test on build host system')
parser.add_argument('--help-runner', action='store_true', dest='help_runner', help='show help for optional run test arguments')
options, unknown = parser.parse_known_args()
diff --git a/test/README.simulator.md b/test/README.simulator.md
new file mode 100644
index 0000000000..c575c35f09
--- /dev/null
+++ b/test/README.simulator.md
@@ -0,0 +1,98 @@
+# ART VIXL Simulator Integration
+
+This file documents the use of the VIXL Simulator for running tests on ART. The
+simulator enables us to run the ART run-tests without the need for a target
+device. This helps to speed up the development/debug/test cycle. The full AOSP
+source tree, as well as the partial master-art AOSP source tree, are supported.
+
+## Quick User Guide
+1. Set lunch target and setup environment:
+
+ ```bash
+ source build/envsetup.sh; lunch armv8-eng
+ ```
+
+2. Build ART target and host:
+
+ ```bash
+ art/tools/buildbot-build.sh --target
+ art/tools/buildbot-build.sh --host
+ ```
+
+3. Run Tests:
+
+ To enable the simulator we use the `--simulate-arm64` flag. The simulator can
+ be used directly with the dalvikvm or the ART test scripts.
+
+ To run a single test on simulator, use the command:
+ ```bash
+ art/test/run-test --host --simulate-arm64 --64 <TEST_NAME>
+ ```
+
+ To run all ART run-tests on simulator, use the `art/test.py` script with the
+ following command:
+ ```bash
+ ./art/test.py --simulate-arm64 --run-test --optimizing
+ ```
+
+4. Enable simulator tracing
+
+ Simulator provides tracing feature which is useful in debugging. Setting
+ runtime option `-verbose:simulator` will enable instruction trace and register
+ updates.
+ For example,
+ ```bash
+ ./art/test/run-test --host --runtime-option -verbose:simulator --optimizing \
+ --never-clean --simulate-arm64 --64 640-checker-simd
+ ```
+
+5. Debug
+
+ Another useful usecase of the simulator is debugging using the `--gdb` flag.
+ ```bash
+ ./art/test/run-test --gdb --host --simulate-arm64 --64 527-checker-array-access-split
+ ```
+ If developing a compiler optimization which affects the test case
+ `527-checker-array-access-split`, you can use the simulator to run and
+ generate the control flow graph with:
+ ```bash
+ ./art/test/run-test --host --dex2oat-jobs 1 -Xcompiler-option --dump-cfg=oat.cfg \
+ --never-clean --simulate-arm64 --64 527-checker-array-access-split
+ ```
+
+6. Control simulation
+
+ By default, in simulator mode, all methods in `art/test/` run-tests files are
+ simulated. However, within `art/simulator/code_simulator_arm64.cc`, the
+ `CanSimulate()` function provides options for developer to control simulation:
+ - the `kEnableSimulateMethodAllowList` to restrict the methods run in the simulator;
+ - the `$simulate$` tag to force the simulator to run a method.
+
+ #### Allow list to control simulation
+ Sometimes we may wish to restrict the methods run in the simulator, this can
+ be done using the `simulate_method_white_list`. Here a list of methods which
+ we know to be safe to run in the simulator is kept in
+ `art/simulator/code_simulator_arm64.cc`, the simulator can be forced to only
+ run the methods on this list by setting
+ ```
+ kEnableSimulateMethodAllowList = true
+ ```
+ and recompile art and rerun the test cases. For example, if we set the white list to
+ ```
+ static const std::vector<std::string> simulate_method_white_list = {
+ "other.TestByte.testDotProdComplex",
+ "other.TestByte.testDotProdComplexSignedCastedToUnsigned",
+ "other.TestByte.testDotProdComplexUnsigned",
+ "other.TestByte.testDotProdComplexUnsignedCastedToSigned",
+ };
+ ```
+ We only allow these methods to be run in simulator and all the other methods
+ will run in the interpreter.
+
+ #### The `$simulate$` tag to control simulation
+ In the case that we may wish to quickly change a Java method test case and
+ force the simulator to run a method without recompiling art, add the
+ `$simulate$` tag in the method name. For example,
+ ```
+ public void $simulate$foo() {}
+ ```
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 487958f40a..a7190ce6a9 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -109,6 +109,7 @@ ANDROID_FLAGS="${ANDROID_FLAGS} -XX:SlowDebug=true"
# The same for dex2oatd, both prebuild and runtime-driven.
ANDROID_FLAGS="${ANDROID_FLAGS} -Xcompiler-option --runtime-arg -Xcompiler-option -XX:SlowDebug=true"
COMPILER_FLAGS="${COMPILER_FLAGS} --runtime-arg -XX:SlowDebug=true"
+SIMULATOR="none"
# Let the compiler and runtime know that we are running tests.
COMPILE_FLAGS="${COMPILE_FLAGS} --compile-art-test"
@@ -468,6 +469,14 @@ while true; do
elif [ "x$1" = "x--random-profile" ]; then
RANDOM_PROFILE="y"
shift
+ elif [ "x$1" = "x--simulate-isa" ]; then
+ HOST="y"
+ ANDROID_ROOT="${ANDROID_PRODUCT_OUT}/system"
+ ANDROID_RUNTIME_ROOT="${ANDROID_PRODUCT_OUT}/apex/com.android.runtime.debug"
+ shift
+ SIMULATOR=$1
+ FLAGS="${FLAGS} --simulate-isa=${SIMULATOR}"
+ shift
elif expr "x$1" : "x--" >/dev/null 2>&1; then
echo "unknown $0 option: $1" 1>&2
exit 1
@@ -713,7 +722,11 @@ bpath_locations=""
bpath_separator=""
bpath_prefix=""
bpath_location_prefix=""
-if [ "${HOST}" = "y" ]; then
+if [ "$SIMULATOR" != "none" ]; then
+ # Simulator mode uses a mix of host and target bootclasspath locations.
+ bpath_prefix="${ANDROID_HOST_OUT}"
+ bpath_location_prefix=""
+elif [ "${HOST}" = "y" ]; then
bpath_prefix="${ANDROID_HOST_OUT}"
if [ "${ANDROID_HOST_OUT:0:${#ANDROID_BUILD_TOP}+1}" = "${ANDROID_BUILD_TOP}/" ]; then
bpath_location_prefix="${ANDROID_HOST_OUT:${#ANDROID_BUILD_TOP}+1}"
@@ -857,13 +870,15 @@ if [ ${#VDEX_NAME} -gt $max_filename_size ]; then
exit 1
fi
-if [ "$HOST" = "y" ]; then
+if [ "$HOST" = "y" ] && [ "$SIMULATOR" = "none" ]; then
# On host, run binaries (`dex2oat(d)`, `dalvikvm`, `profman`) from the `bin`
# directory under the "Android Root" (usually `out/host/linux-x86`).
#
# TODO(b/130295968): Adjust this if/when ART host artifacts are installed
# under the ART root (usually `out/host/linux-x86/com.android.art`).
ANDROID_ART_BIN_DIR=$ANDROID_ROOT/bin
+elif [ "$SIMULATOR" != "none" ]; then
+ ANDROID_ART_BIN_DIR=$ANDROID_HOST_OUT/bin
else
# On target, run binaries (`dex2oat(d)`, `dalvikvm`, `profman`) from the ART
# APEX's `bin` directory. This means the linker will observe the ART APEX
@@ -873,6 +888,10 @@ else
fi
profman_cmdline="true"
+if [ "$SIMULATOR" != "none" ]; then
+ ISA=$SIMULATOR
+fi
+
dex2oat_cmdline="true"
vdex_cmdline="true"
dm_cmdline="true"
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 6143dc7e90..1eb8e79b58 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -1344,5 +1344,636 @@
"variant": "jvm",
"bug": "b/154802847",
"description": ["Failing on RI. Needs further investigating."]
+ },
+ {
+ "tests": ["004-JniTest",
+ "003-omnibus-opcodes",
+ "004-NativeAllocations",
+ "004-ReferenceMap",
+ "004-SignalTest",
+ "004-StackWalk",
+ "004-ThreadStress",
+ "004-UnsafeTest",
+ "004-checker-UnsafeTest18",
+ "006-args",
+ "007-count10",
+ "008-exceptions",
+ "011-array-copy",
+ "012-math",
+ "013-math2",
+ "014-math3",
+ "015-switch",
+ "017-float",
+ "018-stack-overflow",
+ "020-string",
+ "021-string2",
+ "022-interface",
+ "023-many-interfaces",
+ "024-illegal-access",
+ "027-arithmetic",
+ "028-array-write",
+ "030-bad-finalizer",
+ "031-class-attributes",
+ "032-concrete-sub",
+ "033-class-init-deadlock",
+ "036-finalizer",
+ "037-inherit",
+ "038-inner-null",
+ "039-join-main",
+ "041-narrowing",
+ "042-new-instance",
+ "043-privates",
+ "044-proxy",
+ "045-reflect-array",
+ "046-reflect",
+ "047-returns",
+ "048-reflect-v8",
+ "049-show-object",
+ "050-sync-test",
+ "051-thread",
+ "052-verifier-fun",
+ "054-uncaught",
+ "058-enum-order",
+ "059-finalizer-throw",
+ "061-out-of-memory",
+ "062-character-encodings",
+ "063-process-manager",
+ "064-field-access",
+ "067-preemptive-unpark",
+ "068-classloader",
+ "070-nio-buffer",
+ "071-dexfile",
+ "071-dexfile-get-static-size",
+ "071-dexfile-map-clean",
+ "072-precise-gc",
+ "073-mismatched-field",
+ "074-gc-thrash",
+ "075-verification-error",
+ "076-boolean-put",
+ "077-method-override",
+ "078-polymorphic-virtual",
+ "079-phantom",
+ "080-oom-throw",
+ "080-oom-throw-with-finalizer",
+ "081-hot-exceptions",
+ "082-inline-execute",
+ "083-compiler-regressions",
+ "084-class-init",
+ "086-null-super",
+ "087-gc-after-link",
+ "088-monitor-verification",
+ "090-loop-formation",
+ "091-override-package-private-method",
+ "092-locale",
+ "093-serialization",
+ "096-array-copy-concurrent-gc",
+ "098-ddmc",
+ "099-vmdebug",
+ "100-reflect2",
+ "1002-notify-startup",
+ "1003-metadata-section-strings",
+ "1004-checker-volatile-ref-load",
+ "104-growth-limit",
+ "105-invoke",
+ "106-exceptions2",
+ "107-int-math2",
+ "109-suspend-check",
+ "110-field-access",
+ "111-unresolvable-exception",
+ "113-multidex",
+ "114-ParallelGC",
+ "115-native-bridge",
+ "121-simple-suspend-check",
+ "122-npe",
+ "123-compiler-regressions-mt",
+ "124-missing-classes",
+ "125-gc-and-classloading",
+ "126-miranda-multidex",
+ "127-checker-secondarydex",
+ "129-ThreadGetId",
+ "130-hprof",
+ "132-daemon-locks-shutdown",
+ "1336-short-finalizer-timeout",
+ "1337-gc-coverage",
+ "1339-dead-reference-safe",
+ "134-reg-promotion",
+ "135-MirandaDispatch",
+ "136-daemon-jni-shutdown",
+ "137-cfi",
+ "138-duplicate-classes-check",
+ "138-duplicate-classes-check2",
+ "139-register-natives",
+ "140-dce-regression",
+ "140-field-packing",
+ "141-class-unload",
+ "142-classloader2",
+ "144-static-field-sigquit",
+ "145-alloc-tracking-stress",
+ "146-bad-interface",
+ "148-multithread-gc-annotations",
+ "151-OpenFileLimit",
+ "154-gc-loop",
+ "155-java-set-resolved-type",
+ "156-register-dex-file-multi-loader",
+ "158-app-image-class-table",
+ "159-app-image-fields",
+ "160-read-barrier-stress",
+ "161-final-abstract-class",
+ "162-method-resolution",
+ "163-app-image-methods",
+ "164-resolution-trampoline-dex-cache",
+ "165-lock-owner-proxy",
+ "167-visit-locks",
+ "168-vmstack-annotated",
+ "170-interface-init",
+ "172-app-image-twice",
+ "173-missing-field-type",
+ "174-escaping-instance-of-bad-class",
+ "177-visibly-initialized-deadlock",
+ "178-app-image-native-method",
+ "201-built-in-except-detail-messages",
+ "203-multi-checkpoint",
+ "300-package-override",
+ "302-float-conversion",
+ "303-verification-stress",
+ "304-method-tracing",
+ "305-other-fault-handler",
+ "401-optimizing-compiler",
+ "403-optimizing-long",
+ "406-fields",
+ "407-arrays",
+ "409-materialized-condition",
+ "410-floats",
+ "411-checker-instruct-simplifier-hrem",
+ "411-checker-hdiv-hrem-const",
+ "411-checker-hdiv-hrem-pow2",
+ "411-optimizing-arith",
+ "412-new-array",
+ "414-static-fields",
+ "416-optimizing-arith-not",
+ "420-const-class",
+ "421-exceptions",
+ "421-large-frame",
+ "422-instanceof",
+ "422-type-conversion",
+ "423-invoke-interface",
+ "424-checkcast",
+ "426-monitor",
+ "427-bitwise",
+ "427-bounds",
+ "430-live-register-slow-path",
+ "432-optimizing-cmp",
+ "434-invoke-direct",
+ "435-try-finally-without-catch",
+ "436-rem-float",
+ "438-volatile",
+ "439-npe",
+ "439-swap-double",
+ "440-stmp",
+ "441-checker-inliner",
+ "442-checker-constant-folding",
+ "445-checker-licm",
+ "449-checker-bce",
+ "449-checker-bce-rem",
+ "455-checker-gvn",
+ "458-checker-instruct-simplification",
+ "461-get-reference-vreg",
+ "462-checker-inlining-dex-files",
+ "464-checker-inline-sharpen-calls",
+ "465-checker-clinit-gvn",
+ "466-get-live-vreg",
+ "467-regalloc-pair",
+ "468-checker-bool-simplif-regression",
+ "470-huge-method",
+ "472-type-propagation",
+ "472-unreachable-if-regression",
+ "474-fp-sub-neg",
+ "476-checker-ctor-fence-redun-elim",
+ "476-clinit-inline-static-invoke",
+ "477-long-2-float-convers-precision",
+ "478-checker-clinit-check-pruning",
+ "478-checker-inline-noreturn",
+ "479-regression-implicit-null-check",
+ "480-checker-dead-blocks",
+ "487-checker-inline-calls",
+ "488-checker-inline-recursive-calls",
+ "491-current-method",
+ "492-checker-inline-invoke-interface",
+ "493-checker-inline-invoke-interface",
+ "494-checker-instanceof-tests",
+ "495-checker-checkcast-tests",
+ "496-checker-inlining-class-loader",
+ "508-referrer-method",
+ "510-checker-try-catch",
+ "517-checker-builder-fallthrough",
+ "518-null-array-get",
+ "519-bound-load-class",
+ "524-boolean-simplifier-regression",
+ "525-checker-arrays-fields1",
+ "525-checker-arrays-fields2",
+ "526-checker-caller-callee-regs",
+ "526-long-regalloc",
+ "529-checker-unresolved",
+ "529-long-split",
+ "530-checker-loops1",
+ "530-checker-loops2",
+ "530-checker-loops3",
+ "530-checker-lse",
+ "530-checker-lse-ctor-fences",
+ "530-checker-lse-simd",
+ "530-checker-lse2",
+ "530-checker-peel-unroll",
+ "530-checker-regression-reftyp-final",
+ "530-instanceof-checkcast",
+ "530-regression-lse",
+ "534-checker-bce-deoptimization",
+ "535-deopt-and-inlining",
+ "536-checker-intrinsic-optimization",
+ "536-checker-needs-access-check",
+ "537-checker-inline-and-unverified",
+ "541-regression-inlined-deopt",
+ "542-bitfield-rotates",
+ "542-inline-trycatch",
+ "543-env-long-ref",
+ "545-tracing-and-jit",
+ "550-checker-multiply-accumulate",
+ "550-checker-regression-wide-store",
+ "551-checker-shifter-operand",
+ "551-implicit-null-checks",
+ "551-invoke-super",
+ "552-checker-primitive-typeprop",
+ "552-checker-sharpening",
+ "552-invoke-non-existent-super",
+ "553-invoke-super",
+ "556-invoke-super",
+ "559-checker-irreducible-loop",
+ "561-shared-slowpaths",
+ "563-checker-fakestring",
+ "564-checker-bitcount",
+ "564-checker-irreducible-loop",
+ "565-checker-doublenegbitwise",
+ "565-checker-irreducible-loop",
+ "566-polymorphic-inlining",
+ "567-checker-builder-intrinsics",
+ "569-checker-pattern-replacement",
+ "570-checker-osr",
+ "570-checker-osr-locals",
+ "574-irreducible-and-constant-area",
+ "575-checker-string-init-alias",
+ "576-polymorphic-inlining",
+ "578-bce-visit",
+ "578-polymorphic-inlining",
+ "579-inline-infinite",
+ "580-checker-string-fact-intrinsics",
+ "580-crc32",
+ "580-fp16",
+ "582-checker-bce-length",
+ "584-checker-div-bool",
+ "585-inline-unresolved",
+ "586-checker-null-array-get",
+ "587-inline-class-error",
+ "588-checker-irreducib-lifetime-hole",
+ "589-super-imt",
+ "590-checker-arr-set-null-regression",
+ "591-new-instance-string",
+ "592-checker-regression-bool-input",
+ "593-checker-shift-and-simplifier",
+ "594-invoke-super",
+ "594-load-string-regression",
+ "595-profile-saving",
+ "596-app-images",
+ "596-checker-dead-phi",
+ "596-monitor-inflation",
+ "597-app-images-same-classloader",
+ "597-deopt-busy-loop",
+ "597-deopt-new-string",
+ "600-verifier-fails",
+ "601-method-access",
+ "603-checker-instanceof",
+ "607-daemon-stress",
+ "608-checker-unresolved-lse",
+ "609-checker-inline-interface",
+ "612-jit-dex-cache",
+ "613-inlining-dex-cache",
+ "615-checker-arm64-store-zero",
+ "616-cha",
+ "616-cha-abstract",
+ "616-cha-interface",
+ "616-cha-interface-default",
+ "616-cha-miranda",
+ "616-cha-proxy-method-inline",
+ "616-cha-regression-proxy-method",
+ "616-cha-unloading",
+ "618-checker-induction",
+ "622-simplifyifs-exception-edges",
+ "623-checker-loop-regressions",
+ "624-checker-stringops",
+ "625-checker-licm-regressions",
+ "626-checker-arm64-scratch-register",
+ "626-const-class-linking",
+ "626-set-resolved-string",
+ "633-checker-rtp-getclass",
+ "635-checker-arm64-volatile-load-cc",
+ "636-wrong-static-access",
+ "638-checker-inline-cache-intrinsic",
+ "638-checker-inline-caches",
+ "639-checker-code-sinking",
+ "641-irreducible-inline",
+ "641-iterations",
+ "642-fp-callees",
+ "643-checker-bogus-ic",
+ "647-jni-get-field-id",
+ "647-sinking-catch",
+ "650-checker-inline-access-thunks",
+ "652-deopt-intrinsic",
+ "655-jit-clinit",
+ "656-annotation-lookup-generic-jni",
+ "656-checker-simd-opt",
+ "656-loop-deopt",
+ "657-branches",
+ "658-fp-read-barrier",
+ "660-clinit",
+ "661-classloader-allocator",
+ "661-oat-writer-layout",
+ "662-regression-alias",
+ "666-dex-cache-itf",
+ "667-checker-simd-alignment",
+ "667-jit-jni-stub",
+ "667-out-of-bounds",
+ "668-aiobe",
+ "670-bitstring-type-check",
+ "671-npe-field-opts",
+ "672-checker-throw-method",
+ "673-checker-throw-vmethod",
+ "674-hiddenapi",
+ "674-vdex-uncompress",
+ "676-proxy-jit-at-first-use",
+ "676-resolve-field-type",
+ "677-fsi",
+ "677-fsi2",
+ "678-quickening",
+ "679-locks",
+ "680-checker-deopt-dex-pc-0",
+ "680-sink-regression",
+ "683-clinit-inline-static-invoke",
+ "684-checker-simd-dotprod",
+ "684-select-condition",
+ "686-get-this",
+ "687-deopt",
+ "688-shared-library",
+ "689-multi-catch",
+ "689-zygote-jit-deopt",
+ "690-hiddenapi-same-name-methods",
+ "691-hiddenapi-proxy",
+ "692-vdex-inmem-loader",
+ "693-vdex-inmem-loader-evict",
+ "694-clinit-jit",
+ "695-simplify-throws",
+ "697-checker-string-append",
+ "700-LoadArgRegs",
+ "701-easy-div-rem",
+ "702-LargeBranchOffset",
+ "703-floating-point-div",
+ "704-multiply-accumulate",
+ "706-checker-scheduler",
+ "707-checker-invalid-profile",
+ "708-jit-cache-churn",
+ "710-varhandle-creation",
+ "711-checker-type-conversion",
+ "712-varhandle-invocations",
+ "713-varhandle-invokers",
+ "716-jli-jit-samples",
+ "717-integer-value-of",
+ "718-zipfile-finalizer",
+ "179-nonvirtual-jni",
+ "720-thread-priority",
+ "721-osr",
+ "724-invoke-super-npe",
+ "800-smali",
+ "802-deoptimization",
+ "804-class-extends-itself",
+ "807-method-handle-and-mr",
+ "900-hello-plugin",
+ "901-hello-ti-agent",
+ "902-hello-transformation",
+ "903-hello-tagging",
+ "904-object-allocation",
+ "905-object-free",
+ "906-iterate-heap",
+ "907-get-loaded-classes",
+ "908-gc-start-finish",
+ "909-attach-agent",
+ "910-methods",
+ "911-get-stack-trace",
+ "912-classes",
+ "913-heaps",
+ "914-hello-obsolescence",
+ "915-obsolete-2",
+ "916-obsolete-jit",
+ "917-fields-transformation",
+ "918-fields",
+ "919-obsolete-fields",
+ "920-objects",
+ "921-hello-failure",
+ "922-properties",
+ "923-monitors",
+ "924-threads",
+ "925-threadgroups",
+ "926-multi-obsolescence",
+ "927-timers",
+ "928-jni-table",
+ "929-search",
+ "930-hello-retransform",
+ "931-agent-thread",
+ "932-transform-saves",
+ "933-misc-events",
+ "934-load-transform",
+ "935-non-retransformable",
+ "936-search-onload",
+ "937-hello-retransform-package",
+ "938-load-transform-bcp",
+ "939-hello-transformation-bcp",
+ "940-recursive-obsolete",
+ "941-recursive-obsolete-jit",
+ "942-private-recursive",
+ "943-private-recursive-jit",
+ "944-transform-classloaders",
+ "945-obsolete-native",
+ "946-obsolete-throw",
+ "947-reflect-method",
+ "948-change-annotations",
+ "949-in-memory-transform",
+ "950-redefine-intrinsic",
+ "951-threaded-obsolete",
+ "952-invoke-custom",
+ "953-invoke-polymorphic-compiler",
+ "954-invoke-polymorphic-verifier",
+ "956-methodhandles",
+ "957-methodhandle-transforms",
+ "959-invoke-polymorphic-accessors",
+ "960-default-smali",
+ "961-default-iface-resolution-gen",
+ "962-iface-static",
+ "964-default-iface-init-gen",
+ "965-default-verify",
+ "966-default-conflict",
+ "967-default-ame",
+ "968-default-partial-compile-gen",
+ "969-iface-super",
+ "970-iface-super-resolution-gen",
+ "971-iface-super",
+ "972-default-imt-collision",
+ "975-iface-private",
+ "978-virtual-interface",
+ "979-const-method-handle",
+ "980-redefine-object",
+ "981-dedup-original-dex",
+ "982-ok-no-retransform",
+ "983-source-transform-verify",
+ "984-obsolete-invoke",
+ "985-re-obsolete",
+ "986-native-method-bind",
+ "987-agent-bind",
+ "988-method-trace",
+ "989-method-trace-throw",
+ "990-field-trace",
+ "991-field-trace-2",
+ "992-source-data",
+ "993-breakpoints",
+ "994-breakpoint-line",
+ "995-breakpoints-throw",
+ "996-breakpoint-obsolete",
+ "997-single-step",
+ "998-redefine-use-after-free",
+ "999-redefine-hiddenapi",
+ "1900-track-alloc",
+ "1901-get-bytecodes",
+ "1902-suspend",
+ "1903-suspend-self",
+ "1904-double-suspend",
+ "1905-suspend-native",
+ "1906-suspend-list-me-first",
+ "1907-suspend-list-self-twice",
+ "1908-suspend-native-resume-self",
+ "1909-per-agent-tls",
+ "1910-transform-with-default",
+ "1911-get-local-var-table",
+ "1912-get-set-local-primitive",
+ "1913-get-set-local-objects",
+ "1914-get-local-instance",
+ "1915-get-set-local-current-thread",
+ "1916-get-set-current-frame",
+ "1917-get-stack-frame",
+ "1919-vminit-thread-start-timing",
+ "1920-suspend-native-monitor",
+ "1921-suspend-native-recursive-monitor",
+ "1922-owned-monitors-info",
+ "1923-frame-pop",
+ "1924-frame-pop-toggle",
+ "1925-self-frame-pop",
+ "1926-missed-frame-pop",
+ "1927-exception-event",
+ "1928-exception-event-exception",
+ "1929-exception-catch-exception",
+ "1930-monitor-info",
+ "1931-monitor-events",
+ "1932-monitor-events-misc",
+ "1933-monitor-current-contended",
+ "1934-jvmti-signal-thread",
+ "1935-get-set-current-frame-jit",
+ "1936-thread-end-events",
+ "1937-transform-soft-fail",
+ "1938-transform-abstract-single-impl",
+ "1939-proxy-frames",
+ "1940-ddms-ext",
+ "1941-dispose-stress",
+ "1942-suspend-raw-monitor-exit",
+ "1943-suspend-raw-monitor-wait",
+ "1945-proxy-method-arguments",
+ "1946-list-descriptors",
+ "1947-breakpoint-redefine-deopt",
+ "1948-obsolete-const-method-handle",
+ "1949-short-dex-file",
+ "1950-unprepared-transform",
+ "1951-monitor-enter-no-suspend",
+ "1953-pop-frame",
+ "1954-pop-frame-jit",
+ "1955-pop-frame-jit-called",
+ "1956-pop-frame-jit-calling",
+ "1957-error-ext",
+ "1958-transform-try-jit",
+ "1959-redefine-object-instrument",
+ "1960-checker-bounds-codegen",
+ "1960-obsolete-jit-multithread-native",
+ "1961-checker-loop-vectorizer",
+ "1961-obsolete-jit-multithread",
+ "1962-multi-thread-events",
+ "1963-add-to-dex-classloader-in-memory",
+ "1964-add-to-dex-classloader-file",
+ "1965-get-set-local-primitive-no-tables",
+ "1966-get-set-local-objects-no-table",
+ "1967-get-set-local-bad-slot",
+ "1968-force-early-return",
+ "1969-force-early-return-void",
+ "1970-force-early-return-long",
+ "1971-multi-force-early-return",
+ "1972-jni-id-swap-indices",
+ "1973-jni-id-swap-pointer",
+ "1974-resize-array",
+ "1975-hello-structural-transformation",
+ "1976-hello-structural-static-methods",
+ "1977-hello-structural-obsolescence",
+ "1978-regular-obsolete-then-structural-obsolescence",
+ "1979-threaded-structural-transformation",
+ "1980-obsolete-object-cleared",
+ "1981-structural-redef-private-method-handles",
+ "1982-no-virtuals-structural-redefinition",
+ "1983-structural-redefinition-failures",
+ "1984-structural-redefine-field-trace",
+ "1985-structural-redefine-stack-scope",
+ "1986-structural-redefine-multi-thread-stack-scope",
+ "1988-multi-structural-redefine",
+ "1989-transform-bad-monitor",
+ "1990-structural-bad-verify",
+ "1991-hello-structural-retransform",
+ "1992-retransform-no-such-field",
+ "1993-fallback-non-structural",
+ "1994-final-virtual-structural",
+ "1995-final-virtual-structural-multithread",
+ "1996-final-override-virtual-structural",
+ "1997-structural-shadow-method",
+ "1998-structural-shadow-field",
+ "1999-virtual-structural",
+ "2000-virtual-list-structural",
+ "2001-virtual-structural-multithread",
+ "2002-virtual-structural-initializing",
+ "2003-double-virtual-structural",
+ "2004-double-virtual-structural-abstract",
+ "2005-pause-all-redefine-multithreaded",
+ "2006-virtual-structural-finalizing",
+ "2007-virtual-structural-finalizable",
+ "2008-redefine-then-old-reflect-field",
+ "2009-structural-local-ref",
+ "2011-stack-walk-concurrent-instrument",
+ "2012-structural-redefinition-failures-jni-id",
+ "2019-constantcalculationsinking",
+ "2020-InvokeVirtual-Inlining",
+ "2022-Invariantloops",
+ "2023-InvariantLoops_typecast",
+ "2024-InvariantNegativeLoop",
+ "2025-ChangedArrayValue",
+ "2026-DifferentMemoryLSCouples",
+ "2027-TwiceTheSameMemoryCouple",
+ "2028-MultiBackward",
+ "2029-contended-monitors",
+ "2030-long-running-child",
+ "2032-default-method-private-override",
+ "2033-shutdown-mechanics",
+ "2035-structural-native-method",
+ "2036-jni-filechannel",
+ "1987-structural-redefine-recursive-stack-scope"
+ ],
+ "variant": "simulate-arm64",
+ "description": ["TODO: Support more quick entry points in ART-VIXL simulator."]
}
]
diff --git a/test/run-test b/test/run-test
index 86d30d526f..cfe8111476 100755
--- a/test/run-test
+++ b/test/run-test
@@ -141,6 +141,7 @@ dev_mode="no"
create_runner="no"
update_mode="no"
debug_mode="no"
+simulator_mode="no"
relocate="no"
runtime="art"
usage="no"
@@ -181,6 +182,9 @@ while true; do
DEX_LOCATION=$tmp_dir
run_args+=(--host)
shift
+ elif [ "x$1" = "x--simulate-arm64" ]; then
+ simulator_mode="yes"
+ shift
elif [ "x$1" = "x--quiet" ]; then
quiet="yes"
shift
@@ -674,10 +678,14 @@ if [ "$runtime" = "dalvik" ]; then
true # defaults to using target BOOTCLASSPATH
fi
elif [ "$runtime" = "art" ]; then
- if [ "$target_mode" = "no" ]; then
+ if [ "$target_mode" = "no" ] && [ "$simulator_mode" = "no" ]; then
guess_host_arch_name
run_args+=(--boot "${ANDROID_HOST_OUT}/apex/com.android.art/javalib/boot.art")
run_args+=(--runtime-option "-Djava.library.path=${host_lib_root}/lib${suffix64}:${host_lib_root}/nativetest${suffix64}")
+ elif [ "$simulator_mode" = "yes" ]; then
+ run_args+=(--simulate-isa "arm64")
+ run_args+=(--boot "${ANDROID_PRODUCT_OUT}/system/apex/com.android.art.testing/javalib/boot.art")
+ run_args+=(--runtime-option "-Djava.library.path=${host_lib_root}/lib${suffix64}:${host_lib_root}/nativetest${suffix64}")
else
guess_target_arch_name
run_args+=(--runtime-option "-Djava.library.path=/data/nativetest${suffix64}/art/${target_arch_name}")
@@ -915,7 +923,10 @@ if [[ "$TEST_NAME" =~ ^[0-9]+-checker- ]]; then
if [ "$prebuild_mode" = "yes" -a "$have_image" = "yes" ]; then
run_checker="yes"
- if [ "$target_mode" = "no" ]; then
+ if [ "$simulator_mode" = "yes" ]; then
+ cfg_output_dir="$tmp_dir"
+ checker_args="--arch=ARM64"
+ elif [ "$target_mode" = "no" ]; then
cfg_output_dir="$tmp_dir"
checker_args="--arch=${host_arch_name^^}"
else
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index b8e8cb7808..f547681e62 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -182,7 +182,7 @@ def gather_test_info():
global TOTAL_VARIANTS_SET
# TODO: Avoid duplication of the variant names in different lists.
VARIANT_TYPE_DICT['run'] = {'ndebug', 'debug'}
- VARIANT_TYPE_DICT['target'] = {'target', 'host', 'jvm'}
+ VARIANT_TYPE_DICT['target'] = {'target', 'host', 'jvm', 'simulate-arm64'}
VARIANT_TYPE_DICT['trace'] = {'trace', 'ntrace', 'stream'}
VARIANT_TYPE_DICT['image'] = {'picimage', 'no-image'}
VARIANT_TYPE_DICT['debuggable'] = {'ndebuggable', 'debuggable'}
@@ -254,6 +254,7 @@ def setup_test_env():
_user_input_variants['address_sizes_target'] = collections.defaultdict(set)
if not _user_input_variants['address_sizes']:
+ _user_input_variants['address_sizes_target']['simulate-arm64'].add('64')
_user_input_variants['address_sizes_target']['target'].add(
env.ART_PHONY_TEST_TARGET_SUFFIX)
_user_input_variants['address_sizes_target']['host'].add(
@@ -423,6 +424,8 @@ def run_tests(tests):
if target == 'host':
options_test += ' --host'
+ elif target == 'simulate-arm64':
+ options_test += ' --host --simulate-arm64'
elif target == 'jvm':
options_test += ' --jvm'