MIPS: Fix BlockTrampolinePoolFor() to emit trampoline before blocking, if needed.
authorpaul.lind <paul.lind@imgtec.com>
Mon, 13 Jul 2015 07:28:24 +0000 (00:28 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 13 Jul 2015 07:28:38 +0000 (07:28 +0000)
Fixes possible failure in AssembleArchTableSwitch().

BUG=v8:4294
LOG=y

Review URL: https://codereview.chromium.org/1229863004

Cr-Commit-Position: refs/heads/master@{#29589}

src/mips/assembler-mips-inl.h
src/mips/assembler-mips.cc
src/mips/assembler-mips.h
test/cctest/test-assembler-mips.cc
test/cctest/test-macro-assembler-mips.cc

index afca7d0..bb422a3 100644 (file)
@@ -500,8 +500,8 @@ void Assembler::CheckBuffer() {
 }
 
 
-void Assembler::CheckTrampolinePoolQuick() {
-  if (pc_offset() >= next_buffer_check_) {
+void Assembler::CheckTrampolinePoolQuick(int extra_instructions) {
+  if (pc_offset() >= next_buffer_check_ - extra_instructions * kInstrSize) {
     CheckTrampolinePool();
   }
 }
index eeab5cd..2d1ac05 100644 (file)
@@ -2856,6 +2856,7 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
 
 
 void Assembler::BlockTrampolinePoolFor(int instructions) {
+  CheckTrampolinePoolQuick(instructions);
   BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
 }
 
index 386946d..bc2854a 100644 (file)
@@ -1298,7 +1298,7 @@ class Assembler : public AssemblerBase {
   inline void CheckBuffer();
   void GrowBuffer();
   inline void emit(Instr x);
-  inline void CheckTrampolinePoolQuick();
+  inline void CheckTrampolinePoolQuick(int extra_instructions = 0);
 
   // Instruction generation.
   // We have 3 different kind of encoding layout on MIPS.
index 0b7e4f3..13abbbb 100644 (file)
@@ -2987,6 +2987,7 @@ TEST(jump_tables1) {
 
   Label done;
   {
+    __ BlockTrampolinePoolFor(kNumCases + 7);
     PredictableCodeSizeScope predictable(
         &assm, (kNumCases + 7) * Assembler::kInstrSize);
     Label here;
@@ -3063,6 +3064,7 @@ TEST(jump_tables2) {
 
   __ bind(&dispatch);
   {
+    __ BlockTrampolinePoolFor(kNumCases + 7);
     PredictableCodeSizeScope predictable(
         &assm, (kNumCases + 7) * Assembler::kInstrSize);
     Label here;
@@ -3138,6 +3140,7 @@ TEST(jump_tables3) {
 
   __ bind(&dispatch);
   {
+    __ BlockTrampolinePoolFor(kNumCases + 7);
     PredictableCodeSizeScope predictable(
         &assm, (kNumCases + 7) * Assembler::kInstrSize);
     Label here;
index 3a97d21..515bac9 100644 (file)
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <stdlib.h>
+#include <iostream>  // NOLINT(readability/streams)
 
-#include "src/v8.h"
-#include "test/cctest/cctest.h"
-
+#include "src/base/utils/random-number-generator.h"
 #include "src/macro-assembler.h"
 #include "src/mips/macro-assembler-mips.h"
 #include "src/mips/simulator-mips.h"
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
 
 
 using namespace v8::internal;
 
 typedef void* (*F)(int x, int y, int p2, int p3, int p4);
+typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4);
 
 #define __ masm->
 
@@ -174,4 +176,86 @@ TEST(NaN1) {
 }
 
 
+TEST(jump_tables4) {
+  // Similar to test-assembler-mips jump_tables1, with extra test for branch
+  // trampoline required before emission of the dd table (where trampolines are
+  // blocked), and proper transition to long-branch mode.
+  // Regression test for v8:4294.
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  MacroAssembler assembler(isolate, NULL, 0);
+  MacroAssembler* masm = &assembler;
+
+  const int kNumCases = 512;
+  int values[kNumCases];
+  isolate->random_number_generator()->NextBytes(values, sizeof(values));
+  Label labels[kNumCases];
+  Label near_start, end;
+
+  __ addiu(sp, sp, -4);
+  __ sw(ra, MemOperand(sp));
+
+  __ mov(v0, zero_reg);
+
+  __ Branch(&end);
+  __ bind(&near_start);
+
+  // Generate slightly less than 32K instructions, which will soon require
+  // trampoline for branch distance fixup.
+  for (int i = 0; i < 32768 - 256; ++i) {
+    __ addiu(v0, v0, 1);
+  }
+
+  Label done;
+  {
+    __ BlockTrampolinePoolFor(kNumCases + 6);
+    PredictableCodeSizeScope predictable(
+        masm, (kNumCases + 6) * Assembler::kInstrSize);
+    Label here;
+
+    __ bal(&here);
+    __ sll(at, a0, 2);  // In delay slot.
+    __ bind(&here);
+    __ addu(at, at, ra);
+    __ lw(at, MemOperand(at, 4 * Assembler::kInstrSize));
+    __ jr(at);
+    __ nop();  // Branch delay slot nop.
+    for (int i = 0; i < kNumCases; ++i) {
+      __ dd(&labels[i]);
+    }
+  }
+
+  for (int i = 0; i < kNumCases; ++i) {
+    __ bind(&labels[i]);
+    __ lui(v0, (values[i] >> 16) & 0xffff);
+    __ ori(v0, v0, values[i] & 0xffff);
+    __ Branch(&done);
+  }
+
+  __ bind(&done);
+  __ lw(ra, MemOperand(sp));
+  __ addiu(sp, sp, 4);
+  __ jr(ra);
+  __ nop();
+
+  __ bind(&end);
+  __ Branch(&near_start);
+
+  CodeDesc desc;
+  masm->GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F1 f = FUNCTION_CAST<F1>(code->entry());
+  for (int i = 0; i < kNumCases; ++i) {
+    int res = reinterpret_cast<int>(CALL_GENERATED_CODE(f, i, 0, 0, 0, 0));
+    ::printf("f(%d) = %d\n", i, res);
+    CHECK_EQ(values[i], res);
+  }
+}
+
+
 #undef __