Revert^3 "VIXL simulator for ART (Stage1)"
This reverts commit e886d68b9c40c941d8966b9c90d0e265c75fb19e.
Reason for revert: simulator implemention is not ready yet.
Test: lunch aosp_cf_x86_phone-userdebug && m
Test: art/test.py --run-test --optimizing --host
Change-Id: I03c8c09ea348205b0238d7a26caef3477cd6ae3b
diff --git a/simulator/code_simulator_arm64.cc b/simulator/code_simulator_arm64.cc
index 7521d18..a64bd0b 100644
--- a/simulator/code_simulator_arm64.cc
+++ b/simulator/code_simulator_arm64.cc
@@ -16,178 +16,13 @@
#include "code_simulator_arm64.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.",
-};
+#include <android-base/logging.h>
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`.
@@ -205,11 +40,7 @@
: CodeSimulator(), decoder_(nullptr), simulator_(nullptr) {
DCHECK(kCanSimulate);
decoder_ = new Decoder();
- simulator_ = new CustomSimulator(decoder_);
- if (VLOG_IS_ON(simulator)) {
- simulator_->SetColouredTrace(true);
- simulator_->SetTraceParameters(LOG_DISASM | LOG_WRITE);
- }
+ simulator_ = new Simulator(decoder_);
}
CodeSimulatorArm64::~CodeSimulatorArm64() {
@@ -220,7 +51,7 @@
void CodeSimulatorArm64::RunFrom(intptr_t code_buffer) {
DCHECK(kCanSimulate);
- simulator_->RunFrom(reinterpret_cast<const vixl::aarch64::Instruction*>(code_buffer));
+ simulator_->RunFrom(reinterpret_cast<const Instruction*>(code_buffer));
}
bool CodeSimulatorArm64::GetCReturnBool() const {
@@ -238,208 +69,5 @@
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