Commit 786c213d authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Use an object to control the blocking of the constant pool

Instead of indicating for how many instructions the constant pool needs to be blocked the constant pool is now blocked while at least one instance of ScopedConstPoolBlocker exists.
Review URL: http://codereview.chromium.org/1673006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4456 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 0adfe842
......@@ -306,6 +306,7 @@ Assembler::Assembler(void* buffer, int buffer_size) {
reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
num_prinfo_ = 0;
next_buffer_check_ = 0;
const_pool_blocked_nesting_ = 0;
no_const_pool_before_ = 0;
last_const_pool_end_ = 0;
last_bound_pos_ = 0;
......@@ -1726,11 +1727,6 @@ bool Assembler::ImmediateFitsAddrMode1Instruction(int32_t imm32) {
}
void Assembler::BlockConstPoolFor(int instructions) {
BlockConstPoolBefore(pc_offset() + instructions * kInstrSize);
}
// Debugging.
void Assembler::RecordJSReturn() {
WriteRecordedPositions();
......@@ -1894,12 +1890,17 @@ void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
// However, some small sequences of instructions must not be broken up by the
// insertion of a constant pool; such sequences are protected by setting
// no_const_pool_before_, which is checked here. Also, recursive calls to
// CheckConstPool are blocked by no_const_pool_before_.
if (pc_offset() < no_const_pool_before_) {
// either const_pool_blocked_nesting_ or no_const_pool_before_, which are
// both checked here. Also, recursive calls to CheckConstPool are blocked by
// no_const_pool_before_.
if (const_pool_blocked_nesting_ > 0 || pc_offset() < no_const_pool_before_) {
// Emission is currently blocked; make sure we try again as soon as
// possible.
next_buffer_check_ = no_const_pool_before_;
if (const_pool_blocked_nesting_ > 0) {
next_buffer_check_ = pc_offset() + kInstrSize;
} else {
next_buffer_check_ = no_const_pool_before_;
}
// Something is wrong if emission is forced and blocked at the same time.
ASSERT(!force_emit);
......
......@@ -925,9 +925,21 @@ class Assembler : public Malloced {
// Check whether an immediate fits an addressing mode 1 instruction.
bool ImmediateFitsAddrMode1Instruction(int32_t imm32);
// Postpone the generation of the constant pool for the specified number of
// instructions.
void BlockConstPoolFor(int instructions);
// Class for scoping postponing the constant pool generation.
class BlockConstPoolScope {
public:
explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
assem_->const_pool_blocked_nesting_++;
}
~BlockConstPoolScope() {
assem_->const_pool_blocked_nesting_--;
}
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
Assembler* assem_;
};
// Debugging
......@@ -1022,8 +1034,9 @@ class Assembler : public Malloced {
// distance between pools.
static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
// Emission of the constant pool may be blocked in some code sequences
int no_const_pool_before_; // block emission before this pc offset
// Emission of the constant pool may be blocked in some code sequences.
int const_pool_blocked_nesting_; // Block emission if this is not zero.
int no_const_pool_before_; // Block emission before this pc offset.
// Keep track of the last emitted pool to guarantee a maximal distance
int last_const_pool_end_; // pc offset following the last constant pool
......@@ -1075,6 +1088,7 @@ class Assembler : public Malloced {
friend class RegExpMacroAssemblerARM;
friend class RelocInfo;
friend class CodePatcher;
friend class BlockConstPoolScope;
};
} } // namespace v8::internal
......
......@@ -353,37 +353,37 @@ void CodeGenerator::Generate(CompilationInfo* info) {
frame_->CallRuntime(Runtime::kTraceExit, 1);
}
#ifdef DEBUG
// Add a label for checking the size of the code used for returning.
Label check_exit_codesize;
masm_->bind(&check_exit_codesize);
#endif
// Calculate the exact length of the return sequence and make sure that
// the constant pool is not emitted inside of the return sequence.
int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize;
int return_sequence_length = Assembler::kJSReturnSequenceLength;
if (!masm_->ImmediateFitsAddrMode1Instruction(sp_delta)) {
// Additional mov instruction generated.
return_sequence_length++;
}
masm_->BlockConstPoolFor(return_sequence_length);
{
// Make sure that the constant pool is not emitted inside of the return
// sequence.
Assembler::BlockConstPoolScope block_const_pool(masm_);
// Tear down the frame which will restore the caller's frame pointer and
// the link register.
frame_->Exit();
// Tear down the frame which will restore the caller's frame pointer and
// the link register.
frame_->Exit();
// Here we use masm_-> instead of the __ macro to avoid the code coverage
// tool from instrumenting as we rely on the code size here.
masm_->add(sp, sp, Operand(sp_delta));
masm_->Jump(lr);
// Here we use masm_-> instead of the __ macro to avoid the code coverage
// tool from instrumenting as we rely on the code size here.
int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize;
masm_->add(sp, sp, Operand(sp_delta));
masm_->Jump(lr);
}
#ifdef DEBUG
// Check that the size of the code used for returning matches what is
// expected by the debugger. The add instruction above is an addressing
// mode 1 instruction where there are restrictions on which immediate values
// can be encoded in the instruction and which immediate values requires
// use of an additional instruction for moving the immediate to a temporary
// register.
ASSERT_EQ(return_sequence_length,
masm_->InstructionsGeneratedSince(&check_exit_codesize));
// expected by the debugger. If the sp_delts above cannot be encoded in the
// add instruction the add will generate two instructions.
int return_sequence_length =
masm_->InstructionsGeneratedSince(&check_exit_codesize);
CHECK(return_sequence_length == Assembler::kJSReturnSequenceLength ||
return_sequence_length == Assembler::kJSReturnSequenceLength + 1);
#endif
}
// Adjust for function-level loop nesting.
......
......@@ -194,36 +194,37 @@ void FullCodeGenerator::EmitReturnSequence(int position) {
__ CallRuntime(Runtime::kTraceExit, 1);
}
#ifdef DEBUG
// Add a label for checking the size of the code used for returning.
Label check_exit_codesize;
masm_->bind(&check_exit_codesize);
// Calculate the exact length of the return sequence and make sure that
// the constant pool is not emitted inside of the return sequence.
int num_parameters = scope()->num_parameters();
int32_t sp_delta = (num_parameters + 1) * kPointerSize;
int return_sequence_length = Assembler::kJSReturnSequenceLength;
if (!masm_->ImmediateFitsAddrMode1Instruction(sp_delta)) {
// Additional mov instruction generated.
return_sequence_length++;
#endif
{
// Make sure that the constant pool is not emitted inside of the return
// sequence.
Assembler::BlockConstPoolScope block_const_pool(masm_);
// Here we use masm_-> instead of the __ macro to avoid the code coverage
// tool from instrumenting as we rely on the code size here.
int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize;
CodeGenerator::RecordPositions(masm_, position);
__ RecordJSReturn();
masm_->mov(sp, fp);
masm_->ldm(ia_w, sp, fp.bit() | lr.bit());
masm_->add(sp, sp, Operand(sp_delta));
masm_->Jump(lr);
}
masm_->BlockConstPoolFor(return_sequence_length);
CodeGenerator::RecordPositions(masm_, position);
__ RecordJSReturn();
__ mov(sp, fp);
__ ldm(ia_w, sp, fp.bit() | lr.bit());
__ add(sp, sp, Operand(sp_delta));
__ Jump(lr);
#ifdef DEBUG
// Check that the size of the code used for returning matches what is
// expected by the debugger. The add instruction above is an addressing
// mode 1 instruction where there are restrictions on which immediate values
// can be encoded in the instruction and which immediate values requires
// use of an additional instruction for moving the immediate to a temporary
// register.
ASSERT_EQ(return_sequence_length,
masm_->InstructionsGeneratedSince(&check_exit_codesize));
// expected by the debugger. If the sp_delts above cannot be encoded in the
// add instruction the add will generate two instructions.
int return_sequence_length =
masm_->InstructionsGeneratedSince(&check_exit_codesize);
CHECK(return_sequence_length == Assembler::kJSReturnSequenceLength ||
return_sequence_length == Assembler::kJSReturnSequenceLength + 1);
#endif
}
}
......
......@@ -117,18 +117,20 @@ void MacroAssembler::Call(intptr_t target, RelocInfo::Mode rmode,
// ldr ip, [pc, #...]
// blx ip
// The two instructions (ldr and blx) could be separated by a literal
// pool and the code would still work. The issue comes from the
// patching code which expect the ldr to be just above the blx.
BlockConstPoolFor(2);
// Statement positions are expected to be recorded when the target
// address is loaded. The mov method will automatically record
// positions when pc is the target, since this is not the case here
// we have to do it explicitly.
WriteRecordedPositions();
mov(ip, Operand(target, rmode), LeaveCC, cond);
blx(ip, cond);
{
// The two instructions (ldr and blx) could be separated by a constant
// pool and the code would still work. The issue comes from the
// patching code which expect the ldr to be just above the blx.
BlockConstPoolScope block_const_pool(this);
// Statement positions are expected to be recorded when the target
// address is loaded. The mov method will automatically record
// positions when pc is the target, since this is not the case here
// we have to do it explicitly.
WriteRecordedPositions();
mov(ip, Operand(target, rmode), LeaveCC, cond);
blx(ip, cond);
}
ASSERT(kCallTargetAddressOffset == 2 * kInstrSize);
#else
......
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