From e2f8c938c3aeced3dd73b995cd0dbb2076792488 Mon Sep 17 00:00:00 2001 From: "vitalyr@chromium.org" Date: Wed, 12 Jan 2011 14:14:14 +0000 Subject: [PATCH] Allow arguments in safepoints with registers. This should enable calling runtime functions with arguments from deferred lithium code. Review URL: http://codereview.chromium.org/6125007 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6285 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/deoptimizer-arm.cc | 5 +- src/frames.cc | 45 +++++++------- src/frames.h | 6 +- src/ia32/deoptimizer-ia32.cc | 5 +- src/objects.cc | 18 +++--- src/objects.h | 8 ++- src/safepoint-table.cc | 76 +++++++++++++++--------- src/safepoint-table.h | 110 +++++++++++++++++++++++++---------- 8 files changed, 176 insertions(+), 97 deletions(-) diff --git a/src/arm/deoptimizer-arm.cc b/src/arm/deoptimizer-arm.cc index 3917d6dfb..8a53d1cbd 100644 --- a/src/arm/deoptimizer-arm.cc +++ b/src/arm/deoptimizer-arm.cc @@ -55,8 +55,9 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { SafepointTable table(function->code()); for (unsigned i = 0; i < table.length(); i++) { unsigned pc_offset = table.GetPcOffset(i); - int deoptimization_index = table.GetDeoptimizationIndex(i); - int gap_code_size = table.GetGapCodeSize(i); + SafepointEntry safepoint_entry = table.GetEntry(i); + int deoptimization_index = safepoint_entry.deoptimization_index(); + int gap_code_size = safepoint_entry.gap_code_size(); // Check that we did not shoot past next safepoint. // TODO(srdjan): How do we guarantee that safepoint code does not // overlap other safepoint patching code? diff --git a/src/frames.cc b/src/frames.cc index 3af72887e..bdc76a9bf 100644 --- a/src/frames.cc +++ b/src/frames.cc @@ -329,21 +329,20 @@ void SafeStackTraceFrameIterator::Advance() { Code* StackFrame::GetSafepointData(Address pc, - uint8_t** safepoint_entry, + SafepointEntry* safepoint_entry, unsigned* stack_slots) { PcToCodeCache::PcToCodeCacheEntry* entry = PcToCodeCache::GetCacheEntry(pc); - uint8_t* cached_safepoint_entry = entry->safepoint_entry; - if (cached_safepoint_entry == NULL) { - cached_safepoint_entry = entry->code->GetSafepointEntry(pc); - ASSERT(cached_safepoint_entry != NULL); // No safepoint found. - entry->safepoint_entry = cached_safepoint_entry; + SafepointEntry cached_safepoint_entry = entry->safepoint_entry; + if (!entry->safepoint_entry.is_valid()) { + entry->safepoint_entry = entry->code->GetSafepointEntry(pc); + ASSERT(entry->safepoint_entry.is_valid()); } else { - ASSERT(cached_safepoint_entry == entry->code->GetSafepointEntry(pc)); + ASSERT(entry->safepoint_entry.Equals(entry->code->GetSafepointEntry(pc))); } // Fill in the results and return the code. Code* code = entry->code; - *safepoint_entry = cached_safepoint_entry; + *safepoint_entry = entry->safepoint_entry; *stack_slots = code->stack_slots(); return code; } @@ -536,7 +535,7 @@ void OptimizedFrame::Iterate(ObjectVisitor* v) const { // Compute the safepoint information. unsigned stack_slots = 0; - uint8_t* safepoint_entry = NULL; + SafepointEntry safepoint_entry; Code* code = StackFrame::GetSafepointData( pc(), &safepoint_entry, &stack_slots); unsigned slot_space = stack_slots * kPointerSize; @@ -548,10 +547,17 @@ void OptimizedFrame::Iterate(ObjectVisitor* v) const { Object** parameters_limit = &Memory::Object_at( fp() + JavaScriptFrameConstants::kFunctionOffset - slot_space); + // Visit the parameters that may be on top of the saved registers. + if (safepoint_entry.argument_count() > 0) { + v->VisitPointers(parameters_base, + parameters_base + safepoint_entry.argument_count()); + parameters_base += safepoint_entry.argument_count(); + } + // Visit the registers that contain pointers if any. - if (SafepointTable::HasRegisters(safepoint_entry)) { + if (safepoint_entry.HasRegisters()) { for (int i = kNumSafepointRegisters - 1; i >=0; i--) { - if (SafepointTable::HasRegisterAt(safepoint_entry, i)) { + if (safepoint_entry.HasRegisterAt(i)) { int reg_stack_index = MacroAssembler::SafepointRegisterStackIndex(i); v->VisitPointer(parameters_base + reg_stack_index); } @@ -561,7 +567,8 @@ void OptimizedFrame::Iterate(ObjectVisitor* v) const { } // We're done dealing with the register bits. - safepoint_entry += kNumSafepointRegisters >> kBitsPerByteLog2; + uint8_t* safepoint_bits = safepoint_entry.bits(); + safepoint_bits += kNumSafepointRegisters >> kBitsPerByteLog2; // Visit the rest of the parameters. v->VisitPointers(parameters_base, parameters_limit); @@ -570,7 +577,7 @@ void OptimizedFrame::Iterate(ObjectVisitor* v) const { for (unsigned index = 0; index < stack_slots; index++) { int byte_index = index >> kBitsPerByteLog2; int bit_index = index & (kBitsPerByte - 1); - if ((safepoint_entry[byte_index] & (1U << bit_index)) != 0) { + if ((safepoint_bits[byte_index] & (1U << bit_index)) != 0) { v->VisitPointer(parameters_limit + index); } } @@ -778,14 +785,8 @@ DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData( ASSERT(code != NULL); ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION); - SafepointTable table(code); - unsigned pc_offset = static_cast(pc() - code->instruction_start()); - for (unsigned i = 0; i < table.length(); i++) { - if (table.GetPcOffset(i) == pc_offset) { - *deopt_index = table.GetDeoptimizationIndex(i); - break; - } - } + SafepointEntry safepoint_entry = code->GetSafepointEntry(pc()); + *deopt_index = safepoint_entry.deoptimization_index(); ASSERT(*deopt_index != AstNode::kNoNumber); return DeoptimizationInputData::cast(code->deoptimization_data()); @@ -1150,7 +1151,7 @@ PcToCodeCache::PcToCodeCacheEntry* PcToCodeCache::GetCacheEntry(Address pc) { // been set. Otherwise, we risk trying to use a cache entry before // the code has been computed. entry->code = GcSafeFindCodeForPc(pc); - entry->safepoint_entry = NULL; + entry->safepoint_entry.Reset(); entry->pc = pc; } return entry; diff --git a/src/frames.h b/src/frames.h index 778f9d243..537870906 100644 --- a/src/frames.h +++ b/src/frames.h @@ -28,6 +28,8 @@ #ifndef V8_FRAMES_H_ #define V8_FRAMES_H_ +#include "safepoint-table.h" + namespace v8 { namespace internal { @@ -51,7 +53,7 @@ class PcToCodeCache : AllStatic { struct PcToCodeCacheEntry { Address pc; Code* code; - uint8_t* safepoint_entry; + SafepointEntry safepoint_entry; }; static PcToCodeCacheEntry* cache(int index) { @@ -208,7 +210,7 @@ class StackFrame BASE_EMBEDDED { // safepoint entry and the number of stack slots. The pc must be at // a safepoint. static Code* GetSafepointData(Address pc, - uint8_t** safepoint_entry, + SafepointEntry* safepoint_entry, unsigned* stack_slots); virtual void Iterate(ObjectVisitor* v) const = 0; diff --git a/src/ia32/deoptimizer-ia32.cc b/src/ia32/deoptimizer-ia32.cc index ceba2494a..d1c0f2b03 100644 --- a/src/ia32/deoptimizer-ia32.cc +++ b/src/ia32/deoptimizer-ia32.cc @@ -56,8 +56,9 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) { SafepointTable table(function->code()); for (unsigned i = 0; i < table.length(); i++) { unsigned pc_offset = table.GetPcOffset(i); - int deoptimization_index = table.GetDeoptimizationIndex(i); - int gap_code_size = table.GetGapCodeSize(i); + SafepointEntry safepoint_entry = table.GetEntry(i); + int deoptimization_index = safepoint_entry.deoptimization_index(); + int gap_code_size = safepoint_entry.gap_code_size(); #ifdef DEBUG // Destroy the code which is not supposed to run again. unsigned instructions = pc_offset - last_pc_offset; diff --git a/src/objects.cc b/src/objects.cc index f3f80032a..cbfb9203d 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -5987,14 +5987,9 @@ int Code::SourceStatementPosition(Address pc) { } -uint8_t* Code::GetSafepointEntry(Address pc) { +SafepointEntry Code::GetSafepointEntry(Address pc) { SafepointTable table(this); - unsigned pc_offset = static_cast(pc - instruction_start()); - for (unsigned i = 0; i < table.length(); i++) { - // TODO(kasperl): Replace the linear search with binary search. - if (table.GetPcOffset(i) == pc_offset) return table.GetEntry(i); - } - return NULL; + return table.FindEntry(pc); } @@ -6265,12 +6260,15 @@ void Code::Disassemble(const char* name, FILE* out) { PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset); table.PrintEntry(i); PrintF(out, " (sp -> fp)"); - int deoptimization_index = table.GetDeoptimizationIndex(i); - if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) { - PrintF(out, " %6d", deoptimization_index); + SafepointEntry entry = table.GetEntry(i); + if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) { + PrintF(out, " %6d", entry.deoptimization_index()); } else { PrintF(out, " "); } + if (entry.argument_count() > 0) { + PrintF(out, " argc: %d", entry.argument_count()); + } PrintF(out, "\n"); } PrintF(out, "\n"); diff --git a/src/objects.h b/src/objects.h index 063555e03..c136dc59b 100644 --- a/src/objects.h +++ b/src/objects.h @@ -3121,6 +3121,9 @@ class DeoptimizationOutputData: public FixedArray { }; +class SafepointEntry; + + // Code describes objects with on-the-fly generated machine code. class Code: public HeapObject { public: @@ -3268,9 +3271,8 @@ class Code: public HeapObject { inline byte compare_state(); inline void set_compare_state(byte value); - // Get the safepoint entry for the given pc. Returns NULL for - // non-safepoint pcs. - uint8_t* GetSafepointEntry(Address pc); + // Get the safepoint entry for the given pc. + SafepointEntry GetSafepointEntry(Address pc); // Mark this code object as not having a stack check table. Assumes kind // is FUNCTION. diff --git a/src/safepoint-table.cc b/src/safepoint-table.cc index b9468a50b..39b211cd9 100644 --- a/src/safepoint-table.cc +++ b/src/safepoint-table.cc @@ -26,11 +26,34 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "safepoint-table.h" + #include "disasm.h" +#include "macro-assembler.h" namespace v8 { namespace internal { + +bool SafepointEntry::HasRegisters() const { + ASSERT(is_valid()); + ASSERT(IsAligned(kNumSafepointRegisters, kBitsPerByte)); + const int num_reg_bytes = kNumSafepointRegisters >> kBitsPerByteLog2; + for (int i = 0; i < num_reg_bytes; i++) { + if (bits_[i] != SafepointTable::kNoRegisters) return true; + } + return false; +} + + +bool SafepointEntry::HasRegisterAt(int reg_index) const { + ASSERT(is_valid()); + ASSERT(reg_index >= 0 && reg_index < kNumSafepointRegisters); + int byte_index = reg_index >> kBitsPerByteLog2; + int bit_index = reg_index & (kBitsPerByte - 1); + return (bits_[byte_index] & (1 << bit_index)) != 0; +} + + SafepointTable::SafepointTable(Code* code) { ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION); code_ = code; @@ -41,45 +64,39 @@ SafepointTable::SafepointTable(Code* code) { entries_ = pc_and_deoptimization_indexes_ + (length_ * kPcAndDeoptimizationIndexSize); ASSERT(entry_size_ > 0); - ASSERT_EQ(DeoptimizationIndexField::max(), Safepoint::kNoDeoptimizationIndex); + ASSERT_EQ(SafepointEntry::DeoptimizationIndexField::max(), + Safepoint::kNoDeoptimizationIndex); } -bool SafepointTable::HasRegisters(uint8_t* entry) { - ASSERT(IsAligned(kNumSafepointRegisters, kBitsPerByte)); - const int num_reg_bytes = kNumSafepointRegisters >> kBitsPerByteLog2; - for (int i = 0; i < num_reg_bytes; i++) { - if (entry[i] != kNoRegisters) return true; +SafepointEntry SafepointTable::FindEntry(Address pc) const { + unsigned pc_offset = static_cast(pc - code_->instruction_start()); + for (unsigned i = 0; i < length(); i++) { + // TODO(kasperl): Replace the linear search with binary search. + if (GetPcOffset(i) == pc_offset) return GetEntry(i); } - return false; -} - - -bool SafepointTable::HasRegisterAt(uint8_t* entry, int reg_index) { - ASSERT(reg_index >= 0 && reg_index < kNumSafepointRegisters); - int byte_index = reg_index >> kBitsPerByteLog2; - int bit_index = reg_index & (kBitsPerByte - 1); - return (entry[byte_index] & (1 << bit_index)) != 0; + return SafepointEntry(); } void SafepointTable::PrintEntry(unsigned index) const { disasm::NameConverter converter; - uint8_t* entry = GetEntry(index); + SafepointEntry entry = GetEntry(index); + uint8_t* bits = entry.bits(); // Print the stack slot bits. if (entry_size_ > 0) { ASSERT(IsAligned(kNumSafepointRegisters, kBitsPerByte)); const int first = kNumSafepointRegisters >> kBitsPerByteLog2; int last = entry_size_ - 1; - for (int i = first; i < last; i++) PrintBits(entry[i], kBitsPerByte); + for (int i = first; i < last; i++) PrintBits(bits[i], kBitsPerByte); int last_bits = code_->stack_slots() - ((last - first) * kBitsPerByte); - PrintBits(entry[last], last_bits); + PrintBits(bits[last], last_bits); // Print the registers (if any). - if (!HasRegisters(entry)) return; + if (!entry.HasRegisters()) return; for (int j = 0; j < kNumSafepointRegisters; j++) { - if (HasRegisterAt(entry, j)) { + if (entry.HasRegisterAt(j)) { PrintF(" | %s", converter.NameOfCPURegister(j)); } } @@ -95,6 +112,11 @@ void SafepointTable::PrintBits(uint8_t byte, int digits) { } +void Safepoint::DefinePointerRegister(Register reg) { + registers_->Add(reg.code()); +} + + Safepoint SafepointTableBuilder::DefineSafepoint(Assembler* assembler, int deoptimization_index) { ASSERT(deoptimization_index != -1); @@ -102,6 +124,7 @@ Safepoint SafepointTableBuilder::DefineSafepoint(Assembler* assembler, pc_and_deoptimization_index.pc = assembler->pc_offset(); pc_and_deoptimization_index.deoptimization_index = deoptimization_index; pc_and_deoptimization_index.pc_after_gap = assembler->pc_offset(); + pc_and_deoptimization_index.arguments = 0; deoptimization_info_.Add(pc_and_deoptimization_index); indexes_.Add(new ZoneList(8)); registers_.Add(NULL); @@ -112,11 +135,12 @@ Safepoint SafepointTableBuilder::DefineSafepoint(Assembler* assembler, Safepoint SafepointTableBuilder::DefineSafepointWithRegisters( Assembler* assembler, int arguments, int deoptimization_index) { ASSERT(deoptimization_index != -1); - ASSERT(arguments == 0); // Only case that works for now. + ASSERT(arguments >= 0); DeoptimizationInfo pc_and_deoptimization_index; pc_and_deoptimization_index.pc = assembler->pc_offset(); pc_and_deoptimization_index.deoptimization_index = deoptimization_index; pc_and_deoptimization_index.pc_after_gap = assembler->pc_offset(); + pc_and_deoptimization_index.arguments = arguments; deoptimization_info_.Add(pc_and_deoptimization_index); indexes_.Add(new ZoneList(8)); registers_.Add(new ZoneList(4)); @@ -152,7 +176,7 @@ void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) { // pc after gap information. for (int i = 0; i < length; i++) { assembler->dd(deoptimization_info_[i].pc); - assembler->dd(EncodeDeoptimizationIndexAndGap(deoptimization_info_[i])); + assembler->dd(EncodeExceptPC(deoptimization_info_[i])); } // Emit table of bitmaps. @@ -197,12 +221,12 @@ void SafepointTableBuilder::Emit(Assembler* assembler, int bits_per_entry) { } -uint32_t SafepointTableBuilder::EncodeDeoptimizationIndexAndGap( - DeoptimizationInfo info) { +uint32_t SafepointTableBuilder::EncodeExceptPC(const DeoptimizationInfo& info) { unsigned index = info.deoptimization_index; unsigned gap_size = info.pc_after_gap - info.pc; - uint32_t encoding = SafepointTable::DeoptimizationIndexField::encode(index); - encoding |= SafepointTable::GapCodeSizeField::encode(gap_size); + uint32_t encoding = SafepointEntry::DeoptimizationIndexField::encode(index); + encoding |= SafepointEntry::GapCodeSizeField::encode(gap_size); + encoding |= SafepointEntry::ArgumentsField::encode(info.arguments); return encoding; } diff --git a/src/safepoint-table.h b/src/safepoint-table.h index d92018c22..6e5e0d840 100644 --- a/src/safepoint-table.h +++ b/src/safepoint-table.h @@ -30,56 +30,102 @@ #include "v8.h" -#include "macro-assembler.h" +#include "heap.h" #include "zone.h" #include "zone-inl.h" namespace v8 { namespace internal { -class SafepointTable BASE_EMBEDDED { +struct Register; + +class SafepointEntry BASE_EMBEDDED { public: - explicit SafepointTable(Code* code); + SafepointEntry() : info_(0), bits_(NULL) {} - int size() const { - return kHeaderSize + - (length_ * (kPcAndDeoptimizationIndexSize + entry_size_)); } - unsigned length() const { return length_; } - unsigned entry_size() const { return entry_size_; } + SafepointEntry(unsigned info, uint8_t* bits) : info_(info), bits_(bits) { + ASSERT(is_valid()); + } - unsigned GetPcOffset(unsigned index) const { - ASSERT(index < length_); - return Memory::uint32_at(GetPcOffsetLocation(index)); + bool is_valid() const { return bits_ != NULL; } + + bool Equals(const SafepointEntry& other) const { + return info_ == other.info_ && bits_ == other.bits_; } - int GetDeoptimizationIndex(unsigned index) const { - ASSERT(index < length_); - unsigned value = Memory::uint32_at(GetDeoptimizationLocation(index)); - return DeoptimizationIndexField::decode(value); + void Reset() { + info_ = 0; + bits_ = NULL; } - unsigned GetGapCodeSize(unsigned index) const { - ASSERT(index < length_); - unsigned value = Memory::uint32_at(GetDeoptimizationLocation(index)); - return GapCodeSizeField::decode(value); + int deoptimization_index() const { + ASSERT(is_valid()); + return DeoptimizationIndexField::decode(info_); } - uint8_t* GetEntry(unsigned index) const { - ASSERT(index < length_); - return &Memory::uint8_at(entries_ + (index * entry_size_)); + int gap_code_size() const { + ASSERT(is_valid()); + return GapCodeSizeField::decode(info_); } + int argument_count() const { + ASSERT(is_valid()); + return ArgumentsField::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 kDeoptIndexBits = 32 - kGapCodeSizeBits; + static const int kArgumentsFieldBits = 3; + static const int kDeoptIndexBits = + 32 - kGapCodeSizeBits - kArgumentsFieldBits; class GapCodeSizeField: public BitField {}; - class DeoptimizationIndexField: public BitField {}; // NOLINT + class DeoptimizationIndexField: public BitField {}; // NOLINT + class ArgumentsField: public BitField {}; // NOLINT + private: + unsigned info_; + uint8_t* bits_; +}; + + +class SafepointTable BASE_EMBEDDED { + public: + explicit SafepointTable(Code* code); - static bool HasRegisters(uint8_t* entry); - static bool HasRegisterAt(uint8_t* entry, int reg_index); + 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; @@ -100,7 +146,7 @@ class SafepointTable BASE_EMBEDDED { (index * kPcAndDeoptimizationIndexSize); } - Address GetDeoptimizationLocation(unsigned index) const { + Address GetInfoLocation(unsigned index) const { return GetPcOffsetLocation(index) + kPcSize; } @@ -115,16 +161,19 @@ class SafepointTable BASE_EMBEDDED { Address entries_; friend class SafepointTableBuilder; + friend class SafepointEntry; + + DISALLOW_COPY_AND_ASSIGN(SafepointTable); }; class Safepoint BASE_EMBEDDED { public: static const int kNoDeoptimizationIndex = - (1 << (SafepointTable::kDeoptIndexBits)) - 1; + (1 << (SafepointEntry::kDeoptIndexBits)) - 1; void DefinePointerSlot(int index) { indexes_->Add(index); } - void DefinePointerRegister(Register reg) { registers_->Add(reg.code()); } + void DefinePointerRegister(Register reg); private: Safepoint(ZoneList* indexes, ZoneList* registers) : @@ -177,9 +226,10 @@ class SafepointTableBuilder BASE_EMBEDDED { unsigned pc; unsigned deoptimization_index; unsigned pc_after_gap; + unsigned arguments; }; - uint32_t EncodeDeoptimizationIndexAndGap(DeoptimizationInfo info); + uint32_t EncodeExceptPC(const DeoptimizationInfo& info); ZoneList deoptimization_info_; ZoneList*> indexes_; -- 2.34.1