[viewcompiler] Add support for static field put to DexBuilder
Bug: 111895153
Change-Id: I12b38fa520790debec545d7d1f6b3522a65ce03b
diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc
index 66bc698..09f9c04 100644
--- a/startop/view_compiler/dex_builder.cc
+++ b/startop/view_compiler/dex_builder.cc
@@ -105,6 +105,9 @@
case Instruction::Op::kGetStaticField:
out << "kGetStaticField";
return out;
+ case Instruction::Op::kSetStaticField:
+ out << "kSetStaticField";
+ return out;
}
}
@@ -380,6 +383,7 @@
case Instruction::Op::kCheckCast:
return EncodeCast(instruction);
case Instruction::Op::kGetStaticField:
+ case Instruction::Op::kSetStaticField:
return EncodeStaticFieldOp(instruction);
}
}
@@ -536,13 +540,32 @@
}
void MethodBuilder::EncodeStaticFieldOp(const Instruction& instruction) {
- CHECK_EQ(Instruction::Op::kGetStaticField, instruction.opcode());
- CHECK(instruction.dest().has_value());
- CHECK(instruction.dest()->is_variable());
- CHECK_EQ(0, instruction.args().size());
+ switch (instruction.opcode()) {
+ case Instruction::Op::kGetStaticField: {
+ CHECK(instruction.dest().has_value());
+ CHECK(instruction.dest()->is_variable());
+ CHECK_EQ(0, instruction.args().size());
- Encode21c(
- ::art::Instruction::SGET, RegisterValue(*instruction.dest()), instruction.index_argument());
+ Encode21c(::art::Instruction::SGET,
+ RegisterValue(*instruction.dest()),
+ instruction.index_argument());
+ break;
+ }
+ case Instruction::Op::kSetStaticField: {
+ CHECK(!instruction.dest().has_value());
+ const auto& args = instruction.args();
+ CHECK_EQ(1, args.size());
+ CHECK(args[0].is_variable());
+
+ Encode21c(::art::Instruction::SPUT,
+ RegisterValue(args[0]),
+ instruction.index_argument());
+ break;
+ }
+ default: {
+ LOG(FATAL) << "Unsupported static field operation";
+ }
+ }
}
size_t MethodBuilder::RegisterValue(const Value& value) const {
diff --git a/startop/view_compiler/dex_builder.h b/startop/view_compiler/dex_builder.h
index a7ccb4a..3f9ac43 100644
--- a/startop/view_compiler/dex_builder.h
+++ b/startop/view_compiler/dex_builder.h
@@ -163,6 +163,7 @@
kNew,
kReturn,
kReturnObject,
+ kSetStaticField
};
////////////////////////
@@ -237,6 +238,11 @@
return Instruction{Op::kGetStaticField, field_id, dest};
}
+ static inline Instruction SetStaticField(size_t field_id, Value value) {
+ return Instruction{Op::kSetStaticField, field_id, /*result_is_object=*/false, /*dest=*/{}, value};
+ }
+
+
///////////////
// Accessors //
///////////////
diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
index df11bfa..3138e71 100644
--- a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
+++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
@@ -180,4 +180,14 @@
TestClass.staticInteger = 5;
Assert.assertEquals(5, method.invoke(null));
}
+
+ @Test
+ public void setStaticField() throws Exception {
+ ClassLoader loader = loadDexFile("simple.dex");
+ Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+ Method method = clazz.getMethod("setStaticField");
+ TestClass.staticInteger = 5;
+ method.invoke(null);
+ Assert.assertEquals(7, TestClass.staticInteger);
+ }
}
diff --git a/startop/view_compiler/dex_testcase_generator.cc b/startop/view_compiler/dex_testcase_generator.cc
index 5227f80..fee5e72 100644
--- a/startop/view_compiler/dex_testcase_generator.cc
+++ b/startop/view_compiler/dex_testcase_generator.cc
@@ -297,6 +297,22 @@
method.Encode();
}(readStaticField);
+ // Set a static field
+ // void setStaticField() { TestClass.staticInteger = 7; }
+ MethodBuilder setStaticField{
+ cbuilder.CreateMethod("setStaticField", Prototype{TypeDescriptor::Void()})};
+ [&](MethodBuilder& method) {
+ const ir::FieldDecl* field =
+ dex_file.GetOrAddField(TypeDescriptor::FromClassname("android.startop.test.TestClass"),
+ "staticInteger",
+ TypeDescriptor::Int());
+ Value number{method.MakeRegister()};
+ method.BuildConst4(number, 7);
+ method.AddInstruction(Instruction::SetStaticField(field->orig_index, number));
+ method.BuildReturn();
+ method.Encode();
+ }(setStaticField);
+
slicer::MemView image{dex_file.CreateImage()};
std::ofstream out_file(outdir + "/simple.dex");
out_file.write(image.ptr<const char>(), image.size());