// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef V8_SAFEPOINT_TABLE_H_ #define V8_SAFEPOINT_TABLE_H_ #include "allocation.h" #include "heap.h" #include "v8memory.h" #include "zone.h" namespace v8 { namespace internal { struct Register; class SafepointEntry BASE_EMBEDDED { public: SafepointEntry() : info_(0), bits_(NULL) {} SafepointEntry(unsigned info, uint8_t* bits) : info_(info), bits_(bits) { ASSERT(is_valid()); } bool is_valid() const { return bits_ != NULL; } bool Equals(const SafepointEntry& other) const { return info_ == other.info_ && bits_ == other.bits_; } void Reset() { info_ = 0; bits_ = NULL; } int deoptimization_index() const { ASSERT(is_valid()); return DeoptimizationIndexField::decode(info_); } int gap_code_size() const { ASSERT(is_valid()); return GapCodeSizeField::decode(info_); } int argument_count() const { ASSERT(is_valid()); return ArgumentsField::decode(info_); } bool has_doubles() const { ASSERT(is_valid()); return SaveDoublesField::decode(info_); } uint8_t* bits() { ASSERT(is_valid()); return bits_; } bool HasRegisters() const; bool HasRegisterAt(int reg_index) const; // Reserve 13 bits for the gap code size. On ARM a constant pool can be // emitted when generating the gap code. The size of the const pool is less // than what can be represented in 12 bits, so 13 bits gives room for having // instructions before potentially emitting a constant pool. static const int kGapCodeSizeBits = 13; static const int kArgumentsFieldBits = 3; static const int kSaveDoublesFieldBits = 1; static const int kDeoptIndexBits = 32 - kGapCodeSizeBits - kArgumentsFieldBits - kSaveDoublesFieldBits; class GapCodeSizeField: public BitField {}; class DeoptimizationIndexField: public BitField {}; // NOLINT class ArgumentsField: public BitField {}; // NOLINT class SaveDoublesField: public BitField { }; // NOLINT private: unsigned info_; uint8_t* bits_; }; class SafepointTable BASE_EMBEDDED { public: explicit SafepointTable(Code* code); int size() const { return kHeaderSize + (length_ * (kPcAndDeoptimizationIndexSize + entry_size_)); } unsigned length() const { return length_; } unsigned entry_size() const { return entry_size_; } unsigned GetPcOffset(unsigned index) const { ASSERT(index < length_); return Memory::uint32_at(GetPcOffsetLocation(index)); } SafepointEntry GetEntry(unsigned index) const { ASSERT(index < length_); unsigned info = Memory::uint32_at(GetInfoLocation(index)); uint8_t* bits = &Memory::uint8_at(entries_ + (index * entry_size_)); return SafepointEntry(info, bits); } // Returns the entry for the given pc. SafepointEntry FindEntry(Address pc) const; void PrintEntry(unsigned index) const; private: static const uint8_t kNoRegisters = 0xFF; static const int kLengthOffset = 0; static const int kEntrySizeOffset = kLengthOffset + kIntSize; static const int kHeaderSize = kEntrySizeOffset + kIntSize; static const int kPcSize = kIntSize; static const int kDeoptimizationIndexSize = kIntSize; static const int kPcAndDeoptimizationIndexSize = kPcSize + kDeoptimizationIndexSize; Address GetPcOffsetLocation(unsigned index) const { return pc_and_deoptimization_indexes_ + (index * kPcAndDeoptimizationIndexSize); } Address GetInfoLocation(unsigned index) const { return GetPcOffsetLocation(index) + kPcSize; } static void PrintBits(uint8_t byte, int digits); AssertNoAllocation no_allocation_; Code* code_; unsigned length_; unsigned entry_size_; Address pc_and_deoptimization_indexes_; Address entries_; friend class SafepointTableBuilder; friend class SafepointEntry; DISALLOW_COPY_AND_ASSIGN(SafepointTable); }; class Safepoint BASE_EMBEDDED { public: typedef enum { kSimple = 0, kWithRegisters = 1 << 0, kWithDoubles = 1 << 1, kWithRegistersAndDoubles = kWithRegisters | kWithDoubles } Kind; static const int kNoDeoptimizationIndex = (1 << (SafepointEntry::kDeoptIndexBits)) - 1; void DefinePointerSlot(int index) { indexes_->Add(index); } void DefinePointerRegister(Register reg); private: Safepoint(ZoneList* indexes, ZoneList* registers) : indexes_(indexes), registers_(registers) { } ZoneList* indexes_; ZoneList* registers_; friend class SafepointTableBuilder; }; class SafepointTableBuilder BASE_EMBEDDED { public: SafepointTableBuilder() : deoptimization_info_(32), indexes_(32), registers_(32), emitted_(false) { } // Get the offset of the emitted safepoint table in the code. unsigned GetCodeOffset() const; // Define a new safepoint for the current position in the body. Safepoint DefineSafepoint(Assembler* assembler, Safepoint::Kind kind, int arguments, int deoptimization_index); // Update the last safepoint with the size of the code generated until the // end of the gap following it. void SetPcAfterGap(int pc) { ASSERT(!deoptimization_info_.is_empty()); int index = deoptimization_info_.length() - 1; deoptimization_info_[index].pc_after_gap = pc; } // Get the end pc offset of the last safepoint, including the code generated // until the end of the gap following it. unsigned GetPcAfterGap() { int index = deoptimization_info_.length(); if (index == 0) return 0; return deoptimization_info_[index - 1].pc_after_gap; } // Emit the safepoint table after the body. The number of bits per // entry must be enough to hold all the pointer indexes. void Emit(Assembler* assembler, int bits_per_entry); // Count the number of deoptimization points where the next // following deoptimization point comes less than limit bytes // after the end of this point's gap. int CountShortDeoptimizationIntervals(unsigned limit); private: struct DeoptimizationInfo { unsigned pc; unsigned deoptimization_index; unsigned pc_after_gap; unsigned arguments; bool has_doubles; }; uint32_t EncodeExceptPC(const DeoptimizationInfo& info); ZoneList deoptimization_info_; ZoneList*> indexes_; ZoneList*> registers_; unsigned offset_; bool emitted_; DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder); }; } } // namespace v8::internal #endif // V8_SAFEPOINT_TABLE_H_