| OLD | NEW |
| 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" // NOLINT | 5 #include "vm/globals.h" // NOLINT |
| 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/cpu.h" | 9 #include "vm/cpu.h" |
| 10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 DEFINE_FLAG(bool, use_far_branches, false, "Always use far branches"); | 23 DEFINE_FLAG(bool, use_far_branches, false, "Always use far branches"); |
| 24 DEFINE_FLAG(bool, print_stop_message, false, "Print stop message."); | 24 DEFINE_FLAG(bool, print_stop_message, false, "Print stop message."); |
| 25 DECLARE_FLAG(bool, inline_alloc); | 25 DECLARE_FLAG(bool, inline_alloc); |
| 26 | 26 |
| 27 | 27 |
| 28 Assembler::Assembler(bool use_far_branches) | 28 Assembler::Assembler(bool use_far_branches) |
| 29 : buffer_(), | 29 : buffer_(), |
| 30 prologue_offset_(-1), | 30 prologue_offset_(-1), |
| 31 use_far_branches_(use_far_branches), | 31 use_far_branches_(use_far_branches), |
| 32 comments_(), | 32 comments_(), |
| 33 constant_pool_allowed_(true) { | 33 constant_pool_allowed_(false) { |
| 34 } | 34 } |
| 35 | 35 |
| 36 | 36 |
| 37 void Assembler::InitializeMemoryWithBreakpoints(uword data, intptr_t length) { | 37 void Assembler::InitializeMemoryWithBreakpoints(uword data, intptr_t length) { |
| 38 ASSERT(Utils::IsAligned(data, 4)); | 38 ASSERT(Utils::IsAligned(data, 4)); |
| 39 ASSERT(Utils::IsAligned(length, 4)); | 39 ASSERT(Utils::IsAligned(length, 4)); |
| 40 const uword end = data + length; | 40 const uword end = data + length; |
| 41 while (data < end) { | 41 while (data < end) { |
| 42 *reinterpret_cast<int32_t*>(data) = Instr::kBreakPointInstruction; | 42 *reinterpret_cast<int32_t*>(data) = Instr::kBreakPointInstruction; |
| 43 data += 4; | 43 data += 4; |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 imm_s_fixed >>= 1; | 295 imm_s_fixed >>= 1; |
| 296 continue; | 296 continue; |
| 297 } | 297 } |
| 298 | 298 |
| 299 // 6. Otherwise, the value can't be encoded. | 299 // 6. Otherwise, the value can't be encoded. |
| 300 return false; | 300 return false; |
| 301 } | 301 } |
| 302 } | 302 } |
| 303 | 303 |
| 304 | 304 |
| 305 void Assembler::LoadPoolPointer(Register pp) { | 305 void Assembler::LoadPoolPointer() { |
| 306 const intptr_t object_pool_pc_dist = | 306 const intptr_t object_pool_pc_dist = |
| 307 Instructions::HeaderSize() - Instructions::object_pool_offset() + | 307 Instructions::HeaderSize() - Instructions::object_pool_offset() + |
| 308 CodeSize(); | 308 CodeSize(); |
| 309 // PP <- Read(PC - object_pool_pc_dist). | 309 // PP <- Read(PC - object_pool_pc_dist). |
| 310 ldr(pp, Address::PC(-object_pool_pc_dist)); | 310 ldr(PP, Address::PC(-object_pool_pc_dist)); |
| 311 | 311 |
| 312 // When in the PP register, the pool pointer is untagged. When we | 312 // When in the PP register, the pool pointer is untagged. When we |
| 313 // push it on the stack with TagAndPushPP it is tagged again. PopAndUntagPP | 313 // push it on the stack with TagAndPushPP it is tagged again. PopAndUntagPP |
| 314 // then untags when restoring from the stack. This will make loading from the | 314 // then untags when restoring from the stack. This will make loading from the |
| 315 // object pool only one instruction for the first 4096 entries. Otherwise, | 315 // object pool only one instruction for the first 4096 entries. Otherwise, |
| 316 // because the offset wouldn't be aligned, it would be only one instruction | 316 // because the offset wouldn't be aligned, it would be only one instruction |
| 317 // for the first 64 entries. | 317 // for the first 64 entries. |
| 318 sub(pp, pp, Operand(kHeapObjectTag)); | 318 sub(PP, PP, Operand(kHeapObjectTag)); |
| 319 set_constant_pool_allowed(true); |
| 319 } | 320 } |
| 320 | 321 |
| 321 | 322 |
| 322 void Assembler::LoadWordFromPoolOffset(Register dst, Register pp, | 323 void Assembler::LoadWordFromPoolOffset(Register dst, uint32_t offset) { |
| 323 uint32_t offset) { | 324 ASSERT(constant_pool_allowed()); |
| 324 ASSERT(dst != pp); | 325 ASSERT(dst != PP); |
| 325 Operand op; | 326 Operand op; |
| 326 const uint32_t upper20 = offset & 0xfffff000; | 327 const uint32_t upper20 = offset & 0xfffff000; |
| 327 if (Address::CanHoldOffset(offset)) { | 328 if (Address::CanHoldOffset(offset)) { |
| 328 ldr(dst, Address(pp, offset)); | 329 ldr(dst, Address(PP, offset)); |
| 329 } else if (Operand::CanHold(upper20, kXRegSizeInBits, &op) == | 330 } else if (Operand::CanHold(upper20, kXRegSizeInBits, &op) == |
| 330 Operand::Immediate) { | 331 Operand::Immediate) { |
| 331 const uint32_t lower12 = offset & 0x00000fff; | 332 const uint32_t lower12 = offset & 0x00000fff; |
| 332 ASSERT(Address::CanHoldOffset(lower12)); | 333 ASSERT(Address::CanHoldOffset(lower12)); |
| 333 add(dst, pp, op); | 334 add(dst, PP, op); |
| 334 ldr(dst, Address(dst, lower12)); | 335 ldr(dst, Address(dst, lower12)); |
| 335 } else { | 336 } else { |
| 336 const uint16_t offset_low = Utils::Low16Bits(offset); | 337 const uint16_t offset_low = Utils::Low16Bits(offset); |
| 337 const uint16_t offset_high = Utils::High16Bits(offset); | 338 const uint16_t offset_high = Utils::High16Bits(offset); |
| 338 movz(dst, Immediate(offset_low), 0); | 339 movz(dst, Immediate(offset_low), 0); |
| 339 if (offset_high != 0) { | 340 if (offset_high != 0) { |
| 340 movk(dst, Immediate(offset_high), 1); | 341 movk(dst, Immediate(offset_high), 1); |
| 341 } | 342 } |
| 342 ldr(dst, Address(pp, dst)); | 343 ldr(dst, Address(PP, dst)); |
| 343 } | 344 } |
| 344 } | 345 } |
| 345 | 346 |
| 346 | 347 |
| 347 void Assembler::LoadWordFromPoolOffsetFixed(Register dst, Register pp, | 348 void Assembler::LoadWordFromPoolOffsetFixed(Register dst, uint32_t offset) { |
| 348 uint32_t offset) { | 349 ASSERT(constant_pool_allowed()); |
| 349 ASSERT(dst != pp); | 350 ASSERT(dst != PP); |
| 350 Operand op; | 351 Operand op; |
| 351 const uint32_t upper20 = offset & 0xfffff000; | 352 const uint32_t upper20 = offset & 0xfffff000; |
| 352 const uint32_t lower12 = offset & 0x00000fff; | 353 const uint32_t lower12 = offset & 0x00000fff; |
| 353 const Operand::OperandType ot = | 354 const Operand::OperandType ot = |
| 354 Operand::CanHold(upper20, kXRegSizeInBits, &op); | 355 Operand::CanHold(upper20, kXRegSizeInBits, &op); |
| 355 ASSERT(ot == Operand::Immediate); | 356 ASSERT(ot == Operand::Immediate); |
| 356 ASSERT(Address::CanHoldOffset(lower12)); | 357 ASSERT(Address::CanHoldOffset(lower12)); |
| 357 add(dst, pp, op); | 358 add(dst, PP, op); |
| 358 ldr(dst, Address(dst, lower12)); | 359 ldr(dst, Address(dst, lower12)); |
| 359 } | 360 } |
| 360 | 361 |
| 361 | 362 |
| 362 intptr_t Assembler::FindImmediate(int64_t imm) { | 363 intptr_t Assembler::FindImmediate(int64_t imm) { |
| 363 return object_pool_wrapper_.FindImmediate(imm); | 364 return object_pool_wrapper_.FindImmediate(imm); |
| 364 } | 365 } |
| 365 | 366 |
| 366 | 367 |
| 367 bool Assembler::CanLoadFromObjectPool(const Object& object) const { | 368 bool Assembler::CanLoadFromObjectPool(const Object& object) const { |
| 368 ASSERT(!Thread::CanLoadFromThread(object)); | 369 ASSERT(!Thread::CanLoadFromThread(object)); |
| 369 if (!constant_pool_allowed()) { | 370 if (!constant_pool_allowed()) { |
| 370 return false; | 371 return false; |
| 371 } | 372 } |
| 372 | 373 |
| 373 // TODO(zra, kmillikin): Also load other large immediates from the object | 374 // TODO(zra, kmillikin): Also load other large immediates from the object |
| 374 // pool | 375 // pool |
| 375 if (object.IsSmi()) { | 376 if (object.IsSmi()) { |
| 376 // If the raw smi does not fit into a 32-bit signed int, then we'll keep | 377 // If the raw smi does not fit into a 32-bit signed int, then we'll keep |
| 377 // the raw value in the object pool. | 378 // the raw value in the object pool. |
| 378 return !Utils::IsInt(32, reinterpret_cast<int64_t>(object.raw())); | 379 return !Utils::IsInt(32, reinterpret_cast<int64_t>(object.raw())); |
| 379 } | 380 } |
| 380 ASSERT(object.IsNotTemporaryScopedHandle()); | 381 ASSERT(object.IsNotTemporaryScopedHandle()); |
| 381 ASSERT(object.IsOld()); | 382 ASSERT(object.IsOld()); |
| 382 return true; | 383 return true; |
| 383 } | 384 } |
| 384 | 385 |
| 385 | 386 |
| 386 bool Assembler::CanLoadImmediateFromPool(int64_t imm, Register pp) { | 387 void Assembler::LoadExternalLabel(Register dst, const ExternalLabel* label) { |
| 387 if (!constant_pool_allowed()) { | 388 if (constant_pool_allowed()) { |
| 388 return false; | |
| 389 } | |
| 390 return !Utils::IsInt(32, imm) && (pp != kNoPP); | |
| 391 } | |
| 392 | |
| 393 | |
| 394 void Assembler::LoadExternalLabel(Register dst, | |
| 395 const ExternalLabel* label, | |
| 396 Patchability patchable, | |
| 397 Register pp) { | |
| 398 const int64_t target = static_cast<int64_t>(label->address()); | |
| 399 if (CanLoadImmediateFromPool(target, pp)) { | |
| 400 const int32_t offset = ObjectPool::element_offset( | 389 const int32_t offset = ObjectPool::element_offset( |
| 401 object_pool_wrapper_.FindExternalLabel(label, patchable)); | 390 object_pool_wrapper_.FindExternalLabel(label, kNotPatchable)); |
| 402 LoadWordFromPoolOffset(dst, pp, offset); | 391 LoadWordFromPoolOffset(dst, offset); |
| 403 } else { | 392 } else { |
| 404 LoadImmediate(dst, target, kNoPP); | 393 const int64_t target = static_cast<int64_t>(label->address()); |
| 394 LoadImmediate(dst, target); |
| 405 } | 395 } |
| 406 } | 396 } |
| 407 | 397 |
| 408 | 398 |
| 409 void Assembler::LoadExternalLabelFixed(Register dst, | 399 void Assembler::LoadExternalLabelFixed(Register dst, |
| 410 const ExternalLabel* label, | 400 const ExternalLabel* label, |
| 411 Patchability patchable, | 401 Patchability patchable) { |
| 412 Register pp) { | |
| 413 const int32_t offset = ObjectPool::element_offset( | 402 const int32_t offset = ObjectPool::element_offset( |
| 414 object_pool_wrapper_.FindExternalLabel(label, patchable)); | 403 object_pool_wrapper_.FindExternalLabel(label, patchable)); |
| 415 LoadWordFromPoolOffsetFixed(dst, pp, offset); | 404 LoadWordFromPoolOffsetFixed(dst, offset); |
| 416 } | 405 } |
| 417 | 406 |
| 418 | 407 |
| 419 void Assembler::LoadIsolate(Register dst) { | 408 void Assembler::LoadIsolate(Register dst) { |
| 420 ldr(dst, Address(THR, Thread::isolate_offset())); | 409 ldr(dst, Address(THR, Thread::isolate_offset())); |
| 421 } | 410 } |
| 422 | 411 |
| 423 | 412 |
| 424 void Assembler::LoadObjectHelper(Register dst, | 413 void Assembler::LoadObjectHelper(Register dst, |
| 425 const Object& object, | 414 const Object& object, |
| 426 Register pp, | |
| 427 bool is_unique) { | 415 bool is_unique) { |
| 428 if (Thread::CanLoadFromThread(object)) { | 416 if (Thread::CanLoadFromThread(object)) { |
| 429 ldr(dst, Address(THR, Thread::OffsetFromThread(object))); | 417 ldr(dst, Address(THR, Thread::OffsetFromThread(object))); |
| 430 } else if (CanLoadFromObjectPool(object)) { | 418 } else if (CanLoadFromObjectPool(object)) { |
| 431 const int32_t offset = ObjectPool::element_offset( | 419 const int32_t offset = ObjectPool::element_offset( |
| 432 is_unique ? object_pool_wrapper_.AddObject(object) | 420 is_unique ? object_pool_wrapper_.AddObject(object) |
| 433 : object_pool_wrapper_.FindObject(object)); | 421 : object_pool_wrapper_.FindObject(object)); |
| 434 LoadWordFromPoolOffset(dst, pp, offset); | 422 LoadWordFromPoolOffset(dst, offset); |
| 435 } else { | 423 } else { |
| 436 ASSERT(object.IsSmi() || object.InVMHeap()); | 424 ASSERT(object.IsSmi() || object.InVMHeap()); |
| 437 LoadDecodableImmediate(dst, reinterpret_cast<int64_t>(object.raw()), pp); | 425 LoadDecodableImmediate(dst, reinterpret_cast<int64_t>(object.raw())); |
| 438 } | 426 } |
| 439 } | 427 } |
| 440 | 428 |
| 441 | 429 |
| 442 void Assembler::LoadObject(Register dst, const Object& object, Register pp) { | 430 void Assembler::LoadObject(Register dst, const Object& object) { |
| 443 LoadObjectHelper(dst, object, pp, false); | 431 LoadObjectHelper(dst, object, false); |
| 444 } | 432 } |
| 445 | 433 |
| 446 | 434 |
| 447 void Assembler::LoadUniqueObject(Register dst, | 435 void Assembler::LoadUniqueObject(Register dst, const Object& object) { |
| 448 const Object& object, | 436 LoadObjectHelper(dst, object, true); |
| 449 Register pp) { | |
| 450 LoadObjectHelper(dst, object, pp, true); | |
| 451 } | 437 } |
| 452 | 438 |
| 453 | 439 |
| 454 void Assembler::CompareObject(Register reg, const Object& object, Register pp) { | 440 void Assembler::CompareObject(Register reg, const Object& object) { |
| 455 if (Thread::CanLoadFromThread(object)) { | 441 if (Thread::CanLoadFromThread(object)) { |
| 456 ldr(TMP, Address(THR, Thread::OffsetFromThread(object))); | 442 ldr(TMP, Address(THR, Thread::OffsetFromThread(object))); |
| 457 CompareRegisters(reg, TMP); | 443 CompareRegisters(reg, TMP); |
| 458 } else if (CanLoadFromObjectPool(object)) { | 444 } else if (CanLoadFromObjectPool(object)) { |
| 459 LoadObject(TMP, object, pp); | 445 LoadObject(TMP, object); |
| 460 CompareRegisters(reg, TMP); | 446 CompareRegisters(reg, TMP); |
| 461 } else { | 447 } else { |
| 462 CompareImmediate(reg, reinterpret_cast<int64_t>(object.raw()), pp); | 448 CompareImmediate(reg, reinterpret_cast<int64_t>(object.raw())); |
| 463 } | 449 } |
| 464 } | 450 } |
| 465 | 451 |
| 466 | 452 |
| 467 void Assembler::LoadDecodableImmediate(Register reg, int64_t imm, Register pp) { | 453 void Assembler::LoadDecodableImmediate(Register reg, int64_t imm) { |
| 468 if ((pp != kNoPP) && constant_pool_allowed()) { | 454 if (constant_pool_allowed()) { |
| 469 const int32_t offset = ObjectPool::element_offset(FindImmediate(imm)); | 455 const int32_t offset = ObjectPool::element_offset(FindImmediate(imm)); |
| 470 LoadWordFromPoolOffset(reg, pp, offset); | 456 LoadWordFromPoolOffset(reg, offset); |
| 471 } else { | 457 } else { |
| 472 // TODO(zra): Since this sequence only needs to be decodable, it can be | 458 // TODO(zra): Since this sequence only needs to be decodable, it can be |
| 473 // of variable length. | 459 // of variable length. |
| 474 LoadImmediateFixed(reg, imm); | 460 LoadImmediateFixed(reg, imm); |
| 475 } | 461 } |
| 476 } | 462 } |
| 477 | 463 |
| 478 | 464 |
| 479 void Assembler::LoadImmediateFixed(Register reg, int64_t imm) { | 465 void Assembler::LoadImmediateFixed(Register reg, int64_t imm) { |
| 480 const uint32_t w0 = Utils::Low32Bits(imm); | 466 const uint32_t w0 = Utils::Low32Bits(imm); |
| 481 const uint32_t w1 = Utils::High32Bits(imm); | 467 const uint32_t w1 = Utils::High32Bits(imm); |
| 482 const uint16_t h0 = Utils::Low16Bits(w0); | 468 const uint16_t h0 = Utils::Low16Bits(w0); |
| 483 const uint16_t h1 = Utils::High16Bits(w0); | 469 const uint16_t h1 = Utils::High16Bits(w0); |
| 484 const uint16_t h2 = Utils::Low16Bits(w1); | 470 const uint16_t h2 = Utils::Low16Bits(w1); |
| 485 const uint16_t h3 = Utils::High16Bits(w1); | 471 const uint16_t h3 = Utils::High16Bits(w1); |
| 486 movz(reg, Immediate(h0), 0); | 472 movz(reg, Immediate(h0), 0); |
| 487 movk(reg, Immediate(h1), 1); | 473 movk(reg, Immediate(h1), 1); |
| 488 movk(reg, Immediate(h2), 2); | 474 movk(reg, Immediate(h2), 2); |
| 489 movk(reg, Immediate(h3), 3); | 475 movk(reg, Immediate(h3), 3); |
| 490 } | 476 } |
| 491 | 477 |
| 492 | 478 |
| 493 void Assembler::LoadImmediate(Register reg, int64_t imm, Register pp) { | 479 void Assembler::LoadImmediate(Register reg, int64_t imm) { |
| 494 Comment("LoadImmediate"); | 480 Comment("LoadImmediate"); |
| 495 if (CanLoadImmediateFromPool(imm, pp)) { | 481 // Is it 0? |
| 482 if (imm == 0) { |
| 483 movz(reg, Immediate(0), 0); |
| 484 return; |
| 485 } |
| 486 |
| 487 // Can we use one orri operation? |
| 488 Operand op; |
| 489 Operand::OperandType ot; |
| 490 ot = Operand::CanHold(imm, kXRegSizeInBits, &op); |
| 491 if (ot == Operand::BitfieldImm) { |
| 492 orri(reg, ZR, Immediate(imm)); |
| 493 return; |
| 494 } |
| 495 |
| 496 // We may fall back on movz, movk, movn. |
| 497 const uint32_t w0 = Utils::Low32Bits(imm); |
| 498 const uint32_t w1 = Utils::High32Bits(imm); |
| 499 const uint16_t h0 = Utils::Low16Bits(w0); |
| 500 const uint16_t h1 = Utils::High16Bits(w0); |
| 501 const uint16_t h2 = Utils::Low16Bits(w1); |
| 502 const uint16_t h3 = Utils::High16Bits(w1); |
| 503 |
| 504 // Special case for w1 == 0xffffffff |
| 505 if (w1 == 0xffffffff) { |
| 506 if (h1 == 0xffff) { |
| 507 movn(reg, Immediate(~h0), 0); |
| 508 } else { |
| 509 movn(reg, Immediate(~h1), 1); |
| 510 movk(reg, Immediate(h0), 0); |
| 511 } |
| 512 return; |
| 513 } |
| 514 |
| 515 // Special case for h3 == 0xffff |
| 516 if (h3 == 0xffff) { |
| 517 // We know h2 != 0xffff. |
| 518 movn(reg, Immediate(~h2), 2); |
| 519 if (h1 != 0xffff) { |
| 520 movk(reg, Immediate(h1), 1); |
| 521 } |
| 522 if (h0 != 0xffff) { |
| 523 movk(reg, Immediate(h0), 0); |
| 524 } |
| 525 return; |
| 526 } |
| 527 |
| 528 // Use constant pool if allowed, unless we can load imm with 2 instructions. |
| 529 if ((w1 != 0) && constant_pool_allowed()) { |
| 496 const int32_t offset = ObjectPool::element_offset(FindImmediate(imm)); | 530 const int32_t offset = ObjectPool::element_offset(FindImmediate(imm)); |
| 497 LoadWordFromPoolOffset(reg, pp, offset); | 531 LoadWordFromPoolOffset(reg, offset); |
| 498 } else { | 532 return; |
| 499 // 0. Is it 0? | 533 } |
| 500 if (imm == 0) { | |
| 501 movz(reg, Immediate(0), 0); | |
| 502 return; | |
| 503 } | |
| 504 | 534 |
| 505 // 1. Can we use one orri operation? | 535 bool initialized = false; |
| 506 Operand op; | 536 if (h0 != 0) { |
| 507 Operand::OperandType ot; | 537 movz(reg, Immediate(h0), 0); |
| 508 ot = Operand::CanHold(imm, kXRegSizeInBits, &op); | 538 initialized = true; |
| 509 if (ot == Operand::BitfieldImm) { | 539 } |
| 510 orri(reg, ZR, Immediate(imm)); | 540 if (h1 != 0) { |
| 511 return; | 541 if (initialized) { |
| 512 } | 542 movk(reg, Immediate(h1), 1); |
| 513 | 543 } else { |
| 514 // 2. Fall back on movz, movk, movn. | 544 movz(reg, Immediate(h1), 1); |
| 515 const uint32_t w0 = Utils::Low32Bits(imm); | |
| 516 const uint32_t w1 = Utils::High32Bits(imm); | |
| 517 const uint16_t h0 = Utils::Low16Bits(w0); | |
| 518 const uint16_t h1 = Utils::High16Bits(w0); | |
| 519 const uint16_t h2 = Utils::Low16Bits(w1); | |
| 520 const uint16_t h3 = Utils::High16Bits(w1); | |
| 521 | |
| 522 // Special case for w1 == 0xffffffff | |
| 523 if (w1 == 0xffffffff) { | |
| 524 if (h1 == 0xffff) { | |
| 525 movn(reg, Immediate(~h0), 0); | |
| 526 } else { | |
| 527 movn(reg, Immediate(~h1), 1); | |
| 528 movk(reg, Immediate(h0), 0); | |
| 529 } | |
| 530 return; | |
| 531 } | |
| 532 | |
| 533 // Special case for h3 == 0xffff | |
| 534 if (h3 == 0xffff) { | |
| 535 // We know h2 != 0xffff. | |
| 536 movn(reg, Immediate(~h2), 2); | |
| 537 if (h1 != 0xffff) { | |
| 538 movk(reg, Immediate(h1), 1); | |
| 539 } | |
| 540 if (h0 != 0xffff) { | |
| 541 movk(reg, Immediate(h0), 0); | |
| 542 } | |
| 543 return; | |
| 544 } | |
| 545 | |
| 546 bool initialized = false; | |
| 547 if (h0 != 0) { | |
| 548 movz(reg, Immediate(h0), 0); | |
| 549 initialized = true; | 545 initialized = true; |
| 550 } | 546 } |
| 551 if (h1 != 0) { | 547 } |
| 552 if (initialized) { | 548 if (h2 != 0) { |
| 553 movk(reg, Immediate(h1), 1); | 549 if (initialized) { |
| 554 } else { | 550 movk(reg, Immediate(h2), 2); |
| 555 movz(reg, Immediate(h1), 1); | 551 } else { |
| 556 initialized = true; | 552 movz(reg, Immediate(h2), 2); |
| 557 } | 553 initialized = true; |
| 558 } | 554 } |
| 559 if (h2 != 0) { | 555 } |
| 560 if (initialized) { | 556 if (h3 != 0) { |
| 561 movk(reg, Immediate(h2), 2); | 557 if (initialized) { |
| 562 } else { | 558 movk(reg, Immediate(h3), 3); |
| 563 movz(reg, Immediate(h2), 2); | 559 } else { |
| 564 initialized = true; | 560 movz(reg, Immediate(h3), 3); |
| 565 } | |
| 566 } | |
| 567 if (h3 != 0) { | |
| 568 if (initialized) { | |
| 569 movk(reg, Immediate(h3), 3); | |
| 570 } else { | |
| 571 movz(reg, Immediate(h3), 3); | |
| 572 } | |
| 573 } | 561 } |
| 574 } | 562 } |
| 575 } | 563 } |
| 576 | 564 |
| 577 | 565 |
| 578 void Assembler::LoadDImmediate(VRegister vd, double immd, Register pp) { | 566 void Assembler::LoadDImmediate(VRegister vd, double immd) { |
| 579 if (!fmovdi(vd, immd)) { | 567 if (!fmovdi(vd, immd)) { |
| 580 int64_t imm = bit_cast<int64_t, double>(immd); | 568 int64_t imm = bit_cast<int64_t, double>(immd); |
| 581 LoadImmediate(TMP, imm, pp); | 569 LoadImmediate(TMP, imm); |
| 582 fmovdr(vd, TMP); | 570 fmovdr(vd, TMP); |
| 583 } | 571 } |
| 584 } | 572 } |
| 585 | 573 |
| 586 | 574 |
| 587 void Assembler::AddImmediate( | 575 void Assembler::AddImmediate(Register dest, Register rn, int64_t imm) { |
| 588 Register dest, Register rn, int64_t imm, Register pp) { | |
| 589 Operand op; | 576 Operand op; |
| 590 if (imm == 0) { | 577 if (imm == 0) { |
| 591 if (dest != rn) { | 578 if (dest != rn) { |
| 592 mov(dest, rn); | 579 mov(dest, rn); |
| 593 } | 580 } |
| 594 return; | 581 return; |
| 595 } | 582 } |
| 596 if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) { | 583 if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) { |
| 597 add(dest, rn, op); | 584 add(dest, rn, op); |
| 598 } else if (Operand::CanHold(-imm, kXRegSizeInBits, &op) == | 585 } else if (Operand::CanHold(-imm, kXRegSizeInBits, &op) == |
| 599 Operand::Immediate) { | 586 Operand::Immediate) { |
| 600 sub(dest, rn, op); | 587 sub(dest, rn, op); |
| 601 } else { | 588 } else { |
| 602 // TODO(zra): Try adding top 12 bits, then bottom 12 bits. | 589 // TODO(zra): Try adding top 12 bits, then bottom 12 bits. |
| 603 ASSERT(rn != TMP2); | 590 ASSERT(rn != TMP2); |
| 604 LoadImmediate(TMP2, imm, pp); | 591 LoadImmediate(TMP2, imm); |
| 605 add(dest, rn, Operand(TMP2)); | 592 add(dest, rn, Operand(TMP2)); |
| 606 } | 593 } |
| 607 } | 594 } |
| 608 | 595 |
| 609 | 596 |
| 610 void Assembler::AddImmediateSetFlags( | 597 void Assembler::AddImmediateSetFlags(Register dest, Register rn, int64_t imm) { |
| 611 Register dest, Register rn, int64_t imm, Register pp) { | |
| 612 Operand op; | 598 Operand op; |
| 613 if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) { | 599 if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) { |
| 614 // Handles imm == kMinInt64. | 600 // Handles imm == kMinInt64. |
| 615 adds(dest, rn, op); | 601 adds(dest, rn, op); |
| 616 } else if (Operand::CanHold(-imm, kXRegSizeInBits, &op) == | 602 } else if (Operand::CanHold(-imm, kXRegSizeInBits, &op) == |
| 617 Operand::Immediate) { | 603 Operand::Immediate) { |
| 618 ASSERT(imm != kMinInt64); // Would cause erroneous overflow detection. | 604 ASSERT(imm != kMinInt64); // Would cause erroneous overflow detection. |
| 619 subs(dest, rn, op); | 605 subs(dest, rn, op); |
| 620 } else { | 606 } else { |
| 621 // TODO(zra): Try adding top 12 bits, then bottom 12 bits. | 607 // TODO(zra): Try adding top 12 bits, then bottom 12 bits. |
| 622 ASSERT(rn != TMP2); | 608 ASSERT(rn != TMP2); |
| 623 LoadImmediate(TMP2, imm, pp); | 609 LoadImmediate(TMP2, imm); |
| 624 adds(dest, rn, Operand(TMP2)); | 610 adds(dest, rn, Operand(TMP2)); |
| 625 } | 611 } |
| 626 } | 612 } |
| 627 | 613 |
| 628 | 614 |
| 629 void Assembler::SubImmediateSetFlags( | 615 void Assembler::SubImmediateSetFlags(Register dest, Register rn, int64_t imm) { |
| 630 Register dest, Register rn, int64_t imm, Register pp) { | |
| 631 Operand op; | 616 Operand op; |
| 632 if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) { | 617 if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) { |
| 633 // Handles imm == kMinInt64. | 618 // Handles imm == kMinInt64. |
| 634 subs(dest, rn, op); | 619 subs(dest, rn, op); |
| 635 } else if (Operand::CanHold(-imm, kXRegSizeInBits, &op) == | 620 } else if (Operand::CanHold(-imm, kXRegSizeInBits, &op) == |
| 636 Operand::Immediate) { | 621 Operand::Immediate) { |
| 637 ASSERT(imm != kMinInt64); // Would cause erroneous overflow detection. | 622 ASSERT(imm != kMinInt64); // Would cause erroneous overflow detection. |
| 638 adds(dest, rn, op); | 623 adds(dest, rn, op); |
| 639 } else { | 624 } else { |
| 640 // TODO(zra): Try subtracting top 12 bits, then bottom 12 bits. | 625 // TODO(zra): Try subtracting top 12 bits, then bottom 12 bits. |
| 641 ASSERT(rn != TMP2); | 626 ASSERT(rn != TMP2); |
| 642 LoadImmediate(TMP2, imm, pp); | 627 LoadImmediate(TMP2, imm); |
| 643 subs(dest, rn, Operand(TMP2)); | 628 subs(dest, rn, Operand(TMP2)); |
| 644 } | 629 } |
| 645 } | 630 } |
| 646 | 631 |
| 647 | 632 |
| 648 void Assembler::AndImmediate( | 633 void Assembler::AndImmediate(Register rd, Register rn, int64_t imm) { |
| 649 Register rd, Register rn, int64_t imm, Register pp) { | |
| 650 Operand imm_op; | 634 Operand imm_op; |
| 651 if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) { | 635 if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) { |
| 652 andi(rd, rn, Immediate(imm)); | 636 andi(rd, rn, Immediate(imm)); |
| 653 } else { | 637 } else { |
| 654 LoadImmediate(TMP, imm, pp); | 638 LoadImmediate(TMP, imm); |
| 655 and_(rd, rn, Operand(TMP)); | 639 and_(rd, rn, Operand(TMP)); |
| 656 } | 640 } |
| 657 } | 641 } |
| 658 | 642 |
| 659 | 643 |
| 660 void Assembler::OrImmediate( | 644 void Assembler::OrImmediate(Register rd, Register rn, int64_t imm) { |
| 661 Register rd, Register rn, int64_t imm, Register pp) { | |
| 662 Operand imm_op; | 645 Operand imm_op; |
| 663 if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) { | 646 if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) { |
| 664 orri(rd, rn, Immediate(imm)); | 647 orri(rd, rn, Immediate(imm)); |
| 665 } else { | 648 } else { |
| 666 LoadImmediate(TMP, imm, pp); | 649 LoadImmediate(TMP, imm); |
| 667 orr(rd, rn, Operand(TMP)); | 650 orr(rd, rn, Operand(TMP)); |
| 668 } | 651 } |
| 669 } | 652 } |
| 670 | 653 |
| 671 | 654 |
| 672 void Assembler::XorImmediate( | 655 void Assembler::XorImmediate(Register rd, Register rn, int64_t imm) { |
| 673 Register rd, Register rn, int64_t imm, Register pp) { | |
| 674 Operand imm_op; | 656 Operand imm_op; |
| 675 if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) { | 657 if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) { |
| 676 eori(rd, rn, Immediate(imm)); | 658 eori(rd, rn, Immediate(imm)); |
| 677 } else { | 659 } else { |
| 678 LoadImmediate(TMP, imm, pp); | 660 LoadImmediate(TMP, imm); |
| 679 eor(rd, rn, Operand(TMP)); | 661 eor(rd, rn, Operand(TMP)); |
| 680 } | 662 } |
| 681 } | 663 } |
| 682 | 664 |
| 683 | 665 |
| 684 void Assembler::TestImmediate(Register rn, int64_t imm, Register pp) { | 666 void Assembler::TestImmediate(Register rn, int64_t imm) { |
| 685 Operand imm_op; | 667 Operand imm_op; |
| 686 if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) { | 668 if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) { |
| 687 tsti(rn, Immediate(imm)); | 669 tsti(rn, Immediate(imm)); |
| 688 } else { | 670 } else { |
| 689 LoadImmediate(TMP, imm, pp); | 671 LoadImmediate(TMP, imm); |
| 690 tst(rn, Operand(TMP)); | 672 tst(rn, Operand(TMP)); |
| 691 } | 673 } |
| 692 } | 674 } |
| 693 | 675 |
| 694 | 676 |
| 695 void Assembler::CompareImmediate(Register rn, int64_t imm, Register pp) { | 677 void Assembler::CompareImmediate(Register rn, int64_t imm) { |
| 696 Operand op; | 678 Operand op; |
| 697 if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) { | 679 if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) { |
| 698 cmp(rn, op); | 680 cmp(rn, op); |
| 699 } else if (Operand::CanHold(-imm, kXRegSizeInBits, &op) == | 681 } else if (Operand::CanHold(-imm, kXRegSizeInBits, &op) == |
| 700 Operand::Immediate) { | 682 Operand::Immediate) { |
| 701 cmn(rn, op); | 683 cmn(rn, op); |
| 702 } else { | 684 } else { |
| 703 ASSERT(rn != TMP2); | 685 ASSERT(rn != TMP2); |
| 704 LoadImmediate(TMP2, imm, pp); | 686 LoadImmediate(TMP2, imm); |
| 705 cmp(rn, Operand(TMP2)); | 687 cmp(rn, Operand(TMP2)); |
| 706 } | 688 } |
| 707 } | 689 } |
| 708 | 690 |
| 709 | 691 |
| 710 void Assembler::LoadFromOffset( | 692 void Assembler::LoadFromOffset( |
| 711 Register dest, Register base, int32_t offset, Register pp, OperandSize sz) { | 693 Register dest, Register base, int32_t offset, OperandSize sz) { |
| 712 if (Address::CanHoldOffset(offset, Address::Offset, sz)) { | 694 if (Address::CanHoldOffset(offset, Address::Offset, sz)) { |
| 713 ldr(dest, Address(base, offset, Address::Offset, sz), sz); | 695 ldr(dest, Address(base, offset, Address::Offset, sz), sz); |
| 714 } else { | 696 } else { |
| 715 ASSERT(base != TMP2); | 697 ASSERT(base != TMP2); |
| 716 AddImmediate(TMP2, base, offset, pp); | 698 AddImmediate(TMP2, base, offset); |
| 717 ldr(dest, Address(TMP2), sz); | 699 ldr(dest, Address(TMP2), sz); |
| 718 } | 700 } |
| 719 } | 701 } |
| 720 | 702 |
| 721 | 703 |
| 722 void Assembler::LoadDFromOffset( | 704 void Assembler::LoadDFromOffset(VRegister dest, Register base, int32_t offset) { |
| 723 VRegister dest, Register base, int32_t offset, Register pp) { | |
| 724 if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) { | 705 if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) { |
| 725 fldrd(dest, Address(base, offset, Address::Offset, kDWord)); | 706 fldrd(dest, Address(base, offset, Address::Offset, kDWord)); |
| 726 } else { | 707 } else { |
| 727 ASSERT(base != TMP2); | 708 ASSERT(base != TMP2); |
| 728 AddImmediate(TMP2, base, offset, pp); | 709 AddImmediate(TMP2, base, offset); |
| 729 fldrd(dest, Address(TMP2)); | 710 fldrd(dest, Address(TMP2)); |
| 730 } | 711 } |
| 731 } | 712 } |
| 732 | 713 |
| 733 | 714 |
| 734 void Assembler::LoadQFromOffset( | 715 void Assembler::LoadQFromOffset(VRegister dest, Register base, int32_t offset) { |
| 735 VRegister dest, Register base, int32_t offset, Register pp) { | |
| 736 if (Address::CanHoldOffset(offset, Address::Offset, kQWord)) { | 716 if (Address::CanHoldOffset(offset, Address::Offset, kQWord)) { |
| 737 fldrq(dest, Address(base, offset, Address::Offset, kQWord)); | 717 fldrq(dest, Address(base, offset, Address::Offset, kQWord)); |
| 738 } else { | 718 } else { |
| 739 ASSERT(base != TMP2); | 719 ASSERT(base != TMP2); |
| 740 AddImmediate(TMP2, base, offset, pp); | 720 AddImmediate(TMP2, base, offset); |
| 741 fldrq(dest, Address(TMP2)); | 721 fldrq(dest, Address(TMP2)); |
| 742 } | 722 } |
| 743 } | 723 } |
| 744 | 724 |
| 745 | 725 |
| 746 void Assembler::StoreToOffset( | 726 void Assembler::StoreToOffset( |
| 747 Register src, Register base, int32_t offset, Register pp, OperandSize sz) { | 727 Register src, Register base, int32_t offset, OperandSize sz) { |
| 748 ASSERT(base != TMP2); | 728 ASSERT(base != TMP2); |
| 749 if (Address::CanHoldOffset(offset, Address::Offset, sz)) { | 729 if (Address::CanHoldOffset(offset, Address::Offset, sz)) { |
| 750 str(src, Address(base, offset, Address::Offset, sz), sz); | 730 str(src, Address(base, offset, Address::Offset, sz), sz); |
| 751 } else { | 731 } else { |
| 752 ASSERT(src != TMP2); | 732 ASSERT(src != TMP2); |
| 753 AddImmediate(TMP2, base, offset, pp); | 733 AddImmediate(TMP2, base, offset); |
| 754 str(src, Address(TMP2), sz); | 734 str(src, Address(TMP2), sz); |
| 755 } | 735 } |
| 756 } | 736 } |
| 757 | 737 |
| 758 | 738 |
| 759 void Assembler::StoreDToOffset( | 739 void Assembler::StoreDToOffset(VRegister src, Register base, int32_t offset) { |
| 760 VRegister src, Register base, int32_t offset, Register pp) { | |
| 761 if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) { | 740 if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) { |
| 762 fstrd(src, Address(base, offset, Address::Offset, kDWord)); | 741 fstrd(src, Address(base, offset, Address::Offset, kDWord)); |
| 763 } else { | 742 } else { |
| 764 ASSERT(base != TMP2); | 743 ASSERT(base != TMP2); |
| 765 AddImmediate(TMP2, base, offset, pp); | 744 AddImmediate(TMP2, base, offset); |
| 766 fstrd(src, Address(TMP2)); | 745 fstrd(src, Address(TMP2)); |
| 767 } | 746 } |
| 768 } | 747 } |
| 769 | 748 |
| 770 | 749 |
| 771 void Assembler::StoreQToOffset( | 750 void Assembler::StoreQToOffset(VRegister src, Register base, int32_t offset) { |
| 772 VRegister src, Register base, int32_t offset, Register pp) { | |
| 773 if (Address::CanHoldOffset(offset, Address::Offset, kQWord)) { | 751 if (Address::CanHoldOffset(offset, Address::Offset, kQWord)) { |
| 774 fstrq(src, Address(base, offset, Address::Offset, kQWord)); | 752 fstrq(src, Address(base, offset, Address::Offset, kQWord)); |
| 775 } else { | 753 } else { |
| 776 ASSERT(base != TMP2); | 754 ASSERT(base != TMP2); |
| 777 AddImmediate(TMP2, base, offset, pp); | 755 AddImmediate(TMP2, base, offset); |
| 778 fstrq(src, Address(TMP2)); | 756 fstrq(src, Address(TMP2)); |
| 779 } | 757 } |
| 780 } | 758 } |
| 781 | 759 |
| 782 | 760 |
| 783 void Assembler::VRecps(VRegister vd, VRegister vn) { | 761 void Assembler::VRecps(VRegister vd, VRegister vn) { |
| 784 ASSERT(vn != VTMP); | 762 ASSERT(vn != VTMP); |
| 785 ASSERT(vd != VTMP); | 763 ASSERT(vd != VTMP); |
| 786 | 764 |
| 787 // Reciprocal estimate. | 765 // Reciprocal estimate. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 841 // And the result with the negated space bit of the object. | 819 // And the result with the negated space bit of the object. |
| 842 bic(TMP, TMP, Operand(object)); | 820 bic(TMP, TMP, Operand(object)); |
| 843 tsti(TMP, Immediate(kNewObjectAlignmentOffset)); | 821 tsti(TMP, Immediate(kNewObjectAlignmentOffset)); |
| 844 b(no_update, EQ); | 822 b(no_update, EQ); |
| 845 } | 823 } |
| 846 | 824 |
| 847 | 825 |
| 848 void Assembler::StoreIntoObjectOffset(Register object, | 826 void Assembler::StoreIntoObjectOffset(Register object, |
| 849 int32_t offset, | 827 int32_t offset, |
| 850 Register value, | 828 Register value, |
| 851 Register pp, | |
| 852 bool can_value_be_smi) { | 829 bool can_value_be_smi) { |
| 853 if (Address::CanHoldOffset(offset - kHeapObjectTag)) { | 830 if (Address::CanHoldOffset(offset - kHeapObjectTag)) { |
| 854 StoreIntoObject( | 831 StoreIntoObject( |
| 855 object, FieldAddress(object, offset), value, can_value_be_smi); | 832 object, FieldAddress(object, offset), value, can_value_be_smi); |
| 856 } else { | 833 } else { |
| 857 AddImmediate(TMP, object, offset - kHeapObjectTag, pp); | 834 AddImmediate(TMP, object, offset - kHeapObjectTag); |
| 858 StoreIntoObject(object, Address(TMP), value, can_value_be_smi); | 835 StoreIntoObject(object, Address(TMP), value, can_value_be_smi); |
| 859 } | 836 } |
| 860 } | 837 } |
| 861 | 838 |
| 862 | 839 |
| 863 void Assembler::StoreIntoObject(Register object, | 840 void Assembler::StoreIntoObject(Register object, |
| 864 const Address& dest, | 841 const Address& dest, |
| 865 Register value, | 842 Register value, |
| 866 bool can_value_be_smi) { | 843 bool can_value_be_smi) { |
| 867 ASSERT(object != value); | 844 ASSERT(object != value); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 901 StoreIntoObjectFilter(object, value, &done); | 878 StoreIntoObjectFilter(object, value, &done); |
| 902 Stop("Store buffer update is required"); | 879 Stop("Store buffer update is required"); |
| 903 Bind(&done); | 880 Bind(&done); |
| 904 #endif // defined(DEBUG) | 881 #endif // defined(DEBUG) |
| 905 // No store buffer update. | 882 // No store buffer update. |
| 906 } | 883 } |
| 907 | 884 |
| 908 | 885 |
| 909 void Assembler::StoreIntoObjectOffsetNoBarrier(Register object, | 886 void Assembler::StoreIntoObjectOffsetNoBarrier(Register object, |
| 910 int32_t offset, | 887 int32_t offset, |
| 911 Register value, | 888 Register value) { |
| 912 Register pp) { | |
| 913 if (Address::CanHoldOffset(offset - kHeapObjectTag)) { | 889 if (Address::CanHoldOffset(offset - kHeapObjectTag)) { |
| 914 StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value); | 890 StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value); |
| 915 } else { | 891 } else { |
| 916 AddImmediate(TMP, object, offset - kHeapObjectTag, pp); | 892 AddImmediate(TMP, object, offset - kHeapObjectTag); |
| 917 StoreIntoObjectNoBarrier(object, Address(TMP), value); | 893 StoreIntoObjectNoBarrier(object, Address(TMP), value); |
| 918 } | 894 } |
| 919 } | 895 } |
| 920 | 896 |
| 921 | 897 |
| 922 void Assembler::StoreIntoObjectNoBarrier(Register object, | 898 void Assembler::StoreIntoObjectNoBarrier(Register object, |
| 923 const Address& dest, | 899 const Address& dest, |
| 924 const Object& value) { | 900 const Object& value) { |
| 925 ASSERT(value.IsSmi() || value.InVMHeap() || | 901 ASSERT(value.IsSmi() || value.InVMHeap() || |
| 926 (value.IsOld() && value.IsNotTemporaryScopedHandle())); | 902 (value.IsOld() && value.IsNotTemporaryScopedHandle())); |
| 927 // No store buffer update. | 903 // No store buffer update. |
| 928 LoadObject(TMP2, value, PP); | 904 LoadObject(TMP2, value); |
| 929 str(TMP2, dest); | 905 str(TMP2, dest); |
| 930 } | 906 } |
| 931 | 907 |
| 932 | 908 |
| 933 void Assembler::StoreIntoObjectOffsetNoBarrier(Register object, | 909 void Assembler::StoreIntoObjectOffsetNoBarrier(Register object, |
| 934 int32_t offset, | 910 int32_t offset, |
| 935 const Object& value, | 911 const Object& value) { |
| 936 Register pp) { | |
| 937 if (Address::CanHoldOffset(offset - kHeapObjectTag)) { | 912 if (Address::CanHoldOffset(offset - kHeapObjectTag)) { |
| 938 StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value); | 913 StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value); |
| 939 } else { | 914 } else { |
| 940 AddImmediate(TMP, object, offset - kHeapObjectTag, pp); | 915 AddImmediate(TMP, object, offset - kHeapObjectTag); |
| 941 StoreIntoObjectNoBarrier(object, Address(TMP), value); | 916 StoreIntoObjectNoBarrier(object, Address(TMP), value); |
| 942 } | 917 } |
| 943 } | 918 } |
| 944 | 919 |
| 945 | 920 |
| 946 void Assembler::LoadClassId(Register result, Register object, Register pp) { | 921 void Assembler::LoadClassId(Register result, Register object) { |
| 947 ASSERT(RawObject::kClassIdTagPos == kBitsPerInt32); | 922 ASSERT(RawObject::kClassIdTagPos == kBitsPerInt32); |
| 948 ASSERT(RawObject::kClassIdTagSize == kBitsPerInt32); | 923 ASSERT(RawObject::kClassIdTagSize == kBitsPerInt32); |
| 949 const intptr_t class_id_offset = Object::tags_offset() + | 924 const intptr_t class_id_offset = Object::tags_offset() + |
| 950 RawObject::kClassIdTagPos / kBitsPerByte; | 925 RawObject::kClassIdTagPos / kBitsPerByte; |
| 951 LoadFromOffset(result, object, class_id_offset - kHeapObjectTag, pp, | 926 LoadFromOffset(result, object, class_id_offset - kHeapObjectTag, |
| 952 kUnsignedWord); | 927 kUnsignedWord); |
| 953 } | 928 } |
| 954 | 929 |
| 955 | 930 |
| 956 void Assembler::LoadClassById(Register result, Register class_id, Register pp) { | 931 void Assembler::LoadClassById(Register result, Register class_id) { |
| 957 ASSERT(result != class_id); | 932 ASSERT(result != class_id); |
| 958 LoadIsolate(result); | 933 LoadIsolate(result); |
| 959 const intptr_t offset = | 934 const intptr_t offset = |
| 960 Isolate::class_table_offset() + ClassTable::table_offset(); | 935 Isolate::class_table_offset() + ClassTable::table_offset(); |
| 961 LoadFromOffset(result, result, offset, pp); | 936 LoadFromOffset(result, result, offset); |
| 962 ldr(result, Address(result, class_id, UXTX, Address::Scaled)); | 937 ldr(result, Address(result, class_id, UXTX, Address::Scaled)); |
| 963 } | 938 } |
| 964 | 939 |
| 965 | 940 |
| 966 void Assembler::LoadClass(Register result, Register object, Register pp) { | 941 void Assembler::LoadClass(Register result, Register object) { |
| 967 ASSERT(object != TMP); | 942 ASSERT(object != TMP); |
| 968 LoadClassId(TMP, object, pp); | 943 LoadClassId(TMP, object); |
| 969 LoadClassById(result, TMP, pp); | 944 LoadClassById(result, TMP); |
| 970 } | 945 } |
| 971 | 946 |
| 972 | 947 |
| 973 void Assembler::CompareClassId( | 948 void Assembler::CompareClassId(Register object, intptr_t class_id) { |
| 974 Register object, intptr_t class_id, Register pp) { | 949 LoadClassId(TMP, object); |
| 975 LoadClassId(TMP, object, pp); | 950 CompareImmediate(TMP, class_id); |
| 976 CompareImmediate(TMP, class_id, pp); | |
| 977 } | 951 } |
| 978 | 952 |
| 979 | 953 |
| 980 void Assembler::LoadClassIdMayBeSmi(Register result, Register object) { | 954 void Assembler::LoadClassIdMayBeSmi(Register result, Register object) { |
| 981 // Load up a null object. We only need it so we can use LoadClassId on it in | 955 // Load up a null object. We only need it so we can use LoadClassId on it in |
| 982 // the case that object is a Smi.. | 956 // the case that object is a Smi.. |
| 983 LoadObject(TMP, Object::null_object(), PP); | 957 LoadObject(TMP, Object::null_object()); |
| 984 // Check if the object is a Smi. | 958 // Check if the object is a Smi. |
| 985 tsti(object, Immediate(kSmiTagMask)); | 959 tsti(object, Immediate(kSmiTagMask)); |
| 986 // If the object *is* a Smi, use the null object instead. o/w leave alone. | 960 // If the object *is* a Smi, use the null object instead. o/w leave alone. |
| 987 csel(TMP, TMP, object, EQ); | 961 csel(TMP, TMP, object, EQ); |
| 988 // Loads either the cid of the object if it isn't a Smi, or the cid of null | 962 // Loads either the cid of the object if it isn't a Smi, or the cid of null |
| 989 // if it is a Smi, which will be ignored. | 963 // if it is a Smi, which will be ignored. |
| 990 LoadClassId(result, TMP, PP); | 964 LoadClassId(result, TMP); |
| 991 | 965 |
| 992 LoadImmediate(TMP, kSmiCid, PP); | 966 LoadImmediate(TMP, kSmiCid); |
| 993 // If object is a Smi, move the Smi cid into result. o/w leave alone. | 967 // If object is a Smi, move the Smi cid into result. o/w leave alone. |
| 994 csel(result, TMP, result, EQ); | 968 csel(result, TMP, result, EQ); |
| 995 } | 969 } |
| 996 | 970 |
| 997 | 971 |
| 998 void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) { | 972 void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) { |
| 999 LoadClassIdMayBeSmi(result, object); | 973 LoadClassIdMayBeSmi(result, object); |
| 1000 // Finally, tag the result. | 974 // Finally, tag the result. |
| 1001 SmiTag(result); | 975 SmiTag(result); |
| 1002 } | 976 } |
| 1003 | 977 |
| 1004 | 978 |
| 1005 void Assembler::ComputeRange(Register result, | 979 void Assembler::ComputeRange(Register result, |
| 1006 Register value, | 980 Register value, |
| 1007 Register scratch, | 981 Register scratch, |
| 1008 Label* not_mint) { | 982 Label* not_mint) { |
| 1009 Label done, not_smi; | 983 Label done, not_smi; |
| 1010 tsti(value, Immediate(kSmiTagMask)); | 984 tsti(value, Immediate(kSmiTagMask)); |
| 1011 b(¬_smi, NE); | 985 b(¬_smi, NE); |
| 1012 | 986 |
| 1013 AsrImmediate(scratch, value, 32); | 987 AsrImmediate(scratch, value, 32); |
| 1014 LoadImmediate(result, ICData::kUint32RangeBit, PP); | 988 LoadImmediate(result, ICData::kUint32RangeBit); |
| 1015 cmp(scratch, Operand(1)); | 989 cmp(scratch, Operand(1)); |
| 1016 b(&done, EQ); | 990 b(&done, EQ); |
| 1017 | 991 |
| 1018 neg(scratch, scratch); | 992 neg(scratch, scratch); |
| 1019 add(result, scratch, Operand(ICData::kInt32RangeBit)); | 993 add(result, scratch, Operand(ICData::kInt32RangeBit)); |
| 1020 cmp(scratch, Operand(1)); | 994 cmp(scratch, Operand(1)); |
| 1021 LoadImmediate(TMP, ICData::kSignedRangeBit, PP); | 995 LoadImmediate(TMP, ICData::kSignedRangeBit); |
| 1022 csel(result, result, TMP, LS); | 996 csel(result, result, TMP, LS); |
| 1023 b(&done); | 997 b(&done); |
| 1024 | 998 |
| 1025 Bind(¬_smi); | 999 Bind(¬_smi); |
| 1026 CompareClassId(value, kMintCid, PP); | 1000 CompareClassId(value, kMintCid); |
| 1027 b(not_mint, NE); | 1001 b(not_mint, NE); |
| 1028 | 1002 |
| 1029 LoadImmediate(result, ICData::kInt64RangeBit, PP); | 1003 LoadImmediate(result, ICData::kInt64RangeBit); |
| 1030 Bind(&done); | 1004 Bind(&done); |
| 1031 } | 1005 } |
| 1032 | 1006 |
| 1033 | 1007 |
| 1034 void Assembler::UpdateRangeFeedback(Register value, | 1008 void Assembler::UpdateRangeFeedback(Register value, |
| 1035 intptr_t index, | 1009 intptr_t index, |
| 1036 Register ic_data, | 1010 Register ic_data, |
| 1037 Register scratch1, | 1011 Register scratch1, |
| 1038 Register scratch2, | 1012 Register scratch2, |
| 1039 Label* miss) { | 1013 Label* miss) { |
| 1040 ASSERT(ICData::IsValidRangeFeedbackIndex(index)); | 1014 ASSERT(ICData::IsValidRangeFeedbackIndex(index)); |
| 1041 ComputeRange(scratch1, value, scratch2, miss); | 1015 ComputeRange(scratch1, value, scratch2, miss); |
| 1042 ldr(scratch2, FieldAddress(ic_data, ICData::state_bits_offset()), kWord); | 1016 ldr(scratch2, FieldAddress(ic_data, ICData::state_bits_offset()), kWord); |
| 1043 orrw(scratch2, | 1017 orrw(scratch2, |
| 1044 scratch2, | 1018 scratch2, |
| 1045 Operand(scratch1, LSL, ICData::RangeFeedbackShift(index))); | 1019 Operand(scratch1, LSL, ICData::RangeFeedbackShift(index))); |
| 1046 str(scratch2, FieldAddress(ic_data, ICData::state_bits_offset()), kWord); | 1020 str(scratch2, FieldAddress(ic_data, ICData::state_bits_offset()), kWord); |
| 1047 } | 1021 } |
| 1048 | 1022 |
| 1049 | 1023 |
| 1050 // Frame entry and exit. | 1024 // Frame entry and exit. |
| 1051 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { | 1025 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { |
| 1052 // Reserve space for arguments and align frame before entering | 1026 // Reserve space for arguments and align frame before entering |
| 1053 // the C++ world. | 1027 // the C++ world. |
| 1054 if (frame_space != 0) { | 1028 if (frame_space != 0) { |
| 1055 AddImmediate(SP, SP, -frame_space, kNoPP); | 1029 AddImmediate(SP, SP, -frame_space); |
| 1056 } | 1030 } |
| 1057 if (OS::ActivationFrameAlignment() > 1) { | 1031 if (OS::ActivationFrameAlignment() > 1) { |
| 1058 andi(SP, SP, Immediate(~(OS::ActivationFrameAlignment() - 1))); | 1032 andi(SP, SP, Immediate(~(OS::ActivationFrameAlignment() - 1))); |
| 1059 } | 1033 } |
| 1060 } | 1034 } |
| 1061 | 1035 |
| 1062 | 1036 |
| 1063 void Assembler::EnterFrame(intptr_t frame_size) { | 1037 void Assembler::EnterFrame(intptr_t frame_size) { |
| 1064 PushPair(LR, FP); | 1038 PushPair(LR, FP); |
| 1065 mov(FP, SP); | 1039 mov(FP, SP); |
| 1066 | 1040 |
| 1067 if (frame_size > 0) { | 1041 if (frame_size > 0) { |
| 1068 sub(SP, SP, Operand(frame_size)); | 1042 sub(SP, SP, Operand(frame_size)); |
| 1069 } | 1043 } |
| 1070 } | 1044 } |
| 1071 | 1045 |
| 1072 | 1046 |
| 1073 void Assembler::LeaveFrame() { | 1047 void Assembler::LeaveFrame() { |
| 1074 mov(SP, FP); | 1048 mov(SP, FP); |
| 1075 PopPair(LR, FP); | 1049 PopPair(LR, FP); |
| 1076 } | 1050 } |
| 1077 | 1051 |
| 1078 | 1052 |
| 1079 void Assembler::EnterDartFrame(intptr_t frame_size) { | 1053 void Assembler::EnterDartFrame(intptr_t frame_size) { |
| 1054 ASSERT(!constant_pool_allowed()); |
| 1080 // Setup the frame. | 1055 // Setup the frame. |
| 1081 adr(TMP, Immediate(-CodeSize())); // TMP gets PC marker. | 1056 adr(TMP, Immediate(-CodeSize())); // TMP gets PC marker. |
| 1082 EnterFrame(0); | 1057 EnterFrame(0); |
| 1083 TagAndPushPPAndPcMarker(TMP); // Save PP and PC marker. | 1058 TagAndPushPPAndPcMarker(TMP); // Save PP and PC marker. |
| 1084 | 1059 |
| 1085 // Load the pool pointer. | 1060 // Load the pool pointer. |
| 1086 LoadPoolPointer(PP); | 1061 LoadPoolPointer(); |
| 1087 | 1062 |
| 1088 // Reserve space. | 1063 // Reserve space. |
| 1089 if (frame_size > 0) { | 1064 if (frame_size > 0) { |
| 1090 AddImmediate(SP, SP, -frame_size, PP); | 1065 AddImmediate(SP, SP, -frame_size); |
| 1091 } | 1066 } |
| 1092 } | 1067 } |
| 1093 | 1068 |
| 1094 | 1069 |
| 1095 void Assembler::EnterDartFrameWithInfo(intptr_t frame_size, Register new_pp) { | 1070 void Assembler::EnterDartFrameWithInfo(intptr_t frame_size, Register new_pp) { |
| 1071 ASSERT(!constant_pool_allowed()); |
| 1096 // Setup the frame. | 1072 // Setup the frame. |
| 1097 adr(TMP, Immediate(-CodeSize())); // TMP gets PC marker. | 1073 adr(TMP, Immediate(-CodeSize())); // TMP gets PC marker. |
| 1098 EnterFrame(0); | 1074 EnterFrame(0); |
| 1099 TagAndPushPPAndPcMarker(TMP); // Save PP and PC marker. | 1075 TagAndPushPPAndPcMarker(TMP); // Save PP and PC marker. |
| 1100 | 1076 |
| 1101 // Load the pool pointer. | 1077 // Load the pool pointer. |
| 1102 if (new_pp == kNoPP) { | 1078 if (new_pp == kNoRegister) { |
| 1103 LoadPoolPointer(PP); | 1079 LoadPoolPointer(); |
| 1104 } else { | 1080 } else { |
| 1105 mov(PP, new_pp); | 1081 mov(PP, new_pp); |
| 1082 set_constant_pool_allowed(true); |
| 1106 } | 1083 } |
| 1107 | 1084 |
| 1108 // Reserve space. | 1085 // Reserve space. |
| 1109 if (frame_size > 0) { | 1086 if (frame_size > 0) { |
| 1110 AddImmediate(SP, SP, -frame_size, PP); | 1087 AddImmediate(SP, SP, -frame_size); |
| 1111 } | 1088 } |
| 1112 } | 1089 } |
| 1113 | 1090 |
| 1114 | 1091 |
| 1115 // On entry to a function compiled for OSR, the caller's frame pointer, the | 1092 // On entry to a function compiled for OSR, the caller's frame pointer, the |
| 1116 // stack locals, and any copied parameters are already in place. The frame | 1093 // stack locals, and any copied parameters are already in place. The frame |
| 1117 // pointer is already set up. The PC marker is not correct for the | 1094 // pointer is already set up. The PC marker is not correct for the |
| 1118 // optimized function and there may be extra space for spill slots to | 1095 // optimized function and there may be extra space for spill slots to |
| 1119 // allocate. We must also set up the pool pointer for the function. | 1096 // allocate. We must also set up the pool pointer for the function. |
| 1120 void Assembler::EnterOsrFrame(intptr_t extra_size, Register new_pp) { | 1097 void Assembler::EnterOsrFrame(intptr_t extra_size, Register new_pp) { |
| 1098 ASSERT(!constant_pool_allowed()); |
| 1121 Comment("EnterOsrFrame"); | 1099 Comment("EnterOsrFrame"); |
| 1122 adr(TMP, Immediate(-CodeSize())); | 1100 adr(TMP, Immediate(-CodeSize())); |
| 1123 | 1101 |
| 1124 StoreToOffset(TMP, FP, kPcMarkerSlotFromFp * kWordSize, kNoPP); | 1102 StoreToOffset(TMP, FP, kPcMarkerSlotFromFp * kWordSize); |
| 1125 | 1103 |
| 1126 // Setup pool pointer for this dart function. | 1104 // Setup pool pointer for this dart function. |
| 1127 if (new_pp == kNoPP) { | 1105 if (new_pp == kNoRegister) { |
| 1128 LoadPoolPointer(PP); | 1106 LoadPoolPointer(); |
| 1129 } else { | 1107 } else { |
| 1130 mov(PP, new_pp); | 1108 mov(PP, new_pp); |
| 1109 set_constant_pool_allowed(true); |
| 1131 } | 1110 } |
| 1132 | 1111 |
| 1133 if (extra_size > 0) { | 1112 if (extra_size > 0) { |
| 1134 AddImmediate(SP, SP, -extra_size, PP); | 1113 AddImmediate(SP, SP, -extra_size); |
| 1135 } | 1114 } |
| 1136 } | 1115 } |
| 1137 | 1116 |
| 1138 | 1117 |
| 1139 void Assembler::LeaveDartFrame() { | 1118 void Assembler::LeaveDartFrame() { |
| 1119 // LeaveDartFrame is called from stubs (pp disallowed) and from Dart code (pp |
| 1120 // allowed), so there is no point in checking the current value of |
| 1121 // constant_pool_allowed(). |
| 1122 set_constant_pool_allowed(false); |
| 1140 // Restore and untag PP. | 1123 // Restore and untag PP. |
| 1141 LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize, kNoPP); | 1124 LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize); |
| 1142 sub(PP, PP, Operand(kHeapObjectTag)); | 1125 sub(PP, PP, Operand(kHeapObjectTag)); |
| 1143 LeaveFrame(); | 1126 LeaveFrame(); |
| 1144 } | 1127 } |
| 1145 | 1128 |
| 1146 | 1129 |
| 1147 void Assembler::EnterCallRuntimeFrame(intptr_t frame_size) { | 1130 void Assembler::EnterCallRuntimeFrame(intptr_t frame_size) { |
| 1148 EnterFrame(0); | 1131 EnterFrame(0); |
| 1149 | 1132 |
| 1150 // Store fpu registers with the lowest register number at the lowest | 1133 // Store fpu registers with the lowest register number at the lowest |
| 1151 // address. | 1134 // address. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1169 } | 1152 } |
| 1170 | 1153 |
| 1171 | 1154 |
| 1172 void Assembler::LeaveCallRuntimeFrame() { | 1155 void Assembler::LeaveCallRuntimeFrame() { |
| 1173 // SP might have been modified to reserve space for arguments | 1156 // SP might have been modified to reserve space for arguments |
| 1174 // and ensure proper alignment of the stack frame. | 1157 // and ensure proper alignment of the stack frame. |
| 1175 // We need to restore it before restoring registers. | 1158 // We need to restore it before restoring registers. |
| 1176 const intptr_t kPushedRegistersSize = | 1159 const intptr_t kPushedRegistersSize = |
| 1177 kDartVolatileCpuRegCount * kWordSize + | 1160 kDartVolatileCpuRegCount * kWordSize + |
| 1178 kDartVolatileFpuRegCount * kWordSize; | 1161 kDartVolatileFpuRegCount * kWordSize; |
| 1179 AddImmediate(SP, FP, -kPushedRegistersSize, PP); | 1162 AddImmediate(SP, FP, -kPushedRegistersSize); |
| 1180 for (int i = kDartLastVolatileCpuReg; i >= kDartFirstVolatileCpuReg; i--) { | 1163 for (int i = kDartLastVolatileCpuReg; i >= kDartFirstVolatileCpuReg; i--) { |
| 1181 const Register reg = static_cast<Register>(i); | 1164 const Register reg = static_cast<Register>(i); |
| 1182 Pop(reg); | 1165 Pop(reg); |
| 1183 } | 1166 } |
| 1184 | 1167 |
| 1185 for (int i = 0; i < kNumberOfVRegisters; i++) { | 1168 for (int i = 0; i < kNumberOfVRegisters; i++) { |
| 1186 if ((i >= kAbiFirstPreservedFpuReg) && (i <= kAbiLastPreservedFpuReg)) { | 1169 if ((i >= kAbiFirstPreservedFpuReg) && (i <= kAbiLastPreservedFpuReg)) { |
| 1187 // TODO(zra): When SIMD is added, we must also restore the top | 1170 // TODO(zra): When SIMD is added, we must also restore the top |
| 1188 // 64-bits of the callee-saved registers. | 1171 // 64-bits of the callee-saved registers. |
| 1189 continue; | 1172 continue; |
| 1190 } | 1173 } |
| 1191 // TODO(zra): Restore the whole V register. | 1174 // TODO(zra): Restore the whole V register. |
| 1192 VRegister reg = static_cast<VRegister>(i); | 1175 VRegister reg = static_cast<VRegister>(i); |
| 1193 PopDouble(reg); | 1176 PopDouble(reg); |
| 1194 } | 1177 } |
| 1195 | 1178 |
| 1196 PopPair(LR, FP); | 1179 PopPair(LR, FP); |
| 1197 } | 1180 } |
| 1198 | 1181 |
| 1199 | 1182 |
| 1200 void Assembler::CallRuntime(const RuntimeEntry& entry, | 1183 void Assembler::CallRuntime(const RuntimeEntry& entry, |
| 1201 intptr_t argument_count) { | 1184 intptr_t argument_count) { |
| 1202 entry.Call(this, argument_count); | 1185 entry.Call(this, argument_count); |
| 1203 } | 1186 } |
| 1204 | 1187 |
| 1205 | 1188 |
| 1206 void Assembler::EnterStubFrame() { | 1189 void Assembler::EnterStubFrame() { |
| 1190 set_constant_pool_allowed(false); |
| 1207 EnterFrame(0); | 1191 EnterFrame(0); |
| 1208 // Save caller's pool pointer. Push 0 in the saved PC area for stub frames. | 1192 // Save caller's pool pointer. Push 0 in the saved PC area for stub frames. |
| 1209 TagAndPushPPAndPcMarker(ZR); | 1193 TagAndPushPPAndPcMarker(ZR); |
| 1210 LoadPoolPointer(PP); | 1194 LoadPoolPointer(); |
| 1211 } | 1195 } |
| 1212 | 1196 |
| 1213 | 1197 |
| 1214 void Assembler::LeaveStubFrame() { | 1198 void Assembler::LeaveStubFrame() { |
| 1199 set_constant_pool_allowed(false); |
| 1215 // Restore and untag PP. | 1200 // Restore and untag PP. |
| 1216 LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize, kNoPP); | 1201 LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize); |
| 1217 sub(PP, PP, Operand(kHeapObjectTag)); | 1202 sub(PP, PP, Operand(kHeapObjectTag)); |
| 1218 LeaveFrame(); | 1203 LeaveFrame(); |
| 1219 } | 1204 } |
| 1220 | 1205 |
| 1221 | 1206 |
| 1222 void Assembler::UpdateAllocationStats(intptr_t cid, | 1207 void Assembler::UpdateAllocationStats(intptr_t cid, |
| 1223 Register pp, | |
| 1224 Heap::Space space, | 1208 Heap::Space space, |
| 1225 bool inline_isolate) { | 1209 bool inline_isolate) { |
| 1226 ASSERT(cid > 0); | 1210 ASSERT(cid > 0); |
| 1227 intptr_t counter_offset = | 1211 intptr_t counter_offset = |
| 1228 ClassTable::CounterOffsetFor(cid, space == Heap::kNew); | 1212 ClassTable::CounterOffsetFor(cid, space == Heap::kNew); |
| 1229 if (inline_isolate) { | 1213 if (inline_isolate) { |
| 1230 ClassTable* class_table = Isolate::Current()->class_table(); | 1214 ClassTable* class_table = Isolate::Current()->class_table(); |
| 1231 ClassHeapStats** table_ptr = class_table->TableAddressFor(cid); | 1215 ClassHeapStats** table_ptr = class_table->TableAddressFor(cid); |
| 1232 if (cid < kNumPredefinedCids) { | 1216 if (cid < kNumPredefinedCids) { |
| 1233 LoadImmediate( | 1217 LoadImmediate( |
| 1234 TMP2, reinterpret_cast<uword>(*table_ptr) + counter_offset, pp); | 1218 TMP2, reinterpret_cast<uword>(*table_ptr) + counter_offset); |
| 1235 } else { | 1219 } else { |
| 1236 LoadImmediate(TMP2, reinterpret_cast<uword>(table_ptr), pp); | 1220 LoadImmediate(TMP2, reinterpret_cast<uword>(table_ptr)); |
| 1237 ldr(TMP, Address(TMP2)); | 1221 ldr(TMP, Address(TMP2)); |
| 1238 AddImmediate(TMP2, TMP, counter_offset, pp); | 1222 AddImmediate(TMP2, TMP, counter_offset); |
| 1239 } | 1223 } |
| 1240 } else { | 1224 } else { |
| 1241 LoadIsolate(TMP2); | 1225 LoadIsolate(TMP2); |
| 1242 intptr_t table_offset = | 1226 intptr_t table_offset = |
| 1243 Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid); | 1227 Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid); |
| 1244 ldr(TMP, Address(TMP2, table_offset)); | 1228 ldr(TMP, Address(TMP2, table_offset)); |
| 1245 AddImmediate(TMP2, TMP, counter_offset, pp); | 1229 AddImmediate(TMP2, TMP, counter_offset); |
| 1246 } | 1230 } |
| 1247 ldr(TMP, Address(TMP2, 0)); | 1231 ldr(TMP, Address(TMP2, 0)); |
| 1248 AddImmediate(TMP, TMP, 1, pp); | 1232 AddImmediate(TMP, TMP, 1); |
| 1249 str(TMP, Address(TMP2, 0)); | 1233 str(TMP, Address(TMP2, 0)); |
| 1250 } | 1234 } |
| 1251 | 1235 |
| 1252 | 1236 |
| 1253 void Assembler::UpdateAllocationStatsWithSize(intptr_t cid, | 1237 void Assembler::UpdateAllocationStatsWithSize(intptr_t cid, |
| 1254 Register size_reg, | 1238 Register size_reg, |
| 1255 Register pp, | |
| 1256 Heap::Space space, | 1239 Heap::Space space, |
| 1257 bool inline_isolate) { | 1240 bool inline_isolate) { |
| 1258 ASSERT(cid > 0); | 1241 ASSERT(cid > 0); |
| 1259 const uword class_offset = ClassTable::ClassOffsetFor(cid); | 1242 const uword class_offset = ClassTable::ClassOffsetFor(cid); |
| 1260 const uword count_field_offset = (space == Heap::kNew) ? | 1243 const uword count_field_offset = (space == Heap::kNew) ? |
| 1261 ClassHeapStats::allocated_since_gc_new_space_offset() : | 1244 ClassHeapStats::allocated_since_gc_new_space_offset() : |
| 1262 ClassHeapStats::allocated_since_gc_old_space_offset(); | 1245 ClassHeapStats::allocated_since_gc_old_space_offset(); |
| 1263 const uword size_field_offset = (space == Heap::kNew) ? | 1246 const uword size_field_offset = (space == Heap::kNew) ? |
| 1264 ClassHeapStats::allocated_size_since_gc_new_space_offset() : | 1247 ClassHeapStats::allocated_size_since_gc_new_space_offset() : |
| 1265 ClassHeapStats::allocated_size_since_gc_old_space_offset(); | 1248 ClassHeapStats::allocated_size_since_gc_old_space_offset(); |
| 1266 if (inline_isolate) { | 1249 if (inline_isolate) { |
| 1267 ClassTable* class_table = Isolate::Current()->class_table(); | 1250 ClassTable* class_table = Isolate::Current()->class_table(); |
| 1268 ClassHeapStats** table_ptr = class_table->TableAddressFor(cid); | 1251 ClassHeapStats** table_ptr = class_table->TableAddressFor(cid); |
| 1269 if (cid < kNumPredefinedCids) { | 1252 if (cid < kNumPredefinedCids) { |
| 1270 LoadImmediate(TMP2, | 1253 LoadImmediate(TMP2, |
| 1271 reinterpret_cast<uword>(*table_ptr) + class_offset, pp); | 1254 reinterpret_cast<uword>(*table_ptr) + class_offset); |
| 1272 } else { | 1255 } else { |
| 1273 LoadImmediate(TMP2, reinterpret_cast<uword>(table_ptr), pp); | 1256 LoadImmediate(TMP2, reinterpret_cast<uword>(table_ptr)); |
| 1274 ldr(TMP, Address(TMP2)); | 1257 ldr(TMP, Address(TMP2)); |
| 1275 AddImmediate(TMP2, TMP, class_offset, pp); | 1258 AddImmediate(TMP2, TMP, class_offset); |
| 1276 } | 1259 } |
| 1277 } else { | 1260 } else { |
| 1278 LoadIsolate(TMP2); | 1261 LoadIsolate(TMP2); |
| 1279 intptr_t table_offset = | 1262 intptr_t table_offset = |
| 1280 Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid); | 1263 Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid); |
| 1281 ldr(TMP, Address(TMP2, table_offset)); | 1264 ldr(TMP, Address(TMP2, table_offset)); |
| 1282 AddImmediate(TMP2, TMP, class_offset, pp); | 1265 AddImmediate(TMP2, TMP, class_offset); |
| 1283 } | 1266 } |
| 1284 ldr(TMP, Address(TMP2, count_field_offset)); | 1267 ldr(TMP, Address(TMP2, count_field_offset)); |
| 1285 AddImmediate(TMP, TMP, 1, pp); | 1268 AddImmediate(TMP, TMP, 1); |
| 1286 str(TMP, Address(TMP2, count_field_offset)); | 1269 str(TMP, Address(TMP2, count_field_offset)); |
| 1287 ldr(TMP, Address(TMP2, size_field_offset)); | 1270 ldr(TMP, Address(TMP2, size_field_offset)); |
| 1288 add(TMP, TMP, Operand(size_reg)); | 1271 add(TMP, TMP, Operand(size_reg)); |
| 1289 str(TMP, Address(TMP2, size_field_offset)); | 1272 str(TMP, Address(TMP2, size_field_offset)); |
| 1290 } | 1273 } |
| 1291 | 1274 |
| 1292 | 1275 |
| 1293 void Assembler::MaybeTraceAllocation(intptr_t cid, | 1276 void Assembler::MaybeTraceAllocation(intptr_t cid, |
| 1294 Register temp_reg, | 1277 Register temp_reg, |
| 1295 Register pp, | |
| 1296 Label* trace, | 1278 Label* trace, |
| 1297 bool inline_isolate) { | 1279 bool inline_isolate) { |
| 1298 ASSERT(cid > 0); | 1280 ASSERT(cid > 0); |
| 1299 intptr_t state_offset = ClassTable::StateOffsetFor(cid); | 1281 intptr_t state_offset = ClassTable::StateOffsetFor(cid); |
| 1300 if (inline_isolate) { | 1282 if (inline_isolate) { |
| 1301 ClassTable* class_table = Isolate::Current()->class_table(); | 1283 ClassTable* class_table = Isolate::Current()->class_table(); |
| 1302 ClassHeapStats** table_ptr = class_table->TableAddressFor(cid); | 1284 ClassHeapStats** table_ptr = class_table->TableAddressFor(cid); |
| 1303 if (cid < kNumPredefinedCids) { | 1285 if (cid < kNumPredefinedCids) { |
| 1304 LoadImmediate( | 1286 LoadImmediate( |
| 1305 temp_reg, reinterpret_cast<uword>(*table_ptr) + state_offset, pp); | 1287 temp_reg, reinterpret_cast<uword>(*table_ptr) + state_offset); |
| 1306 } else { | 1288 } else { |
| 1307 LoadImmediate(temp_reg, reinterpret_cast<uword>(table_ptr), pp); | 1289 LoadImmediate(temp_reg, reinterpret_cast<uword>(table_ptr)); |
| 1308 ldr(temp_reg, Address(temp_reg, 0)); | 1290 ldr(temp_reg, Address(temp_reg, 0)); |
| 1309 AddImmediate(temp_reg, temp_reg, state_offset, pp); | 1291 AddImmediate(temp_reg, temp_reg, state_offset); |
| 1310 } | 1292 } |
| 1311 } else { | 1293 } else { |
| 1312 LoadIsolate(temp_reg); | 1294 LoadIsolate(temp_reg); |
| 1313 intptr_t table_offset = | 1295 intptr_t table_offset = |
| 1314 Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid); | 1296 Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid); |
| 1315 ldr(temp_reg, Address(temp_reg, table_offset)); | 1297 ldr(temp_reg, Address(temp_reg, table_offset)); |
| 1316 AddImmediate(temp_reg, temp_reg, state_offset, pp); | 1298 AddImmediate(temp_reg, temp_reg, state_offset); |
| 1317 } | 1299 } |
| 1318 ldr(temp_reg, Address(temp_reg, 0)); | 1300 ldr(temp_reg, Address(temp_reg, 0)); |
| 1319 tsti(temp_reg, Immediate(ClassHeapStats::TraceAllocationMask())); | 1301 tsti(temp_reg, Immediate(ClassHeapStats::TraceAllocationMask())); |
| 1320 b(trace, NE); | 1302 b(trace, NE); |
| 1321 } | 1303 } |
| 1322 | 1304 |
| 1323 | 1305 |
| 1324 void Assembler::TryAllocate(const Class& cls, | 1306 void Assembler::TryAllocate(const Class& cls, |
| 1325 Label* failure, | 1307 Label* failure, |
| 1326 Register instance_reg, | 1308 Register instance_reg, |
| 1327 Register temp_reg, | 1309 Register temp_reg) { |
| 1328 Register pp) { | |
| 1329 ASSERT(failure != NULL); | 1310 ASSERT(failure != NULL); |
| 1330 if (FLAG_inline_alloc) { | 1311 if (FLAG_inline_alloc) { |
| 1331 // If this allocation is traced, program will jump to failure path | 1312 // If this allocation is traced, program will jump to failure path |
| 1332 // (i.e. the allocation stub) which will allocate the object and trace the | 1313 // (i.e. the allocation stub) which will allocate the object and trace the |
| 1333 // allocation call site. | 1314 // allocation call site. |
| 1334 MaybeTraceAllocation(cls.id(), temp_reg, pp, failure); | 1315 MaybeTraceAllocation(cls.id(), temp_reg, failure); |
| 1335 const intptr_t instance_size = cls.instance_size(); | 1316 const intptr_t instance_size = cls.instance_size(); |
| 1336 Heap* heap = Isolate::Current()->heap(); | 1317 Heap* heap = Isolate::Current()->heap(); |
| 1337 Heap::Space space = heap->SpaceForAllocation(cls.id()); | 1318 Heap::Space space = heap->SpaceForAllocation(cls.id()); |
| 1338 const uword top_address = heap->TopAddress(space); | 1319 const uword top_address = heap->TopAddress(space); |
| 1339 LoadImmediate(temp_reg, top_address, pp); | 1320 LoadImmediate(temp_reg, top_address); |
| 1340 ldr(instance_reg, Address(temp_reg)); | 1321 ldr(instance_reg, Address(temp_reg)); |
| 1341 // TODO(koda): Protect against unsigned overflow here. | 1322 // TODO(koda): Protect against unsigned overflow here. |
| 1342 AddImmediateSetFlags(instance_reg, instance_reg, instance_size, pp); | 1323 AddImmediateSetFlags(instance_reg, instance_reg, instance_size); |
| 1343 | 1324 |
| 1344 // instance_reg: potential next object start. | 1325 // instance_reg: potential next object start. |
| 1345 const uword end_address = heap->EndAddress(space); | 1326 const uword end_address = heap->EndAddress(space); |
| 1346 ASSERT(top_address < end_address); | 1327 ASSERT(top_address < end_address); |
| 1347 // Could use ldm to load (top, end), but no benefit seen experimentally. | 1328 // Could use ldm to load (top, end), but no benefit seen experimentally. |
| 1348 ldr(TMP, Address(temp_reg, end_address - top_address)); | 1329 ldr(TMP, Address(temp_reg, end_address - top_address)); |
| 1349 CompareRegisters(TMP, instance_reg); | 1330 CompareRegisters(TMP, instance_reg); |
| 1350 // fail if heap end unsigned less than or equal to instance_reg. | 1331 // fail if heap end unsigned less than or equal to instance_reg. |
| 1351 b(failure, LS); | 1332 b(failure, LS); |
| 1352 | 1333 |
| 1353 // Successfully allocated the object, now update top to point to | 1334 // Successfully allocated the object, now update top to point to |
| 1354 // next object start and store the class in the class field of object. | 1335 // next object start and store the class in the class field of object. |
| 1355 str(instance_reg, Address(temp_reg)); | 1336 str(instance_reg, Address(temp_reg)); |
| 1356 | 1337 |
| 1357 ASSERT(instance_size >= kHeapObjectTag); | 1338 ASSERT(instance_size >= kHeapObjectTag); |
| 1358 AddImmediate( | 1339 AddImmediate( |
| 1359 instance_reg, instance_reg, -instance_size + kHeapObjectTag, pp); | 1340 instance_reg, instance_reg, -instance_size + kHeapObjectTag); |
| 1360 UpdateAllocationStats(cls.id(), pp, space); | 1341 UpdateAllocationStats(cls.id(), space); |
| 1361 | 1342 |
| 1362 uword tags = 0; | 1343 uword tags = 0; |
| 1363 tags = RawObject::SizeTag::update(instance_size, tags); | 1344 tags = RawObject::SizeTag::update(instance_size, tags); |
| 1364 ASSERT(cls.id() != kIllegalCid); | 1345 ASSERT(cls.id() != kIllegalCid); |
| 1365 tags = RawObject::ClassIdTag::update(cls.id(), tags); | 1346 tags = RawObject::ClassIdTag::update(cls.id(), tags); |
| 1366 LoadImmediate(TMP, tags, pp); | 1347 LoadImmediate(TMP, tags); |
| 1367 StoreFieldToOffset(TMP, instance_reg, Object::tags_offset(), pp); | 1348 StoreFieldToOffset(TMP, instance_reg, Object::tags_offset()); |
| 1368 } else { | 1349 } else { |
| 1369 b(failure); | 1350 b(failure); |
| 1370 } | 1351 } |
| 1371 } | 1352 } |
| 1372 | 1353 |
| 1373 | 1354 |
| 1374 void Assembler::TryAllocateArray(intptr_t cid, | 1355 void Assembler::TryAllocateArray(intptr_t cid, |
| 1375 intptr_t instance_size, | 1356 intptr_t instance_size, |
| 1376 Label* failure, | 1357 Label* failure, |
| 1377 Register instance, | 1358 Register instance, |
| 1378 Register end_address, | 1359 Register end_address, |
| 1379 Register temp1, | 1360 Register temp1, |
| 1380 Register temp2) { | 1361 Register temp2) { |
| 1381 if (FLAG_inline_alloc) { | 1362 if (FLAG_inline_alloc) { |
| 1382 // If this allocation is traced, program will jump to failure path | 1363 // If this allocation is traced, program will jump to failure path |
| 1383 // (i.e. the allocation stub) which will allocate the object and trace the | 1364 // (i.e. the allocation stub) which will allocate the object and trace the |
| 1384 // allocation call site. | 1365 // allocation call site. |
| 1385 MaybeTraceAllocation(cid, temp1, PP, failure); | 1366 MaybeTraceAllocation(cid, temp1, failure); |
| 1386 Isolate* isolate = Isolate::Current(); | 1367 Isolate* isolate = Isolate::Current(); |
| 1387 Heap* heap = isolate->heap(); | 1368 Heap* heap = isolate->heap(); |
| 1388 Heap::Space space = heap->SpaceForAllocation(cid); | 1369 Heap::Space space = heap->SpaceForAllocation(cid); |
| 1389 LoadImmediate(temp1, heap->TopAddress(space), PP); | 1370 LoadImmediate(temp1, heap->TopAddress(space)); |
| 1390 ldr(instance, Address(temp1, 0)); // Potential new object start. | 1371 ldr(instance, Address(temp1, 0)); // Potential new object start. |
| 1391 AddImmediateSetFlags(end_address, instance, instance_size, PP); | 1372 AddImmediateSetFlags(end_address, instance, instance_size); |
| 1392 b(failure, CS); // Fail on unsigned overflow. | 1373 b(failure, CS); // Fail on unsigned overflow. |
| 1393 | 1374 |
| 1394 // Check if the allocation fits into the remaining space. | 1375 // Check if the allocation fits into the remaining space. |
| 1395 // instance: potential new object start. | 1376 // instance: potential new object start. |
| 1396 // end_address: potential next object start. | 1377 // end_address: potential next object start. |
| 1397 LoadImmediate(temp2, heap->EndAddress(space), PP); | 1378 LoadImmediate(temp2, heap->EndAddress(space)); |
| 1398 ldr(temp2, Address(temp2, 0)); | 1379 ldr(temp2, Address(temp2, 0)); |
| 1399 cmp(end_address, Operand(temp2)); | 1380 cmp(end_address, Operand(temp2)); |
| 1400 b(failure, CS); | 1381 b(failure, CS); |
| 1401 | 1382 |
| 1402 // Successfully allocated the object(s), now update top to point to | 1383 // Successfully allocated the object(s), now update top to point to |
| 1403 // next object start and initialize the object. | 1384 // next object start and initialize the object. |
| 1404 str(end_address, Address(temp1, 0)); | 1385 str(end_address, Address(temp1, 0)); |
| 1405 add(instance, instance, Operand(kHeapObjectTag)); | 1386 add(instance, instance, Operand(kHeapObjectTag)); |
| 1406 LoadImmediate(temp2, instance_size, PP); | 1387 LoadImmediate(temp2, instance_size); |
| 1407 UpdateAllocationStatsWithSize(cid, temp2, PP, space); | 1388 UpdateAllocationStatsWithSize(cid, temp2, space); |
| 1408 | 1389 |
| 1409 // Initialize the tags. | 1390 // Initialize the tags. |
| 1410 // instance: new object start as a tagged pointer. | 1391 // instance: new object start as a tagged pointer. |
| 1411 uword tags = 0; | 1392 uword tags = 0; |
| 1412 tags = RawObject::ClassIdTag::update(cid, tags); | 1393 tags = RawObject::ClassIdTag::update(cid, tags); |
| 1413 tags = RawObject::SizeTag::update(instance_size, tags); | 1394 tags = RawObject::SizeTag::update(instance_size, tags); |
| 1414 LoadImmediate(temp2, tags, PP); | 1395 LoadImmediate(temp2, tags); |
| 1415 str(temp2, FieldAddress(instance, Array::tags_offset())); // Store tags. | 1396 str(temp2, FieldAddress(instance, Array::tags_offset())); // Store tags. |
| 1416 } else { | 1397 } else { |
| 1417 b(failure); | 1398 b(failure); |
| 1418 } | 1399 } |
| 1419 } | 1400 } |
| 1420 | 1401 |
| 1421 | 1402 |
| 1422 Address Assembler::ElementAddressForIntIndex(bool is_external, | 1403 Address Assembler::ElementAddressForIntIndex(bool is_external, |
| 1423 intptr_t cid, | 1404 intptr_t cid, |
| 1424 intptr_t index_scale, | 1405 intptr_t index_scale, |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1455 add(base, array, Operand(index, LSL, shift)); | 1436 add(base, array, Operand(index, LSL, shift)); |
| 1456 } | 1437 } |
| 1457 const OperandSize size = Address::OperandSizeFor(cid); | 1438 const OperandSize size = Address::OperandSizeFor(cid); |
| 1458 ASSERT(Address::CanHoldOffset(offset, Address::Offset, size)); | 1439 ASSERT(Address::CanHoldOffset(offset, Address::Offset, size)); |
| 1459 return Address(base, offset, Address::Offset, size); | 1440 return Address(base, offset, Address::Offset, size); |
| 1460 } | 1441 } |
| 1461 | 1442 |
| 1462 } // namespace dart | 1443 } // namespace dart |
| 1463 | 1444 |
| 1464 #endif // defined TARGET_ARCH_ARM64 | 1445 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |