Improve positions recording for calls.
Review URL: http://codereview.chromium.org/4469002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5768 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
455cfe5932
commit
746d72420c
@ -317,7 +317,8 @@ static const Instr kLdrStrOffsetMask = 0x00000fff;
|
||||
static const int kMinimalBufferSize = 4*KB;
|
||||
static byte* spare_buffer_ = NULL;
|
||||
|
||||
Assembler::Assembler(void* buffer, int buffer_size) {
|
||||
Assembler::Assembler(void* buffer, int buffer_size)
|
||||
: positions_recorder_(this) {
|
||||
if (buffer == NULL) {
|
||||
// Do our own buffer management.
|
||||
if (buffer_size <= kMinimalBufferSize) {
|
||||
@ -354,10 +355,6 @@ Assembler::Assembler(void* buffer, int buffer_size) {
|
||||
no_const_pool_before_ = 0;
|
||||
last_const_pool_end_ = 0;
|
||||
last_bound_pos_ = 0;
|
||||
current_statement_position_ = RelocInfo::kNoPosition;
|
||||
current_position_ = RelocInfo::kNoPosition;
|
||||
written_statement_position_ = current_statement_position_;
|
||||
written_position_ = current_position_;
|
||||
}
|
||||
|
||||
|
||||
@ -999,7 +996,7 @@ void Assembler::bl(int branch_offset, Condition cond) {
|
||||
|
||||
|
||||
void Assembler::blx(int branch_offset) { // v5 and above
|
||||
WriteRecordedPositions();
|
||||
positions_recorder()->WriteRecordedPositions();
|
||||
ASSERT((branch_offset & 1) == 0);
|
||||
int h = ((branch_offset & 2) >> 1)*B24;
|
||||
int imm24 = branch_offset >> 2;
|
||||
@ -1009,14 +1006,14 @@ void Assembler::blx(int branch_offset) { // v5 and above
|
||||
|
||||
|
||||
void Assembler::blx(Register target, Condition cond) { // v5 and above
|
||||
WriteRecordedPositions();
|
||||
positions_recorder()->WriteRecordedPositions();
|
||||
ASSERT(!target.is(pc));
|
||||
emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | 3*B4 | target.code());
|
||||
}
|
||||
|
||||
|
||||
void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t
|
||||
WriteRecordedPositions();
|
||||
positions_recorder()->WriteRecordedPositions();
|
||||
ASSERT(!target.is(pc)); // use of pc is actually allowed, but discouraged
|
||||
emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | B4 | target.code());
|
||||
}
|
||||
@ -1114,7 +1111,7 @@ void Assembler::orr(Register dst, Register src1, const Operand& src2,
|
||||
|
||||
void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
|
||||
if (dst.is(pc)) {
|
||||
WriteRecordedPositions();
|
||||
positions_recorder()->WriteRecordedPositions();
|
||||
}
|
||||
// Don't allow nop instructions in the form mov rn, rn to be generated using
|
||||
// the mov instruction. They must be generated using nop(int)
|
||||
@ -1359,7 +1356,7 @@ void Assembler::msr(SRegisterFieldMask fields, const Operand& src,
|
||||
// Load/Store instructions.
|
||||
void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
|
||||
if (dst.is(pc)) {
|
||||
WriteRecordedPositions();
|
||||
positions_recorder()->WriteRecordedPositions();
|
||||
}
|
||||
addrmod2(cond | B26 | L, dst, src);
|
||||
|
||||
@ -2377,14 +2374,14 @@ void Assembler::BlockConstPoolFor(int instructions) {
|
||||
|
||||
// Debugging.
|
||||
void Assembler::RecordJSReturn() {
|
||||
WriteRecordedPositions();
|
||||
positions_recorder()->WriteRecordedPositions();
|
||||
CheckBuffer();
|
||||
RecordRelocInfo(RelocInfo::JS_RETURN);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::RecordDebugBreakSlot() {
|
||||
WriteRecordedPositions();
|
||||
positions_recorder()->WriteRecordedPositions();
|
||||
CheckBuffer();
|
||||
RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
|
||||
}
|
||||
@ -2398,47 +2395,6 @@ void Assembler::RecordComment(const char* msg) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::RecordPosition(int pos) {
|
||||
if (pos == RelocInfo::kNoPosition) return;
|
||||
ASSERT(pos >= 0);
|
||||
current_position_ = pos;
|
||||
}
|
||||
|
||||
|
||||
void Assembler::RecordStatementPosition(int pos) {
|
||||
if (pos == RelocInfo::kNoPosition) return;
|
||||
ASSERT(pos >= 0);
|
||||
current_statement_position_ = pos;
|
||||
}
|
||||
|
||||
|
||||
bool Assembler::WriteRecordedPositions() {
|
||||
bool written = false;
|
||||
|
||||
// Write the statement position if it is different from what was written last
|
||||
// time.
|
||||
if (current_statement_position_ != written_statement_position_) {
|
||||
CheckBuffer();
|
||||
RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
|
||||
written_statement_position_ = current_statement_position_;
|
||||
written = true;
|
||||
}
|
||||
|
||||
// Write the position if it is different from what was written last time and
|
||||
// also different from the written statement position.
|
||||
if (current_position_ != written_position_ &&
|
||||
current_position_ != written_statement_position_) {
|
||||
CheckBuffer();
|
||||
RecordRelocInfo(RelocInfo::POSITION, current_position_);
|
||||
written_position_ = current_position_;
|
||||
written = true;
|
||||
}
|
||||
|
||||
// Return whether something was written.
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
void Assembler::GrowBuffer() {
|
||||
if (!own_buffer_) FATAL("external code buffer is too small");
|
||||
|
||||
|
@ -1117,13 +1117,9 @@ class Assembler : public Malloced {
|
||||
// Use --debug_code to enable.
|
||||
void RecordComment(const char* msg);
|
||||
|
||||
void RecordPosition(int pos);
|
||||
void RecordStatementPosition(int pos);
|
||||
bool WriteRecordedPositions();
|
||||
|
||||
int pc_offset() const { return pc_ - buffer_; }
|
||||
int current_position() const { return current_position_; }
|
||||
int current_statement_position() const { return current_statement_position_; }
|
||||
|
||||
PositionsRecorder* positions_recorder() { return &positions_recorder_; }
|
||||
|
||||
bool can_peephole_optimize(int instructions) {
|
||||
if (!FLAG_peephole_optimization) return false;
|
||||
@ -1259,12 +1255,6 @@ class Assembler : public Malloced {
|
||||
// The bound position, before this we cannot do instruction elimination.
|
||||
int last_bound_pos_;
|
||||
|
||||
// source position information
|
||||
int current_position_;
|
||||
int current_statement_position_;
|
||||
int written_position_;
|
||||
int written_statement_position_;
|
||||
|
||||
// Code emission
|
||||
inline void CheckBuffer();
|
||||
void GrowBuffer();
|
||||
@ -1290,8 +1280,21 @@ class Assembler : public Malloced {
|
||||
friend class RelocInfo;
|
||||
friend class CodePatcher;
|
||||
friend class BlockConstPoolScope;
|
||||
|
||||
PositionsRecorder positions_recorder_;
|
||||
friend class PositionsRecorder;
|
||||
friend class EnsureSpace;
|
||||
};
|
||||
|
||||
|
||||
class EnsureSpace BASE_EMBEDDED {
|
||||
public:
|
||||
EnsureSpace(Assembler* assembler) {
|
||||
assembler->CheckBuffer();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_ARM_ASSEMBLER_ARM_H_
|
||||
|
@ -1688,12 +1688,14 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
|
||||
// Code common for calls using the IC.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
}
|
||||
__ mov(r2, Operand(name));
|
||||
}
|
||||
__ mov(r2, Operand(name));
|
||||
// Record source position for debugger.
|
||||
SetSourcePosition(expr->position());
|
||||
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||
// Call the IC initialization code.
|
||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
|
||||
@ -1710,13 +1712,15 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
|
||||
// Code common for calls using the IC.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
}
|
||||
VisitForAccumulatorValue(key);
|
||||
__ mov(r2, r0);
|
||||
}
|
||||
VisitForAccumulatorValue(key);
|
||||
__ mov(r2, r0);
|
||||
// Record source position for debugger.
|
||||
SetSourcePosition(expr->position());
|
||||
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||
// Call the IC initialization code.
|
||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count,
|
||||
@ -1732,11 +1736,13 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) {
|
||||
// Code common for calls using the call stub.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
}
|
||||
}
|
||||
// Record source position for debugger.
|
||||
SetSourcePosition(expr->position());
|
||||
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
||||
__ CallStub(&stub);
|
||||
@ -1756,41 +1762,46 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
// resolve the function we need to call and the receiver of the
|
||||
// call. Then we call the resolved function using the given
|
||||
// arguments.
|
||||
VisitForStackValue(fun);
|
||||
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
|
||||
__ push(r2); // Reserved receiver slot.
|
||||
|
||||
// Push the arguments.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
}
|
||||
|
||||
// Push copy of the function - found below the arguments.
|
||||
__ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
|
||||
__ push(r1);
|
||||
{ PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
|
||||
|
||||
// Push copy of the first argument or undefined if it doesn't exist.
|
||||
if (arg_count > 0) {
|
||||
__ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
|
||||
VisitForStackValue(fun);
|
||||
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
|
||||
__ push(r2); // Reserved receiver slot.
|
||||
|
||||
// Push the arguments.
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
}
|
||||
|
||||
// Push copy of the function - found below the arguments.
|
||||
__ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
|
||||
__ push(r1);
|
||||
} else {
|
||||
__ push(r2);
|
||||
|
||||
// Push copy of the first argument or undefined if it doesn't exist.
|
||||
if (arg_count > 0) {
|
||||
__ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
|
||||
__ push(r1);
|
||||
} else {
|
||||
__ push(r2);
|
||||
}
|
||||
|
||||
// Push the receiver of the enclosing function and do runtime call.
|
||||
__ ldr(r1,
|
||||
MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
|
||||
__ push(r1);
|
||||
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
|
||||
|
||||
// The runtime call returns a pair of values in r0 (function) and
|
||||
// r1 (receiver). Touch up the stack with the right values.
|
||||
__ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
|
||||
__ str(r1, MemOperand(sp, arg_count * kPointerSize));
|
||||
}
|
||||
|
||||
// Push the receiver of the enclosing function and do runtime call.
|
||||
__ ldr(r1, MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
|
||||
__ push(r1);
|
||||
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
|
||||
|
||||
// The runtime call returns a pair of values in r0 (function) and
|
||||
// r1 (receiver). Touch up the stack with the right values.
|
||||
__ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
|
||||
__ str(r1, MemOperand(sp, arg_count * kPointerSize));
|
||||
|
||||
// Record source position for debugger.
|
||||
SetSourcePosition(expr->position());
|
||||
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
||||
__ CallStub(&stub);
|
||||
@ -1807,12 +1818,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
// Call to a lookup slot (dynamically introduced variable).
|
||||
Label slow, done;
|
||||
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
|
||||
NOT_INSIDE_TYPEOF,
|
||||
&slow,
|
||||
&done);
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
|
||||
NOT_INSIDE_TYPEOF,
|
||||
&slow,
|
||||
&done);
|
||||
}
|
||||
|
||||
__ bind(&slow);
|
||||
// Call the runtime to find the function to call (returned in r0)
|
||||
@ -1846,17 +1859,23 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
Literal* key = prop->key()->AsLiteral();
|
||||
if (key != NULL && key->handle()->IsSymbol()) {
|
||||
// Call to a named property, use call IC.
|
||||
VisitForStackValue(prop->obj());
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(prop->obj());
|
||||
}
|
||||
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
|
||||
} else {
|
||||
// Call to a keyed property.
|
||||
// For a synthetic property use keyed load IC followed by function call,
|
||||
// for a regular property use keyed CallIC.
|
||||
VisitForStackValue(prop->obj());
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(prop->obj());
|
||||
}
|
||||
if (prop->is_synthetic()) {
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
}
|
||||
// Record source code position for IC call.
|
||||
SetSourcePosition(prop->position());
|
||||
SetSourcePosition(prop->position(), FORCED_POSITION);
|
||||
__ pop(r1); // We do not need to keep the receiver.
|
||||
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
|
||||
@ -1879,7 +1898,10 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
loop_depth() == 0) {
|
||||
lit->set_try_full_codegen(true);
|
||||
}
|
||||
VisitForStackValue(fun);
|
||||
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(fun);
|
||||
}
|
||||
// Load global receiver object.
|
||||
__ ldr(r1, CodeGenerator::GlobalObject());
|
||||
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
|
||||
|
@ -129,7 +129,7 @@ void MacroAssembler::Call(intptr_t target, RelocInfo::Mode rmode,
|
||||
// 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();
|
||||
positions_recorder()->WriteRecordedPositions();
|
||||
|
||||
mov(ip, Operand(target, rmode), LeaveCC, cond);
|
||||
blx(ip, cond);
|
||||
|
@ -804,4 +804,53 @@ ExternalReference ExternalReference::debug_step_in_fp_address() {
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void PositionsRecorder::RecordPosition(int pos,
|
||||
PositionRecordingType recording_type) {
|
||||
ASSERT(pos != RelocInfo::kNoPosition);
|
||||
ASSERT(pos >= 0);
|
||||
current_position_ = pos;
|
||||
current_position_recording_type_ = recording_type;
|
||||
}
|
||||
|
||||
|
||||
void PositionsRecorder::RecordStatementPosition(int pos) {
|
||||
ASSERT(pos != RelocInfo::kNoPosition);
|
||||
ASSERT(pos >= 0);
|
||||
current_statement_position_ = pos;
|
||||
}
|
||||
|
||||
|
||||
bool PositionsRecorder::WriteRecordedPositions() {
|
||||
bool written = false;
|
||||
|
||||
// Write the statement position if it is different from what was written last
|
||||
// time.
|
||||
if (current_statement_position_ != written_statement_position_) {
|
||||
EnsureSpace ensure_space(assembler_);
|
||||
assembler_->RecordRelocInfo(RelocInfo::STATEMENT_POSITION,
|
||||
current_statement_position_);
|
||||
written_statement_position_ = current_statement_position_;
|
||||
written = true;
|
||||
}
|
||||
|
||||
// Write the position if it is different from what was written last time and
|
||||
// also different from the written statement position or was forced.
|
||||
if (current_position_ != written_position_ &&
|
||||
(current_position_ != current_statement_position_ || !written) &&
|
||||
(current_position_ != written_statement_position_
|
||||
|| current_position_recording_type_ == FORCED_POSITION)) {
|
||||
EnsureSpace ensure_space(assembler_);
|
||||
assembler_->RecordRelocInfo(RelocInfo::POSITION, current_position_);
|
||||
written_position_ = current_position_;
|
||||
written = true;
|
||||
}
|
||||
|
||||
current_position_recording_type_ = NORMAL_POSITION;
|
||||
|
||||
// Return whether something was written.
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -584,6 +584,67 @@ class ExternalReference BASE_EMBEDDED {
|
||||
};
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Position recording support
|
||||
|
||||
enum PositionRecordingType { FORCED_POSITION, NORMAL_POSITION };
|
||||
|
||||
class PositionsRecorder BASE_EMBEDDED {
|
||||
public:
|
||||
explicit PositionsRecorder(Assembler* assembler)
|
||||
: assembler_(assembler),
|
||||
current_position_(RelocInfo::kNoPosition),
|
||||
current_position_recording_type_(NORMAL_POSITION),
|
||||
written_position_(RelocInfo::kNoPosition),
|
||||
current_statement_position_(RelocInfo::kNoPosition),
|
||||
written_statement_position_(RelocInfo::kNoPosition) { }
|
||||
|
||||
// Set current position to pos. If recording_type is FORCED_POSITION then
|
||||
// WriteRecordedPositions will write this position even if it is equal to
|
||||
// statement position previously written for another pc.
|
||||
void RecordPosition(int pos,
|
||||
PositionRecordingType recording_type = NORMAL_POSITION);
|
||||
|
||||
// Set current statement position to pos.
|
||||
void RecordStatementPosition(int pos);
|
||||
|
||||
// Write recorded positions to relocation information.
|
||||
bool WriteRecordedPositions();
|
||||
|
||||
int current_position() const { return current_position_; }
|
||||
|
||||
int current_statement_position() const { return current_statement_position_; }
|
||||
|
||||
private:
|
||||
Assembler* assembler_;
|
||||
|
||||
int current_position_;
|
||||
PositionRecordingType current_position_recording_type_;
|
||||
int written_position_;
|
||||
|
||||
int current_statement_position_;
|
||||
int written_statement_position_;
|
||||
};
|
||||
|
||||
|
||||
class PreserveStatementPositionScope BASE_EMBEDDED {
|
||||
public:
|
||||
PreserveStatementPositionScope(PositionsRecorder* positions_recorder)
|
||||
: positions_recorder_(positions_recorder),
|
||||
statement_position_(positions_recorder->current_statement_position()) {}
|
||||
|
||||
~PreserveStatementPositionScope() {
|
||||
if (statement_position_ != RelocInfo::kNoPosition) {
|
||||
positions_recorder_->RecordStatementPosition(statement_position_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
PositionsRecorder* positions_recorder_;
|
||||
int statement_position_;
|
||||
};
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Utility functions
|
||||
|
||||
|
@ -70,9 +70,10 @@ void CodeGenerator::ProcessDeferred() {
|
||||
DeferredCode* code = deferred_.RemoveLast();
|
||||
ASSERT(masm_ == code->masm());
|
||||
// Record position of deferred code stub.
|
||||
masm_->RecordStatementPosition(code->statement_position());
|
||||
masm_->positions_recorder()->RecordStatementPosition(
|
||||
code->statement_position());
|
||||
if (code->position() != RelocInfo::kNoPosition) {
|
||||
masm_->RecordPosition(code->position());
|
||||
masm_->positions_recorder()->RecordPosition(code->position());
|
||||
}
|
||||
// Generate the code.
|
||||
Comment cmnt(masm_, code->comment());
|
||||
@ -402,10 +403,10 @@ bool CodeGenerator::RecordPositions(MacroAssembler* masm,
|
||||
int pos,
|
||||
bool right_here) {
|
||||
if (pos != RelocInfo::kNoPosition) {
|
||||
masm->RecordStatementPosition(pos);
|
||||
masm->RecordPosition(pos);
|
||||
masm->positions_recorder()->RecordStatementPosition(pos);
|
||||
masm->positions_recorder()->RecordPosition(pos);
|
||||
if (right_here) {
|
||||
return masm->WriteRecordedPositions();
|
||||
return masm->positions_recorder()->WriteRecordedPositions();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -435,7 +436,7 @@ void CodeGenerator::CodeForDoWhileConditionPosition(DoWhileStatement* stmt) {
|
||||
|
||||
void CodeGenerator::CodeForSourcePosition(int pos) {
|
||||
if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
|
||||
masm()->RecordPosition(pos);
|
||||
masm()->positions_recorder()->RecordPosition(pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -563,9 +563,10 @@ void FullCodeGenerator::SetStatementPosition(int pos) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::SetSourcePosition(int pos) {
|
||||
void FullCodeGenerator::SetSourcePosition(
|
||||
int pos, PositionRecordingType recording_type) {
|
||||
if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
|
||||
masm_->RecordPosition(pos);
|
||||
masm_->positions_recorder()->RecordPosition(pos, recording_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -423,7 +423,9 @@ class FullCodeGenerator: public AstVisitor {
|
||||
void SetStatementPosition(Statement* stmt);
|
||||
void SetExpressionPosition(Expression* expr, int pos);
|
||||
void SetStatementPosition(int pos);
|
||||
void SetSourcePosition(int pos);
|
||||
void SetSourcePosition(
|
||||
int pos,
|
||||
PositionRecordingType recording_type = NORMAL_POSITION);
|
||||
|
||||
// Non-local control flow support.
|
||||
void EnterFinallyBlock();
|
||||
|
@ -298,7 +298,8 @@ static void InitCoverageLog();
|
||||
// Spare buffer.
|
||||
byte* Assembler::spare_buffer_ = NULL;
|
||||
|
||||
Assembler::Assembler(void* buffer, int buffer_size) {
|
||||
Assembler::Assembler(void* buffer, int buffer_size)
|
||||
: positions_recorder_(this) {
|
||||
if (buffer == NULL) {
|
||||
// Do our own buffer management.
|
||||
if (buffer_size <= kMinimalBufferSize) {
|
||||
@ -339,10 +340,6 @@ Assembler::Assembler(void* buffer, int buffer_size) {
|
||||
reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
|
||||
|
||||
last_pc_ = NULL;
|
||||
current_statement_position_ = RelocInfo::kNoPosition;
|
||||
current_position_ = RelocInfo::kNoPosition;
|
||||
written_statement_position_ = current_statement_position_;
|
||||
written_position_ = current_position_;
|
||||
#ifdef GENERATED_CODE_COVERAGE
|
||||
InitCoverageLog();
|
||||
#endif
|
||||
@ -1581,7 +1578,7 @@ void Assembler::call(const Operand& adr) {
|
||||
|
||||
|
||||
void Assembler::call(Handle<Code> code, RelocInfo::Mode rmode) {
|
||||
WriteRecordedPositions();
|
||||
positions_recorder()->WriteRecordedPositions();
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
ASSERT(RelocInfo::IsCodeTarget(rmode));
|
||||
@ -2464,14 +2461,14 @@ void Assembler::Print() {
|
||||
|
||||
|
||||
void Assembler::RecordJSReturn() {
|
||||
WriteRecordedPositions();
|
||||
positions_recorder()->WriteRecordedPositions();
|
||||
EnsureSpace ensure_space(this);
|
||||
RecordRelocInfo(RelocInfo::JS_RETURN);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::RecordDebugBreakSlot() {
|
||||
WriteRecordedPositions();
|
||||
positions_recorder()->WriteRecordedPositions();
|
||||
EnsureSpace ensure_space(this);
|
||||
RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
|
||||
}
|
||||
@ -2485,47 +2482,6 @@ void Assembler::RecordComment(const char* msg) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::RecordPosition(int pos) {
|
||||
ASSERT(pos != RelocInfo::kNoPosition);
|
||||
ASSERT(pos >= 0);
|
||||
current_position_ = pos;
|
||||
}
|
||||
|
||||
|
||||
void Assembler::RecordStatementPosition(int pos) {
|
||||
ASSERT(pos != RelocInfo::kNoPosition);
|
||||
ASSERT(pos >= 0);
|
||||
current_statement_position_ = pos;
|
||||
}
|
||||
|
||||
|
||||
bool Assembler::WriteRecordedPositions() {
|
||||
bool written = false;
|
||||
|
||||
// Write the statement position if it is different from what was written last
|
||||
// time.
|
||||
if (current_statement_position_ != written_statement_position_) {
|
||||
EnsureSpace ensure_space(this);
|
||||
RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
|
||||
written_statement_position_ = current_statement_position_;
|
||||
written = true;
|
||||
}
|
||||
|
||||
// Write the position if it is different from what was written last time and
|
||||
// also different from the written statement position.
|
||||
if (current_position_ != written_position_ &&
|
||||
current_position_ != written_statement_position_) {
|
||||
EnsureSpace ensure_space(this);
|
||||
RecordRelocInfo(RelocInfo::POSITION, current_position_);
|
||||
written_position_ = current_position_;
|
||||
written = true;
|
||||
}
|
||||
|
||||
// Return whether something was written.
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
void Assembler::GrowBuffer() {
|
||||
ASSERT(overflow());
|
||||
if (!own_buffer_) FATAL("external code buffer is too small");
|
||||
|
@ -847,17 +847,11 @@ class Assembler : public Malloced {
|
||||
// Use --debug_code to enable.
|
||||
void RecordComment(const char* msg);
|
||||
|
||||
void RecordPosition(int pos);
|
||||
void RecordStatementPosition(int pos);
|
||||
bool WriteRecordedPositions();
|
||||
|
||||
// Writes a single word of data in the code stream.
|
||||
// Used for inline tables, e.g., jump-tables.
|
||||
void dd(uint32_t data, RelocInfo::Mode reloc_info);
|
||||
|
||||
int pc_offset() const { return pc_ - buffer_; }
|
||||
int current_statement_position() const { return current_statement_position_; }
|
||||
int current_position() const { return current_position_; }
|
||||
|
||||
// Check if there is less than kGap bytes available in the buffer.
|
||||
// If this is the case, we need to grow the buffer before emitting
|
||||
@ -869,6 +863,8 @@ class Assembler : public Malloced {
|
||||
|
||||
static bool IsNop(Address addr) { return *addr == 0x90; }
|
||||
|
||||
PositionsRecorder* positions_recorder() { return &positions_recorder_; }
|
||||
|
||||
// Avoid overflows for displacements etc.
|
||||
static const int kMaximalBufferSize = 512*MB;
|
||||
static const int kMinimalBufferSize = 4*KB;
|
||||
@ -947,11 +943,9 @@ class Assembler : public Malloced {
|
||||
// push-pop elimination
|
||||
byte* last_pc_;
|
||||
|
||||
// source position information
|
||||
int current_statement_position_;
|
||||
int current_position_;
|
||||
int written_statement_position_;
|
||||
int written_position_;
|
||||
PositionsRecorder positions_recorder_;
|
||||
|
||||
friend class PositionsRecorder;
|
||||
};
|
||||
|
||||
|
||||
|
@ -3734,7 +3734,7 @@ void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
|
||||
CodeForStatementPosition(node);
|
||||
Load(node->expression());
|
||||
Result return_value = frame_->Pop();
|
||||
masm()->WriteRecordedPositions();
|
||||
masm()->positions_recorder()->WriteRecordedPositions();
|
||||
if (function_return_is_shadowed_) {
|
||||
function_return_.Jump(&return_value);
|
||||
} else {
|
||||
|
@ -1996,12 +1996,14 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
|
||||
// Code common for calls using the IC.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
}
|
||||
__ Set(ecx, Immediate(name));
|
||||
}
|
||||
__ Set(ecx, Immediate(name));
|
||||
// Record source position of the IC call.
|
||||
SetSourcePosition(expr->position());
|
||||
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
|
||||
EmitCallIC(ic, mode);
|
||||
@ -2017,13 +2019,15 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
|
||||
// Code common for calls using the IC.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
}
|
||||
VisitForAccumulatorValue(key);
|
||||
__ mov(ecx, eax);
|
||||
}
|
||||
VisitForAccumulatorValue(key);
|
||||
__ mov(ecx, eax);
|
||||
// Record source position of the IC call.
|
||||
SetSourcePosition(expr->position());
|
||||
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(
|
||||
arg_count, in_loop);
|
||||
@ -2038,11 +2042,13 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) {
|
||||
// Code common for calls using the call stub.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
}
|
||||
}
|
||||
// Record source position for debugger.
|
||||
SetSourcePosition(expr->position());
|
||||
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
||||
__ CallStub(&stub);
|
||||
@ -2062,37 +2068,38 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
// resolve the function we need to call and the receiver of the
|
||||
// call. Then we call the resolved function using the given
|
||||
// arguments.
|
||||
VisitForStackValue(fun);
|
||||
__ push(Immediate(Factory::undefined_value())); // Reserved receiver slot.
|
||||
|
||||
// Push the arguments.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
{ PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
|
||||
VisitForStackValue(fun);
|
||||
__ push(Immediate(Factory::undefined_value())); // Reserved receiver slot.
|
||||
|
||||
// Push the arguments.
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
}
|
||||
|
||||
// Push copy of the function - found below the arguments.
|
||||
__ push(Operand(esp, (arg_count + 1) * kPointerSize));
|
||||
|
||||
// Push copy of the first argument or undefined if it doesn't exist.
|
||||
if (arg_count > 0) {
|
||||
__ push(Operand(esp, arg_count * kPointerSize));
|
||||
} else {
|
||||
__ push(Immediate(Factory::undefined_value()));
|
||||
}
|
||||
|
||||
// Push the receiver of the enclosing function and do runtime call.
|
||||
__ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
|
||||
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
|
||||
|
||||
// The runtime call returns a pair of values in eax (function) and
|
||||
// edx (receiver). Touch up the stack with the right values.
|
||||
__ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
|
||||
__ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
|
||||
}
|
||||
|
||||
// Push copy of the function - found below the arguments.
|
||||
__ push(Operand(esp, (arg_count + 1) * kPointerSize));
|
||||
|
||||
// Push copy of the first argument or undefined if it doesn't exist.
|
||||
if (arg_count > 0) {
|
||||
__ push(Operand(esp, arg_count * kPointerSize));
|
||||
} else {
|
||||
__ push(Immediate(Factory::undefined_value()));
|
||||
}
|
||||
|
||||
// Push the receiver of the enclosing function and do runtime call.
|
||||
__ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
|
||||
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
|
||||
|
||||
// The runtime call returns a pair of values in eax (function) and
|
||||
// edx (receiver). Touch up the stack with the right values.
|
||||
__ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
|
||||
__ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
|
||||
|
||||
// Record source position for debugger.
|
||||
SetSourcePosition(expr->position());
|
||||
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
||||
__ CallStub(&stub);
|
||||
@ -2108,12 +2115,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
// Call to a lookup slot (dynamically introduced variable).
|
||||
Label slow, done;
|
||||
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
|
||||
NOT_INSIDE_TYPEOF,
|
||||
&slow,
|
||||
&done);
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
|
||||
NOT_INSIDE_TYPEOF,
|
||||
&slow,
|
||||
&done);
|
||||
}
|
||||
|
||||
__ bind(&slow);
|
||||
// Call the runtime to find the function to call (returned in eax)
|
||||
@ -2152,11 +2161,15 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
// Call to a keyed property.
|
||||
// For a synthetic property use keyed load IC followed by function call,
|
||||
// for a regular property use keyed EmitCallIC.
|
||||
VisitForStackValue(prop->obj());
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(prop->obj());
|
||||
}
|
||||
if (prop->is_synthetic()) {
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
}
|
||||
// Record source code position for IC call.
|
||||
SetSourcePosition(prop->position());
|
||||
SetSourcePosition(prop->position(), FORCED_POSITION);
|
||||
__ pop(edx); // We do not need to keep the receiver.
|
||||
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
|
||||
@ -2181,7 +2194,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
loop_depth() == 0) {
|
||||
lit->set_try_full_codegen(true);
|
||||
}
|
||||
VisitForStackValue(fun);
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(fun);
|
||||
}
|
||||
// Load global receiver object.
|
||||
__ mov(ebx, CodeGenerator::GlobalObject());
|
||||
__ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
|
||||
|
@ -414,8 +414,9 @@ void BreakTarget::Branch(Condition cc, Hint hint) {
|
||||
|
||||
DeferredCode::DeferredCode()
|
||||
: masm_(CodeGeneratorScope::Current()->masm()),
|
||||
statement_position_(masm_->current_statement_position()),
|
||||
position_(masm_->current_position()),
|
||||
statement_position_(masm_->positions_recorder()->
|
||||
current_statement_position()),
|
||||
position_(masm_->positions_recorder()->current_position()),
|
||||
frame_state_(CodeGeneratorScope::Current()->frame()) {
|
||||
ASSERT(statement_position_ != RelocInfo::kNoPosition);
|
||||
ASSERT(position_ != RelocInfo::kNoPosition);
|
||||
|
@ -36,8 +36,9 @@ namespace internal {
|
||||
|
||||
DeferredCode::DeferredCode()
|
||||
: masm_(CodeGeneratorScope::Current()->masm()),
|
||||
statement_position_(masm_->current_statement_position()),
|
||||
position_(masm_->current_position()),
|
||||
statement_position_(masm_->positions_recorder()->
|
||||
current_statement_position()),
|
||||
position_(masm_->positions_recorder()->current_position()),
|
||||
frame_state_(*CodeGeneratorScope::Current()->frame()) {
|
||||
ASSERT(statement_position_ != RelocInfo::kNoPosition);
|
||||
ASSERT(position_ != RelocInfo::kNoPosition);
|
||||
|
@ -296,7 +296,7 @@ static void InitCoverageLog();
|
||||
byte* Assembler::spare_buffer_ = NULL;
|
||||
|
||||
Assembler::Assembler(void* buffer, int buffer_size)
|
||||
: code_targets_(100) {
|
||||
: code_targets_(100), positions_recorder_(this) {
|
||||
if (buffer == NULL) {
|
||||
// Do our own buffer management.
|
||||
if (buffer_size <= kMinimalBufferSize) {
|
||||
@ -337,10 +337,7 @@ Assembler::Assembler(void* buffer, int buffer_size)
|
||||
reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
|
||||
|
||||
last_pc_ = NULL;
|
||||
current_statement_position_ = RelocInfo::kNoPosition;
|
||||
current_position_ = RelocInfo::kNoPosition;
|
||||
written_statement_position_ = current_statement_position_;
|
||||
written_position_ = current_position_;
|
||||
|
||||
#ifdef GENERATED_CODE_COVERAGE
|
||||
InitCoverageLog();
|
||||
#endif
|
||||
@ -845,7 +842,7 @@ void Assembler::call(Label* L) {
|
||||
|
||||
|
||||
void Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) {
|
||||
WriteRecordedPositions();
|
||||
positions_recorder()->WriteRecordedPositions();
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
// 1110 1000 #32-bit disp.
|
||||
@ -2935,14 +2932,14 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
|
||||
}
|
||||
|
||||
void Assembler::RecordJSReturn() {
|
||||
WriteRecordedPositions();
|
||||
positions_recorder()->WriteRecordedPositions();
|
||||
EnsureSpace ensure_space(this);
|
||||
RecordRelocInfo(RelocInfo::JS_RETURN);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::RecordDebugBreakSlot() {
|
||||
WriteRecordedPositions();
|
||||
positions_recorder()->WriteRecordedPositions();
|
||||
EnsureSpace ensure_space(this);
|
||||
RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
|
||||
}
|
||||
@ -2956,47 +2953,6 @@ void Assembler::RecordComment(const char* msg) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::RecordPosition(int pos) {
|
||||
ASSERT(pos != RelocInfo::kNoPosition);
|
||||
ASSERT(pos >= 0);
|
||||
current_position_ = pos;
|
||||
}
|
||||
|
||||
|
||||
void Assembler::RecordStatementPosition(int pos) {
|
||||
ASSERT(pos != RelocInfo::kNoPosition);
|
||||
ASSERT(pos >= 0);
|
||||
current_statement_position_ = pos;
|
||||
}
|
||||
|
||||
|
||||
bool Assembler::WriteRecordedPositions() {
|
||||
bool written = false;
|
||||
|
||||
// Write the statement position if it is different from what was written last
|
||||
// time.
|
||||
if (current_statement_position_ != written_statement_position_) {
|
||||
EnsureSpace ensure_space(this);
|
||||
RecordRelocInfo(RelocInfo::STATEMENT_POSITION, current_statement_position_);
|
||||
written_statement_position_ = current_statement_position_;
|
||||
written = true;
|
||||
}
|
||||
|
||||
// Write the position if it is different from what was written last time and
|
||||
// also different from the written statement position.
|
||||
if (current_position_ != written_position_ &&
|
||||
current_position_ != written_statement_position_) {
|
||||
EnsureSpace ensure_space(this);
|
||||
RecordRelocInfo(RelocInfo::POSITION, current_position_);
|
||||
written_position_ = current_position_;
|
||||
written = true;
|
||||
}
|
||||
|
||||
// Return whether something was written.
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
|
||||
1 << RelocInfo::INTERNAL_REFERENCE;
|
||||
|
||||
|
@ -1174,13 +1174,9 @@ class Assembler : public Malloced {
|
||||
// Use --debug_code to enable.
|
||||
void RecordComment(const char* msg);
|
||||
|
||||
void RecordPosition(int pos);
|
||||
void RecordStatementPosition(int pos);
|
||||
bool WriteRecordedPositions();
|
||||
|
||||
int pc_offset() const { return static_cast<int>(pc_ - buffer_); }
|
||||
int current_statement_position() const { return current_statement_position_; }
|
||||
int current_position() const { return current_position_; }
|
||||
|
||||
PositionsRecorder* positions_recorder() { return &positions_recorder_; }
|
||||
|
||||
// Check if there is less than kGap bytes available in the buffer.
|
||||
// If this is the case, we need to grow the buffer before emitting
|
||||
@ -1404,11 +1400,8 @@ class Assembler : public Malloced {
|
||||
// push-pop elimination
|
||||
byte* last_pc_;
|
||||
|
||||
// source position information
|
||||
int current_statement_position_;
|
||||
int current_position_;
|
||||
int written_statement_position_;
|
||||
int written_position_;
|
||||
PositionsRecorder positions_recorder_;
|
||||
friend class PositionsRecorder;
|
||||
};
|
||||
|
||||
|
||||
|
@ -2956,7 +2956,7 @@ void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
|
||||
CodeForStatementPosition(node);
|
||||
Load(node->expression());
|
||||
Result return_value = frame_->Pop();
|
||||
masm()->WriteRecordedPositions();
|
||||
masm()->positions_recorder()->WriteRecordedPositions();
|
||||
if (function_return_is_shadowed_) {
|
||||
function_return_.Jump(&return_value);
|
||||
} else {
|
||||
|
@ -1717,12 +1717,14 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
|
||||
// Code common for calls using the IC.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
}
|
||||
__ Move(rcx, name);
|
||||
}
|
||||
__ Move(rcx, name);
|
||||
// Record source position for debugger.
|
||||
SetSourcePosition(expr->position());
|
||||
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||
// Call the IC initialization code.
|
||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
|
||||
@ -1740,13 +1742,15 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
|
||||
// Code common for calls using the IC.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
}
|
||||
VisitForAccumulatorValue(key);
|
||||
__ movq(rcx, rax);
|
||||
}
|
||||
VisitForAccumulatorValue(key);
|
||||
__ movq(rcx, rax);
|
||||
// Record source position for debugger.
|
||||
SetSourcePosition(expr->position());
|
||||
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||
// Call the IC initialization code.
|
||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count,
|
||||
@ -1762,11 +1766,13 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) {
|
||||
// Code common for calls using the call stub.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
}
|
||||
}
|
||||
// Record source position for debugger.
|
||||
SetSourcePosition(expr->position());
|
||||
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
||||
__ CallStub(&stub);
|
||||
@ -1787,37 +1793,39 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
// resolve the function we need to call and the receiver of the
|
||||
// call. The we call the resolved function using the given
|
||||
// arguments.
|
||||
VisitForStackValue(fun);
|
||||
__ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
|
||||
|
||||
// Push the arguments.
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
int arg_count = args->length();
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
}
|
||||
{ PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
|
||||
|
||||
// Push copy of the function - found below the arguments.
|
||||
__ push(Operand(rsp, (arg_count + 1) * kPointerSize));
|
||||
VisitForStackValue(fun);
|
||||
__ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
|
||||
|
||||
// Push copy of the first argument or undefined if it doesn't exist.
|
||||
if (arg_count > 0) {
|
||||
__ push(Operand(rsp, arg_count * kPointerSize));
|
||||
} else {
|
||||
// Push the arguments.
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
VisitForStackValue(args->at(i));
|
||||
}
|
||||
|
||||
// Push copy of the function - found below the arguments.
|
||||
__ push(Operand(rsp, (arg_count + 1) * kPointerSize));
|
||||
|
||||
// Push copy of the first argument or undefined if it doesn't exist.
|
||||
if (arg_count > 0) {
|
||||
__ push(Operand(rsp, arg_count * kPointerSize));
|
||||
} else {
|
||||
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||
}
|
||||
|
||||
// Push the receiver of the enclosing function and do runtime call.
|
||||
__ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize));
|
||||
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
|
||||
|
||||
// The runtime call returns a pair of values in rax (function) and
|
||||
// rdx (receiver). Touch up the stack with the right values.
|
||||
__ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
|
||||
__ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
|
||||
}
|
||||
|
||||
// Push the receiver of the enclosing function and do runtime call.
|
||||
__ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize));
|
||||
__ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
|
||||
|
||||
// The runtime call returns a pair of values in rax (function) and
|
||||
// rdx (receiver). Touch up the stack with the right values.
|
||||
__ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx);
|
||||
__ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax);
|
||||
|
||||
// Record source position for debugger.
|
||||
SetSourcePosition(expr->position());
|
||||
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
||||
__ CallStub(&stub);
|
||||
@ -1834,35 +1842,37 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
// Call to a lookup slot (dynamically introduced variable).
|
||||
Label slow, done;
|
||||
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
|
||||
NOT_INSIDE_TYPEOF,
|
||||
&slow,
|
||||
&done);
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
// Generate code for loading from variables potentially shadowed
|
||||
// by eval-introduced variables.
|
||||
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
|
||||
NOT_INSIDE_TYPEOF,
|
||||
&slow,
|
||||
&done);
|
||||
|
||||
__ bind(&slow);
|
||||
// Call the runtime to find the function to call (returned in rax)
|
||||
// and the object holding it (returned in rdx).
|
||||
__ push(context_register());
|
||||
__ Push(var->name());
|
||||
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
||||
__ push(rax); // Function.
|
||||
__ push(rdx); // Receiver.
|
||||
__ bind(&slow);
|
||||
// Call the runtime to find the function to call (returned in rax)
|
||||
// and the object holding it (returned in rdx).
|
||||
__ push(context_register());
|
||||
__ Push(var->name());
|
||||
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
||||
__ push(rax); // Function.
|
||||
__ push(rdx); // Receiver.
|
||||
|
||||
// If fast case code has been generated, emit code to push the
|
||||
// function and receiver and have the slow path jump around this
|
||||
// code.
|
||||
if (done.is_linked()) {
|
||||
NearLabel call;
|
||||
__ jmp(&call);
|
||||
__ bind(&done);
|
||||
// Push function.
|
||||
__ push(rax);
|
||||
// Push global receiver.
|
||||
__ movq(rbx, CodeGenerator::GlobalObject());
|
||||
__ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
|
||||
__ bind(&call);
|
||||
// If fast case code has been generated, emit code to push the
|
||||
// function and receiver and have the slow path jump around this
|
||||
// code.
|
||||
if (done.is_linked()) {
|
||||
NearLabel call;
|
||||
__ jmp(&call);
|
||||
__ bind(&done);
|
||||
// Push function.
|
||||
__ push(rax);
|
||||
// Push global receiver.
|
||||
__ movq(rbx, CodeGenerator::GlobalObject());
|
||||
__ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
|
||||
__ bind(&call);
|
||||
}
|
||||
}
|
||||
|
||||
EmitCallWithStub(expr);
|
||||
@ -1873,18 +1883,24 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
Literal* key = prop->key()->AsLiteral();
|
||||
if (key != NULL && key->handle()->IsSymbol()) {
|
||||
// Call to a named property, use call IC.
|
||||
VisitForStackValue(prop->obj());
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(prop->obj());
|
||||
}
|
||||
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
|
||||
} else {
|
||||
// Call to a keyed property.
|
||||
// For a synthetic property use keyed load IC followed by function call,
|
||||
// for a regular property use KeyedCallIC.
|
||||
VisitForStackValue(prop->obj());
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(prop->obj());
|
||||
}
|
||||
if (prop->is_synthetic()) {
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
__ movq(rdx, Operand(rsp, 0));
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
VisitForAccumulatorValue(prop->key());
|
||||
__ movq(rdx, Operand(rsp, 0));
|
||||
}
|
||||
// Record source code position for IC call.
|
||||
SetSourcePosition(prop->position());
|
||||
SetSourcePosition(prop->position(), FORCED_POSITION);
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
|
||||
EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
||||
// Pop receiver.
|
||||
@ -1909,7 +1925,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
||||
loop_depth() == 0) {
|
||||
lit->set_try_full_codegen(true);
|
||||
}
|
||||
VisitForStackValue(fun);
|
||||
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||
VisitForStackValue(fun);
|
||||
}
|
||||
// Load global receiver object.
|
||||
__ movq(rbx, CodeGenerator::GlobalObject());
|
||||
__ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
|
||||
|
95
test/mjsunit/regress/regress-conditional-position.js
Normal file
95
test/mjsunit/regress/regress-conditional-position.js
Normal file
@ -0,0 +1,95 @@
|
||||
// Copyright 2010 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.
|
||||
|
||||
// Flags: --always-full-compiler
|
||||
|
||||
var functionToCatch;
|
||||
var lineNumber;
|
||||
|
||||
function catchLineNumber () {
|
||||
var x = {};
|
||||
|
||||
Error.prepareStackTrace = function (error, stackTrace) {
|
||||
stackTrace.some(function (frame) {
|
||||
if (frame.getFunction() == functionToCatch) {
|
||||
lineNumber = frame.getLineNumber();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return lineNumber;
|
||||
};
|
||||
|
||||
Error.captureStackTrace(x);
|
||||
return x.stack;
|
||||
}
|
||||
|
||||
function log() {
|
||||
catchLineNumber();
|
||||
}
|
||||
|
||||
function foo() {}
|
||||
|
||||
function test1() {
|
||||
log(foo() == foo()
|
||||
? 'a'
|
||||
: 'b');
|
||||
}
|
||||
|
||||
function test2() {
|
||||
var o = { foo: function () {}}
|
||||
log(o.foo() == o.foo()
|
||||
? 'a'
|
||||
: 'b');
|
||||
}
|
||||
|
||||
function test3() {
|
||||
var o = { log: log, foo: function() { } };
|
||||
o.log(o.foo() == o.foo()
|
||||
? 'a'
|
||||
: 'b');
|
||||
|
||||
}
|
||||
|
||||
function test(f, expectedLineNumber) {
|
||||
functionToCatch = f;
|
||||
f();
|
||||
|
||||
assertEquals(expectedLineNumber, lineNumber);
|
||||
}
|
||||
|
||||
test(test1, 58);
|
||||
test(test2, 65);
|
||||
test(test3, 72);
|
||||
|
||||
eval(test1.toString() + "//@ sourceUrl=foo");
|
||||
eval(test2.toString() + "//@ sourceUrl=foo");
|
||||
eval(test3.toString() + "//@ sourceUrl=foo");
|
||||
|
||||
test(test1, 2);
|
||||
test(test2, 3);
|
||||
test(test3, 3);
|
Loading…
Reference in New Issue
Block a user