diff options
Diffstat (limited to 'runtime/common_test.h')
-rw-r--r-- | runtime/common_test.h | 124 |
1 files changed, 123 insertions, 1 deletions
diff --git a/runtime/common_test.h b/runtime/common_test.h index 673a03b35..79fa68039 100644 --- a/runtime/common_test.h +++ b/runtime/common_test.h @@ -22,6 +22,7 @@ #include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> +#include <fstream> #include "../../external/icu4c/common/unicode/uvernum.h" #include "base/macros.h" @@ -152,6 +153,113 @@ class ScratchFile { UniquePtr<File> file_; }; +#if defined(__arm__) + + +#include <signal.h> +#include <asm/sigcontext.h> +#include <asm/ucontext.h> + + +// A signal handler called when have an illegal instruction. We record the fact in +// a global boolean and then increment the PC in the signal context to return to +// the next instruction. We know the instruction is an sdiv (4 bytes long). +static void baddivideinst(int signo, siginfo *si, void *data) { + (void)signo; + (void)si; + struct ucontext *uc = (struct ucontext *)data; + struct sigcontext *sc = &uc->uc_mcontext; + sc->arm_r0 = 0; // set R0 to #0 to signal error + sc->arm_pc += 4; // skip offending instruction +} + +// This is in arch/arm/arm_sdiv.S. It does the following: +// mov r1,#1 +// sdiv r0,r1,r1 +// bx lr +// +// the result will be the value 1 if sdiv is supported. If it is not supported +// a SIGILL signal will be raised and the signal handler (baddivideinst) called. +// The signal handler sets r0 to #0 and then increments pc beyond the failed instruction. +// Thus if the instruction is not supported, the result of this function will be #0 + +extern "C" bool CheckForARMSDIVInstruction(); + +static InstructionSetFeatures GuessInstructionFeatures() { + InstructionSetFeatures f; + + // Uncomment this for processing of /proc/cpuinfo. + if (false) { + // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that + // the kernel puts the appropriate feature flags in here. Sometimes it doesn't. + std::ifstream in("/proc/cpuinfo"); + if (in) { + while (!in.eof()) { + std::string line; + std::getline(in, line); + if (!in.eof()) { + if (line.find("Features") != std::string::npos) { + if (line.find("idivt") != std::string::npos) { + f.SetHasDivideInstruction(true); + } + } + } + in.close(); + } + } else { + LOG(INFO) << "Failed to open /proc/cpuinfo"; + } + } + + // See if have a sdiv instruction. Register a signal handler and try to execute + // an sdiv instruction. If we get a SIGILL then it's not supported. We can't use + // the /proc/cpuinfo method for this because Krait devices don't always put the idivt + // feature in the list. + struct sigaction sa, osa; + sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO; + sa.sa_sigaction = baddivideinst; + sigaction(SIGILL, &sa, &osa); + + if (CheckForARMSDIVInstruction()) { + f.SetHasDivideInstruction(true); + } + + // Restore the signal handler. + sigaction(SIGILL, &osa, NULL); + + // Other feature guesses in here. + return f; +} + +#endif + +// Given a set of instruction features from the build, parse it. The +// input 'str' is a comma separated list of feature names. Parse it and +// return the InstructionSetFeatures object. +static InstructionSetFeatures ParseFeatureList(std::string str) { + LOG(INFO) << "Parsing features " << str; + InstructionSetFeatures result; + typedef std::vector<std::string> FeatureList; + FeatureList features; + Split(str, ',', features); + for (FeatureList::iterator i = features.begin(); i != features.end(); i++) { + std::string feature = Trim(*i); + if (feature == "default") { + // Nothing to do. + } else if (feature == "div") { + // Supports divide instruction. + result.SetHasDivideInstruction(true); + } else if (feature == "nodiv") { + // Turn off support for divide instruction. + result.SetHasDivideInstruction(false); + } else { + LOG(FATAL) << "Unknown instruction set feature: '" << feature << "'"; + } + } + // Others... + return result; +} + class CommonTest : public testing::Test { public: static void MakeExecutable(const mirror::ByteArray* code_array) { @@ -314,8 +422,22 @@ class CommonTest : public testing::Test { class_linker_ = runtime_->GetClassLinker(); InstructionSet instruction_set = kNone; + + // take the default set of instruction features from the build if present + InstructionSetFeatures instruction_set_features = +#ifdef ART_DEFAULT_INSTRUCTION_SET_FEATURES + ParseFeatureList(STRINGIFY(ART_DEFAULT_INSTRUCTION_SET_FEATURES)); +#else + ParseFeatureList("default"); +#endif + #if defined(__arm__) instruction_set = kThumb2; + InstructionSetFeatures runtime_features = GuessInstructionFeatures(); + + // for ARM, do a runtime check to make sure that the features we are passed from + // the build match the features we actually determine at runtime. + ASSERT_EQ(instruction_set_features, runtime_features); #elif defined(__mips__) instruction_set = kMips; #elif defined(__i386__) @@ -338,6 +460,7 @@ class CommonTest : public testing::Test { } class_linker_->FixupDexCaches(runtime_->GetResolutionMethod()); compiler_driver_.reset(new CompilerDriver(compiler_backend, instruction_set, + instruction_set_features, true, new CompilerDriver::DescriptorSet, 2, true)); } @@ -568,7 +691,6 @@ class CheckJniAbortCatcher { #else #define TEST_DISABLED_FOR_PORTABLE() #endif - } // namespace art namespace std { |