Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(817)

Side by Side Diff: runtime/vm/instructions_arm64.cc

Issue 241573002: Code patching for ARM64. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64.
6 #if defined(TARGET_ARCH_ARM64) 6 #if defined(TARGET_ARCH_ARM64)
7 7
8 #include "vm/assembler.h" 8 #include "vm/assembler.h"
9 #include "vm/constants_arm64.h" 9 #include "vm/constants_arm64.h"
10 #include "vm/cpu.h" 10 #include "vm/cpu.h"
11 #include "vm/instructions.h" 11 #include "vm/instructions.h"
12 #include "vm/object.h" 12 #include "vm/object.h"
13 13
14 namespace dart { 14 namespace dart {
15 15
16 CallPattern::CallPattern(uword pc, const Code& code) 16 CallPattern::CallPattern(uword pc, const Code& code)
17 : object_pool_(Array::Handle(code.ObjectPool())), 17 : object_pool_(Array::Handle(code.ObjectPool())),
18 end_(pc), 18 end_(pc),
19 args_desc_load_end_(0), 19 args_desc_load_end_(0),
20 ic_data_load_end_(0), 20 ic_data_load_end_(0),
21 target_address_pool_index_(-1), 21 target_address_pool_index_(-1),
22 args_desc_(Array::Handle()), 22 args_desc_(Array::Handle()),
23 ic_data_(ICData::Handle()) { 23 ic_data_(ICData::Handle()) {
24 UNIMPLEMENTED(); 24 ASSERT(code.ContainsInstructionAt(pc));
25 // Last instruction: blr ip0.
26 ASSERT(*(reinterpret_cast<uint32_t*>(end_) - 1) == 0xd63f0200);
27
28 Register reg;
29 ic_data_load_end_ =
30 InstructionPattern::DecodeLoadWordFromPool(end_ - Instr::kInstrSize,
31 &reg,
32 &target_address_pool_index_);
33 ASSERT(reg == IP0);
25 } 34 }
26 35
27 36
28 int CallPattern::LengthInBytes() {
29 UNIMPLEMENTED();
30 return 0;
31 }
32
33
34 // Decodes a load sequence ending at 'end' (the last instruction of the load 37 // Decodes a load sequence ending at 'end' (the last instruction of the load
35 // sequence is the instruction before the one at end). Returns a pointer to 38 // sequence is the instruction before the one at end). Returns a pointer to
36 // the first instruction in the sequence. Returns the register being loaded 39 // the first instruction in the sequence. Returns the register being loaded
37 // and the loaded object in the output parameters 'reg' and 'obj' 40 // and the loaded object in the output parameters 'reg' and 'obj'
38 // respectively. 41 // respectively.
39 uword InstructionPattern::DecodeLoadObject(uword end, 42 uword InstructionPattern::DecodeLoadObject(uword end,
40 const Array& object_pool, 43 const Array& object_pool,
41 Register* reg, 44 Register* reg,
42 Object* obj) { 45 Object* obj) {
43 UNIMPLEMENTED(); 46 // 1. LoadWordFromPool
44 return 0; 47 // or
48 // 2. LoadDecodableImmediate
49 uword start = 0;
50 Instr* instr = Instr::At(end - Instr::kInstrSize);
51 if (instr->IsLoadStoreRegOp()) {
52 // Case 1.
53 intptr_t index = 0;
54 start = DecodeLoadWordFromPool(end, reg, &index);
55 *obj = object_pool.At(index);
56 } else {
57 // Case 2.
58 intptr_t value = 0;
59 start = DecodeLoadWordImmediate(end, reg, &value);
60 *obj = reinterpret_cast<RawObject*>(value);
61 }
62 return start;
45 } 63 }
46 64
47 65
48 // Decodes a load sequence ending at 'end' (the last instruction of the load 66 // Decodes a load sequence ending at 'end' (the last instruction of the load
49 // sequence is the instruction before the one at end). Returns a pointer to 67 // sequence is the instruction before the one at end). Returns a pointer to
50 // the first instruction in the sequence. Returns the register being loaded 68 // the first instruction in the sequence. Returns the register being loaded
51 // and the loaded immediate value in the output parameters 'reg' and 'value' 69 // and the loaded immediate value in the output parameters 'reg' and 'value'
52 // respectively. 70 // respectively.
53 uword InstructionPattern::DecodeLoadWordImmediate(uword end, 71 uword InstructionPattern::DecodeLoadWordImmediate(uword end,
54 Register* reg, 72 Register* reg,
55 intptr_t* value) { 73 intptr_t* value) {
56 UNIMPLEMENTED(); 74 // 1. LoadWordFromPool
57 return 0; 75 // or
76 // 2. LoadWordFromPool
77 // orri
78 // or
79 // 3. LoadPatchableImmediate
80 uword start = end - Instr::kInstrSize;
81 Instr* instr = Instr::At(start);
82 bool odd = false;
83
84 // Case 2.
85 if (instr->IsLogicalImmOp()) {
86 ASSERT(instr->Bit(29) == 1);
87 odd = true;
88 // end points at orri so that we can pass it to DecodeLoadWordFromPool.
89 end = start;
90 start -= Instr::kInstrSize;
91 instr = Instr::At(start);
92 // Case 2 falls through to case 1.
93 }
94
95 // Case 1.
96 if (instr->IsLoadStoreRegOp()) {
97 start = DecodeLoadWordFromPool(end, reg, value);
98 if (odd) {
99 *value |= 1;
100 }
101 return start;
102 }
103
104 // Case 3.
105 // movk dst, imm3, 3; movk dst, imm2, 2; movk dst, imm1, 1; movz dst, imm0, 0
106 ASSERT(instr->IsMoveWideOp());
107 ASSERT(instr->Bits(29, 2) == 3);
108 ASSERT(instr->HWField() == 3); // movk dst, imm3, 3
109 *reg = instr->RdField();
110 *value = static_cast<int64_t>(instr->Imm16Field()) << 48;
111
112 start -= Instr::kInstrSize;
113 instr = Instr::At(start);
114 ASSERT(instr->IsMoveWideOp());
115 ASSERT(instr->Bits(29, 2) == 3);
116 ASSERT(instr->HWField() == 2); // movk dst, imm2, 2
117 ASSERT(instr->RdField() == *reg);
118 *value |= static_cast<int64_t>(instr->Imm16Field()) << 32;
119
120 start -= Instr::kInstrSize;
121 instr = Instr::At(start);
122 ASSERT(instr->IsMoveWideOp());
123 ASSERT(instr->Bits(29, 2) == 3);
124 ASSERT(instr->HWField() == 1); // movk dst, imm1, 1
125 ASSERT(instr->RdField() == *reg);
126 *value |= static_cast<int64_t>(instr->Imm16Field()) << 16;
127
128 start -= Instr::kInstrSize;
129 instr = Instr::At(start);
130 ASSERT(instr->IsMoveWideOp());
131 ASSERT(instr->Bits(29, 2) == 2);
132 ASSERT(instr->HWField() == 0); // movz dst, imm0, 0
133 ASSERT(instr->RdField() == *reg);
134 *value |= static_cast<int64_t>(instr->Imm16Field());
135
136 return start;
58 } 137 }
59 138
60 139
61 // Decodes a load sequence ending at 'end' (the last instruction of the load 140 // Decodes a load sequence ending at 'end' (the last instruction of the load
62 // sequence is the instruction before the one at end). Returns a pointer to 141 // sequence is the instruction before the one at end). Returns a pointer to
63 // the first instruction in the sequence. Returns the register being loaded 142 // the first instruction in the sequence. Returns the register being loaded
64 // and the index in the pool being read from in the output parameters 'reg' 143 // and the index in the pool being read from in the output parameters 'reg'
65 // and 'index' respectively. 144 // and 'index' respectively.
66 uword InstructionPattern::DecodeLoadWordFromPool(uword end, 145 uword InstructionPattern::DecodeLoadWordFromPool(uword end,
67 Register* reg, 146 Register* reg,
68 intptr_t* index) { 147 intptr_t* index) {
69 UNIMPLEMENTED(); 148 // 1. ldr dst, [pp, offset]
70 return 0; 149 // or
150 // 2. movz dst, low_offset, 0
151 // movk dst, hi_offset, 1 (optional)
152 // ldr dst, [pp, dst]
153 uword start = end - Instr::kInstrSize;
154 Instr* instr = Instr::At(start);
155 intptr_t offset = 0;
156
157 // Last instruction is always an ldr into a 64-bit X register.
158 ASSERT(instr->IsLoadStoreRegOp() && (instr->Bit(22) == 1) &&
159 (instr->Bits(30, 2) == 3));
160
161 // Grab the destination register from the ldr instruction.
162 *reg = instr->RtField();
163
164 if (instr->Bit(24) == 1) {
165 // pp + scaled unsigned 12-bit immediate offset.
166 // Case 1.
167 offset = instr->Imm12Field() << 3;
168 } else {
169 ASSERT(instr->Bits(10, 2) == 2);
170 // We have to look at the preceding one or two instructions to find the
171 // offset.
172
173 start -= Instr::kInstrSize;
174 instr = Instr::At(start);
175 ASSERT(instr->IsMoveWideOp());
176 ASSERT(instr->RdField() == *reg);
177 if (instr->Bits(29, 2) == 2) { // movz dst, low_offset, 0
178 ASSERT(instr->HWField() == 0);
179 offset = instr->Imm16Field();
180 // no high offset.
181 } else {
182 ASSERT(instr->Bits(29, 2) == 3); // movk dst, high_offset, 1
183 ASSERT(instr->HWField() == 1);
184 offset = instr->Imm16Field() << 16;
185
186 start -= Instr::kInstrSize;
187 instr = Instr::At(start);
188 ASSERT(instr->IsMoveWideOp());
189 ASSERT(instr->RdField() == *reg);
190 ASSERT(instr->Bits(29, 2) == 2); // movz dst, low_offset, 0
191 ASSERT(instr->HWField() == 0);
192 offset |= instr->Imm16Field();
193 }
194 }
195 ASSERT(Utils::IsAligned(offset, 8));
196 *index = (offset - Array::data_offset()) / 8;
197 return start;
71 } 198 }
72 199
73 200
74 RawICData* CallPattern::IcData() { 201 RawICData* CallPattern::IcData() {
75 UNIMPLEMENTED(); 202 if (ic_data_.IsNull()) {
76 return NULL; 203 Register reg;
204 args_desc_load_end_ =
205 InstructionPattern::DecodeLoadObject(ic_data_load_end_,
206 object_pool_,
207 &reg,
208 &ic_data_);
209 ASSERT(reg == R5);
210 }
211 return ic_data_.raw();
77 } 212 }
78 213
79 214
80 RawArray* CallPattern::ClosureArgumentsDescriptor() { 215 RawArray* CallPattern::ClosureArgumentsDescriptor() {
81 UNIMPLEMENTED(); 216 if (args_desc_.IsNull()) {
82 return NULL; 217 IcData(); // Loading of the ic_data must be decoded first, if not already.
218 Register reg;
219 InstructionPattern::DecodeLoadObject(args_desc_load_end_,
220 object_pool_,
221 &reg,
222 &args_desc_);
223 ASSERT(reg == R4);
224 }
225 return args_desc_.raw();
83 } 226 }
84 227
85 228
86 uword CallPattern::TargetAddress() const { 229 uword CallPattern::TargetAddress() const {
87 UNIMPLEMENTED(); 230 ASSERT(target_address_pool_index_ >= 0);
88 return 0; 231 const Object& target_address =
232 Object::Handle(object_pool_.At(target_address_pool_index_));
233 ASSERT(target_address.IsSmi());
234 // The address is stored in the object array as a RawSmi.
235 return reinterpret_cast<uword>(target_address.raw());
89 } 236 }
90 237
91 238
92 void CallPattern::SetTargetAddress(uword target_address) const { 239 void CallPattern::SetTargetAddress(uword target_address) const {
93 UNIMPLEMENTED(); 240 ASSERT(Utils::IsAligned(target_address, 4));
241 // The address is stored in the object array as a RawSmi.
242 const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(target_address));
243 object_pool_.SetAt(target_address_pool_index_, smi);
244 // No need to flush the instruction cache, since the code is not modified.
94 } 245 }
95 246
96 247
97 void CallPattern::InsertAt(uword pc, uword target_address) { 248 void CallPattern::InsertAt(uword pc, uword target_address) {
98 UNIMPLEMENTED(); 249 Instr* movz0 = Instr::At(pc + (0 * Instr::kInstrSize));
250 Instr* movk1 = Instr::At(pc + (1 * Instr::kInstrSize));
251 Instr* movk2 = Instr::At(pc + (2 * Instr::kInstrSize));
252 Instr* movk3 = Instr::At(pc + (3 * Instr::kInstrSize));
253 Instr* blr = Instr::At(pc + (4 * Instr::kInstrSize));
254 const uint32_t w0 = Utils::Low32Bits(target_address);
255 const uint32_t w1 = Utils::High32Bits(target_address);
256 const uint16_t h0 = Utils::Low16Bits(w0);
257 const uint16_t h1 = Utils::High16Bits(w0);
258 const uint16_t h2 = Utils::Low16Bits(w1);
259 const uint16_t h3 = Utils::High16Bits(w1);
260
261 movz0->SetMoveWideBits(MOVZ, IP0, h0, 0, kDoubleWord);
262 movk1->SetMoveWideBits(MOVK, IP0, h1, 1, kDoubleWord);
263 movk2->SetMoveWideBits(MOVK, IP0, h2, 2, kDoubleWord);
264 movk3->SetMoveWideBits(MOVK, IP0, h3, 3, kDoubleWord);
265 blr->SetUnconditionalBranchRegBits(BLR, IP0);
266
267 ASSERT(kLengthInBytes == 5 * Instr::kInstrSize);
268 CPU::FlushICache(pc, kLengthInBytes);
99 } 269 }
100 270
101 271
102 JumpPattern::JumpPattern(uword pc, const Code& code) : pc_(pc) { } 272 JumpPattern::JumpPattern(uword pc, const Code& code) : pc_(pc) { }
103 273
104 274
105 int JumpPattern::pattern_length_in_bytes() {
106 UNIMPLEMENTED();
107 return 0;
108 }
109
110
111 bool JumpPattern::IsValid() const { 275 bool JumpPattern::IsValid() const {
112 UNIMPLEMENTED(); 276 Instr* movz0 = Instr::At(pc_ + (0 * Instr::kInstrSize));
113 return false; 277 Instr* movk1 = Instr::At(pc_ + (1 * Instr::kInstrSize));
278 Instr* movk2 = Instr::At(pc_ + (2 * Instr::kInstrSize));
279 Instr* movk3 = Instr::At(pc_ + (3 * Instr::kInstrSize));
280 Instr* br = Instr::At(pc_ + (4 * Instr::kInstrSize));
281 return (movz0->IsMoveWideOp()) && (movz0->Bits(29, 2) == 2) &&
282 (movk1->IsMoveWideOp()) && (movk1->Bits(29, 2) == 3) &&
283 (movk2->IsMoveWideOp()) && (movk2->Bits(29, 2) == 3) &&
284 (movk3->IsMoveWideOp()) && (movk3->Bits(29, 2) == 3) &&
285 (br->IsUnconditionalBranchRegOp()) && (br->Bits(16, 5) == 31);
114 } 286 }
115 287
116 288
117 uword JumpPattern::TargetAddress() const { 289 uword JumpPattern::TargetAddress() const {
118 UNIMPLEMENTED(); 290 Instr* movz0 = Instr::At(pc_ + (0 * Instr::kInstrSize));
119 return 0; 291 Instr* movk1 = Instr::At(pc_ + (1 * Instr::kInstrSize));
292 Instr* movk2 = Instr::At(pc_ + (2 * Instr::kInstrSize));
293 Instr* movk3 = Instr::At(pc_ + (3 * Instr::kInstrSize));
294 const uint16_t imm0 = movz0->Imm16Field();
295 const uint16_t imm1 = movk1->Imm16Field();
296 const uint16_t imm2 = movk2->Imm16Field();
297 const uint16_t imm3 = movk3->Imm16Field();
298 const int64_t target =
299 (static_cast<int64_t>(imm0)) |
300 (static_cast<int64_t>(imm1) << 16) |
301 (static_cast<int64_t>(imm2) << 32) |
302 (static_cast<int64_t>(imm3) << 48);
303 return target;
120 } 304 }
121 305
122 306
123 void JumpPattern::SetTargetAddress(uword target_address) const { 307 void JumpPattern::SetTargetAddress(uword target_address) const {
124 UNIMPLEMENTED(); 308 Instr* movz0 = Instr::At(pc_ + (0 * Instr::kInstrSize));
309 Instr* movk1 = Instr::At(pc_ + (1 * Instr::kInstrSize));
310 Instr* movk2 = Instr::At(pc_ + (2 * Instr::kInstrSize));
311 Instr* movk3 = Instr::At(pc_ + (3 * Instr::kInstrSize));
312 const int32_t movz0_bits = movz0->InstructionBits();
313 const int32_t movk1_bits = movk1->InstructionBits();
314 const int32_t movk2_bits = movk2->InstructionBits();
315 const int32_t movk3_bits = movk3->InstructionBits();
316
317 const uint32_t w0 = Utils::Low32Bits(target_address);
318 const uint32_t w1 = Utils::High32Bits(target_address);
319 const uint16_t h0 = Utils::Low16Bits(w0);
320 const uint16_t h1 = Utils::High16Bits(w0);
321 const uint16_t h2 = Utils::Low16Bits(w1);
322 const uint16_t h3 = Utils::High16Bits(w1);
323
324 movz0->SetInstructionBits((movz0_bits & ~kImm16Mask) | (h0 << kImm16Shift));
325 movk1->SetInstructionBits((movk1_bits & ~kImm16Mask) | (h1 << kImm16Shift));
326 movk2->SetInstructionBits((movk2_bits & ~kImm16Mask) | (h2 << kImm16Shift));
327 movk3->SetInstructionBits((movk3_bits & ~kImm16Mask) | (h3 << kImm16Shift));
328 CPU::FlushICache(pc_, 4 * Instr::kInstrSize);
125 } 329 }
126 330
127 } // namespace dart 331 } // namespace dart
128 332
129 #endif // defined TARGET_ARCH_ARM64 333 #endif // defined TARGET_ARCH_ARM64
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698