Improve positions recording for calls.
authorvegorov@chromium.org <vegorov@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 4 Nov 2010 15:12:03 +0000 (15:12 +0000)
committervegorov@chromium.org <vegorov@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 4 Nov 2010 15:12:03 +0000 (15:12 +0000)
Review URL: http://codereview.chromium.org/4469002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5768 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

20 files changed:
src/arm/assembler-arm.cc
src/arm/assembler-arm.h
src/arm/full-codegen-arm.cc
src/arm/macro-assembler-arm.cc
src/assembler.cc
src/assembler.h
src/codegen.cc
src/full-codegen.cc
src/full-codegen.h
src/ia32/assembler-ia32.cc
src/ia32/assembler-ia32.h
src/ia32/codegen-ia32.cc
src/ia32/full-codegen-ia32.cc
src/jump-target-heavy.cc
src/jump-target-light.cc
src/x64/assembler-x64.cc
src/x64/assembler-x64.h
src/x64/codegen-x64.cc
src/x64/full-codegen-x64.cc
test/mjsunit/regress/regress-conditional-position.js [new file with mode: 0644]

index ebbd9b1..d32547c 100644 (file)
@@ -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");
 
index 5b647a7..de9dbf3 100644 (file)
@@ -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_
index 9935e03..2b2d50b 100644 (file)
@@ -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 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);
+      // 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);
+      }
 
-    // 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));
index 7f6090b..c7d7c05 100644 (file)
@@ -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);
index ce90dce..7493673 100644 (file)
@@ -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
index 6681177..b71c570 100644 (file)
@@ -585,6 +585,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
 
 static inline bool is_intn(int x, int n)  {
index bda697a..2e32418 100644 (file)
@@ -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);
   }
 }
 
index 80f3788..c770e18 100644 (file)
@@ -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);
   }
 }
 
index 201507b..a3270aa 100644 (file)
@@ -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();
index 019f478..125f503 100644 (file)
@@ -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");
index 5286788..624be0c 100644 (file)
@@ -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;
 };
 
 
index aa03789..7295340 100644 (file)
@@ -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 {
index ee4e645..7452668 100644 (file)
@@ -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 copy of the function - found below the arguments.
-    __ push(Operand(esp, (arg_count + 1) * kPointerSize));
+      // Push the arguments.
+      for (int i = 0; i < arg_count; i++) {
+        VisitForStackValue(args->at(i));
+      }
 
-    // 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 copy of the function - found below the arguments.
+      __ push(Operand(esp, (arg_count + 1) * kPointerSize));
 
-    // Push the receiver of the enclosing function and do runtime call.
-    __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
-    __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
+      // 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()));
+      }
 
-    // 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 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));
index e0585e7..c3c22f1 100644 (file)
@@ -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);
index 19f7bfe..36dc176 100644 (file)
@@ -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);
index bf5ee5b..caed7c8 100644 (file)
@@ -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;
 
index bbc1010..c7f7632 100644 (file)
@@ -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;
 };
 
 
index c1a23fc..e0e4095 100644 (file)
@@ -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 {
index 4e0f6d4..96a0d93 100644 (file)
@@ -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 {
-      __ PushRoot(Heap::kUndefinedValueRootIndex);
-    }
+      // Push the arguments.
+      for (int i = 0; i < arg_count; i++) {
+        VisitForStackValue(args->at(i));
+      }
 
-    // Push the receiver of the enclosing function and do runtime call.
-    __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize));
-    __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
+      // Push copy of the function - found below the arguments.
+      __ push(Operand(rsp, (arg_count + 1) * kPointerSize));
 
-    // 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 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);
+    }
     // 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);
-
-    __ 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);
+    { 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.
+
+      // 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));
diff --git a/test/mjsunit/regress/regress-conditional-position.js b/test/mjsunit/regress/regress-conditional-position.js
new file mode 100644 (file)
index 0000000..cd8f7bd
--- /dev/null
@@ -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);