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

Commit f5617abe authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Refactor DexViewBuilder"

parents 37f8bfb2 5c6a1a51
Loading
Loading
Loading
Loading
+17 −4
Original line number Original line Diff line number Diff line
@@ -161,7 +161,7 @@ void WriteTestDexFile(const string& filename) {


  MethodBuilder method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int(), string_type})};
  MethodBuilder method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int(), string_type})};


  Value result = method.MakeRegister();
  LiveRegister result = method.AllocRegister();


  MethodDeclData string_length =
  MethodDeclData string_length =
      dex_file.GetOrDeclareMethod(string_type, "length", Prototype{TypeDescriptor::Int()});
      dex_file.GetOrDeclareMethod(string_type, "length", Prototype{TypeDescriptor::Int()});
@@ -314,7 +314,7 @@ ir::EncodedMethod* MethodBuilder::Encode() {
  CHECK(decl_->prototype != nullptr);
  CHECK(decl_->prototype != nullptr);
  size_t const num_args =
  size_t const num_args =
      decl_->prototype->param_types != nullptr ? decl_->prototype->param_types->types.size() : 0;
      decl_->prototype->param_types != nullptr ? decl_->prototype->param_types->types.size() : 0;
  code->registers = num_registers_ + num_args + kMaxScratchRegisters;
  code->registers = NumRegisters() + num_args + kMaxScratchRegisters;
  code->ins_count = num_args;
  code->ins_count = num_args;
  EncodeInstructions();
  EncodeInstructions();
  code->instructions = slicer::ArrayView<const ::dex::u2>(buffer_.data(), buffer_.size());
  code->instructions = slicer::ArrayView<const ::dex::u2>(buffer_.data(), buffer_.size());
@@ -327,7 +327,20 @@ ir::EncodedMethod* MethodBuilder::Encode() {
  return method;
  return method;
}
}


Value MethodBuilder::MakeRegister() { return Value::Local(num_registers_++); }
LiveRegister MethodBuilder::AllocRegister() {
  // Find a free register
  for (size_t i = 0; i < register_liveness_.size(); ++i) {
    if (!register_liveness_[i]) {
      register_liveness_[i] = true;
      return LiveRegister{&register_liveness_, i};
    }
  }

  // If we get here, all the registers are in use, so we have to allocate a new
  // one.
  register_liveness_.push_back(true);
  return LiveRegister{&register_liveness_, register_liveness_.size() - 1};
}


Value MethodBuilder::MakeLabel() {
Value MethodBuilder::MakeLabel() {
  labels_.push_back({});
  labels_.push_back({});
@@ -600,7 +613,7 @@ size_t MethodBuilder::RegisterValue(const Value& value) const {
  if (value.is_register()) {
  if (value.is_register()) {
    return value.value();
    return value.value();
  } else if (value.is_parameter()) {
  } else if (value.is_parameter()) {
    return value.value() + num_registers_ + kMaxScratchRegisters;
    return value.value() + NumRegisters() + kMaxScratchRegisters;
  }
  }
  CHECK(false && "Must be either a parameter or a register");
  CHECK(false && "Must be either a parameter or a register");
  return 0;
  return 0;
+40 −14
Original line number Original line Diff line number Diff line
@@ -140,6 +140,29 @@ class Value {
  constexpr Value(size_t value, Kind kind) : value_{value}, kind_{kind} {}
  constexpr Value(size_t value, Kind kind) : value_{value}, kind_{kind} {}
};
};


// Represents an allocated register returned by MethodBuilder::AllocRegister
class LiveRegister {
  friend class MethodBuilder;

 public:
  LiveRegister(LiveRegister&& other) : liveness_{other.liveness_}, index_{other.index_} {
    other.index_ = {};
  };
  ~LiveRegister() {
    if (index_.has_value()) {
      (*liveness_)[*index_] = false;
    }
  };

  operator const Value() const { return Value::Local(*index_); }

 private:
  LiveRegister(std::vector<bool>* liveness, size_t index) : liveness_{liveness}, index_{index} {}

  std::vector<bool>* const liveness_;
  std::optional<size_t> index_;
};

// A virtual instruction. We convert these to real instructions in MethodBuilder::Encode.
// A virtual instruction. We convert these to real instructions in MethodBuilder::Encode.
// Virtual instructions are needed to keep track of information that is not known until all of the
// Virtual instructions are needed to keep track of information that is not known until all of the
// code is generated. This information includes things like how many local registers are created and
// code is generated. This information includes things like how many local registers are created and
@@ -178,7 +201,8 @@ class Instruction {
  }
  }
  // For most instructions, which take some number of arguments and have an optional return value.
  // For most instructions, which take some number of arguments and have an optional return value.
  template <typename... T>
  template <typename... T>
  static inline Instruction OpWithArgs(Op opcode, std::optional<const Value> dest, T... args) {
  static inline Instruction OpWithArgs(Op opcode, std::optional<const Value> dest,
                                       const T&... args) {
    return Instruction{opcode, /*index_argument=*/0, /*result_is_object=*/false, dest, args...};
    return Instruction{opcode, /*index_argument=*/0, /*result_is_object=*/false, dest, args...};
  }
  }


@@ -199,14 +223,14 @@ class Instruction {
  template <typename... T>
  template <typename... T>
  static inline Instruction InvokeVirtualObject(size_t index_argument,
  static inline Instruction InvokeVirtualObject(size_t index_argument,
                                                std::optional<const Value> dest, Value this_arg,
                                                std::optional<const Value> dest, Value this_arg,
                                                T... args) {
                                                const T&... args) {
    return Instruction{
    return Instruction{
        Op::kInvokeVirtual, index_argument, /*result_is_object=*/true, dest, this_arg, args...};
        Op::kInvokeVirtual, index_argument, /*result_is_object=*/true, dest, this_arg, args...};
  }
  }
  // For direct calls (basically, constructors).
  // For direct calls (basically, constructors).
  template <typename... T>
  template <typename... T>
  static inline Instruction InvokeDirect(size_t index_argument, std::optional<const Value> dest,
  static inline Instruction InvokeDirect(size_t index_argument, std::optional<const Value> dest,
                                         Value this_arg, T... args) {
                                         Value this_arg, const T&... args) {
    return Instruction{
    return Instruction{
        Op::kInvokeDirect, index_argument, /*result_is_object=*/false, dest, this_arg, args...};
        Op::kInvokeDirect, index_argument, /*result_is_object=*/false, dest, this_arg, args...};
  }
  }
@@ -234,7 +258,7 @@ class Instruction {
  // For static calls.
  // For static calls.
  template <typename... T>
  template <typename... T>
  static inline Instruction InvokeInterface(size_t index_argument, std::optional<const Value> dest,
  static inline Instruction InvokeInterface(size_t index_argument, std::optional<const Value> dest,
                                            T... args) {
                                            const T&... args) {
    return Instruction{
    return Instruction{
        Op::kInvokeInterface, index_argument, /*result_is_object=*/false, dest, args...};
        Op::kInvokeInterface, index_argument, /*result_is_object=*/false, dest, args...};
  }
  }
@@ -277,7 +301,7 @@ class Instruction {


  template <typename... T>
  template <typename... T>
  inline Instruction(Op opcode, size_t index_argument, bool result_is_object,
  inline Instruction(Op opcode, size_t index_argument, bool result_is_object,
                               std::optional<const Value> dest, T... args)
                     std::optional<const Value> dest, const T&... args)
      : opcode_{opcode},
      : opcode_{opcode},
        index_argument_{index_argument},
        index_argument_{index_argument},
        result_is_object_{result_is_object},
        result_is_object_{result_is_object},
@@ -309,10 +333,8 @@ class MethodBuilder {
  // Encode the method into DEX format.
  // Encode the method into DEX format.
  ir::EncodedMethod* Encode();
  ir::EncodedMethod* Encode();


  // Create a new register to be used to storing values. Note that these are not SSA registers, like
  // Create a new register to be used to storing values.
  // might be expected in similar code generators. This does no liveness tracking or anything, so
  LiveRegister AllocRegister();
  // it's up to the caller to reuse registers as appropriate.
  Value MakeRegister();


  Value MakeLabel();
  Value MakeLabel();


@@ -329,7 +351,7 @@ class MethodBuilder {
  void BuildConst4(Value target, int value);
  void BuildConst4(Value target, int value);
  void BuildConstString(Value target, const std::string& value);
  void BuildConstString(Value target, const std::string& value);
  template <typename... T>
  template <typename... T>
  void BuildNew(Value target, TypeDescriptor type, Prototype constructor, T... args);
  void BuildNew(Value target, TypeDescriptor type, Prototype constructor, const T&... args);


  // TODO: add builders for more instructions
  // TODO: add builders for more instructions


@@ -427,7 +449,7 @@ class MethodBuilder {
    static_assert(num_regs <= kMaxScratchRegisters);
    static_assert(num_regs <= kMaxScratchRegisters);
    std::array<Value, num_regs> regs;
    std::array<Value, num_regs> regs;
    for (size_t i = 0; i < num_regs; ++i) {
    for (size_t i = 0; i < num_regs; ++i) {
      regs[i] = std::move(Value::Local(num_registers_ + i));
      regs[i] = std::move(Value::Local(NumRegisters() + i));
    }
    }
    return regs;
    return regs;
  }
  }
@@ -457,8 +479,9 @@ class MethodBuilder {
  // around to make legal DEX code.
  // around to make legal DEX code.
  static constexpr size_t kMaxScratchRegisters = 5;
  static constexpr size_t kMaxScratchRegisters = 5;


  // How many registers we've allocated
  size_t NumRegisters() const {
  size_t num_registers_{0};
    return register_liveness_.size();
  }


  // Stores information needed to back-patch a label once it is bound. We need to know the start of
  // Stores information needed to back-patch a label once it is bound. We need to know the start of
  // the instruction that refers to the label, and the offset to where the actual label value should
  // the instruction that refers to the label, and the offset to where the actual label value should
@@ -478,6 +501,8 @@ class MethodBuilder {
  // During encoding, keep track of the largest number of arguments needed, so we can use it for our
  // During encoding, keep track of the largest number of arguments needed, so we can use it for our
  // outs count
  // outs count
  size_t max_args_{0};
  size_t max_args_{0};

  std::vector<bool> register_liveness_;
};
};


// A helper to build class definitions.
// A helper to build class definitions.
@@ -576,7 +601,8 @@ class DexBuilder {
};
};


template <typename... T>
template <typename... T>
void MethodBuilder::BuildNew(Value target, TypeDescriptor type, Prototype constructor, T... args) {
void MethodBuilder::BuildNew(Value target, TypeDescriptor type, Prototype constructor,
                             const T&... args) {
  MethodDeclData constructor_data{dex_->GetOrDeclareMethod(type, "<init>", constructor)};
  MethodDeclData constructor_data{dex_->GetOrDeclareMethod(type, "<init>", constructor)};
  // allocate the object
  // allocate the object
  ir::Type* type_def = dex_->GetOrAddType(type.descriptor());
  ir::Type* type_def = dex_->GetOrAddType(type.descriptor());
+106 −105
Original line number Original line Diff line number Diff line
@@ -22,76 +22,94 @@
namespace startop {
namespace startop {


using android::base::StringPrintf;
using android::base::StringPrintf;
using dex::Instruction;
using dex::LiveRegister;
using dex::Prototype;
using dex::TypeDescriptor;
using dex::Value;

namespace {
// TODO: these are a bunch of static initializers, which we should avoid. See if
// we can make them constexpr.
const TypeDescriptor kAttributeSet = TypeDescriptor::FromClassname("android.util.AttributeSet");
const TypeDescriptor kContext = TypeDescriptor::FromClassname("android.content.Context");
const TypeDescriptor kLayoutInflater = TypeDescriptor::FromClassname("android.view.LayoutInflater");
const TypeDescriptor kResources = TypeDescriptor::FromClassname("android.content.res.Resources");
const TypeDescriptor kString = TypeDescriptor::FromClassname("java.lang.String");
const TypeDescriptor kView = TypeDescriptor::FromClassname("android.view.View");
const TypeDescriptor kViewGroup = TypeDescriptor::FromClassname("android.view.ViewGroup");
const TypeDescriptor kXmlResourceParser =
    TypeDescriptor::FromClassname("android.content.res.XmlResourceParser");
}  // namespace


DexViewBuilder::DexViewBuilder(dex::MethodBuilder* method)
DexViewBuilder::DexViewBuilder(dex::MethodBuilder* method)
    : method_{method},
    : method_{method},
      context_{dex::Value::Parameter(0)},
      context_{Value::Parameter(0)},
      resid_{dex::Value::Parameter(1)},
      resid_{Value::Parameter(1)},
      inflater_{method->MakeRegister()},
      inflater_{method->AllocRegister()},
      xml_{method->MakeRegister()},
      xml_{method->AllocRegister()},
      attrs_{method->MakeRegister()},
      attrs_{method->AllocRegister()},
      classname_tmp_{method->MakeRegister()},
      classname_tmp_{method->AllocRegister()},
      xml_next_{method->dex_file()->GetOrDeclareMethod(
      xml_next_{method->dex_file()->GetOrDeclareMethod(kXmlResourceParser, "next",
          dex::TypeDescriptor::FromClassname("android.content.res.XmlResourceParser"), "next",
                                                       Prototype{TypeDescriptor::Int()})},
          dex::Prototype{dex::TypeDescriptor::Int()})},
      try_create_view_{method->dex_file()->GetOrDeclareMethod(
      try_create_view_{method->dex_file()->GetOrDeclareMethod(
          dex::TypeDescriptor::FromClassname("android.view.LayoutInflater"), "tryCreateView",
          kLayoutInflater, "tryCreateView",
          dex::Prototype{dex::TypeDescriptor::FromClassname("android.view.View"),
          Prototype{kView, kView, kString, kContext, kAttributeSet})},
                         dex::TypeDescriptor::FromClassname("android.view.View"),
                         dex::TypeDescriptor::FromClassname("java.lang.String"),
                         dex::TypeDescriptor::FromClassname("android.content.Context"),
                         dex::TypeDescriptor::FromClassname("android.util.AttributeSet")})},
      generate_layout_params_{method->dex_file()->GetOrDeclareMethod(
      generate_layout_params_{method->dex_file()->GetOrDeclareMethod(
          dex::TypeDescriptor::FromClassname("android.view.ViewGroup"), "generateLayoutParams",
          kViewGroup, "generateLayoutParams",
          dex::Prototype{dex::TypeDescriptor::FromClassname("android.view.ViewGroup$LayoutParams"),
          Prototype{TypeDescriptor::FromClassname("android.view.ViewGroup$LayoutParams"),
                         dex::TypeDescriptor::FromClassname("android.util.AttributeSet")})},
                    kAttributeSet})},
      add_view_{method->dex_file()->GetOrDeclareMethod(
      add_view_{method->dex_file()->GetOrDeclareMethod(
          dex::TypeDescriptor::FromClassname("android.view.ViewGroup"), "addView",
          kViewGroup, "addView",
          dex::Prototype{
          Prototype{TypeDescriptor::Void(),
              dex::TypeDescriptor::Void(),
                    kView,
              dex::TypeDescriptor::FromClassname("android.view.View"),
                    TypeDescriptor::FromClassname("android.view.ViewGroup$LayoutParams")})} {}
              dex::TypeDescriptor::FromClassname("android.view.ViewGroup$LayoutParams")})},

      // The register stack starts with one register, which will be null for the root view.
void DexViewBuilder::BuildGetLayoutInflater(Value dest) {
      register_stack_{{method->MakeRegister()}} {}
  // dest = LayoutInflater.from(context);

  auto layout_inflater_from = method_->dex_file()->GetOrDeclareMethod(
void DexViewBuilder::Start() {
      kLayoutInflater, "from", Prototype{kLayoutInflater, kContext});
  dex::DexBuilder* const dex = method_->dex_file();
  method_->AddInstruction(Instruction::InvokeStaticObject(layout_inflater_from.id, dest, context_));

}
  // LayoutInflater inflater = LayoutInflater.from(context);
  auto layout_inflater_from = dex->GetOrDeclareMethod(
      dex::TypeDescriptor::FromClassname("android.view.LayoutInflater"),
      "from",
      dex::Prototype{dex::TypeDescriptor::FromClassname("android.view.LayoutInflater"),
                     dex::TypeDescriptor::FromClassname("android.content.Context")});
  method_->AddInstruction(
      dex::Instruction::InvokeStaticObject(layout_inflater_from.id, /*dest=*/inflater_, context_));


  // Resources res = context.getResources();
void DexViewBuilder::BuildGetResources(Value dest) {
  auto context_type = dex::TypeDescriptor::FromClassname("android.content.Context");
  // dest = context.getResources();
  auto resources_type = dex::TypeDescriptor::FromClassname("android.content.res.Resources");
  auto get_resources =
  auto get_resources =
      dex->GetOrDeclareMethod(context_type, "getResources", dex::Prototype{resources_type});
      method_->dex_file()->GetOrDeclareMethod(kContext, "getResources", Prototype{kResources});
  method_->AddInstruction(dex::Instruction::InvokeVirtualObject(get_resources.id, xml_, context_));
  method_->AddInstruction(Instruction::InvokeVirtualObject(get_resources.id, dest, context_));

}
  // XmlResourceParser xml = res.getLayout(resid);

  auto xml_resource_parser_type =
void DexViewBuilder::BuildGetLayoutResource(Value dest, Value resources, Value resid) {
      dex::TypeDescriptor::FromClassname("android.content.res.XmlResourceParser");
  // dest = resources.getLayout(resid);
  auto get_layout =
  auto get_layout = method_->dex_file()->GetOrDeclareMethod(
      dex->GetOrDeclareMethod(resources_type,
      kResources, "getLayout", Prototype{kXmlResourceParser, TypeDescriptor::Int()});
                              "getLayout",
  method_->AddInstruction(Instruction::InvokeVirtualObject(get_layout.id, dest, resources, resid));
                              dex::Prototype{xml_resource_parser_type, dex::TypeDescriptor::Int()});
}
  method_->AddInstruction(dex::Instruction::InvokeVirtualObject(get_layout.id, xml_, xml_, resid_));


void DexViewBuilder::BuildLayoutResourceToAttributeSet(dex::Value dest,
  // AttributeSet attrs = Xml.asAttributeSet(xml);
                                                       dex::Value layout_resource) {
  auto as_attribute_set = dex->GetOrDeclareMethod(
  // dest = Xml.asAttributeSet(layout_resource);
      dex::TypeDescriptor::FromClassname("android.util.Xml"),
  auto as_attribute_set = method_->dex_file()->GetOrDeclareMethod(
      TypeDescriptor::FromClassname("android.util.Xml"),
      "asAttributeSet",
      "asAttributeSet",
      dex::Prototype{dex::TypeDescriptor::FromClassname("android.util.AttributeSet"),
      Prototype{kAttributeSet, TypeDescriptor::FromClassname("org.xmlpull.v1.XmlPullParser")});
                     dex::TypeDescriptor::FromClassname("org.xmlpull.v1.XmlPullParser")});
  method_->AddInstruction(
  method_->AddInstruction(dex::Instruction::InvokeStaticObject(as_attribute_set.id, attrs_, xml_));
      Instruction::InvokeStaticObject(as_attribute_set.id, dest, layout_resource));
}


  // xml.next(); // start document
void DexViewBuilder::BuildXmlNext() {
  method_->AddInstruction(dex::Instruction::InvokeInterface(xml_next_.id, {}, xml_));
  // xml_.next();
  method_->AddInstruction(Instruction::InvokeInterface(xml_next_.id, {}, xml_));
}

void DexViewBuilder::Start() {
  BuildGetLayoutInflater(/*dest=*/inflater_);
  BuildGetResources(/*dest=*/xml_);
  BuildGetLayoutResource(/*dest=*/xml_, /*resources=*/xml_, resid_);
  BuildLayoutResourceToAttributeSet(/*dest=*/attrs_, /*layout_resource=*/xml_);

  // Advance past start document tag
  BuildXmlNext();
}
}


void DexViewBuilder::Finish() {}
void DexViewBuilder::Finish() {}
@@ -107,58 +125,57 @@ std::string ResolveName(const std::string& name) {
}
}
}  // namespace
}  // namespace


void DexViewBuilder::BuildTryCreateView(Value dest, Value parent, Value classname) {
  // dest = inflater_.tryCreateView(parent, classname, context_, attrs_);
  method_->AddInstruction(Instruction::InvokeVirtualObject(
      try_create_view_.id, dest, inflater_, parent, classname, context_, attrs_));
}

void DexViewBuilder::StartView(const std::string& name, bool is_viewgroup) {
void DexViewBuilder::StartView(const std::string& name, bool is_viewgroup) {
  bool const is_root_view = view_stack_.empty();
  bool const is_root_view = view_stack_.empty();


  // xml.next(); // start tag
  // Advance to start tag
  method_->AddInstruction(dex::Instruction::InvokeInterface(xml_next_.id, {}, xml_));
  BuildXmlNext();


  dex::Value view = AcquireRegister();
  LiveRegister view = AcquireRegister();
  // try to create the view using the factories
  // try to create the view using the factories
  method_->BuildConstString(classname_tmp_,
  method_->BuildConstString(classname_tmp_,
                            name);  // TODO: the need to fully qualify the classname
                            name);  // TODO: the need to fully qualify the classname
  if (is_root_view) {
  if (is_root_view) {
    dex::Value null = AcquireRegister();
    LiveRegister null = AcquireRegister();
    method_->BuildConst4(null, 0);
    method_->BuildConst4(null, 0);
    method_->AddInstruction(dex::Instruction::InvokeVirtualObject(
    BuildTryCreateView(/*dest=*/view, /*parent=*/null, classname_tmp_);
        try_create_view_.id, view, inflater_, null, classname_tmp_, context_, attrs_));
    ReleaseRegister();
  } else {
  } else {
    method_->AddInstruction(dex::Instruction::InvokeVirtualObject(
    BuildTryCreateView(/*dest=*/view, /*parent=*/GetCurrentView(), classname_tmp_);
        try_create_view_.id, view, inflater_, GetCurrentView(), classname_tmp_, context_, attrs_));
  }
  }
  auto label = method_->MakeLabel();
  auto label = method_->MakeLabel();
  // branch if not null
  // branch if not null
  method_->AddInstruction(
  method_->AddInstruction(
      dex::Instruction::OpWithArgs(dex::Instruction::Op::kBranchNEqz, /*dest=*/{}, view, label));
      Instruction::OpWithArgs(Instruction::Op::kBranchNEqz, /*dest=*/{}, view, label));


  // If null, create the class directly.
  // If null, create the class directly.
  method_->BuildNew(view,
  method_->BuildNew(view,
                    dex::TypeDescriptor::FromClassname(ResolveName(name)),
                    TypeDescriptor::FromClassname(ResolveName(name)),
                    dex::Prototype{dex::TypeDescriptor::Void(),
                    Prototype{TypeDescriptor::Void(), kContext, kAttributeSet},
                                   dex::TypeDescriptor::FromClassname("android.content.Context"),
                                   dex::TypeDescriptor::FromClassname("android.util.AttributeSet")},
                    context_,
                    context_,
                    attrs_);
                    attrs_);


  method_->AddInstruction(
  method_->AddInstruction(Instruction::OpWithArgs(Instruction::Op::kBindLabel, /*dest=*/{}, label));
      dex::Instruction::OpWithArgs(dex::Instruction::Op::kBindLabel, /*dest=*/{}, label));


  if (is_viewgroup) {
  if (is_viewgroup) {
    // Cast to a ViewGroup so we can add children later.
    // Cast to a ViewGroup so we can add children later.
    const ir::Type* view_group_def = method_->dex_file()->GetOrAddType(
    const ir::Type* view_group_def = method_->dex_file()->GetOrAddType(kViewGroup.descriptor());
        dex::TypeDescriptor::FromClassname("android.view.ViewGroup").descriptor());
    method_->AddInstruction(Instruction::Cast(view, Value::Type(view_group_def->orig_index)));
    method_->AddInstruction(dex::Instruction::Cast(view, dex::Value::Type(view_group_def->orig_index)));
  }
  }


  if (!is_root_view) {
  if (!is_root_view) {
    // layout_params = parent.generateLayoutParams(attrs);
    // layout_params = parent.generateLayoutParams(attrs);
    dex::Value layout_params{AcquireRegister()};
    LiveRegister layout_params{AcquireRegister()};
    method_->AddInstruction(dex::Instruction::InvokeVirtualObject(
    method_->AddInstruction(Instruction::InvokeVirtualObject(
        generate_layout_params_.id, layout_params, GetCurrentView(), attrs_));
        generate_layout_params_.id, layout_params, GetCurrentView(), attrs_));
    view_stack_.push_back({view, layout_params});
    view_stack_.push_back({std::move(view), std::move(layout_params)});
  } else {
  } else {
    view_stack_.push_back({view, {}});
    view_stack_.push_back({std::move(view), {}});
  }
  }
}
}


@@ -167,40 +184,24 @@ void DexViewBuilder::FinishView() {
    method_->BuildReturn(GetCurrentView(), /*is_object=*/true);
    method_->BuildReturn(GetCurrentView(), /*is_object=*/true);
  } else {
  } else {
    // parent.add(view, layout_params)
    // parent.add(view, layout_params)
    method_->AddInstruction(dex::Instruction::InvokeVirtual(
    method_->AddInstruction(Instruction::InvokeVirtual(
        add_view_.id, /*dest=*/{}, GetParentView(), GetCurrentView(), GetCurrentLayoutParams()));
        add_view_.id, /*dest=*/{}, GetParentView(), GetCurrentView(), GetCurrentLayoutParams()));
    // xml.next(); // end tag
    // xml.next(); // end tag
    method_->AddInstruction(dex::Instruction::InvokeInterface(xml_next_.id, {}, xml_));
    method_->AddInstruction(Instruction::InvokeInterface(xml_next_.id, {}, xml_));
  }
  }
  PopViewStack();
  PopViewStack();
}
}


dex::Value DexViewBuilder::AcquireRegister() {
LiveRegister DexViewBuilder::AcquireRegister() { return method_->AllocRegister(); }
  top_register_++;
  if (register_stack_.size() == top_register_) {
    register_stack_.push_back(method_->MakeRegister());
  }
  return register_stack_[top_register_];
}

void DexViewBuilder::ReleaseRegister() { top_register_--; }


dex::Value DexViewBuilder::GetCurrentView() const { return view_stack_.back().view; }
Value DexViewBuilder::GetCurrentView() const { return view_stack_.back().view; }
dex::Value DexViewBuilder::GetCurrentLayoutParams() const {
Value DexViewBuilder::GetCurrentLayoutParams() const {
  return view_stack_.back().layout_params.value();
  return view_stack_.back().layout_params.value();
}
}
dex::Value DexViewBuilder::GetParentView() const {
Value DexViewBuilder::GetParentView() const { return view_stack_[view_stack_.size() - 2].view; }
  return view_stack_[view_stack_.size() - 2].view;
}


void DexViewBuilder::PopViewStack() {
void DexViewBuilder::PopViewStack() {
  const auto& top = view_stack_.back();
  // release the layout params if we have them
  if (top.layout_params.has_value()) {
    ReleaseRegister();
  }
  // Unconditionally release the view register.
  // Unconditionally release the view register.
  ReleaseRegister();
  view_stack_.pop_back();
  view_stack_.pop_back();
}
}


+18 −13
Original line number Original line Diff line number Diff line
@@ -79,36 +79,41 @@ class DexViewBuilder {


 private:
 private:
  // Accessors for the stack of views that are under construction.
  // Accessors for the stack of views that are under construction.
  dex::Value AcquireRegister();
  dex::LiveRegister AcquireRegister();
  void ReleaseRegister();
  dex::Value GetCurrentView() const;
  dex::Value GetCurrentView() const;
  dex::Value GetCurrentLayoutParams() const;
  dex::Value GetCurrentLayoutParams() const;
  dex::Value GetParentView() const;
  dex::Value GetParentView() const;
  void PopViewStack();
  void PopViewStack();


  // Methods to simplify building different code fragments.
  void BuildGetLayoutInflater(dex::Value dest);
  void BuildGetResources(dex::Value dest);
  void BuildGetLayoutResource(dex::Value dest, dex::Value resources, dex::Value resid);
  void BuildLayoutResourceToAttributeSet(dex::Value dest, dex::Value layout_resource);
  void BuildXmlNext();
  void BuildTryCreateView(dex::Value dest, dex::Value parent, dex::Value classname);

  dex::MethodBuilder* method_;
  dex::MethodBuilder* method_;


  // Registers used for code generation
  // Parameters to the generated method
  dex::Value const context_;
  dex::Value const context_;
  dex::Value const resid_;
  dex::Value const resid_;
  const dex::Value inflater_;

  const dex::Value xml_;
  // Registers used for code generation
  const dex::Value attrs_;
  const dex::LiveRegister inflater_;
  const dex::Value classname_tmp_;
  const dex::LiveRegister xml_;
  const dex::LiveRegister attrs_;
  const dex::LiveRegister classname_tmp_;


  const dex::MethodDeclData xml_next_;
  const dex::MethodDeclData xml_next_;
  const dex::MethodDeclData try_create_view_;
  const dex::MethodDeclData try_create_view_;
  const dex::MethodDeclData generate_layout_params_;
  const dex::MethodDeclData generate_layout_params_;
  const dex::MethodDeclData add_view_;
  const dex::MethodDeclData add_view_;


  // used for keeping track of which registers are in use
  size_t top_register_{0};
  std::vector<dex::Value> register_stack_;

  // Keep track of the views currently in progress.
  // Keep track of the views currently in progress.
  struct ViewEntry {
  struct ViewEntry {
    dex::Value view;
    dex::LiveRegister view;
    std::optional<dex::Value> layout_params;
    std::optional<dex::LiveRegister> layout_params;
  };
  };
  std::vector<ViewEntry> view_stack_;
  std::vector<ViewEntry> view_stack_;
};
};
+18 −18

File changed.

Preview size limit exceeded, changes collapsed.