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 const int kMinimalBufferSize = 4*KB;
|
||||||
static byte* spare_buffer_ = NULL;
|
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) {
|
if (buffer == NULL) {
|
||||||
// Do our own buffer management.
|
// Do our own buffer management.
|
||||||
if (buffer_size <= kMinimalBufferSize) {
|
if (buffer_size <= kMinimalBufferSize) {
|
||||||
@ -354,10 +355,6 @@ Assembler::Assembler(void* buffer, int buffer_size) {
|
|||||||
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;
|
||||||
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
|
void Assembler::blx(int branch_offset) { // v5 and above
|
||||||
WriteRecordedPositions();
|
positions_recorder()->WriteRecordedPositions();
|
||||||
ASSERT((branch_offset & 1) == 0);
|
ASSERT((branch_offset & 1) == 0);
|
||||||
int h = ((branch_offset & 2) >> 1)*B24;
|
int h = ((branch_offset & 2) >> 1)*B24;
|
||||||
int imm24 = branch_offset >> 2;
|
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
|
void Assembler::blx(Register target, Condition cond) { // v5 and above
|
||||||
WriteRecordedPositions();
|
positions_recorder()->WriteRecordedPositions();
|
||||||
ASSERT(!target.is(pc));
|
ASSERT(!target.is(pc));
|
||||||
emit(cond | B24 | B21 | 15*B16 | 15*B12 | 15*B8 | 3*B4 | target.code());
|
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
|
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
|
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());
|
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) {
|
void Assembler::mov(Register dst, const Operand& src, SBit s, Condition cond) {
|
||||||
if (dst.is(pc)) {
|
if (dst.is(pc)) {
|
||||||
WriteRecordedPositions();
|
positions_recorder()->WriteRecordedPositions();
|
||||||
}
|
}
|
||||||
// Don't allow nop instructions in the form mov rn, rn to be generated using
|
// 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)
|
// 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.
|
// Load/Store instructions.
|
||||||
void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
|
void Assembler::ldr(Register dst, const MemOperand& src, Condition cond) {
|
||||||
if (dst.is(pc)) {
|
if (dst.is(pc)) {
|
||||||
WriteRecordedPositions();
|
positions_recorder()->WriteRecordedPositions();
|
||||||
}
|
}
|
||||||
addrmod2(cond | B26 | L, dst, src);
|
addrmod2(cond | B26 | L, dst, src);
|
||||||
|
|
||||||
@ -2377,14 +2374,14 @@ void Assembler::BlockConstPoolFor(int instructions) {
|
|||||||
|
|
||||||
// Debugging.
|
// Debugging.
|
||||||
void Assembler::RecordJSReturn() {
|
void Assembler::RecordJSReturn() {
|
||||||
WriteRecordedPositions();
|
positions_recorder()->WriteRecordedPositions();
|
||||||
CheckBuffer();
|
CheckBuffer();
|
||||||
RecordRelocInfo(RelocInfo::JS_RETURN);
|
RecordRelocInfo(RelocInfo::JS_RETURN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Assembler::RecordDebugBreakSlot() {
|
void Assembler::RecordDebugBreakSlot() {
|
||||||
WriteRecordedPositions();
|
positions_recorder()->WriteRecordedPositions();
|
||||||
CheckBuffer();
|
CheckBuffer();
|
||||||
RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
|
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() {
|
void Assembler::GrowBuffer() {
|
||||||
if (!own_buffer_) FATAL("external code buffer is too small");
|
if (!own_buffer_) FATAL("external code buffer is too small");
|
||||||
|
|
||||||
|
@ -1117,13 +1117,9 @@ class Assembler : public Malloced {
|
|||||||
// Use --debug_code to enable.
|
// Use --debug_code to enable.
|
||||||
void RecordComment(const char* msg);
|
void RecordComment(const char* msg);
|
||||||
|
|
||||||
void RecordPosition(int pos);
|
|
||||||
void RecordStatementPosition(int pos);
|
|
||||||
bool WriteRecordedPositions();
|
|
||||||
|
|
||||||
int pc_offset() const { return pc_ - buffer_; }
|
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) {
|
bool can_peephole_optimize(int instructions) {
|
||||||
if (!FLAG_peephole_optimization) return false;
|
if (!FLAG_peephole_optimization) return false;
|
||||||
@ -1259,12 +1255,6 @@ class Assembler : public Malloced {
|
|||||||
// The bound position, before this we cannot do instruction elimination.
|
// The bound position, before this we cannot do instruction elimination.
|
||||||
int last_bound_pos_;
|
int last_bound_pos_;
|
||||||
|
|
||||||
// source position information
|
|
||||||
int current_position_;
|
|
||||||
int current_statement_position_;
|
|
||||||
int written_position_;
|
|
||||||
int written_statement_position_;
|
|
||||||
|
|
||||||
// Code emission
|
// Code emission
|
||||||
inline void CheckBuffer();
|
inline void CheckBuffer();
|
||||||
void GrowBuffer();
|
void GrowBuffer();
|
||||||
@ -1290,8 +1280,21 @@ class Assembler : public Malloced {
|
|||||||
friend class RelocInfo;
|
friend class RelocInfo;
|
||||||
friend class CodePatcher;
|
friend class CodePatcher;
|
||||||
friend class BlockConstPoolScope;
|
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
|
} } // namespace v8::internal
|
||||||
|
|
||||||
#endif // V8_ARM_ASSEMBLER_ARM_H_
|
#endif // V8_ARM_ASSEMBLER_ARM_H_
|
||||||
|
@ -1688,12 +1688,14 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
|
|||||||
// Code common for calls using the IC.
|
// Code common for calls using the IC.
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
int arg_count = args->length();
|
int arg_count = args->length();
|
||||||
for (int i = 0; i < arg_count; i++) {
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
VisitForStackValue(args->at(i));
|
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.
|
// Record source position for debugger.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||||
// Call the IC initialization code.
|
// Call the IC initialization code.
|
||||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||||
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, 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.
|
// Code common for calls using the IC.
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
int arg_count = args->length();
|
int arg_count = args->length();
|
||||||
for (int i = 0; i < arg_count; i++) {
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
VisitForStackValue(args->at(i));
|
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.
|
// Record source position for debugger.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||||
// Call the IC initialization code.
|
// Call the IC initialization code.
|
||||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||||
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count,
|
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count,
|
||||||
@ -1732,11 +1736,13 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) {
|
|||||||
// Code common for calls using the call stub.
|
// Code common for calls using the call stub.
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
int arg_count = args->length();
|
int arg_count = args->length();
|
||||||
for (int i = 0; i < arg_count; i++) {
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
VisitForStackValue(args->at(i));
|
for (int i = 0; i < arg_count; i++) {
|
||||||
|
VisitForStackValue(args->at(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Record source position for debugger.
|
// Record source position for debugger.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||||
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
||||||
__ CallStub(&stub);
|
__ CallStub(&stub);
|
||||||
@ -1756,41 +1762,46 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
|||||||
// resolve the function we need to call and the receiver of the
|
// resolve the function we need to call and the receiver of the
|
||||||
// call. Then we call the resolved function using the given
|
// call. Then we call the resolved function using the given
|
||||||
// arguments.
|
// arguments.
|
||||||
VisitForStackValue(fun);
|
|
||||||
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
|
|
||||||
__ push(r2); // Reserved receiver slot.
|
|
||||||
|
|
||||||
// Push the arguments.
|
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
int arg_count = args->length();
|
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.
|
{ PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
|
||||||
__ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
|
|
||||||
__ push(r1);
|
|
||||||
|
|
||||||
// Push copy of the first argument or undefined if it doesn't exist.
|
VisitForStackValue(fun);
|
||||||
if (arg_count > 0) {
|
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
|
||||||
__ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
|
__ 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);
|
__ 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.
|
// Record source position for debugger.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||||
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
||||||
__ CallStub(&stub);
|
__ CallStub(&stub);
|
||||||
@ -1807,12 +1818,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
|||||||
// Call to a lookup slot (dynamically introduced variable).
|
// Call to a lookup slot (dynamically introduced variable).
|
||||||
Label slow, done;
|
Label slow, done;
|
||||||
|
|
||||||
// Generate code for loading from variables potentially shadowed
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
// by eval-introduced variables.
|
// Generate code for loading from variables potentially shadowed
|
||||||
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
|
// by eval-introduced variables.
|
||||||
NOT_INSIDE_TYPEOF,
|
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
|
||||||
&slow,
|
NOT_INSIDE_TYPEOF,
|
||||||
&done);
|
&slow,
|
||||||
|
&done);
|
||||||
|
}
|
||||||
|
|
||||||
__ bind(&slow);
|
__ bind(&slow);
|
||||||
// Call the runtime to find the function to call (returned in r0)
|
// 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();
|
Literal* key = prop->key()->AsLiteral();
|
||||||
if (key != NULL && key->handle()->IsSymbol()) {
|
if (key != NULL && key->handle()->IsSymbol()) {
|
||||||
// Call to a named property, use call IC.
|
// 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);
|
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
|
||||||
} else {
|
} else {
|
||||||
// Call to a keyed property.
|
// Call to a keyed property.
|
||||||
// For a synthetic property use keyed load IC followed by function call,
|
// For a synthetic property use keyed load IC followed by function call,
|
||||||
// for a regular property use keyed CallIC.
|
// for a regular property use keyed CallIC.
|
||||||
VisitForStackValue(prop->obj());
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
|
VisitForStackValue(prop->obj());
|
||||||
|
}
|
||||||
if (prop->is_synthetic()) {
|
if (prop->is_synthetic()) {
|
||||||
VisitForAccumulatorValue(prop->key());
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
|
VisitForAccumulatorValue(prop->key());
|
||||||
|
}
|
||||||
// Record source code position for IC call.
|
// 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.
|
__ pop(r1); // We do not need to keep the receiver.
|
||||||
|
|
||||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
|
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
|
||||||
@ -1879,7 +1898,10 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
|||||||
loop_depth() == 0) {
|
loop_depth() == 0) {
|
||||||
lit->set_try_full_codegen(true);
|
lit->set_try_full_codegen(true);
|
||||||
}
|
}
|
||||||
VisitForStackValue(fun);
|
|
||||||
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
|
VisitForStackValue(fun);
|
||||||
|
}
|
||||||
// Load global receiver object.
|
// Load global receiver object.
|
||||||
__ ldr(r1, CodeGenerator::GlobalObject());
|
__ ldr(r1, CodeGenerator::GlobalObject());
|
||||||
__ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
|
__ 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
|
// address is loaded. The mov method will automatically record
|
||||||
// positions when pc is the target, since this is not the case here
|
// positions when pc is the target, since this is not the case here
|
||||||
// we have to do it explicitly.
|
// we have to do it explicitly.
|
||||||
WriteRecordedPositions();
|
positions_recorder()->WriteRecordedPositions();
|
||||||
|
|
||||||
mov(ip, Operand(target, rmode), LeaveCC, cond);
|
mov(ip, Operand(target, rmode), LeaveCC, cond);
|
||||||
blx(ip, cond);
|
blx(ip, cond);
|
||||||
|
@ -804,4 +804,53 @@ ExternalReference ExternalReference::debug_step_in_fp_address() {
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
} } // 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
|
// Utility functions
|
||||||
|
|
||||||
|
@ -70,9 +70,10 @@ void CodeGenerator::ProcessDeferred() {
|
|||||||
DeferredCode* code = deferred_.RemoveLast();
|
DeferredCode* code = deferred_.RemoveLast();
|
||||||
ASSERT(masm_ == code->masm());
|
ASSERT(masm_ == code->masm());
|
||||||
// Record position of deferred code stub.
|
// Record position of deferred code stub.
|
||||||
masm_->RecordStatementPosition(code->statement_position());
|
masm_->positions_recorder()->RecordStatementPosition(
|
||||||
|
code->statement_position());
|
||||||
if (code->position() != RelocInfo::kNoPosition) {
|
if (code->position() != RelocInfo::kNoPosition) {
|
||||||
masm_->RecordPosition(code->position());
|
masm_->positions_recorder()->RecordPosition(code->position());
|
||||||
}
|
}
|
||||||
// Generate the code.
|
// Generate the code.
|
||||||
Comment cmnt(masm_, code->comment());
|
Comment cmnt(masm_, code->comment());
|
||||||
@ -402,10 +403,10 @@ bool CodeGenerator::RecordPositions(MacroAssembler* masm,
|
|||||||
int pos,
|
int pos,
|
||||||
bool right_here) {
|
bool right_here) {
|
||||||
if (pos != RelocInfo::kNoPosition) {
|
if (pos != RelocInfo::kNoPosition) {
|
||||||
masm->RecordStatementPosition(pos);
|
masm->positions_recorder()->RecordStatementPosition(pos);
|
||||||
masm->RecordPosition(pos);
|
masm->positions_recorder()->RecordPosition(pos);
|
||||||
if (right_here) {
|
if (right_here) {
|
||||||
return masm->WriteRecordedPositions();
|
return masm->positions_recorder()->WriteRecordedPositions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -435,7 +436,7 @@ void CodeGenerator::CodeForDoWhileConditionPosition(DoWhileStatement* stmt) {
|
|||||||
|
|
||||||
void CodeGenerator::CodeForSourcePosition(int pos) {
|
void CodeGenerator::CodeForSourcePosition(int pos) {
|
||||||
if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
|
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) {
|
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 SetStatementPosition(Statement* stmt);
|
||||||
void SetExpressionPosition(Expression* expr, int pos);
|
void SetExpressionPosition(Expression* expr, int pos);
|
||||||
void SetStatementPosition(int pos);
|
void SetStatementPosition(int pos);
|
||||||
void SetSourcePosition(int pos);
|
void SetSourcePosition(
|
||||||
|
int pos,
|
||||||
|
PositionRecordingType recording_type = NORMAL_POSITION);
|
||||||
|
|
||||||
// Non-local control flow support.
|
// Non-local control flow support.
|
||||||
void EnterFinallyBlock();
|
void EnterFinallyBlock();
|
||||||
|
@ -298,7 +298,8 @@ static void InitCoverageLog();
|
|||||||
// Spare buffer.
|
// Spare buffer.
|
||||||
byte* Assembler::spare_buffer_ = NULL;
|
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) {
|
if (buffer == NULL) {
|
||||||
// Do our own buffer management.
|
// Do our own buffer management.
|
||||||
if (buffer_size <= kMinimalBufferSize) {
|
if (buffer_size <= kMinimalBufferSize) {
|
||||||
@ -339,10 +340,6 @@ Assembler::Assembler(void* buffer, int buffer_size) {
|
|||||||
reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
|
reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
|
||||||
|
|
||||||
last_pc_ = NULL;
|
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
|
#ifdef GENERATED_CODE_COVERAGE
|
||||||
InitCoverageLog();
|
InitCoverageLog();
|
||||||
#endif
|
#endif
|
||||||
@ -1581,7 +1578,7 @@ void Assembler::call(const Operand& adr) {
|
|||||||
|
|
||||||
|
|
||||||
void Assembler::call(Handle<Code> code, RelocInfo::Mode rmode) {
|
void Assembler::call(Handle<Code> code, RelocInfo::Mode rmode) {
|
||||||
WriteRecordedPositions();
|
positions_recorder()->WriteRecordedPositions();
|
||||||
EnsureSpace ensure_space(this);
|
EnsureSpace ensure_space(this);
|
||||||
last_pc_ = pc_;
|
last_pc_ = pc_;
|
||||||
ASSERT(RelocInfo::IsCodeTarget(rmode));
|
ASSERT(RelocInfo::IsCodeTarget(rmode));
|
||||||
@ -2464,14 +2461,14 @@ void Assembler::Print() {
|
|||||||
|
|
||||||
|
|
||||||
void Assembler::RecordJSReturn() {
|
void Assembler::RecordJSReturn() {
|
||||||
WriteRecordedPositions();
|
positions_recorder()->WriteRecordedPositions();
|
||||||
EnsureSpace ensure_space(this);
|
EnsureSpace ensure_space(this);
|
||||||
RecordRelocInfo(RelocInfo::JS_RETURN);
|
RecordRelocInfo(RelocInfo::JS_RETURN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Assembler::RecordDebugBreakSlot() {
|
void Assembler::RecordDebugBreakSlot() {
|
||||||
WriteRecordedPositions();
|
positions_recorder()->WriteRecordedPositions();
|
||||||
EnsureSpace ensure_space(this);
|
EnsureSpace ensure_space(this);
|
||||||
RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
|
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() {
|
void Assembler::GrowBuffer() {
|
||||||
ASSERT(overflow());
|
ASSERT(overflow());
|
||||||
if (!own_buffer_) FATAL("external code buffer is too small");
|
if (!own_buffer_) FATAL("external code buffer is too small");
|
||||||
|
@ -847,17 +847,11 @@ class Assembler : public Malloced {
|
|||||||
// Use --debug_code to enable.
|
// Use --debug_code to enable.
|
||||||
void RecordComment(const char* msg);
|
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.
|
// Writes a single word of data in the code stream.
|
||||||
// Used for inline tables, e.g., jump-tables.
|
// Used for inline tables, e.g., jump-tables.
|
||||||
void dd(uint32_t data, RelocInfo::Mode reloc_info);
|
void dd(uint32_t data, RelocInfo::Mode reloc_info);
|
||||||
|
|
||||||
int pc_offset() const { return pc_ - buffer_; }
|
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.
|
// 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
|
// 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; }
|
static bool IsNop(Address addr) { return *addr == 0x90; }
|
||||||
|
|
||||||
|
PositionsRecorder* positions_recorder() { return &positions_recorder_; }
|
||||||
|
|
||||||
// Avoid overflows for displacements etc.
|
// Avoid overflows for displacements etc.
|
||||||
static const int kMaximalBufferSize = 512*MB;
|
static const int kMaximalBufferSize = 512*MB;
|
||||||
static const int kMinimalBufferSize = 4*KB;
|
static const int kMinimalBufferSize = 4*KB;
|
||||||
@ -947,11 +943,9 @@ class Assembler : public Malloced {
|
|||||||
// push-pop elimination
|
// push-pop elimination
|
||||||
byte* last_pc_;
|
byte* last_pc_;
|
||||||
|
|
||||||
// source position information
|
PositionsRecorder positions_recorder_;
|
||||||
int current_statement_position_;
|
|
||||||
int current_position_;
|
friend class PositionsRecorder;
|
||||||
int written_statement_position_;
|
|
||||||
int written_position_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -3734,7 +3734,7 @@ void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
|
|||||||
CodeForStatementPosition(node);
|
CodeForStatementPosition(node);
|
||||||
Load(node->expression());
|
Load(node->expression());
|
||||||
Result return_value = frame_->Pop();
|
Result return_value = frame_->Pop();
|
||||||
masm()->WriteRecordedPositions();
|
masm()->positions_recorder()->WriteRecordedPositions();
|
||||||
if (function_return_is_shadowed_) {
|
if (function_return_is_shadowed_) {
|
||||||
function_return_.Jump(&return_value);
|
function_return_.Jump(&return_value);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1996,12 +1996,14 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
|
|||||||
// Code common for calls using the IC.
|
// Code common for calls using the IC.
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
int arg_count = args->length();
|
int arg_count = args->length();
|
||||||
for (int i = 0; i < arg_count; i++) {
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
VisitForStackValue(args->at(i));
|
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.
|
// 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;
|
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||||
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
|
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
|
||||||
EmitCallIC(ic, mode);
|
EmitCallIC(ic, mode);
|
||||||
@ -2017,13 +2019,15 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
|
|||||||
// Code common for calls using the IC.
|
// Code common for calls using the IC.
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
int arg_count = args->length();
|
int arg_count = args->length();
|
||||||
for (int i = 0; i < arg_count; i++) {
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
VisitForStackValue(args->at(i));
|
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.
|
// 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;
|
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||||
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(
|
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(
|
||||||
arg_count, in_loop);
|
arg_count, in_loop);
|
||||||
@ -2038,11 +2042,13 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) {
|
|||||||
// Code common for calls using the call stub.
|
// Code common for calls using the call stub.
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
int arg_count = args->length();
|
int arg_count = args->length();
|
||||||
for (int i = 0; i < arg_count; i++) {
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
VisitForStackValue(args->at(i));
|
for (int i = 0; i < arg_count; i++) {
|
||||||
|
VisitForStackValue(args->at(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Record source position for debugger.
|
// Record source position for debugger.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||||
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
||||||
__ CallStub(&stub);
|
__ CallStub(&stub);
|
||||||
@ -2062,37 +2068,38 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
|||||||
// resolve the function we need to call and the receiver of the
|
// resolve the function we need to call and the receiver of the
|
||||||
// call. Then we call the resolved function using the given
|
// call. Then we call the resolved function using the given
|
||||||
// arguments.
|
// arguments.
|
||||||
VisitForStackValue(fun);
|
|
||||||
__ push(Immediate(Factory::undefined_value())); // Reserved receiver slot.
|
|
||||||
|
|
||||||
// Push the arguments.
|
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
int arg_count = args->length();
|
int arg_count = args->length();
|
||||||
for (int i = 0; i < arg_count; i++) {
|
{ PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
|
||||||
VisitForStackValue(args->at(i));
|
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.
|
// Record source position for debugger.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||||
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
||||||
__ CallStub(&stub);
|
__ CallStub(&stub);
|
||||||
@ -2108,12 +2115,14 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
|||||||
// Call to a lookup slot (dynamically introduced variable).
|
// Call to a lookup slot (dynamically introduced variable).
|
||||||
Label slow, done;
|
Label slow, done;
|
||||||
|
|
||||||
// Generate code for loading from variables potentially shadowed
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
// by eval-introduced variables.
|
// Generate code for loading from variables potentially shadowed
|
||||||
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
|
// by eval-introduced variables.
|
||||||
NOT_INSIDE_TYPEOF,
|
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
|
||||||
&slow,
|
NOT_INSIDE_TYPEOF,
|
||||||
&done);
|
&slow,
|
||||||
|
&done);
|
||||||
|
}
|
||||||
|
|
||||||
__ bind(&slow);
|
__ bind(&slow);
|
||||||
// Call the runtime to find the function to call (returned in eax)
|
// 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.
|
// Call to a keyed property.
|
||||||
// For a synthetic property use keyed load IC followed by function call,
|
// For a synthetic property use keyed load IC followed by function call,
|
||||||
// for a regular property use keyed EmitCallIC.
|
// for a regular property use keyed EmitCallIC.
|
||||||
VisitForStackValue(prop->obj());
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
|
VisitForStackValue(prop->obj());
|
||||||
|
}
|
||||||
if (prop->is_synthetic()) {
|
if (prop->is_synthetic()) {
|
||||||
VisitForAccumulatorValue(prop->key());
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
|
VisitForAccumulatorValue(prop->key());
|
||||||
|
}
|
||||||
// Record source code position for IC call.
|
// 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.
|
__ pop(edx); // We do not need to keep the receiver.
|
||||||
|
|
||||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
|
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
|
||||||
@ -2181,7 +2194,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
|||||||
loop_depth() == 0) {
|
loop_depth() == 0) {
|
||||||
lit->set_try_full_codegen(true);
|
lit->set_try_full_codegen(true);
|
||||||
}
|
}
|
||||||
VisitForStackValue(fun);
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
|
VisitForStackValue(fun);
|
||||||
|
}
|
||||||
// Load global receiver object.
|
// Load global receiver object.
|
||||||
__ mov(ebx, CodeGenerator::GlobalObject());
|
__ mov(ebx, CodeGenerator::GlobalObject());
|
||||||
__ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
|
__ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
|
||||||
|
@ -414,8 +414,9 @@ void BreakTarget::Branch(Condition cc, Hint hint) {
|
|||||||
|
|
||||||
DeferredCode::DeferredCode()
|
DeferredCode::DeferredCode()
|
||||||
: masm_(CodeGeneratorScope::Current()->masm()),
|
: masm_(CodeGeneratorScope::Current()->masm()),
|
||||||
statement_position_(masm_->current_statement_position()),
|
statement_position_(masm_->positions_recorder()->
|
||||||
position_(masm_->current_position()),
|
current_statement_position()),
|
||||||
|
position_(masm_->positions_recorder()->current_position()),
|
||||||
frame_state_(CodeGeneratorScope::Current()->frame()) {
|
frame_state_(CodeGeneratorScope::Current()->frame()) {
|
||||||
ASSERT(statement_position_ != RelocInfo::kNoPosition);
|
ASSERT(statement_position_ != RelocInfo::kNoPosition);
|
||||||
ASSERT(position_ != RelocInfo::kNoPosition);
|
ASSERT(position_ != RelocInfo::kNoPosition);
|
||||||
|
@ -36,8 +36,9 @@ namespace internal {
|
|||||||
|
|
||||||
DeferredCode::DeferredCode()
|
DeferredCode::DeferredCode()
|
||||||
: masm_(CodeGeneratorScope::Current()->masm()),
|
: masm_(CodeGeneratorScope::Current()->masm()),
|
||||||
statement_position_(masm_->current_statement_position()),
|
statement_position_(masm_->positions_recorder()->
|
||||||
position_(masm_->current_position()),
|
current_statement_position()),
|
||||||
|
position_(masm_->positions_recorder()->current_position()),
|
||||||
frame_state_(*CodeGeneratorScope::Current()->frame()) {
|
frame_state_(*CodeGeneratorScope::Current()->frame()) {
|
||||||
ASSERT(statement_position_ != RelocInfo::kNoPosition);
|
ASSERT(statement_position_ != RelocInfo::kNoPosition);
|
||||||
ASSERT(position_ != RelocInfo::kNoPosition);
|
ASSERT(position_ != RelocInfo::kNoPosition);
|
||||||
|
@ -296,7 +296,7 @@ static void InitCoverageLog();
|
|||||||
byte* Assembler::spare_buffer_ = NULL;
|
byte* Assembler::spare_buffer_ = NULL;
|
||||||
|
|
||||||
Assembler::Assembler(void* buffer, int buffer_size)
|
Assembler::Assembler(void* buffer, int buffer_size)
|
||||||
: code_targets_(100) {
|
: code_targets_(100), positions_recorder_(this) {
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
// Do our own buffer management.
|
// Do our own buffer management.
|
||||||
if (buffer_size <= kMinimalBufferSize) {
|
if (buffer_size <= kMinimalBufferSize) {
|
||||||
@ -337,10 +337,7 @@ Assembler::Assembler(void* buffer, int buffer_size)
|
|||||||
reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
|
reloc_info_writer.Reposition(buffer_ + buffer_size, pc_);
|
||||||
|
|
||||||
last_pc_ = NULL;
|
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
|
#ifdef GENERATED_CODE_COVERAGE
|
||||||
InitCoverageLog();
|
InitCoverageLog();
|
||||||
#endif
|
#endif
|
||||||
@ -845,7 +842,7 @@ void Assembler::call(Label* L) {
|
|||||||
|
|
||||||
|
|
||||||
void Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) {
|
void Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) {
|
||||||
WriteRecordedPositions();
|
positions_recorder()->WriteRecordedPositions();
|
||||||
EnsureSpace ensure_space(this);
|
EnsureSpace ensure_space(this);
|
||||||
last_pc_ = pc_;
|
last_pc_ = pc_;
|
||||||
// 1110 1000 #32-bit disp.
|
// 1110 1000 #32-bit disp.
|
||||||
@ -2935,14 +2932,14 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Assembler::RecordJSReturn() {
|
void Assembler::RecordJSReturn() {
|
||||||
WriteRecordedPositions();
|
positions_recorder()->WriteRecordedPositions();
|
||||||
EnsureSpace ensure_space(this);
|
EnsureSpace ensure_space(this);
|
||||||
RecordRelocInfo(RelocInfo::JS_RETURN);
|
RecordRelocInfo(RelocInfo::JS_RETURN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Assembler::RecordDebugBreakSlot() {
|
void Assembler::RecordDebugBreakSlot() {
|
||||||
WriteRecordedPositions();
|
positions_recorder()->WriteRecordedPositions();
|
||||||
EnsureSpace ensure_space(this);
|
EnsureSpace ensure_space(this);
|
||||||
RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
|
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 |
|
const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
|
||||||
1 << RelocInfo::INTERNAL_REFERENCE;
|
1 << RelocInfo::INTERNAL_REFERENCE;
|
||||||
|
|
||||||
|
@ -1174,13 +1174,9 @@ class Assembler : public Malloced {
|
|||||||
// Use --debug_code to enable.
|
// Use --debug_code to enable.
|
||||||
void RecordComment(const char* msg);
|
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 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.
|
// 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
|
// If this is the case, we need to grow the buffer before emitting
|
||||||
@ -1404,11 +1400,8 @@ class Assembler : public Malloced {
|
|||||||
// push-pop elimination
|
// push-pop elimination
|
||||||
byte* last_pc_;
|
byte* last_pc_;
|
||||||
|
|
||||||
// source position information
|
PositionsRecorder positions_recorder_;
|
||||||
int current_statement_position_;
|
friend class PositionsRecorder;
|
||||||
int current_position_;
|
|
||||||
int written_statement_position_;
|
|
||||||
int written_position_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -2956,7 +2956,7 @@ void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
|
|||||||
CodeForStatementPosition(node);
|
CodeForStatementPosition(node);
|
||||||
Load(node->expression());
|
Load(node->expression());
|
||||||
Result return_value = frame_->Pop();
|
Result return_value = frame_->Pop();
|
||||||
masm()->WriteRecordedPositions();
|
masm()->positions_recorder()->WriteRecordedPositions();
|
||||||
if (function_return_is_shadowed_) {
|
if (function_return_is_shadowed_) {
|
||||||
function_return_.Jump(&return_value);
|
function_return_.Jump(&return_value);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1717,12 +1717,14 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
|
|||||||
// Code common for calls using the IC.
|
// Code common for calls using the IC.
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
int arg_count = args->length();
|
int arg_count = args->length();
|
||||||
for (int i = 0; i < arg_count; i++) {
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
VisitForStackValue(args->at(i));
|
for (int i = 0; i < arg_count; i++) {
|
||||||
|
VisitForStackValue(args->at(i));
|
||||||
|
}
|
||||||
|
__ Move(rcx, name);
|
||||||
}
|
}
|
||||||
__ Move(rcx, name);
|
|
||||||
// Record source position for debugger.
|
// Record source position for debugger.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||||
// Call the IC initialization code.
|
// Call the IC initialization code.
|
||||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||||
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
|
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
|
||||||
@ -1740,13 +1742,15 @@ void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
|
|||||||
// Code common for calls using the IC.
|
// Code common for calls using the IC.
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
int arg_count = args->length();
|
int arg_count = args->length();
|
||||||
for (int i = 0; i < arg_count; i++) {
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
VisitForStackValue(args->at(i));
|
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.
|
// Record source position for debugger.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||||
// Call the IC initialization code.
|
// Call the IC initialization code.
|
||||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||||
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count,
|
Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(arg_count,
|
||||||
@ -1762,11 +1766,13 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) {
|
|||||||
// Code common for calls using the call stub.
|
// Code common for calls using the call stub.
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
int arg_count = args->length();
|
int arg_count = args->length();
|
||||||
for (int i = 0; i < arg_count; i++) {
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
VisitForStackValue(args->at(i));
|
for (int i = 0; i < arg_count; i++) {
|
||||||
|
VisitForStackValue(args->at(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Record source position for debugger.
|
// Record source position for debugger.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||||
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
||||||
__ CallStub(&stub);
|
__ CallStub(&stub);
|
||||||
@ -1787,37 +1793,39 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
|||||||
// resolve the function we need to call and the receiver of the
|
// resolve the function we need to call and the receiver of the
|
||||||
// call. The we call the resolved function using the given
|
// call. The we call the resolved function using the given
|
||||||
// arguments.
|
// arguments.
|
||||||
VisitForStackValue(fun);
|
|
||||||
__ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
|
|
||||||
|
|
||||||
// Push the arguments.
|
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
int arg_count = args->length();
|
int arg_count = args->length();
|
||||||
for (int i = 0; i < arg_count; i++) {
|
{ PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
|
||||||
VisitForStackValue(args->at(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push copy of the function - found below the arguments.
|
VisitForStackValue(fun);
|
||||||
__ push(Operand(rsp, (arg_count + 1) * kPointerSize));
|
__ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot.
|
||||||
|
|
||||||
// Push copy of the first argument or undefined if it doesn't exist.
|
// Push the arguments.
|
||||||
if (arg_count > 0) {
|
for (int i = 0; i < arg_count; i++) {
|
||||||
__ push(Operand(rsp, arg_count * kPointerSize));
|
VisitForStackValue(args->at(i));
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
// 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);
|
__ 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.
|
// Record source position for debugger.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position(), FORCED_POSITION);
|
||||||
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||||
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
|
||||||
__ CallStub(&stub);
|
__ CallStub(&stub);
|
||||||
@ -1834,35 +1842,37 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
|||||||
// Call to a lookup slot (dynamically introduced variable).
|
// Call to a lookup slot (dynamically introduced variable).
|
||||||
Label slow, done;
|
Label slow, done;
|
||||||
|
|
||||||
// Generate code for loading from variables potentially shadowed
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
// by eval-introduced variables.
|
// Generate code for loading from variables potentially shadowed
|
||||||
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
|
// by eval-introduced variables.
|
||||||
NOT_INSIDE_TYPEOF,
|
EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
|
||||||
&slow,
|
NOT_INSIDE_TYPEOF,
|
||||||
&done);
|
&slow,
|
||||||
|
&done);
|
||||||
|
|
||||||
__ bind(&slow);
|
__ bind(&slow);
|
||||||
// Call the runtime to find the function to call (returned in rax)
|
// Call the runtime to find the function to call (returned in rax)
|
||||||
// and the object holding it (returned in rdx).
|
// and the object holding it (returned in rdx).
|
||||||
__ push(context_register());
|
__ push(context_register());
|
||||||
__ Push(var->name());
|
__ Push(var->name());
|
||||||
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
__ CallRuntime(Runtime::kLoadContextSlot, 2);
|
||||||
__ push(rax); // Function.
|
__ push(rax); // Function.
|
||||||
__ push(rdx); // Receiver.
|
__ push(rdx); // Receiver.
|
||||||
|
|
||||||
// If fast case code has been generated, emit code to push the
|
// If fast case code has been generated, emit code to push the
|
||||||
// function and receiver and have the slow path jump around this
|
// function and receiver and have the slow path jump around this
|
||||||
// code.
|
// code.
|
||||||
if (done.is_linked()) {
|
if (done.is_linked()) {
|
||||||
NearLabel call;
|
NearLabel call;
|
||||||
__ jmp(&call);
|
__ jmp(&call);
|
||||||
__ bind(&done);
|
__ bind(&done);
|
||||||
// Push function.
|
// Push function.
|
||||||
__ push(rax);
|
__ push(rax);
|
||||||
// Push global receiver.
|
// Push global receiver.
|
||||||
__ movq(rbx, CodeGenerator::GlobalObject());
|
__ movq(rbx, CodeGenerator::GlobalObject());
|
||||||
__ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
|
__ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
|
||||||
__ bind(&call);
|
__ bind(&call);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitCallWithStub(expr);
|
EmitCallWithStub(expr);
|
||||||
@ -1873,18 +1883,24 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
|||||||
Literal* key = prop->key()->AsLiteral();
|
Literal* key = prop->key()->AsLiteral();
|
||||||
if (key != NULL && key->handle()->IsSymbol()) {
|
if (key != NULL && key->handle()->IsSymbol()) {
|
||||||
// Call to a named property, use call IC.
|
// 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);
|
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
|
||||||
} else {
|
} else {
|
||||||
// Call to a keyed property.
|
// Call to a keyed property.
|
||||||
// For a synthetic property use keyed load IC followed by function call,
|
// For a synthetic property use keyed load IC followed by function call,
|
||||||
// for a regular property use KeyedCallIC.
|
// for a regular property use KeyedCallIC.
|
||||||
VisitForStackValue(prop->obj());
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
|
VisitForStackValue(prop->obj());
|
||||||
|
}
|
||||||
if (prop->is_synthetic()) {
|
if (prop->is_synthetic()) {
|
||||||
VisitForAccumulatorValue(prop->key());
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
__ movq(rdx, Operand(rsp, 0));
|
VisitForAccumulatorValue(prop->key());
|
||||||
|
__ movq(rdx, Operand(rsp, 0));
|
||||||
|
}
|
||||||
// Record source code position for IC call.
|
// Record source code position for IC call.
|
||||||
SetSourcePosition(prop->position());
|
SetSourcePosition(prop->position(), FORCED_POSITION);
|
||||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
|
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
|
||||||
EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
EmitCallIC(ic, RelocInfo::CODE_TARGET);
|
||||||
// Pop receiver.
|
// Pop receiver.
|
||||||
@ -1909,7 +1925,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
|||||||
loop_depth() == 0) {
|
loop_depth() == 0) {
|
||||||
lit->set_try_full_codegen(true);
|
lit->set_try_full_codegen(true);
|
||||||
}
|
}
|
||||||
VisitForStackValue(fun);
|
{ PreserveStatementPositionScope scope(masm()->positions_recorder());
|
||||||
|
VisitForStackValue(fun);
|
||||||
|
}
|
||||||
// Load global receiver object.
|
// Load global receiver object.
|
||||||
__ movq(rbx, CodeGenerator::GlobalObject());
|
__ movq(rbx, CodeGenerator::GlobalObject());
|
||||||
__ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
|
__ 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