Revision: 7089
Author: [email protected]
Date: Tue Mar  8 03:21:38 2011
Log: Fix Issue 1234.

Ensure that there is always enough bytes between consequtive calls in
unoptimized code to write a call instruction at the return points
without overlapping.

This handles the case where two return points were only four bytes
apart (because the latter call was to a register).

BUG=v8:1234

Review URL: http://codereview.chromium.org/6624091
http://code.google.com/p/v8/source/detail?r=7089

Modified:
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h
 /branches/bleeding_edge/src/safepoint-table.h
 /branches/bleeding_edge/src/x64/assembler-x64.h
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.h
 /branches/bleeding_edge/src/x64/macro-assembler-x64.cc
 /branches/bleeding_edge/src/x64/macro-assembler-x64.h

=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Mon Feb 21 03:29:45 2011 +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Tue Mar 8 03:21:38 2011
@@ -1424,7 +1424,7 @@
                                     const ParameterCount& actual,
                                     Handle<Code> code_constant,
                                     const Operand& code_operand,
-                                    Label* done,
+                                    NearLabel* done,
                                     InvokeFlag flag,
PostCallGenerator* post_call_generator) {
   bool definitely_matches = false;
@@ -1492,7 +1492,7 @@
                                 const ParameterCount& actual,
                                 InvokeFlag flag,
                                 PostCallGenerator* post_call_generator) {
-  Label done;
+  NearLabel done;
   InvokePrologue(expected, actual, Handle<Code>::null(), code,
                  &done, flag, post_call_generator);
   if (flag == CALL_FUNCTION) {
@@ -1512,7 +1512,7 @@
                                 RelocInfo::Mode rmode,
                                 InvokeFlag flag,
                                 PostCallGenerator* post_call_generator) {
-  Label done;
+  NearLabel done;
   Operand dummy(eax);
   InvokePrologue(expected, actual, code, dummy, &done,
                  flag, post_call_generator);
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Mon Feb 21 03:29:45 2011 +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Tue Mar 8 03:21:38 2011
@@ -646,7 +646,7 @@
                       const ParameterCount& actual,
                       Handle<Code> code_constant,
                       const Operand& code_operand,
-                      Label* done,
+                      NearLabel* done,
                       InvokeFlag flag,
                       PostCallGenerator* post_call_generator = NULL);

=======================================
--- /branches/bleeding_edge/src/safepoint-table.h       Fri Feb  4 06:09:03 2011
+++ /branches/bleeding_edge/src/safepoint-table.h       Tue Mar  8 03:21:38 2011
@@ -227,6 +227,14 @@
     int index = deoptimization_info_.length() - 1;
     deoptimization_info_[index].pc_after_gap = pc;
   }
+
+ // Get the end pc offset of the last safepoint, including the code generated
+  // until the end of the gap following it.
+  unsigned GetPcAfterGap() {
+    int index = deoptimization_info_.length();
+    if (index == 0) return 0;
+    return deoptimization_info_[index - 1].pc_after_gap;
+  }

   // Emit the safepoint table after the body. The number of bits per
   // entry must be enough to hold all the pointer indexes.
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.h     Fri Feb 25 05:22:38 2011
+++ /branches/bleeding_edge/src/x64/assembler-x64.h     Tue Mar  8 03:21:38 2011
@@ -394,6 +394,13 @@
   // Checks whether either base or index register is the given register.
   // Does not check the "reg" part of the Operand.
   bool AddressUsesRegister(Register reg) const;
+
+  // Queries related to the size of the generated instruction.
+  // Whether the generated instruction will have a REX prefix.
+  bool requires_rex() const { return rex_ != 0; }
+  // Size of the ModR/M, SIB and displacement parts of the generated
+  // instruction.
+  int operand_size() const { return len_; }

  private:
   byte rex_;
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Mar 8 02:29:40 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Mar 8 03:21:38 2011
@@ -39,7 +39,7 @@

 // When invoking builtins, we need to record the safepoint in the middle of
 // the invoke instruction sequence generated by the macro assembler.
-class SafepointGenerator : public PostCallGenerator {
+class SafepointGenerator : public CallWrapper {
  public:
   SafepointGenerator(LCodeGen* codegen,
                      LPointerMap* pointers,
@@ -48,29 +48,29 @@
       : codegen_(codegen),
         pointers_(pointers),
         deoptimization_index_(deoptimization_index),
-        ensure_reloc_space_(ensure_reloc_space),
-        previous_safepoint_position_(-kMinSafepointSize) { }
+        ensure_reloc_space_(ensure_reloc_space) { }
   virtual ~SafepointGenerator() { }

-  virtual void Generate() {
+  virtual void BeforeCall(int call_size) {
+    ASSERT(call_size >= 0);
// Ensure that we have enough space after the previous safepoint position
-    // for the generated code there.
-    int position = codegen_->masm()->pc_offset();
-    ASSERT(position > previous_safepoint_position_);
-    if (position < previous_safepoint_position_ + kMinSafepointSize) {
-      int padding_size =
-          previous_safepoint_position_ + kMinSafepointSize - position;
+    // for the jump generated there.
+    int call_end = codegen_->masm()->pc_offset() + call_size;
+    int prev_jump_end = codegen_->LastSafepointEnd() + kMinSafepointSize;
+    if (call_end < prev_jump_end) {
+      int padding_size = prev_jump_end - call_end;
STATIC_ASSERT(kMinSafepointSize <= 9); // One multibyte nop is enough.
       codegen_->masm()->nop(padding_size);
-      position += padding_size;
-    }
+    }
+  }
+
+  virtual void AfterCall() {
     // Ensure that we have enough space in the reloc info to patch
     // this with calls when doing deoptimization.
     if (ensure_reloc_space_) {
codegen_->masm()->RecordComment(RelocInfo::kFillerCommentString, true);
     }
     codegen_->RecordSafepoint(pointers_, deoptimization_index_);
-    previous_safepoint_position_ = position;
   }

  private:
@@ -80,7 +80,6 @@
   LPointerMap* pointers_;
   int deoptimization_index_;
   bool ensure_reloc_space_;
-  int previous_safepoint_position_;
 };


=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Mon Mar 7 03:52:36 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Tue Mar 8 03:21:38 2011
@@ -210,6 +210,9 @@
                                     int arguments,
                                     int deoptimization_index);
   void RecordPosition(int position);
+  int LastSafepointEnd() {
+    return static_cast<int>(safepoints_.GetPcAfterGap());
+  }

   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
   void EmitGoto(int block, LDeferredCode* deferred_stack_check = NULL);
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Mon Mar 7 03:26:43 2011 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Tue Mar 8 03:21:38 2011
@@ -638,7 +638,7 @@

 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
                                    InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+                                   CallWrapper* call_wrapper) {
   // Calls are not allowed in some stubs.
   ASSERT(flag == JUMP_FUNCTION || allow_stub_calls());

@@ -647,7 +647,7 @@
   // parameter count to avoid emitting code to do the check.
   ParameterCount expected(0);
   GetBuiltinEntry(rdx, id);
-  InvokeCode(rdx, expected, expected, flag, post_call_generator);
+  InvokeCode(rdx, expected, expected, flag, call_wrapper);
 }


@@ -1424,20 +1424,41 @@


 void MacroAssembler::Call(ExternalReference ext) {
+#ifdef DEBUG
+  int pre_position = pc_offset();
+#endif
   movq(kScratchRegister, ext);
   call(kScratchRegister);
+#ifdef DEBUG
+  int post_position = pc_offset();
+  CHECK_EQ(pre_position + CallSize(ext), post_position);
+#endif
 }


 void MacroAssembler::Call(Address destination, RelocInfo::Mode rmode) {
+#ifdef DEBUG
+  int pre_position = pc_offset();
+#endif
   movq(kScratchRegister, destination, rmode);
   call(kScratchRegister);
+#ifdef DEBUG
+  int post_position = pc_offset();
+  CHECK_EQ(pre_position + CallSize(destination, rmode), post_position);
+#endif
 }


void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) {
+#ifdef DEBUG
+  int pre_position = pc_offset();
+#endif
   ASSERT(RelocInfo::IsCodeTarget(rmode));
   call(code_object, rmode);
+#ifdef DEBUG
+  int post_position = pc_offset();
+  CHECK_EQ(pre_position + CallSize(code_object), post_position);
+#endif
 }


@@ -1868,7 +1889,7 @@
                                 const ParameterCount& expected,
                                 const ParameterCount& actual,
                                 InvokeFlag flag,
-                                PostCallGenerator* post_call_generator) {
+                                CallWrapper* call_wrapper) {
   NearLabel done;
   InvokePrologue(expected,
                  actual,
@@ -1876,10 +1897,11 @@
                  code,
                  &done,
                  flag,
-                 post_call_generator);
+                 call_wrapper);
   if (flag == CALL_FUNCTION) {
+    if (call_wrapper != NULL) call_wrapper->BeforeCall(CallSize(code));
     call(code);
-    if (post_call_generator != NULL) post_call_generator->Generate();
+    if (call_wrapper != NULL) call_wrapper->AfterCall();
   } else {
     ASSERT(flag == JUMP_FUNCTION);
     jmp(code);
@@ -1893,7 +1915,7 @@
                                 const ParameterCount& actual,
                                 RelocInfo::Mode rmode,
                                 InvokeFlag flag,
-                                PostCallGenerator* post_call_generator) {
+                                CallWrapper* call_wrapper) {
   NearLabel done;
   Register dummy = rax;
   InvokePrologue(expected,
@@ -1902,10 +1924,11 @@
                  dummy,
                  &done,
                  flag,
-                 post_call_generator);
+                 call_wrapper);
   if (flag == CALL_FUNCTION) {
+    if (call_wrapper != NULL) call_wrapper->BeforeCall(CallSize(code));
     Call(code, rmode);
-    if (post_call_generator != NULL) post_call_generator->Generate();
+    if (call_wrapper != NULL) call_wrapper->AfterCall();
   } else {
     ASSERT(flag == JUMP_FUNCTION);
     Jump(code, rmode);
@@ -1917,7 +1940,7 @@
 void MacroAssembler::InvokeFunction(Register function,
                                     const ParameterCount& actual,
                                     InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+                                    CallWrapper* call_wrapper) {
   ASSERT(function.is(rdi));
   movq(rdx, FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
   movq(rsi, FieldOperand(function, JSFunction::kContextOffset));
@@ -1928,14 +1951,14 @@
   movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));

   ParameterCount expected(rbx);
-  InvokeCode(rdx, expected, actual, flag, post_call_generator);
+  InvokeCode(rdx, expected, actual, flag, call_wrapper);
 }


 void MacroAssembler::InvokeFunction(JSFunction* function,
                                     const ParameterCount& actual,
                                     InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+                                    CallWrapper* call_wrapper) {
   ASSERT(function->is_compiled());
   // Get the function and setup the context.
   Move(rdi, Handle<JSFunction>(function));
@@ -1946,7 +1969,7 @@
     // the Code object every time we call the function.
     movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
     ParameterCount expected(function->shared()->formal_parameter_count());
-    InvokeCode(rdx, expected, actual, flag, post_call_generator);
+    InvokeCode(rdx, expected, actual, flag, call_wrapper);
   } else {
     // Invoke the cached code.
     Handle<Code> code(function->code());
@@ -1956,7 +1979,7 @@
                actual,
                RelocInfo::CODE_TARGET,
                flag,
-               post_call_generator);
+               call_wrapper);
   }
 }

=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.h Mon Mar 7 00:35:19 2011 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.h Tue Mar 8 03:21:38 2011
@@ -61,7 +61,7 @@

 // Forward declaration.
 class JumpTarget;
-class PostCallGenerator;
+class CallWrapper;

 struct SmiIndex {
   SmiIndex(Register index_register, ScaleFactor scale)
@@ -199,32 +199,32 @@
                   const ParameterCount& expected,
                   const ParameterCount& actual,
                   InvokeFlag flag,
-                  PostCallGenerator* post_call_generator = NULL);
+                  CallWrapper* call_wrapper = NULL);

   void InvokeCode(Handle<Code> code,
                   const ParameterCount& expected,
                   const ParameterCount& actual,
                   RelocInfo::Mode rmode,
                   InvokeFlag flag,
-                  PostCallGenerator* post_call_generator = NULL);
+                  CallWrapper* call_wrapper = NULL);

   // Invoke the JavaScript function in the given register. Changes the
   // current context to the context in the function before invoking.
   void InvokeFunction(Register function,
                       const ParameterCount& actual,
                       InvokeFlag flag,
-                      PostCallGenerator* post_call_generator = NULL);
+                      CallWrapper* call_wrapper = NULL);

   void InvokeFunction(JSFunction* function,
                       const ParameterCount& actual,
                       InvokeFlag flag,
-                      PostCallGenerator* post_call_generator = NULL);
+                      CallWrapper* call_wrapper = NULL);

   // Invoke specified builtin JavaScript function. Adds an entry to
   // the unresolved list if the name does not resolve.
   void InvokeBuiltin(Builtins::JavaScript id,
                      InvokeFlag flag,
-                     PostCallGenerator* post_call_generator = NULL);
+                     CallWrapper* call_wrapper = NULL);

   // Store the function for the given builtin in the target register.
   void GetBuiltinFunction(Register target, Builtins::JavaScript id);
@@ -625,6 +625,26 @@
   void Call(Address destination, RelocInfo::Mode rmode);
   void Call(ExternalReference ext);
   void Call(Handle<Code> code_object, RelocInfo::Mode rmode);
+
+  // The size of the code generated for different call instructions.
+  int CallSize(Address destination, RelocInfo::Mode rmode) {
+    return kCallInstructionLength;
+  }
+  int CallSize(ExternalReference ext) {
+    return kCallInstructionLength;
+  }
+  int CallSize(Handle<Code> code_object) {
+    // Code calls use 32-bit relative addressing.
+    return kShortCallInstructionLength;
+  }
+  int CallSize(Register target) {
+    // Opcode: REX_opt FF /2 m64
+    return (target.high_bit() != 0) ? 3 : 2;
+  }
+  int CallSize(const Operand& target) {
+    // Opcode: REX_opt FF /2 m64
+    return (target.requires_rex() ? 2 : 1) + target.operand_size();
+  }

   // Emit call to the code we are currently generating.
   void CallSelf() {
@@ -1018,7 +1038,7 @@
                       Register code_register,
                       LabelType* done,
                       InvokeFlag flag,
-                      PostCallGenerator* post_call_generator);
+                      CallWrapper* call_wrapper);

   // Activation support.
   void EnterFrame(StackFrame::Type type);
@@ -1084,13 +1104,17 @@


 // Helper class for generating code or data associated with the code
-// right after a call instruction. As an example this can be used to
+// right before or after a call instruction. As an example this can be used to
 // generate safepoint data after calls for crankshaft.
-class PostCallGenerator {
+class CallWrapper {
  public:
-  PostCallGenerator() { }
-  virtual ~PostCallGenerator() { }
-  virtual void Generate() = 0;
+  CallWrapper() { }
+  virtual ~CallWrapper() { }
+ // Called just before emitting a call. Argument is the size of the generated
+  // call code.
+  virtual void BeforeCall(int call_size) = 0;
+ // Called just after emitting a call, i.e., at the return site for the call.
+  virtual void AfterCall() = 0;
 };


@@ -1801,7 +1825,7 @@
                                     Register code_register,
                                     LabelType* done,
                                     InvokeFlag flag,
- PostCallGenerator* post_call_generator) {
+                                    CallWrapper* call_wrapper) {
   bool definitely_matches = false;
   NearLabel invoke;
   if (expected.is_immediate()) {
@@ -1851,8 +1875,9 @@
     }

     if (flag == CALL_FUNCTION) {
+ if (call_wrapper != NULL) call_wrapper->BeforeCall(CallSize(adaptor));
       Call(adaptor, RelocInfo::CODE_TARGET);
-      if (post_call_generator != NULL) post_call_generator->Generate();
+      if (call_wrapper != NULL) call_wrapper->AfterCall();
       jmp(done);
     } else {
       Jump(adaptor, RelocInfo::CODE_TARGET);

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to