Merge "[view-compiler] DexBuilder: Add check-cast instruction"

am: bce4bd1745

Change-Id: If8acd8f77f4eb54b0efacabaff8a09bee9ce3bb9
This commit is contained in:
Eric Holk
2018-12-18 15:46:05 -08:00
committed by android-build-merger
4 changed files with 67 additions and 8 deletions

View File

@@ -79,6 +79,9 @@ std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode) {
case Instruction::Op::kNew:
out << "kNew";
return out;
case Instruction::Op::kCheckCast:
out << "kCheckCast";
return out;
}
}
@@ -329,6 +332,8 @@ void MethodBuilder::EncodeInstruction(const Instruction& instruction) {
return EncodeBranch(art::Instruction::IF_NEZ, instruction);
case Instruction::Op::kNew:
return EncodeNew(instruction);
case Instruction::Op::kCheckCast:
return EncodeCast(instruction);
}
}
@@ -422,6 +427,18 @@ void MethodBuilder::EncodeNew(const Instruction& instruction) {
Encode21c(::art::Instruction::NEW_INSTANCE, RegisterValue(*instruction.dest()), type.value());
}
void MethodBuilder::EncodeCast(const Instruction& instruction) {
DCHECK_EQ(Instruction::Op::kCheckCast, instruction.opcode());
DCHECK(instruction.dest().has_value());
DCHECK(instruction.dest()->is_variable());
DCHECK_EQ(1, instruction.args().size());
const Value& type = instruction.args()[0];
DCHECK_LT(RegisterValue(*instruction.dest()), 256);
DCHECK(type.is_type());
Encode21c(::art::Instruction::CHECK_CAST, RegisterValue(*instruction.dest()), type.value());
}
size_t MethodBuilder::RegisterValue(const Value& value) const {
if (value.is_register()) {
return value.value();

View File

@@ -142,17 +142,18 @@ class Instruction {
// The operation performed by this instruction. These are virtual instructions that do not
// correspond exactly to DEX instructions.
enum class Op {
kReturn,
kReturnObject,
kMove,
kInvokeVirtual,
kInvokeDirect,
kInvokeStatic,
kInvokeInterface,
kBindLabel,
kBranchEqz,
kBranchNEqz,
kNew
kCheckCast,
kInvokeDirect,
kInvokeInterface,
kInvokeStatic,
kInvokeVirtual,
kMove,
kNew,
kReturn,
kReturnObject,
};
////////////////////////
@@ -168,6 +169,13 @@ class Instruction {
static inline Instruction OpWithArgs(Op opcode, std::optional<const Value> dest, T... args) {
return Instruction{opcode, /*method_id=*/0, /*result_is_object=*/false, dest, args...};
}
// A cast instruction. Basically, `(type)val`
static inline Instruction Cast(Value val, Value type) {
DCHECK(type.is_type());
return OpWithArgs(Op::kCheckCast, val, type);
}
// For method calls.
template <typename... T>
static inline Instruction InvokeVirtual(size_t method_id, std::optional<const Value> dest,
@@ -302,6 +310,7 @@ class MethodBuilder {
void EncodeInvoke(const Instruction& instruction, ::art::Instruction::Code opcode);
void EncodeBranch(art::Instruction::Code op, const Instruction& instruction);
void EncodeNew(const Instruction& instruction);
void EncodeCast(const Instruction& instruction);
// Low-level instruction format encoding. See
// https://source.android.com/devices/tech/dalvik/instruction-formats for documentation of

View File

@@ -20,6 +20,7 @@ import com.google.common.io.ByteStreams;
import dalvik.system.InMemoryDexClassLoader;
import dalvik.system.PathClassLoader;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import org.junit.Assert;
@@ -151,4 +152,23 @@ public class DexBuilderTest {
Method method = clazz.getMethod("invokeVirtualReturnObject", String.class, int.class);
Assert.assertEquals("bc", method.invoke(null, "abc", 1));
}
@Test
public void castObjectToString() throws Exception {
ClassLoader loader = loadDexFile("simple.dex");
Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
Method method = clazz.getMethod("castObjectToString", Object.class);
Assert.assertEquals("abc", method.invoke(null, "abc"));
boolean castFailed = false;
try {
method.invoke(null, 5);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof ClassCastException) {
castFailed = true;
} else {
throw e;
}
}
Assert.assertTrue(castFailed);
}
}

View File

@@ -269,6 +269,19 @@ void GenerateSimpleTestCases(const string& outdir) {
method.Encode();
}(invokeVirtualReturnObject);
// Make sure we can cast objects
// String castObjectToString(Object o) { return (String)o; }
MethodBuilder castObjectToString{cbuilder.CreateMethod(
"castObjectToString",
Prototype{string_type, TypeDescriptor::FromClassname("java.lang.Object")})};
[&](MethodBuilder& method) {
const ir::Type* type_def = dex_file.GetOrAddType(string_type.descriptor());
method.AddInstruction(
Instruction::Cast(Value::Parameter(0), Value::Type(type_def->orig_index)));
method.BuildReturn(Value::Parameter(0), /*is_object=*/true);
method.Encode();
}(castObjectToString);
slicer::MemView image{dex_file.CreateImage()};
std::ofstream out_file(outdir + "/simple.dex");
out_file.write(image.ptr<const char>(), image.size());