Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5787f7c9 authored by Android Build Merger (Role)'s avatar Android Build Merger (Role) Committed by Android (Google) Code Review
Browse files

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

Merge "Merge "[view-compiler] DexBuilder: Add check-cast instruction" am: bce4bd17 am: 758823ae am: 77e86782"
parents a79ef358 d050d986
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -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();
+17 −8
Original line number Diff line number Diff line
@@ -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
+20 −0
Original line number Diff line number Diff line
@@ -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);
  }
}
+13 −0
Original line number Diff line number Diff line
@@ -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());