Commit e2f8c938 authored by vitalyr@chromium.org's avatar vitalyr@chromium.org

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
parent 855ffcd1
......@@ -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?
......
......@@ -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<unsigned>(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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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<unsigned>(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, " <none>");
}
if (entry.argument_count() > 0) {
PrintF(out, " argc: %d", entry.argument_count());
}
PrintF(out, "\n");
}
PrintF(out, "\n");
......
......@@ -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.
......
......@@ -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<unsigned>(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<int>(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<int>(8));
registers_.Add(new ZoneList<int>(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;
}
......
......@@ -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<unsigned, 0, kGapCodeSizeBits> {};
class DeoptimizationIndexField: public BitField<int, kGapCodeSizeBits, kDeoptIndexBits> {}; // NOLINT
class DeoptimizationIndexField: public BitField<int,
kGapCodeSizeBits,
kDeoptIndexBits> {}; // NOLINT
class ArgumentsField: public BitField<unsigned,
kGapCodeSizeBits + kDeoptIndexBits,
kArgumentsFieldBits> {}; // 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<int>* indexes, ZoneList<int>* 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<DeoptimizationInfo> deoptimization_info_;
ZoneList<ZoneList<int>*> indexes_;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment