1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef DEX_LAYOUT_COMPILER_H_ 18 #define DEX_LAYOUT_COMPILER_H_ 19 20 #include "dex_builder.h" 21 22 #include <codecvt> 23 #include <locale> 24 #include <string> 25 #include <vector> 26 27 namespace startop { 28 29 // This visitor does the actual view compilation, using a supplied builder. 30 template <typename Builder> 31 class LayoutCompilerVisitor { 32 public: LayoutCompilerVisitor(Builder * builder)33 explicit LayoutCompilerVisitor(Builder* builder) : builder_{builder} {} 34 VisitStartDocument()35 void VisitStartDocument() { builder_->Start(); } VisitEndDocument()36 void VisitEndDocument() { builder_->Finish(); } VisitStartTag(const std::u16string & name)37 void VisitStartTag(const std::u16string& name) { 38 parent_stack_.push_back(ViewEntry{ 39 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(name), {}}); 40 } VisitEndTag()41 void VisitEndTag() { 42 auto entry = parent_stack_.back(); 43 parent_stack_.pop_back(); 44 45 if (parent_stack_.empty()) { 46 GenerateCode(entry); 47 } else { 48 parent_stack_.back().children.push_back(entry); 49 } 50 } 51 52 private: 53 struct ViewEntry { 54 std::string name; 55 std::vector<ViewEntry> children; 56 }; 57 GenerateCode(const ViewEntry & view)58 void GenerateCode(const ViewEntry& view) { 59 builder_->StartView(view.name, !view.children.empty()); 60 for (const auto& child : view.children) { 61 GenerateCode(child); 62 } 63 builder_->FinishView(); 64 } 65 66 Builder* builder_; 67 68 std::vector<ViewEntry> parent_stack_; 69 }; 70 71 class DexViewBuilder { 72 public: 73 DexViewBuilder(dex::MethodBuilder* method); 74 75 void Start(); 76 void Finish(); 77 void StartView(const std::string& name, bool is_viewgroup); 78 void FinishView(); 79 80 private: 81 // Accessors for the stack of views that are under construction. 82 dex::LiveRegister AcquireRegister(); 83 dex::Value GetCurrentView() const; 84 dex::Value GetCurrentLayoutParams() const; 85 dex::Value GetParentView() const; 86 void PopViewStack(); 87 88 // Methods to simplify building different code fragments. 89 void BuildGetLayoutInflater(dex::Value dest); 90 void BuildGetResources(dex::Value dest); 91 void BuildGetLayoutResource(dex::Value dest, dex::Value resources, dex::Value resid); 92 void BuildLayoutResourceToAttributeSet(dex::Value dest, dex::Value layout_resource); 93 void BuildXmlNext(); 94 void BuildTryCreateView(dex::Value dest, dex::Value parent, dex::Value classname); 95 96 dex::MethodBuilder* method_; 97 98 // Parameters to the generated method 99 dex::Value const context_; 100 dex::Value const resid_; 101 102 // Registers used for code generation 103 const dex::LiveRegister inflater_; 104 const dex::LiveRegister xml_; 105 const dex::LiveRegister attrs_; 106 const dex::LiveRegister classname_tmp_; 107 108 const dex::MethodDeclData xml_next_; 109 const dex::MethodDeclData try_create_view_; 110 const dex::MethodDeclData generate_layout_params_; 111 const dex::MethodDeclData add_view_; 112 113 // Keep track of the views currently in progress. 114 struct ViewEntry { 115 dex::LiveRegister view; 116 std::optional<dex::LiveRegister> layout_params; 117 }; 118 std::vector<ViewEntry> view_stack_; 119 }; 120 121 } // namespace startop 122 123 #endif // DEX_LAYOUT_COMPILER_H_ 124