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