diff options
author | 2020-07-16 15:09:38 +0000 | |
---|---|---|
committer | 2020-07-17 11:04:27 +0000 | |
commit | e886d68b9c40c941d8966b9c90d0e265c75fb19e (patch) | |
tree | ad78c4e375c95a96e200baa2786e748505ab928b | |
parent | f12dd5861e0eaf1822c12137fd353b5e79761a6c (diff) |
Revert^2 "VIXL simulator for ART (Stage1)"
This reverts commit 3060bb919cd2f37c6a97e87c1581ac5294af72b3.
Reason for revert: relanding original change. The fix is setting
`device_supported: false` for libart(d)-simulator module in the .bp
file (`m checkbuild` attempted to build it for arm32 and failed).
Original commit message:
VIXL simulator for ART (Stage1)
Quick User Guide: test/README.simulator.md
This CL enables running ART run-tests in a simulator on host machine.
Some benefits of using this simulator approach:
- No need to use a target device at all.
Save developers from solving the device troubles: build, flash, usb,
adb, etc.
- Speed up development/debug/test cycle.
- Allows easy debugging/testing new instruction features without real
hardware.
- Allows using a smaller AOSP Android manifest master-art.
The Stage1 CL provides support for running 30% of current run-tests.
The rest unsupported test cases are kept in knownfailures.json.
Future work will be supporting proper stack frame layout between
simulator and quick entrypoints, so that stack walk,
QuickArgumentVisitor, deoptimization, etc can be supported.
This CL adds libart(d)-simulator-container library to the ART APEX. It
has caused the following increase of the APEX size (small, about 0.13%
for release APEX, measured for target aosp_arm64-userdebug):
Before:
88992 com.android.art.debug.apex
51612 com.android.art.release.apex
112352 com.android.art.testing.apex
After:
89124 com.android.art.debug.apex
51680 com.android.art.release.apex
112468 com.android.art.testing.apex
Change-Id: I461c80aa9c4ce0673eef1c0254d2c539f2b6a8d5
Test: art/test.py --run-test --optimizing --simulate-arm64
Test: art/test.py --run-test --optimizing --host
Test: m test-art-host-gtest
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); }; @@ -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' |