Move ti-stress to use slicer directly
Now that slicer is in the AOSP tree we can use it directly for ti
stress tests.
Test: ./test/run-test --host --jvmti-redefine-stress 001-HelloWorld
Change-Id: I89a9f532458b24466b453f493ab63c9c4af6de6d
diff --git a/test/ti-stress/stress.cc b/test/ti-stress/stress.cc
index 5d7c2f3..4e0f48d 100644
--- a/test/ti-stress/stress.cc
+++ b/test/ti-stress/stress.cc
@@ -28,15 +28,20 @@
#include "jvmti.h"
#include "utils.h"
+#include "code_ir.h"
+#include "control_flow_graph.h"
+#include "dex_ir.h"
+#include "dex_ir_builder.h"
+#include "instrumentation.h"
+#include "reader.h"
+#include "writer.h"
+
namespace art {
// Should we do a 'full_rewrite' with this test?
static constexpr bool kDoFullRewrite = true;
struct StressData {
- std::string dexter_cmd;
- std::string out_temp_dex;
- std::string in_temp_dex;
bool vm_class_loader_initialized;
bool trace_stress;
bool redefine_stress;
@@ -44,51 +49,60 @@
bool step_stress;
};
-static void WriteToFile(const std::string& fname, jint data_len, const unsigned char* data) {
- std::ofstream file(fname, std::ios::binary | std::ios::out | std::ios::trunc);
- file.write(reinterpret_cast<const char*>(data), data_len);
- file.flush();
-}
-
-static bool ReadIntoBuffer(const std::string& fname, /*out*/std::vector<unsigned char>* data) {
- std::ifstream file(fname, std::ios::binary | std::ios::in);
- file.seekg(0, std::ios::end);
- size_t len = file.tellg();
- data->resize(len);
- file.seekg(0);
- file.read(reinterpret_cast<char*>(data->data()), len);
- return len != 0;
-}
-
-// TODO rewrite later.
-static bool DoExtractClassFromData(StressData* data,
- const std::string& class_name,
+static bool DoExtractClassFromData(jvmtiEnv* env,
+ const std::string& descriptor,
jint in_len,
const unsigned char* in_data,
- /*out*/std::vector<unsigned char>* dex) {
- // Write the dex file into a temporary file.
- WriteToFile(data->in_temp_dex, in_len, in_data);
- // Clear out file so even if something suppresses the exit value we will still detect dexter
- // failure.
- WriteToFile(data->out_temp_dex, 0, nullptr);
- // Have dexter do the extraction.
- std::vector<std::string> args;
- args.push_back(data->dexter_cmd);
- if (kDoFullRewrite) {
- args.push_back("-x");
- args.push_back("full_rewrite");
- }
- args.push_back("-e");
- args.push_back(class_name);
- args.push_back("-o");
- args.push_back(data->out_temp_dex);
- args.push_back(data->in_temp_dex);
- std::string error;
- if (ExecAndReturnCode(args, &error) != 0) {
- LOG(ERROR) << "unable to execute dexter: " << error;
+ /*out*/jint* out_len,
+ /*out*/unsigned char** out_data) {
+ dex::Reader reader(in_data, in_len);
+ dex::u4 class_idx = reader.FindClassIndex(descriptor.c_str());
+ if (class_idx != dex::kNoIndex) {
+ reader.CreateClassIr(class_idx);
+ } else {
+ LOG(ERROR) << "ERROR: Can't find class " << descriptor;
return false;
}
- return ReadIntoBuffer(data->out_temp_dex, dex);
+ auto dex_ir = reader.GetIr();
+
+ if (kDoFullRewrite) {
+ for (auto& ir_method : dex_ir->encoded_methods) {
+ if (ir_method->code != nullptr) {
+ lir::CodeIr code_ir(ir_method.get(), dex_ir);
+ lir::ControlFlowGraph cfg_compact(&code_ir, false);
+ lir::ControlFlowGraph cfg_verbose(&code_ir, true);
+ code_ir.Assemble();
+ }
+ }
+ }
+ dex::Writer writer(dex_ir);
+
+ struct Allocator : public dex::Writer::Allocator {
+ explicit Allocator(jvmtiEnv* jvmti_env) : jvmti_env_(jvmti_env) {}
+ virtual void* Allocate(size_t size) {
+ unsigned char* out = nullptr;
+ if (JVMTI_ERROR_NONE != jvmti_env_->Allocate(size, &out)) {
+ return nullptr;
+ } else {
+ return out;
+ }
+ }
+ virtual void Free(void* ptr) {
+ jvmti_env_->Deallocate(reinterpret_cast<unsigned char*>(ptr));
+ }
+ private:
+ jvmtiEnv* jvmti_env_;
+ };
+ Allocator alloc(env);
+ size_t res_len;
+ unsigned char* res = writer.CreateImage(&alloc, &res_len);
+ if (res != nullptr) {
+ *out_data = res;
+ *out_len = res_len;
+ return true;
+ } else {
+ return false;
+ }
}
class ScopedThreadInfo {
@@ -615,10 +629,10 @@
jint* new_class_data_len,
unsigned char** new_class_data) {
std::vector<unsigned char> out;
- std::string name_str(name);
- // Make the jvmti semi-descriptor into the java style descriptor (though with $ for inner
- // classes).
- std::replace(name_str.begin(), name_str.end(), '/', '.');
+ // Make the jvmti semi-descriptor into the full descriptor.
+ std::string name_str("L");
+ name_str += name;
+ name_str += ";";
StressData* data = nullptr;
CHECK_EQ(jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)),
JVMTI_ERROR_NONE);
@@ -626,15 +640,11 @@
LOG(WARNING) << "Ignoring load of class " << name << " because VMClassLoader is not yet "
<< "initialized. Transforming this class could cause spurious test failures.";
return;
- } else if (DoExtractClassFromData(data, name_str, class_data_len, class_data, /*out*/ &out)) {
+ } else if (DoExtractClassFromData(jvmti, name_str, class_data_len, class_data,
+ /*out*/ new_class_data_len, /*out*/ new_class_data)) {
LOG(INFO) << "Extracted class: " << name;
- unsigned char* new_data;
- CHECK_EQ(JVMTI_ERROR_NONE, jvmti->Allocate(out.size(), &new_data));
- memcpy(new_data, out.data(), out.size());
- *new_class_data_len = static_cast<jint>(out.size());
- *new_class_data = new_data;
} else {
- std::cerr << "Unable to extract class " << name_str << std::endl;
+ std::cerr << "Unable to extract class " << name << std::endl;
*new_class_data_len = 0;
*new_class_data = nullptr;
}
@@ -653,7 +663,7 @@
}
// Options are
-// jvmti-stress,[redefine,${DEXTER_BINARY},${TEMP_FILE_1},${TEMP_FILE_2},][trace,][field]
+// jvmti-stress,[redefine,][trace,][field]
static void ReadOptions(StressData* data, char* options) {
std::string ops(options);
CHECK_EQ(GetOption(ops), "jvmti-stress") << "Options should start with jvmti-stress";
@@ -668,12 +678,6 @@
data->field_stress = true;
} else if (cur == "redefine") {
data->redefine_stress = true;
- ops = AdvanceOption(ops);
- data->dexter_cmd = GetOption(ops);
- ops = AdvanceOption(ops);
- data->in_temp_dex = GetOption(ops);
- ops = AdvanceOption(ops);
- data->out_temp_dex = GetOption(ops);
} else {
LOG(FATAL) << "Unknown option: " << GetOption(ops);
}