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

Side by Side Diff: src/arm64/assembler-arm64.cc

Issue 338523005: ARM64: updated literal pool implementation. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 6 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
« src/arm64/assembler-arm64.h ('K') | « src/arm64/assembler-arm64.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // 2 //
3 // Redistribution and use in source and binary forms, with or without 3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are 4 // modification, are permitted provided that the following conditions are
5 // met: 5 // met:
6 // 6 //
7 // * Redistributions of source code must retain the above copyright 7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer. 8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above 9 // * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following 10 // copyright notice, this list of conditions and the following
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 RelocInfo::Mode rmode = immediate_.rmode(); 289 RelocInfo::Mode rmode = immediate_.rmode();
290 290
291 if (rmode == RelocInfo::EXTERNAL_REFERENCE) { 291 if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
292 return assembler->serializer_enabled(); 292 return assembler->serializer_enabled();
293 } 293 }
294 294
295 return !RelocInfo::IsNone(rmode); 295 return !RelocInfo::IsNone(rmode);
296 } 296 }
297 297
298 298
299 // Constant Pool.
300 void ConstPool::RecordEntry(intptr_t data,
301 RelocInfo::Mode mode) {
302 ASSERT(mode != RelocInfo::COMMENT &&
303 mode != RelocInfo::POSITION &&
304 mode != RelocInfo::STATEMENT_POSITION &&
305 mode != RelocInfo::CONST_POOL &&
306 mode != RelocInfo::VENEER_POOL &&
307 mode != RelocInfo::CODE_AGE_SEQUENCE);
308
309 uint64_t raw_data = static_cast<uint64_t>(data);
310 int offset = assm_->pc_offset();
311 if (IsEmpty()) {
312 first_use_ = offset;
313 }
314
315 std::pair<uint64_t, int> entry = std::make_pair(raw_data, offset);
316 if (CanBeShared(mode)) {
317 shared_entries_.insert(entry);
318 if (shared_entries_.count(entry.first) == 1) {
319 shared_entries_count++;
320 }
321 } else {
322 unique_entries_.push_back(entry);
323 }
324 }
325
326
327 int ConstPool::DistanceToFirstUse() {
328 ASSERT(first_use_ >= 0);
329 return assm_->pc_offset() - first_use_;
330 }
331
332
333 int ConstPool::MaxPcOffset() {
334 // There are no pending entries in the pool so we can never get out of
335 // range.
336 if (IsEmpty()) return kMaxInt;
337
338 // Entries can be reshuffled so in the worst case the first constant pool use
339 // will be accessing the last entry.
rmcilroy 2014/06/17 13:09:56 nit - this comment was a bit unclear to me first (
Rodolph Perfetta (ARM) 2014/06/18 16:53:22 Done.
340 return first_use_ + kMaxLoadLiteralRange - WorstCaseSize();
341 }
342
343
344 int ConstPool::WorstCaseSize() {
345 if (IsEmpty()) return 0;
346
347 // Max size prologue:
348 // b over
349 // ldr xzr, #pool_size
350 // blr xzr
351 // nop
352 // All entries are 64-bit for now.
353 return 4 * kInstructionSize + EntryCount() * kPointerSize;
354 }
355
356
357 int ConstPool::SizeIfEmittedAtCurrentPc(bool require_jump) {
358 if (IsEmpty()) return 0;
359
360 // Prologue is:
361 // b over ;; if require_jump
362 // ldr xzr, #pool_size
363 // blr xzr
364 // nop ;; if not 64-bit aligned
365 int prologue_size = require_jump ? kInstructionSize : 0;
366 prologue_size += 2 * kInstructionSize;
367 prologue_size += IsAligned(assm_->pc_offset() + prologue_size, 8) ?
368 0 : kInstructionSize;
369
370 // All entries are 64-bit for now.
371 return prologue_size + EntryCount() * kPointerSize;
372 }
373
374
375 void ConstPool::Emit(bool require_jump) {
376 ASSERT(assm_->is_const_pool_blocked());
rmcilroy 2014/06/17 13:09:57 This is a bit counter intuitive - maybe have the B
Rodolph Perfetta (ARM) 2014/06/18 16:53:23 Done.
377
378 int size = SizeIfEmittedAtCurrentPc(require_jump);
379 Label size_check;
380 assm_->bind(&size_check);
381
382 assm_->RecordConstPool(size);
383 // Emit the constant pool. It is preceded by an optional branch if
384 // require_jump and a header which will:
385 // 1) Encode the size of the constant pool, for use by the disassembler.
386 // 2) Terminate the program, to try to prevent execution from accidentally
387 // flowing into the constant pool.
388 // 3) align the pool entries to 64-bit.
389 // The header is therefore made of up to three arm64 instructions:
390 // ldr xzr, #<size of the constant pool in 32-bit words>
391 // blr xzr
392 // nop
393 //
394 // If executed, the header will likely segfault and lr will point to the
395 // instruction following the offending blr.
396 // TODO(all): Make the alignment part less fragile. Currently code is
397 // allocated as a byte array so there are no guarantees the alignment will
398 // be preserved on compaction. Currently it works as allocation seems to be
399 // 64-bit aligned.
400
401 // Emit branch if required
402 Label after_pool;
403 if (require_jump) {
404 assm_->b(&after_pool);
405 }
406
407 // Emit the header.
408 assm_->RecordComment("[ Constant Pool");
409 EmitMarker();
410 EmitGuard();
411 assm_->Align(8);
412
413 // Emit constant pool entries.
414 // TODO(all): currently each relocated constant is 64 bits, consider adding
415 // support for 32-bit entries.
416 EmitEntries();
417 assm_->RecordComment("]");
418
419 if (after_pool.is_linked()) {
420 assm_->bind(&after_pool);
421 }
422
423 ASSERT(assm_->SizeOfCodeGeneratedSince(&size_check) ==
424 static_cast<unsigned>(size));
425 }
426
427
428 void ConstPool::Clear() {
429 shared_entries_.clear();
430 shared_entries_count = 0;
431 unique_entries_.clear();
432 first_use_ = -1;
433 }
434
435
436 bool ConstPool::CanBeShared(RelocInfo::Mode mode) {
437 // Constant pool currently does not support 32-bit entries.
438 ASSERT(mode != RelocInfo::NONE32);
439
440 return RelocInfo::IsNone(mode) ||
441 (!assm_->serializer_enabled() && (mode >= RelocInfo::CELL));
442 }
443
444
445 void ConstPool::EmitMarker() {
446 // A constant pool size is expressed in number of 32-bits words.
447 // Currently all entries are 64-bit.
448 // + 1 is for the crash guard.
449 // + 0/1 for alignment.
450 int word_count = EntryCount() * 2 + 1 +
451 (IsAligned(assm_->pc_offset(), 8)) ? 0 : 1;
452 assm_->Emit(LDR_x_lit |
453 Assembler::ImmLLiteral(word_count) |
454 Assembler::Rt(xzr));
455 }
456
457
458 void ConstPool::EmitGuard() {
459 #ifdef DEBUG
460 Instruction* instr = reinterpret_cast<Instruction*>(assm_->pc());
461 ASSERT(instr->preceding()->IsLdrLiteralX() &&
462 instr->preceding()->Rt() == xzr.code());
463 #endif
464 assm_->EmitPoolGuard();
465 }
466
467
468 void ConstPool::EmitEntries() {
469 ASSERT(IsAligned(assm_->pc_offset(), 8));
470
471 // Emit shared entries.
472 while (!shared_entries_.empty()) {
473 typedef std::multimap<uint64_t, int>::const_iterator shared_entries_it;
rmcilroy 2014/06/17 13:09:57 Use Type style name for shared_entries_it (e.g., C
Rodolph Perfetta (ARM) 2014/06/18 16:53:22 Done.
474 std::pair<shared_entries_it, shared_entries_it> range;
475 uint64_t data = shared_entries_.begin()->first;
476 range = shared_entries_.equal_range(data);
477 shared_entries_it shared_it;
478 for (shared_it = range.first; shared_it != range.second; shared_it++) {
479 Instruction* instr = assm_->InstructionAt(shared_it->second);
480
481 // Instruction to patch must be 'ldr rd, [pc, #offset]' with offset == 0.
482 ASSERT(instr->IsLdrLiteral() && instr->ImmLLiteral() == 0);
483 instr->SetImmPCOffsetTarget(assm_->pc());
484 }
485 assm_->dc64(data);
486 shared_entries_.erase(data);
rmcilroy 2014/06/17 13:09:57 nit - could you leave the entry here and just do s
Rodolph Perfetta (ARM) 2014/06/18 16:53:23 Loop updated to iterate through literals and then
487 }
488 shared_entries_count = 0;
489
490 // Emit unique entries.
491 std::vector<std::pair<uint64_t, int> >::const_iterator unique_it;
492 for (unique_it = unique_entries_.begin();
493 unique_it != unique_entries_.end();
494 unique_it++) {
495 Instruction* instr = assm_->InstructionAt(unique_it->second);
496
497 // Instruction to patch must be 'ldr rd, [pc, #offset]' with offset == 0.
498 ASSERT(instr->IsLdrLiteral() && instr->ImmLLiteral() == 0);
499 instr->SetImmPCOffsetTarget(assm_->pc());
500 assm_->dc64(unique_it->first);
501 }
502 unique_entries_.clear();
503 first_use_ = -1;
504 }
505
506
299 // Assembler 507 // Assembler
300
301 Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size) 508 Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
302 : AssemblerBase(isolate, buffer, buffer_size), 509 : AssemblerBase(isolate, buffer, buffer_size),
510 constpool_(this),
303 recorded_ast_id_(TypeFeedbackId::None()), 511 recorded_ast_id_(TypeFeedbackId::None()),
304 unresolved_branches_(), 512 unresolved_branches_(),
305 positions_recorder_(this) { 513 positions_recorder_(this) {
306 const_pool_blocked_nesting_ = 0; 514 const_pool_blocked_nesting_ = 0;
307 veneer_pool_blocked_nesting_ = 0; 515 veneer_pool_blocked_nesting_ = 0;
308 Reset(); 516 Reset();
309 } 517 }
310 518
311 519
312 Assembler::~Assembler() { 520 Assembler::~Assembler() {
313 ASSERT(num_pending_reloc_info_ == 0); 521 ASSERT(constpool_.IsEmpty());
314 ASSERT(const_pool_blocked_nesting_ == 0); 522 ASSERT(const_pool_blocked_nesting_ == 0);
315 ASSERT(veneer_pool_blocked_nesting_ == 0); 523 ASSERT(veneer_pool_blocked_nesting_ == 0);
316 } 524 }
317 525
318 526
319 void Assembler::Reset() { 527 void Assembler::Reset() {
320 #ifdef DEBUG 528 #ifdef DEBUG
321 ASSERT((pc_ >= buffer_) && (pc_ < buffer_ + buffer_size_)); 529 ASSERT((pc_ >= buffer_) && (pc_ < buffer_ + buffer_size_));
322 ASSERT(const_pool_blocked_nesting_ == 0); 530 ASSERT(const_pool_blocked_nesting_ == 0);
323 ASSERT(veneer_pool_blocked_nesting_ == 0); 531 ASSERT(veneer_pool_blocked_nesting_ == 0);
324 ASSERT(unresolved_branches_.empty()); 532 ASSERT(unresolved_branches_.empty());
325 memset(buffer_, 0, pc_ - buffer_); 533 memset(buffer_, 0, pc_ - buffer_);
326 #endif 534 #endif
327 pc_ = buffer_; 535 pc_ = buffer_;
328 reloc_info_writer.Reposition(reinterpret_cast<byte*>(buffer_ + buffer_size_), 536 reloc_info_writer.Reposition(reinterpret_cast<byte*>(buffer_ + buffer_size_),
329 reinterpret_cast<byte*>(pc_)); 537 reinterpret_cast<byte*>(pc_));
330 num_pending_reloc_info_ = 0; 538 constpool_.Clear();
331 next_constant_pool_check_ = 0; 539 next_constant_pool_check_ = 0;
332 next_veneer_pool_check_ = kMaxInt; 540 next_veneer_pool_check_ = kMaxInt;
333 no_const_pool_before_ = 0; 541 no_const_pool_before_ = 0;
334 first_const_pool_use_ = -1;
335 ClearRecordedAstId(); 542 ClearRecordedAstId();
336 } 543 }
337 544
338 545
339 void Assembler::GetCode(CodeDesc* desc) { 546 void Assembler::GetCode(CodeDesc* desc) {
340 // Emit constant pool if necessary. 547 // Emit constant pool if necessary.
341 CheckConstPool(true, false); 548 CheckConstPool(true, false);
342 ASSERT(num_pending_reloc_info_ == 0); 549 ASSERT(constpool_.IsEmpty());
343 550
344 // Set up code descriptor. 551 // Set up code descriptor.
345 if (desc) { 552 if (desc) {
346 desc->buffer = reinterpret_cast<byte*>(buffer_); 553 desc->buffer = reinterpret_cast<byte*>(buffer_);
347 desc->buffer_size = buffer_size_; 554 desc->buffer_size = buffer_size_;
348 desc->instr_size = pc_offset(); 555 desc->instr_size = pc_offset();
349 desc->reloc_size = (reinterpret_cast<byte*>(buffer_) + buffer_size_) - 556 desc->reloc_size = (reinterpret_cast<byte*>(buffer_) + buffer_size_) -
350 reloc_info_writer.pos(); 557 reloc_info_writer.pos();
351 desc->origin = this; 558 desc->origin = this;
352 } 559 }
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
615 // Prevent constant pool checks happening by setting the next check to 822 // Prevent constant pool checks happening by setting the next check to
616 // the biggest possible offset. 823 // the biggest possible offset.
617 next_constant_pool_check_ = kMaxInt; 824 next_constant_pool_check_ = kMaxInt;
618 } 825 }
619 } 826 }
620 827
621 828
622 void Assembler::EndBlockConstPool() { 829 void Assembler::EndBlockConstPool() {
623 if (--const_pool_blocked_nesting_ == 0) { 830 if (--const_pool_blocked_nesting_ == 0) {
624 // Check the constant pool hasn't been blocked for too long. 831 // Check the constant pool hasn't been blocked for too long.
625 ASSERT((num_pending_reloc_info_ == 0) || 832 ASSERT(pc_offset() < constpool_.MaxPcOffset());
626 (pc_offset() < (first_const_pool_use_ + kMaxDistToConstPool)));
627 // Two cases: 833 // Two cases:
628 // * no_const_pool_before_ >= next_constant_pool_check_ and the emission is 834 // * no_const_pool_before_ >= next_constant_pool_check_ and the emission is
629 // still blocked 835 // still blocked
630 // * no_const_pool_before_ < next_constant_pool_check_ and the next emit 836 // * no_const_pool_before_ < next_constant_pool_check_ and the next emit
631 // will trigger a check. 837 // will trigger a check.
632 next_constant_pool_check_ = no_const_pool_before_; 838 next_constant_pool_check_ = no_const_pool_before_;
633 } 839 }
634 } 840 }
635 841
636 842
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
675 } 881 }
676 #endif 882 #endif
677 if (IsConstantPoolAt(instr)) { 883 if (IsConstantPoolAt(instr)) {
678 return instr->ImmLLiteral(); 884 return instr->ImmLLiteral();
679 } else { 885 } else {
680 return -1; 886 return -1;
681 } 887 }
682 } 888 }
683 889
684 890
685 void Assembler::ConstantPoolMarker(uint32_t size) {
686 ASSERT(is_const_pool_blocked());
687 // + 1 is for the crash guard.
688 Emit(LDR_x_lit | ImmLLiteral(size + 1) | Rt(xzr));
689 }
690
691
692 void Assembler::EmitPoolGuard() { 891 void Assembler::EmitPoolGuard() {
693 // We must generate only one instruction as this is used in scopes that 892 // We must generate only one instruction as this is used in scopes that
694 // control the size of the code generated. 893 // control the size of the code generated.
695 Emit(BLR | Rn(xzr)); 894 Emit(BLR | Rn(xzr));
696 } 895 }
697 896
698 897
699 void Assembler::ConstantPoolGuard() {
700 #ifdef DEBUG
701 // Currently this is only used after a constant pool marker.
702 ASSERT(is_const_pool_blocked());
703 Instruction* instr = reinterpret_cast<Instruction*>(pc_);
704 ASSERT(instr->preceding()->IsLdrLiteralX() &&
705 instr->preceding()->Rt() == xzr.code());
706 #endif
707 EmitPoolGuard();
708 }
709
710
711 void Assembler::StartBlockVeneerPool() { 898 void Assembler::StartBlockVeneerPool() {
712 ++veneer_pool_blocked_nesting_; 899 ++veneer_pool_blocked_nesting_;
713 } 900 }
714 901
715 902
716 void Assembler::EndBlockVeneerPool() { 903 void Assembler::EndBlockVeneerPool() {
717 if (--veneer_pool_blocked_nesting_ == 0) { 904 if (--veneer_pool_blocked_nesting_ == 0) {
718 // Check the veneer pool hasn't been blocked for too long. 905 // Check the veneer pool hasn't been blocked for too long.
719 ASSERT(unresolved_branches_.empty() || 906 ASSERT(unresolved_branches_.empty() ||
720 (pc_offset() < unresolved_branches_first_limit())); 907 (pc_offset() < unresolved_branches_first_limit()));
(...skipping 1738 matching lines...) Expand 10 before | Expand all | Expand 10 after
2459 buffer_ = desc.buffer; 2646 buffer_ = desc.buffer;
2460 buffer_size_ = desc.buffer_size; 2647 buffer_size_ = desc.buffer_size;
2461 pc_ = reinterpret_cast<byte*>(pc_) + pc_delta; 2648 pc_ = reinterpret_cast<byte*>(pc_) + pc_delta;
2462 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, 2649 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
2463 reloc_info_writer.last_pc() + pc_delta); 2650 reloc_info_writer.last_pc() + pc_delta);
2464 2651
2465 // None of our relocation types are pc relative pointing outside the code 2652 // None of our relocation types are pc relative pointing outside the code
2466 // buffer nor pc absolute pointing inside the code buffer, so there is no need 2653 // buffer nor pc absolute pointing inside the code buffer, so there is no need
2467 // to relocate any emitted relocation entries. 2654 // to relocate any emitted relocation entries.
2468 2655
2469 // Relocate pending relocation entries. 2656 // Pending relocation entries are also relative, no need to relocate.
2470 for (int i = 0; i < num_pending_reloc_info_; i++) {
2471 RelocInfo& rinfo = pending_reloc_info_[i];
2472 ASSERT(rinfo.rmode() != RelocInfo::COMMENT &&
2473 rinfo.rmode() != RelocInfo::POSITION);
2474 if (rinfo.rmode() != RelocInfo::JS_RETURN) {
2475 rinfo.set_pc(rinfo.pc() + pc_delta);
2476 }
2477 }
2478 } 2657 }
2479 2658
2480 2659
2481 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { 2660 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
2482 // We do not try to reuse pool constants. 2661 // We do not try to reuse pool constants.
2483 RelocInfo rinfo(reinterpret_cast<byte*>(pc_), rmode, data, NULL); 2662 RelocInfo rinfo(reinterpret_cast<byte*>(pc_), rmode, data, NULL);
2484 if (((rmode >= RelocInfo::JS_RETURN) && 2663 if (((rmode >= RelocInfo::JS_RETURN) &&
2485 (rmode <= RelocInfo::DEBUG_BREAK_SLOT)) || 2664 (rmode <= RelocInfo::DEBUG_BREAK_SLOT)) ||
2486 (rmode == RelocInfo::CONST_POOL) || 2665 (rmode == RelocInfo::CONST_POOL) ||
2487 (rmode == RelocInfo::VENEER_POOL)) { 2666 (rmode == RelocInfo::VENEER_POOL)) {
2488 // Adjust code for new modes. 2667 // Adjust code for new modes.
2489 ASSERT(RelocInfo::IsDebugBreakSlot(rmode) 2668 ASSERT(RelocInfo::IsDebugBreakSlot(rmode)
2490 || RelocInfo::IsJSReturn(rmode) 2669 || RelocInfo::IsJSReturn(rmode)
2491 || RelocInfo::IsComment(rmode) 2670 || RelocInfo::IsComment(rmode)
2492 || RelocInfo::IsPosition(rmode) 2671 || RelocInfo::IsPosition(rmode)
2493 || RelocInfo::IsConstPool(rmode) 2672 || RelocInfo::IsConstPool(rmode)
2494 || RelocInfo::IsVeneerPool(rmode)); 2673 || RelocInfo::IsVeneerPool(rmode));
2495 // These modes do not need an entry in the constant pool. 2674 // These modes do not need an entry in the constant pool.
2496 } else { 2675 } else {
2497 ASSERT(num_pending_reloc_info_ < kMaxNumPendingRelocInfo); 2676 if (constpool_.EntryCount() > kApproximatePoolEntryCount) {
rmcilroy 2014/06/17 13:09:57 Could we just do both this check and the check for
Rodolph Perfetta (ARM) 2014/06/18 16:53:23 moving the this code in RecordEntry is a good idea
2498 if (num_pending_reloc_info_ == 0) { 2677 // It is time to emit the constant pool after this instruction.
2499 first_const_pool_use_ = pc_offset(); 2678 next_constant_pool_check_ = pc_offset() + kInstructionSize;
2500 } 2679 }
2501 pending_reloc_info_[num_pending_reloc_info_++] = rinfo; 2680
2681 constpool_.RecordEntry(data, rmode);
2502 // Make sure the constant pool is not emitted in place of the next 2682 // Make sure the constant pool is not emitted in place of the next
2503 // instruction for which we just recorded relocation info. 2683 // instruction for which we just recorded relocation info.
2504 BlockConstPoolFor(1); 2684 BlockConstPoolFor(1);
2505 } 2685 }
2506 2686
2507 if (!RelocInfo::IsNone(rmode)) { 2687 if (!RelocInfo::IsNone(rmode)) {
2508 // Don't record external references unless the heap will be serialized. 2688 // Don't record external references unless the heap will be serialized.
2509 if (rmode == RelocInfo::EXTERNAL_REFERENCE && 2689 if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
2510 !serializer_enabled() && !emit_debug_code()) { 2690 !serializer_enabled() && !emit_debug_code()) {
2511 return; 2691 return;
2512 } 2692 }
2513 ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here 2693 ASSERT(buffer_space() >= kMaxRelocSize); // too late to grow buffer here
2514 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) { 2694 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
2515 RelocInfo reloc_info_with_ast_id( 2695 RelocInfo reloc_info_with_ast_id(
2516 reinterpret_cast<byte*>(pc_), rmode, RecordedAstId().ToInt(), NULL); 2696 reinterpret_cast<byte*>(pc_), rmode, RecordedAstId().ToInt(), NULL);
2517 ClearRecordedAstId(); 2697 ClearRecordedAstId();
2518 reloc_info_writer.Write(&reloc_info_with_ast_id); 2698 reloc_info_writer.Write(&reloc_info_with_ast_id);
2519 } else { 2699 } else {
2520 reloc_info_writer.Write(&rinfo); 2700 reloc_info_writer.Write(&rinfo);
2521 } 2701 }
2522 } 2702 }
2523 } 2703 }
2524 2704
2525 2705
2526 void Assembler::BlockConstPoolFor(int instructions) { 2706 void Assembler::BlockConstPoolFor(int instructions) {
2527 int pc_limit = pc_offset() + instructions * kInstructionSize; 2707 int pc_limit = pc_offset() + instructions * kInstructionSize;
2528 if (no_const_pool_before_ < pc_limit) { 2708 if (no_const_pool_before_ < pc_limit) {
2529 // If there are some pending entries, the constant pool cannot be blocked
2530 // further than first_const_pool_use_ + kMaxDistToConstPool
2531 ASSERT((num_pending_reloc_info_ == 0) ||
2532 (pc_limit < (first_const_pool_use_ + kMaxDistToConstPool)));
2533 no_const_pool_before_ = pc_limit; 2709 no_const_pool_before_ = pc_limit;
2710 // Make sure the pool won't be blocked for too long.
2711 ASSERT(pc_limit < constpool_.MaxPcOffset());
2534 } 2712 }
2535 2713
2536 if (next_constant_pool_check_ < no_const_pool_before_) { 2714 if (next_constant_pool_check_ < no_const_pool_before_) {
2537 next_constant_pool_check_ = no_const_pool_before_; 2715 next_constant_pool_check_ = no_const_pool_before_;
2538 } 2716 }
2539 } 2717 }
2540 2718
2541 2719
2542 void Assembler::CheckConstPool(bool force_emit, bool require_jump) { 2720 void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
2543 // Some short sequence of instruction mustn't be broken up by constant pool 2721 // Some short sequence of instruction mustn't be broken up by constant pool
2544 // emission, such sequences are protected by calls to BlockConstPoolFor and 2722 // emission, such sequences are protected by calls to BlockConstPoolFor and
2545 // BlockConstPoolScope. 2723 // BlockConstPoolScope.
2546 if (is_const_pool_blocked()) { 2724 if (is_const_pool_blocked()) {
2547 // Something is wrong if emission is forced and blocked at the same time. 2725 // Something is wrong if emission is forced and blocked at the same time.
2548 ASSERT(!force_emit); 2726 ASSERT(!force_emit);
2549 return; 2727 return;
2550 } 2728 }
2551 2729
2552 // There is nothing to do if there are no pending constant pool entries. 2730 // There is nothing to do if there are no pending constant pool entries.
2553 if (num_pending_reloc_info_ == 0) { 2731 if (constpool_.IsEmpty()) {
2554 // Calculate the offset of the next check. 2732 // Calculate the offset of the next check.
2555 next_constant_pool_check_ = pc_offset() + kCheckConstPoolInterval; 2733 next_constant_pool_check_ = pc_offset() + kCheckConstPoolInterval;
2556 return; 2734 return;
2557 } 2735 }
2558 2736
2559 // We emit a constant pool when: 2737 // We emit a constant pool when:
2560 // * requested to do so by parameter force_emit (e.g. after each function). 2738 // * requested to do so by parameter force_emit (e.g. after each function).
2561 // * the distance to the first instruction accessing the constant pool is 2739 // * the distance to the first instruction accessing the constant pool is
2562 // kAvgDistToConstPool or more. 2740 // kApproximateDistToConstPool or more.
2563 // * no jump is required and the distance to the first instruction accessing 2741 // * the number of entries in the pool is kApproximatePoolEntryCount or more.
2564 // the constant pool is at least kMaxDistToPConstool / 2. 2742 int dist = constpool_.DistanceToFirstUse();
2565 ASSERT(first_const_pool_use_ >= 0); 2743 int count = constpool_.EntryCount();
2566 int dist = pc_offset() - first_const_pool_use_; 2744 if (!force_emit &&
2567 if (!force_emit && dist < kAvgDistToConstPool && 2745 (dist < kApproximateDistToConstPool) &&
2568 (require_jump || (dist < (kMaxDistToConstPool / 2)))) { 2746 (count < kApproximatePoolEntryCount)) {
2569 return; 2747 return;
2570 } 2748 }
2571 2749
2572 int jump_instr = require_jump ? kInstructionSize : 0;
2573 int size_pool_marker = kInstructionSize;
2574 int size_pool_guard = kInstructionSize;
2575 int pool_size = jump_instr + size_pool_marker + size_pool_guard +
2576 num_pending_reloc_info_ * kPointerSize;
2577 int needed_space = pool_size + kGap;
2578 2750
2579 // Emit veneers for branches that would go out of range during emission of the 2751 // Emit veneers for branches that would go out of range during emission of the
2580 // constant pool. 2752 // constant pool.
2581 CheckVeneerPool(false, require_jump, kVeneerDistanceMargin + pool_size); 2753 int size = constpool_.WorstCaseSize();
rmcilroy 2014/06/17 13:09:57 s/size/worst_case_size
Rodolph Perfetta (ARM) 2014/06/18 16:53:22 Done.
2754 CheckVeneerPool(false, require_jump, kVeneerDistanceMargin + size);
2582 2755
2583 Label size_check; 2756 // Buffer checks happen after an emit hence the 2 * kInstructionSize.
rmcilroy 2014/06/17 13:09:57 I'm not sure what the buffer checks you mention he
Rodolph Perfetta (ARM) 2014/06/18 16:53:23 My comment is clumsy and inaccurate. What I meant
2584 bind(&size_check); 2757 int needed_space = size + kGap + 2 * kInstructionSize;
2585
2586 // Check that the code buffer is large enough before emitting the constant 2758 // Check that the code buffer is large enough before emitting the constant
2587 // pool (include the jump over the pool, the constant pool marker, the 2759 // pool (include the jump over the pool, the constant pool marker, the
2588 // constant pool guard, and the gap to the relocation information). 2760 // constant pool guard, and the gap to the relocation information).
2589 while (buffer_space() <= needed_space) { 2761 while (buffer_space() < needed_space) {
2590 GrowBuffer(); 2762 GrowBuffer();
2591 } 2763 }
2592 2764
2593 { 2765 {
2594 // Block recursive calls to CheckConstPool and protect from veneer pools. 2766 // Block recursive calls to CheckConstPool and protect from veneer pools.
2595 BlockPoolsScope block_pools(this); 2767 BlockPoolsScope block_pools(this);
2596 RecordConstPool(pool_size); 2768 constpool_.Emit(require_jump);
2597
2598 // Emit jump over constant pool if necessary.
2599 Label after_pool;
2600 if (require_jump) {
2601 b(&after_pool);
2602 }
2603
2604 // Emit a constant pool header. The header has two goals:
2605 // 1) Encode the size of the constant pool, for use by the disassembler.
2606 // 2) Terminate the program, to try to prevent execution from accidentally
2607 // flowing into the constant pool.
2608 // The header is therefore made of two arm64 instructions:
2609 // ldr xzr, #<size of the constant pool in 32-bit words>
2610 // blr xzr
2611 // If executed the code will likely segfault and lr will point to the
2612 // beginning of the constant pool.
2613 // TODO(all): currently each relocated constant is 64 bits, consider adding
2614 // support for 32-bit entries.
2615 RecordComment("[ Constant Pool");
2616 ConstantPoolMarker(2 * num_pending_reloc_info_);
2617 ConstantPoolGuard();
2618
2619 // Emit constant pool entries.
2620 for (int i = 0; i < num_pending_reloc_info_; i++) {
2621 RelocInfo& rinfo = pending_reloc_info_[i];
2622 ASSERT(rinfo.rmode() != RelocInfo::COMMENT &&
2623 rinfo.rmode() != RelocInfo::POSITION &&
2624 rinfo.rmode() != RelocInfo::STATEMENT_POSITION &&
2625 rinfo.rmode() != RelocInfo::CONST_POOL &&
2626 rinfo.rmode() != RelocInfo::VENEER_POOL);
2627
2628 Instruction* instr = reinterpret_cast<Instruction*>(rinfo.pc());
2629 // Instruction to patch must be 'ldr rd, [pc, #offset]' with offset == 0.
2630 ASSERT(instr->IsLdrLiteral() &&
2631 instr->ImmLLiteral() == 0);
2632
2633 instr->SetImmPCOffsetTarget(reinterpret_cast<Instruction*>(pc_));
2634 dc64(rinfo.data());
2635 }
2636
2637 num_pending_reloc_info_ = 0;
2638 first_const_pool_use_ = -1;
2639
2640 RecordComment("]");
2641
2642 if (after_pool.is_linked()) {
2643 bind(&after_pool);
2644 }
2645 } 2769 }
2646 2770
2647 // Since a constant pool was just emitted, move the check offset forward by 2771 // Since a constant pool was just emitted, move the check offset forward by
2648 // the standard interval. 2772 // the standard interval.
2649 next_constant_pool_check_ = pc_offset() + kCheckConstPoolInterval; 2773 next_constant_pool_check_ = pc_offset() + kCheckConstPoolInterval;
2650
2651 ASSERT(SizeOfCodeGeneratedSince(&size_check) ==
2652 static_cast<unsigned>(pool_size));
2653 } 2774 }
rmcilroy 2014/06/17 13:09:57 Add an assert that the size of code generated was
Rodolph Perfetta (ARM) 2014/06/18 16:53:22 Done.
2654 2775
2655 2776
2656 bool Assembler::ShouldEmitVeneer(int max_reachable_pc, int margin) { 2777 bool Assembler::ShouldEmitVeneer(int max_reachable_pc, int margin) {
2657 // Account for the branch around the veneers and the guard. 2778 // Account for the branch around the veneers and the guard.
2658 int protection_offset = 2 * kInstructionSize; 2779 int protection_offset = 2 * kInstructionSize;
2659 return pc_offset() > max_reachable_pc - margin - protection_offset - 2780 return pc_offset() > max_reachable_pc - margin - protection_offset -
2660 static_cast<int>(unresolved_branches_.size() * kMaxVeneerCodeSize); 2781 static_cast<int>(unresolved_branches_.size() * kMaxVeneerCodeSize);
2661 } 2782 }
2662 2783
2663 2784
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
2883 adr(rd, 0); 3004 adr(rd, 0);
2884 MovInt64(scratch, target_offset); 3005 MovInt64(scratch, target_offset);
2885 add(rd, rd, scratch); 3006 add(rd, rd, scratch);
2886 } 3007 }
2887 } 3008 }
2888 3009
2889 3010
2890 } } // namespace v8::internal 3011 } } // namespace v8::internal
2891 3012
2892 #endif // V8_TARGET_ARCH_ARM64 3013 #endif // V8_TARGET_ARCH_ARM64
OLDNEW
« src/arm64/assembler-arm64.h ('K') | « src/arm64/assembler-arm64.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698