| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/heap.h" | 9 #include "vm/heap.h" |
| 10 #include "vm/memory_region.h" | 10 #include "vm/memory_region.h" |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 | 56 |
| 57 | 57 |
| 58 void Assembler::pushq(const Address& address) { | 58 void Assembler::pushq(const Address& address) { |
| 59 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 59 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 60 EmitOperandREX(6, address, REX_NONE); | 60 EmitOperandREX(6, address, REX_NONE); |
| 61 EmitUint8(0xFF); | 61 EmitUint8(0xFF); |
| 62 EmitOperand(6, address); | 62 EmitOperand(6, address); |
| 63 } | 63 } |
| 64 | 64 |
| 65 | 65 |
| 66 void Assembler::pushq(const Immediate& imm) { |
| 67 if (imm.is_int32()) { |
| 68 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 69 EmitUint8(0x68); |
| 70 EmitImmediate(imm); |
| 71 } else { |
| 72 movq(TMP, imm); |
| 73 pushq(TMP); |
| 74 } |
| 75 } |
| 76 |
| 77 |
| 66 void Assembler::popq(Register reg) { | 78 void Assembler::popq(Register reg) { |
| 67 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 79 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 68 EmitRegisterREX(reg, REX_NONE); | 80 EmitRegisterREX(reg, REX_NONE); |
| 69 EmitUint8(0x58 | (reg & 7)); | 81 EmitUint8(0x58 | (reg & 7)); |
| 70 } | 82 } |
| 71 | 83 |
| 72 | 84 |
| 73 void Assembler::popq(const Address& address) { | 85 void Assembler::popq(const Address& address) { |
| 74 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 86 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 75 EmitOperandREX(0, address, REX_NONE); | 87 EmitOperandREX(0, address, REX_NONE); |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 | 280 |
| 269 void Assembler::movq(const Address& dst, Register src) { | 281 void Assembler::movq(const Address& dst, Register src) { |
| 270 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 282 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 271 EmitOperandREX(src, dst, REX_W); | 283 EmitOperandREX(src, dst, REX_W); |
| 272 EmitUint8(0x89); | 284 EmitUint8(0x89); |
| 273 EmitOperand(src & 7, dst); | 285 EmitOperand(src & 7, dst); |
| 274 } | 286 } |
| 275 | 287 |
| 276 | 288 |
| 277 void Assembler::movq(const Address& dst, const Immediate& imm) { | 289 void Assembler::movq(const Address& dst, const Immediate& imm) { |
| 278 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 290 if (imm.is_int32()) { |
| 279 ASSERT(imm.is_int32()); | 291 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 280 Operand operand(dst); | 292 Operand operand(dst); |
| 281 EmitOperandREX(0, operand, REX_W); | 293 EmitOperandREX(0, operand, REX_W); |
| 282 EmitUint8(0xC7); | 294 EmitUint8(0xC7); |
| 283 EmitOperand(0, operand); | 295 EmitOperand(0, operand); |
| 284 EmitImmediate(imm); | 296 EmitImmediate(imm); |
| 297 } else { |
| 298 movq(TMP, imm); |
| 299 movq(dst, TMP); |
| 300 } |
| 285 } | 301 } |
| 286 | 302 |
| 287 | 303 |
| 288 void Assembler::movsxl(Register dst, const Address& src) { | 304 void Assembler::movsxl(Register dst, const Address& src) { |
| 289 UNIMPLEMENTED(); | 305 UNIMPLEMENTED(); |
| 290 } | 306 } |
| 291 | 307 |
| 292 | 308 |
| 293 void Assembler::leaq(Register dst, const Address& src) { | 309 void Assembler::leaq(Register dst, const Address& src) { |
| 294 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 310 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 EmitXmmRegisterOperand(src & 7, dst); | 349 EmitXmmRegisterOperand(src & 7, dst); |
| 334 } | 350 } |
| 335 | 351 |
| 336 | 352 |
| 337 void Assembler::movd(XmmRegister dst, Register src) { | 353 void Assembler::movd(XmmRegister dst, Register src) { |
| 338 ASSERT(dst <= XMM7); | 354 ASSERT(dst <= XMM7); |
| 339 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 355 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 340 EmitUint8(0x66); | 356 EmitUint8(0x66); |
| 341 EmitUint8(0x0F); | 357 EmitUint8(0x0F); |
| 342 EmitUint8(0x6E); | 358 EmitUint8(0x6E); |
| 343 EmitOperand(dst, Operand(src)); | 359 EmitOperand(dst & 7, Operand(src)); |
| 344 } | 360 } |
| 345 | 361 |
| 346 | 362 |
| 347 void Assembler::movd(Register dst, XmmRegister src) { | 363 void Assembler::movd(Register dst, XmmRegister src) { |
| 348 ASSERT(src <= XMM7); | 364 ASSERT(src <= XMM7); |
| 349 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 365 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 350 EmitUint8(0x66); | 366 EmitUint8(0x66); |
| 351 EmitUint8(0x0F); | 367 EmitUint8(0x0F); |
| 352 EmitUint8(0x7E); | 368 EmitUint8(0x7E); |
| 353 EmitOperand(src, Operand(dst)); | 369 EmitOperand(src & 7, Operand(dst)); |
| 354 } | 370 } |
| 355 | 371 |
| 356 | 372 |
| 357 void Assembler::addss(XmmRegister dst, XmmRegister src) { | 373 void Assembler::addss(XmmRegister dst, XmmRegister src) { |
| 358 // TODO(srdjan): implement and test XMM8 - XMM15. | 374 // TODO(srdjan): implement and test XMM8 - XMM15. |
| 359 ASSERT(src <= XMM7); | 375 ASSERT(src <= XMM7); |
| 360 ASSERT(dst <= XMM7); | 376 ASSERT(dst <= XMM7); |
| 361 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 377 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 362 EmitUint8(0xF3); | 378 EmitUint8(0xF3); |
| 363 EmitUint8(0x0F); | 379 EmitUint8(0x0F); |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 529 | 545 |
| 530 | 546 |
| 531 void Assembler::cmpl(const Address& address, const Immediate& imm) { | 547 void Assembler::cmpl(const Address& address, const Immediate& imm) { |
| 532 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 548 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 533 Operand operand(address); | 549 Operand operand(address); |
| 534 EmitOperandREX(7, operand, REX_NONE); | 550 EmitOperandREX(7, operand, REX_NONE); |
| 535 EmitComplex(7, operand, imm); | 551 EmitComplex(7, operand, imm); |
| 536 } | 552 } |
| 537 | 553 |
| 538 | 554 |
| 555 void Assembler::cmpq(const Address& address, Register reg) { |
| 556 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 557 EmitOperandREX(reg, address, REX_W); |
| 558 EmitUint8(0x39); |
| 559 EmitOperand(reg & 7, address); |
| 560 } |
| 561 |
| 562 |
| 539 void Assembler::cmpq(const Address& address, const Immediate& imm) { | 563 void Assembler::cmpq(const Address& address, const Immediate& imm) { |
| 540 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 564 if (imm.is_int32()) { |
| 541 Operand operand(address); | 565 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 542 EmitOperandREX(7, operand, REX_W); | 566 Operand operand(address); |
| 543 EmitComplex(7, operand, imm); | 567 EmitOperandREX(7, operand, REX_W); |
| 568 EmitComplex(7, operand, imm); |
| 569 } else { |
| 570 movq(TMP, imm); |
| 571 cmpq(address, TMP); |
| 572 } |
| 544 } | 573 } |
| 545 | 574 |
| 546 | 575 |
| 547 void Assembler::cmpq(Register reg, const Immediate& imm) { | 576 void Assembler::cmpq(Register reg, const Immediate& imm) { |
| 548 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 577 if (imm.is_int32()) { |
| 549 EmitRegisterREX(reg, REX_W); | 578 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 550 EmitComplex(7, Operand(reg), imm); | 579 EmitRegisterREX(reg, REX_W); |
| 580 EmitComplex(7, Operand(reg), imm); |
| 581 } else { |
| 582 movq(TMP, imm); |
| 583 cmpq(reg, TMP); |
| 584 } |
| 551 } | 585 } |
| 552 | 586 |
| 553 | 587 |
| 554 void Assembler::cmpq(Register reg0, Register reg1) { | 588 void Assembler::cmpq(Register reg0, Register reg1) { |
| 555 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 589 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 556 Operand operand(reg1); | 590 Operand operand(reg1); |
| 557 EmitOperandREX(reg0, operand, REX_W); | 591 EmitOperandREX(reg0, operand, REX_W); |
| 558 EmitUint8(0x3B); | 592 EmitUint8(0x3B); |
| 559 EmitOperand(reg0 & 7, operand); | 593 EmitOperand(reg0 & 7, operand); |
| 560 } | 594 } |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 798 void Assembler::idivq(Register reg) { | 832 void Assembler::idivq(Register reg) { |
| 799 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 833 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 800 EmitRegisterREX(reg, REX_W); | 834 EmitRegisterREX(reg, REX_W); |
| 801 EmitUint8(0xF7); | 835 EmitUint8(0xF7); |
| 802 EmitUint8(0xF8 | (reg & 7)); | 836 EmitUint8(0xF8 | (reg & 7)); |
| 803 } | 837 } |
| 804 | 838 |
| 805 | 839 |
| 806 void Assembler::imull(Register dst, Register src) { | 840 void Assembler::imull(Register dst, Register src) { |
| 807 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 841 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 842 Operand operand(src); |
| 843 EmitOperandREX(dst, operand, REX_NONE); |
| 808 EmitUint8(0x0F); | 844 EmitUint8(0x0F); |
| 809 EmitUint8(0xAF); | 845 EmitUint8(0xAF); |
| 810 EmitOperand(dst, Operand(src)); | 846 EmitOperand(dst & 7, Operand(src)); |
| 811 } | 847 } |
| 812 | 848 |
| 813 | 849 |
| 814 void Assembler::imull(Register reg, const Immediate& imm) { | 850 void Assembler::imull(Register reg, const Immediate& imm) { |
| 815 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 851 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 852 EmitRegisterREX(reg, REX_NONE); |
| 816 EmitUint8(0x69); | 853 EmitUint8(0x69); |
| 817 EmitOperand(reg, Operand(reg)); | 854 EmitOperand(reg & 7, Operand(reg)); |
| 818 EmitImmediate(imm); | 855 EmitImmediate(imm); |
| 819 } | 856 } |
| 820 | 857 |
| 821 | 858 |
| 822 void Assembler::imulq(Register dst, Register src) { | 859 void Assembler::imulq(Register dst, Register src) { |
| 823 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 860 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 824 Operand operand(src); | 861 Operand operand(src); |
| 825 EmitOperandREX(dst, operand, REX_W); | 862 EmitOperandREX(dst, operand, REX_W); |
| 826 EmitUint8(0x0F); | 863 EmitUint8(0x0F); |
| 827 EmitUint8(0xAF); | 864 EmitUint8(0xAF); |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1117 if (value == 1) { | 1154 if (value == 1) { |
| 1118 decq(reg); | 1155 decq(reg); |
| 1119 } else if (value != 0) { | 1156 } else if (value != 0) { |
| 1120 subq(reg, Immediate(value)); | 1157 subq(reg, Immediate(value)); |
| 1121 } | 1158 } |
| 1122 } | 1159 } |
| 1123 } | 1160 } |
| 1124 | 1161 |
| 1125 | 1162 |
| 1126 void Assembler::LoadObject(Register dst, const Object& object) { | 1163 void Assembler::LoadObject(Register dst, const Object& object) { |
| 1127 ASSERT(object.IsZoneHandle()); | 1164 if (object.IsSmi()) { |
| 1128 AssemblerBuffer::EnsureCapacity ensured(&buffer_); | 1165 movq(dst, Immediate(reinterpret_cast<int64_t>(object.raw()))); |
| 1129 EmitRegisterREX(dst, REX_W); | 1166 } else { |
| 1130 EmitUint8(0xB8 | (dst & 7)); | 1167 ASSERT(object.IsZoneHandle()); |
| 1131 buffer_.EmitObject(object); | 1168 AssemblerBuffer::EnsureCapacity ensured(&buffer_); |
| 1169 EmitRegisterREX(dst, REX_W); |
| 1170 EmitUint8(0xB8 | (dst & 7)); |
| 1171 buffer_.EmitObject(object); |
| 1172 } |
| 1132 } | 1173 } |
| 1133 | 1174 |
| 1134 | 1175 |
| 1135 void Assembler::PushObject(const Object& object) { | 1176 void Assembler::PushObject(const Object& object) { |
| 1136 LoadObject(TMP, object); | 1177 if (object.IsSmi()) { |
| 1137 pushq(TMP); | 1178 pushq(Immediate(reinterpret_cast<int64_t>(object.raw()))); |
| 1179 } else { |
| 1180 LoadObject(TMP, object); |
| 1181 pushq(TMP); |
| 1182 } |
| 1138 } | 1183 } |
| 1139 | 1184 |
| 1140 | 1185 |
| 1141 void Assembler::CompareObject(Register reg, const Object& object) { | 1186 void Assembler::CompareObject(Register reg, const Object& object) { |
| 1142 ASSERT(reg != TMP); | 1187 if (object.IsSmi()) { |
| 1143 LoadObject(TMP, object); | 1188 cmpq(reg, Immediate(reinterpret_cast<int64_t>(object.raw()))); |
| 1144 cmpq(reg, TMP); | 1189 } else { |
| 1190 ASSERT(reg != TMP); |
| 1191 LoadObject(TMP, object); |
| 1192 cmpq(reg, TMP); |
| 1193 } |
| 1145 } | 1194 } |
| 1146 | 1195 |
| 1147 | 1196 |
| 1148 void Assembler::Stop(const char* message) { | 1197 void Assembler::Stop(const char* message) { |
| 1149 // Emit the lower half and the higher half of the message address as immediate | 1198 // Emit the lower half and the higher half of the message address as immediate |
| 1150 // operands in the test rax instructions, followed by the int3 instruction. | 1199 // operands in the test rax instructions, followed by the int3 instruction. |
| 1151 // Execution can be resumed with the 'cont' command in gdb. | 1200 // Execution can be resumed with the 'cont' command in gdb. |
| 1152 int64_t message_address = reinterpret_cast<int64_t>(message); | 1201 int64_t message_address = reinterpret_cast<int64_t>(message); |
| 1153 testl(RAX, Immediate(Utils::Low32Bits(message_address))); | 1202 testl(RAX, Immediate(Utils::Low32Bits(message_address))); |
| 1154 testl(RAX, Immediate(Utils::High32Bits(message_address))); | 1203 testl(RAX, Immediate(Utils::High32Bits(message_address))); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1168 while (label->HasNear()) { | 1217 while (label->HasNear()) { |
| 1169 int position = label->NearPosition(); | 1218 int position = label->NearPosition(); |
| 1170 int offset = bound - (position + 1); | 1219 int offset = bound - (position + 1); |
| 1171 ASSERT(Utils::IsInt(8, offset)); | 1220 ASSERT(Utils::IsInt(8, offset)); |
| 1172 buffer_.Store<int8_t>(position, offset); | 1221 buffer_.Store<int8_t>(position, offset); |
| 1173 } | 1222 } |
| 1174 label->BindTo(bound); | 1223 label->BindTo(bound); |
| 1175 } | 1224 } |
| 1176 | 1225 |
| 1177 | 1226 |
| 1227 void Assembler::EnterFrame(intptr_t frame_size) { |
| 1228 if (prolog_offset_ == -1) { |
| 1229 prolog_offset_ = CodeSize(); |
| 1230 } |
| 1231 pushq(RBP); |
| 1232 movq(RBP, RSP); |
| 1233 if (frame_size != 0) { |
| 1234 Immediate frame_space(frame_size); |
| 1235 subq(RSP, frame_space); |
| 1236 } |
| 1237 } |
| 1238 |
| 1239 |
| 1240 void Assembler::LeaveFrame() { |
| 1241 movq(RSP, RBP); |
| 1242 popq(RBP); |
| 1243 } |
| 1244 |
| 1245 |
| 1246 void Assembler::CallRuntimeFromDart(const RuntimeEntry& entry) { |
| 1247 entry.CallFromDart(this); |
| 1248 } |
| 1249 |
| 1250 |
| 1251 void Assembler::CallRuntimeFromStub(const RuntimeEntry& entry) { |
| 1252 entry.CallFromStub(this); |
| 1253 } |
| 1254 |
| 1255 |
| 1178 void Assembler::Align(int alignment, int offset) { | 1256 void Assembler::Align(int alignment, int offset) { |
| 1179 UNIMPLEMENTED(); | 1257 UNIMPLEMENTED(); |
| 1180 } | 1258 } |
| 1181 | 1259 |
| 1182 | 1260 |
| 1183 void Assembler::EmitOperand(int rm, const Operand& operand) { | 1261 void Assembler::EmitOperand(int rm, const Operand& operand) { |
| 1184 ASSERT(rm >= 0 && rm < 8); | 1262 ASSERT(rm >= 0 && rm < 8); |
| 1185 const int length = operand.length_; | 1263 const int length = operand.length_; |
| 1186 ASSERT(length > 0); | 1264 ASSERT(length > 0); |
| 1187 // Emit the ModRM byte updated with the given RM value. | 1265 // Emit the ModRM byte updated with the given RM value. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1204 void Assembler::EmitImmediate(const Immediate& imm) { | 1282 void Assembler::EmitImmediate(const Immediate& imm) { |
| 1205 if (imm.is_int32()) { | 1283 if (imm.is_int32()) { |
| 1206 EmitInt32(static_cast<int32_t>(imm.value())); | 1284 EmitInt32(static_cast<int32_t>(imm.value())); |
| 1207 } else { | 1285 } else { |
| 1208 EmitInt64(imm.value()); | 1286 EmitInt64(imm.value()); |
| 1209 } | 1287 } |
| 1210 } | 1288 } |
| 1211 | 1289 |
| 1212 | 1290 |
| 1213 void Assembler::EmitComplex(int rm, | 1291 void Assembler::EmitComplex(int rm, |
| 1214 const Operand& operand, | 1292 const Operand& operand, |
| 1215 const Immediate& immediate) { | 1293 const Immediate& immediate) { |
| 1216 ASSERT(rm >= 0 && rm < 8); | 1294 ASSERT(rm >= 0 && rm < 8); |
| 1217 ASSERT(immediate.is_int32()); | 1295 ASSERT(immediate.is_int32()); |
| 1218 if (immediate.is_int8()) { | 1296 if (immediate.is_int8()) { |
| 1219 // Use sign-extended 8-bit immediate. | 1297 // Use sign-extended 8-bit immediate. |
| 1220 EmitUint8(0x83); | 1298 EmitUint8(0x83); |
| 1221 EmitOperand(rm, operand); | 1299 EmitOperand(rm, operand); |
| 1222 EmitUint8(immediate.value() & 0xFF); | 1300 EmitUint8(immediate.value() & 0xFF); |
| 1223 } else if (operand.IsRegister(RAX)) { | 1301 } else if (operand.IsRegister(RAX)) { |
| 1224 // Use short form if the destination is rax. | 1302 // Use short form if the destination is rax. |
| 1225 EmitUint8(0x05 + (rm << 3)); | 1303 EmitUint8(0x05 + (rm << 3)); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1292 } else { | 1370 } else { |
| 1293 EmitRegisterREX(operand, REX_NONE); | 1371 EmitRegisterREX(operand, REX_NONE); |
| 1294 } | 1372 } |
| 1295 EmitUint8(0xD3); | 1373 EmitUint8(0xD3); |
| 1296 EmitOperand(rm, Operand(operand)); | 1374 EmitOperand(rm, Operand(operand)); |
| 1297 } | 1375 } |
| 1298 | 1376 |
| 1299 } // namespace dart | 1377 } // namespace dart |
| 1300 | 1378 |
| 1301 #endif // defined TARGET_ARCH_X64 | 1379 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |