1b4536b7de576b20c74c612406c5d3132998075efVladimir Marko/*
2b4536b7de576b20c74c612406c5d3132998075efVladimir Marko * Copyright (C) 2015 The Android Open Source Project
3b4536b7de576b20c74c612406c5d3132998075efVladimir Marko *
4b4536b7de576b20c74c612406c5d3132998075efVladimir Marko * Licensed under the Apache License, Version 2.0 (the "License");
5b4536b7de576b20c74c612406c5d3132998075efVladimir Marko * you may not use this file except in compliance with the License.
6b4536b7de576b20c74c612406c5d3132998075efVladimir Marko * You may obtain a copy of the License at
7b4536b7de576b20c74c612406c5d3132998075efVladimir Marko *
8b4536b7de576b20c74c612406c5d3132998075efVladimir Marko *      http://www.apache.org/licenses/LICENSE-2.0
9b4536b7de576b20c74c612406c5d3132998075efVladimir Marko *
10b4536b7de576b20c74c612406c5d3132998075efVladimir Marko * Unless required by applicable law or agreed to in writing, software
11b4536b7de576b20c74c612406c5d3132998075efVladimir Marko * distributed under the License is distributed on an "AS IS" BASIS,
12b4536b7de576b20c74c612406c5d3132998075efVladimir Marko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b4536b7de576b20c74c612406c5d3132998075efVladimir Marko * See the License for the specific language governing permissions and
14b4536b7de576b20c74c612406c5d3132998075efVladimir Marko * limitations under the License.
15b4536b7de576b20c74c612406c5d3132998075efVladimir Marko */
16b4536b7de576b20c74c612406c5d3132998075efVladimir Marko
17b4536b7de576b20c74c612406c5d3132998075efVladimir Marko#include "dex_cache_array_fixups_arm.h"
18b4536b7de576b20c74c612406c5d3132998075efVladimir Marko
19b4536b7de576b20c74c612406c5d3132998075efVladimir Marko#include "base/arena_containers.h"
20b4536b7de576b20c74c612406c5d3132998075efVladimir Marko#include "utils/dex_cache_arrays_layout-inl.h"
21b4536b7de576b20c74c612406c5d3132998075efVladimir Marko
22b4536b7de576b20c74c612406c5d3132998075efVladimir Markonamespace art {
23b4536b7de576b20c74c612406c5d3132998075efVladimir Markonamespace arm {
24b4536b7de576b20c74c612406c5d3132998075efVladimir Marko
25b4536b7de576b20c74c612406c5d3132998075efVladimir Marko/**
26b4536b7de576b20c74c612406c5d3132998075efVladimir Marko * Finds instructions that need the dex cache arrays base as an input.
27b4536b7de576b20c74c612406c5d3132998075efVladimir Marko */
28b4536b7de576b20c74c612406c5d3132998075efVladimir Markoclass DexCacheArrayFixupsVisitor : public HGraphVisitor {
29b4536b7de576b20c74c612406c5d3132998075efVladimir Marko public:
30b4536b7de576b20c74c612406c5d3132998075efVladimir Marko  explicit DexCacheArrayFixupsVisitor(HGraph* graph)
31b4536b7de576b20c74c612406c5d3132998075efVladimir Marko      : HGraphVisitor(graph),
32b4536b7de576b20c74c612406c5d3132998075efVladimir Marko        dex_cache_array_bases_(std::less<const DexFile*>(),
33b4536b7de576b20c74c612406c5d3132998075efVladimir Marko                               // Attribute memory use to code generator.
34b4536b7de576b20c74c612406c5d3132998075efVladimir Marko                               graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {}
35b4536b7de576b20c74c612406c5d3132998075efVladimir Marko
36fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko  void MoveBasesIfNeeded() {
37fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko    for (const auto& entry : dex_cache_array_bases_) {
38fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko      // Bring the base closer to the first use (previously, it was in the
39fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko      // entry block) and relieve some pressure on the register allocator
40fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko      // while avoiding recalculation of the base in a loop.
41fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko      HArmDexCacheArraysBase* base = entry.second;
42fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko      base->MoveBeforeFirstUserAndOutOfLoops();
43fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko    }
44fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko  }
45fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko
46b4536b7de576b20c74c612406c5d3132998075efVladimir Marko private:
47cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko  void VisitLoadString(HLoadString* load_string) OVERRIDE {
48cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko    // If this is a load with PC-relative access to the dex cache methods array,
49cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko    // we need to add the dex cache arrays base as the special input.
50cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko    if (load_string->GetLoadKind() == HLoadString::LoadKind::kDexCachePcRelative) {
51cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko      // Initialize base for target dex file if needed.
52cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko      const DexFile& dex_file = load_string->GetDexFile();
53cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko      HArmDexCacheArraysBase* base = GetOrCreateDexCacheArrayBase(dex_file);
54cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko      // Update the element offset in base.
55cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko      DexCacheArraysLayout layout(kArmPointerSize, &dex_file);
56cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko      base->UpdateElementOffset(layout.StringOffset(load_string->GetStringIndex()));
57cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko      // Add the special argument base to the load.
58cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko      load_string->AddSpecialInput(base);
59cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko    }
60cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko  }
61cac5a7e871f1f346b317894359ad06fa7bd67fbaVladimir Marko
62b4536b7de576b20c74c612406c5d3132998075efVladimir Marko  void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
63b4536b7de576b20c74c612406c5d3132998075efVladimir Marko    // If this is an invoke with PC-relative access to the dex cache methods array,
64b4536b7de576b20c74c612406c5d3132998075efVladimir Marko    // we need to add the dex cache arrays base as the special input.
65b4536b7de576b20c74c612406c5d3132998075efVladimir Marko    if (invoke->HasPcRelativeDexCache()) {
66b4536b7de576b20c74c612406c5d3132998075efVladimir Marko      // Initialize base for target method dex file if needed.
67b4536b7de576b20c74c612406c5d3132998075efVladimir Marko      MethodReference target_method = invoke->GetTargetMethod();
68fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko      HArmDexCacheArraysBase* base = GetOrCreateDexCacheArrayBase(*target_method.dex_file);
69b4536b7de576b20c74c612406c5d3132998075efVladimir Marko      // Update the element offset in base.
70b4536b7de576b20c74c612406c5d3132998075efVladimir Marko      DexCacheArraysLayout layout(kArmPointerSize, target_method.dex_file);
71b4536b7de576b20c74c612406c5d3132998075efVladimir Marko      base->UpdateElementOffset(layout.MethodOffset(target_method.dex_method_index));
72b4536b7de576b20c74c612406c5d3132998075efVladimir Marko      // Add the special argument base to the method.
73b4536b7de576b20c74c612406c5d3132998075efVladimir Marko      DCHECK(!invoke->HasCurrentMethodInput());
74b4536b7de576b20c74c612406c5d3132998075efVladimir Marko      invoke->AddSpecialInput(base);
75b4536b7de576b20c74c612406c5d3132998075efVladimir Marko    }
76b4536b7de576b20c74c612406c5d3132998075efVladimir Marko  }
77b4536b7de576b20c74c612406c5d3132998075efVladimir Marko
78fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko  HArmDexCacheArraysBase* GetOrCreateDexCacheArrayBase(const DexFile& dex_file) {
79b4536b7de576b20c74c612406c5d3132998075efVladimir Marko    // Ensure we only initialize the pointer once for each dex file.
80b4536b7de576b20c74c612406c5d3132998075efVladimir Marko    auto lb = dex_cache_array_bases_.lower_bound(&dex_file);
81b4536b7de576b20c74c612406c5d3132998075efVladimir Marko    if (lb != dex_cache_array_bases_.end() &&
82b4536b7de576b20c74c612406c5d3132998075efVladimir Marko        !dex_cache_array_bases_.key_comp()(&dex_file, lb->first)) {
83b4536b7de576b20c74c612406c5d3132998075efVladimir Marko      return lb->second;
84b4536b7de576b20c74c612406c5d3132998075efVladimir Marko    }
85b4536b7de576b20c74c612406c5d3132998075efVladimir Marko
86fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko    // Insert the base at the start of the entry block, move it to a better
87fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko    // position later in MoveBaseIfNeeded().
88fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko    HArmDexCacheArraysBase* base = new (GetGraph()->GetArena()) HArmDexCacheArraysBase(dex_file);
89fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko    HBasicBlock* entry_block = GetGraph()->GetEntryBlock();
90fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko    entry_block->InsertInstructionBefore(base, entry_block->GetFirstInstruction());
91b4536b7de576b20c74c612406c5d3132998075efVladimir Marko    dex_cache_array_bases_.PutBefore(lb, &dex_file, base);
92b4536b7de576b20c74c612406c5d3132998075efVladimir Marko    return base;
93b4536b7de576b20c74c612406c5d3132998075efVladimir Marko  }
94b4536b7de576b20c74c612406c5d3132998075efVladimir Marko
95b4536b7de576b20c74c612406c5d3132998075efVladimir Marko  using DexCacheArraysBaseMap =
96b4536b7de576b20c74c612406c5d3132998075efVladimir Marko      ArenaSafeMap<const DexFile*, HArmDexCacheArraysBase*, std::less<const DexFile*>>;
97b4536b7de576b20c74c612406c5d3132998075efVladimir Marko  DexCacheArraysBaseMap dex_cache_array_bases_;
98b4536b7de576b20c74c612406c5d3132998075efVladimir Marko};
99b4536b7de576b20c74c612406c5d3132998075efVladimir Marko
100b4536b7de576b20c74c612406c5d3132998075efVladimir Markovoid DexCacheArrayFixups::Run() {
10115bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray  if (graph_->HasIrreducibleLoops()) {
10215bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray    // Do not run this optimization, as irreducible loops do not work with an instruction
10315bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray    // that can be live-in at the irreducible loop header.
10415bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray    return;
10515bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray  }
106b4536b7de576b20c74c612406c5d3132998075efVladimir Marko  DexCacheArrayFixupsVisitor visitor(graph_);
107b4536b7de576b20c74c612406c5d3132998075efVladimir Marko  visitor.VisitInsertionOrder();
108fb337ea53d1e6fe68b24217a9ea95e9f544ef697Vladimir Marko  visitor.MoveBasesIfNeeded();
109b4536b7de576b20c74c612406c5d3132998075efVladimir Marko}
110b4536b7de576b20c74c612406c5d3132998075efVladimir Marko
111b4536b7de576b20c74c612406c5d3132998075efVladimir Marko}  // namespace arm
112b4536b7de576b20c74c612406c5d3132998075efVladimir Marko}  // namespace art
113