blob: 183e5e6c963d8dac9e47c7032b6bdf7d41446b14 [file] [log] [blame]
Vladimir Markob163bb72015-03-31 21:49:49 +01001/*
2 * Copyright (C) 2015 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 ART_COMPILER_LINKER_ARM_RELATIVE_PATCHER_THUMB2_H_
18#define ART_COMPILER_LINKER_ARM_RELATIVE_PATCHER_THUMB2_H_
19
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010020#include "arch/arm/registers_arm.h"
21#include "base/array_ref.h"
22#include "base/bit_field.h"
23#include "base/bit_utils.h"
Vladimir Markob163bb72015-03-31 21:49:49 +010024#include "linker/arm/relative_patcher_arm_base.h"
25
26namespace art {
Vladimir Marko0a51fc32017-05-02 13:12:02 +010027
28namespace arm {
29class ArmVIXLAssembler;
30} // namespace arm
31
Vladimir Markob163bb72015-03-31 21:49:49 +010032namespace linker {
33
34class Thumb2RelativePatcher FINAL : public ArmBaseRelativePatcher {
35 public:
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010036 static constexpr uint32_t kBakerCcEntrypointRegister = 4u;
37
Vladimir Marko88abba22017-05-03 17:09:25 +010038 static uint32_t EncodeBakerReadBarrierFieldData(uint32_t base_reg,
39 uint32_t holder_reg,
40 bool narrow) {
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010041 CheckValidReg(base_reg);
42 CheckValidReg(holder_reg);
Vladimir Marko88abba22017-05-03 17:09:25 +010043 DCHECK(!narrow || base_reg < 8u) << base_reg;
44 BakerReadBarrierWidth width =
45 narrow ? BakerReadBarrierWidth::kNarrow : BakerReadBarrierWidth::kWide;
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010046 return BakerReadBarrierKindField::Encode(BakerReadBarrierKind::kField) |
47 BakerReadBarrierFirstRegField::Encode(base_reg) |
Vladimir Marko88abba22017-05-03 17:09:25 +010048 BakerReadBarrierSecondRegField::Encode(holder_reg) |
49 BakerReadBarrierWidthField::Encode(width);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010050 }
51
52 static uint32_t EncodeBakerReadBarrierArrayData(uint32_t base_reg) {
53 CheckValidReg(base_reg);
54 return BakerReadBarrierKindField::Encode(BakerReadBarrierKind::kArray) |
55 BakerReadBarrierFirstRegField::Encode(base_reg) |
Vladimir Marko88abba22017-05-03 17:09:25 +010056 BakerReadBarrierSecondRegField::Encode(kInvalidEncodedReg) |
57 BakerReadBarrierWidthField::Encode(BakerReadBarrierWidth::kWide);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010058 }
59
Vladimir Marko88abba22017-05-03 17:09:25 +010060 static uint32_t EncodeBakerReadBarrierGcRootData(uint32_t root_reg, bool narrow) {
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010061 CheckValidReg(root_reg);
Vladimir Marko88abba22017-05-03 17:09:25 +010062 DCHECK(!narrow || root_reg < 8u) << root_reg;
63 BakerReadBarrierWidth width =
64 narrow ? BakerReadBarrierWidth::kNarrow : BakerReadBarrierWidth::kWide;
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010065 return BakerReadBarrierKindField::Encode(BakerReadBarrierKind::kGcRoot) |
66 BakerReadBarrierFirstRegField::Encode(root_reg) |
Vladimir Marko88abba22017-05-03 17:09:25 +010067 BakerReadBarrierSecondRegField::Encode(kInvalidEncodedReg) |
68 BakerReadBarrierWidthField::Encode(width);
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010069 }
70
Vladimir Markob163bb72015-03-31 21:49:49 +010071 explicit Thumb2RelativePatcher(RelativePatcherTargetProvider* provider);
72
Vladimir Marko944da602016-02-19 12:27:55 +000073 void PatchCall(std::vector<uint8_t>* code,
74 uint32_t literal_offset,
75 uint32_t patch_offset,
76 uint32_t target_offset) OVERRIDE;
Vladimir Markocac5a7e2016-02-22 10:39:50 +000077 void PatchPcRelativeReference(std::vector<uint8_t>* code,
78 const LinkerPatch& patch,
79 uint32_t patch_offset,
80 uint32_t target_offset) OVERRIDE;
Vladimir Markof4f2daa2017-03-20 18:26:59 +000081 void PatchBakerReadBarrierBranch(std::vector<uint8_t>* code,
82 const LinkerPatch& patch,
83 uint32_t patch_offset) OVERRIDE;
84
85 protected:
Vladimir Markof4f2daa2017-03-20 18:26:59 +000086 std::vector<uint8_t> CompileThunk(const ThunkKey& key) OVERRIDE;
Vladimir Marko0a51fc32017-05-02 13:12:02 +010087 uint32_t MaxPositiveDisplacement(const ThunkKey& key) OVERRIDE;
88 uint32_t MaxNegativeDisplacement(const ThunkKey& key) OVERRIDE;
Vladimir Markob163bb72015-03-31 21:49:49 +010089
90 private:
Vladimir Markoeee1c0e2017-04-21 17:58:41 +010091 static constexpr uint32_t kInvalidEncodedReg = /* pc is invalid */ 15u;
92
Vladimir Marko0a51fc32017-05-02 13:12:02 +010093 enum class BakerReadBarrierKind : uint8_t {
94 kField, // Field get or array get with constant offset (i.e. constant index).
95 kArray, // Array get with index in register.
96 kGcRoot, // GC root load.
Vladimir Markob59d5fb2017-05-09 14:19:21 +010097 kLast = kGcRoot
Vladimir Marko0a51fc32017-05-02 13:12:02 +010098 };
99
Vladimir Marko88abba22017-05-03 17:09:25 +0100100 enum class BakerReadBarrierWidth : uint8_t {
101 kWide, // 32-bit LDR (and 32-bit NEG if heap poisoning is enabled).
102 kNarrow, // 16-bit LDR (and 16-bit NEG if heap poisoning is enabled).
Vladimir Markob59d5fb2017-05-09 14:19:21 +0100103 kLast = kNarrow
Vladimir Marko88abba22017-05-03 17:09:25 +0100104 };
105
Vladimir Markoeee1c0e2017-04-21 17:58:41 +0100106 static constexpr size_t kBitsForBakerReadBarrierKind =
107 MinimumBitsToStore(static_cast<size_t>(BakerReadBarrierKind::kLast));
108 static constexpr size_t kBitsForRegister = 4u;
109 using BakerReadBarrierKindField =
110 BitField<BakerReadBarrierKind, 0, kBitsForBakerReadBarrierKind>;
111 using BakerReadBarrierFirstRegField =
112 BitField<uint32_t, kBitsForBakerReadBarrierKind, kBitsForRegister>;
113 using BakerReadBarrierSecondRegField =
114 BitField<uint32_t, kBitsForBakerReadBarrierKind + kBitsForRegister, kBitsForRegister>;
Vladimir Marko88abba22017-05-03 17:09:25 +0100115 static constexpr size_t kBitsForBakerReadBarrierWidth =
116 MinimumBitsToStore(static_cast<size_t>(BakerReadBarrierWidth::kLast));
117 using BakerReadBarrierWidthField = BitField<BakerReadBarrierWidth,
118 kBitsForBakerReadBarrierKind + 2 * kBitsForRegister,
119 kBitsForBakerReadBarrierWidth>;
Vladimir Markoeee1c0e2017-04-21 17:58:41 +0100120
121 static void CheckValidReg(uint32_t reg) {
Vladimir Marko88abba22017-05-03 17:09:25 +0100122 DCHECK(reg < 12u && reg != kBakerCcEntrypointRegister) << reg;
Vladimir Markoeee1c0e2017-04-21 17:58:41 +0100123 }
124
Vladimir Marko0a51fc32017-05-02 13:12:02 +0100125 void CompileBakerReadBarrierThunk(arm::ArmVIXLAssembler& assembler, uint32_t encoded_data);
126
Vladimir Markoe5c76c52015-04-06 12:10:19 +0100127 void SetInsn32(std::vector<uint8_t>* code, uint32_t offset, uint32_t value);
128 static uint32_t GetInsn32(ArrayRef<const uint8_t> code, uint32_t offset);
129
Vladimir Markoec7802a2015-10-01 20:57:57 +0100130 template <typename Vector>
131 static uint32_t GetInsn32(Vector* code, uint32_t offset);
Vladimir Markoe5c76c52015-04-06 12:10:19 +0100132
Vladimir Marko88abba22017-05-03 17:09:25 +0100133 static uint32_t GetInsn16(ArrayRef<const uint8_t> code, uint32_t offset);
134
135 template <typename Vector>
136 static uint32_t GetInsn16(Vector* code, uint32_t offset);
137
Vladimir Markof4f2daa2017-03-20 18:26:59 +0000138 friend class Thumb2RelativePatcherTest;
Vladimir Markob163bb72015-03-31 21:49:49 +0100139
140 DISALLOW_COPY_AND_ASSIGN(Thumb2RelativePatcher);
141};
142
143} // namespace linker
144} // namespace art
145
146#endif // ART_COMPILER_LINKER_ARM_RELATIVE_PATCHER_THUMB2_H_