Do stack checks while pushing locals
authordcarney@chromium.org <dcarney@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 24 Mar 2014 08:17:06 +0000 (08:17 +0000)
committerdcarney@chromium.org <dcarney@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 24 Mar 2014 08:17:06 +0000 (08:17 +0000)
R=yangguo@chromium.org

BUG=

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

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

src/arm/full-codegen-arm.cc
src/arm64/full-codegen-arm64.cc
src/arm64/simulator-arm64.cc
src/ia32/full-codegen-ia32.cc
src/x64/full-codegen-x64.cc
test/cctest/test-assembler-arm64.cc

index eec910a..e2753a8 100644 (file)
@@ -111,6 +111,25 @@ class JumpPatchSite BASE_EMBEDDED {
 };
 
 
+static void EmitStackCheck(MacroAssembler* masm_,
+                           Register stack_limit_scratch,
+                           int pointers = 0,
+                           Register scratch = sp) {
+    Isolate* isolate = masm_->isolate();
+  Label ok;
+  ASSERT(scratch.is(sp) == (pointers == 0));
+  if (pointers != 0) {
+    __ sub(scratch, sp, Operand(pointers * kPointerSize));
+  }
+  __ LoadRoot(stack_limit_scratch, Heap::kStackLimitRootIndex);
+  __ cmp(scratch, Operand(stack_limit_scratch));
+  __ b(hs, &ok);
+  PredictableCodeSizeScope predictable(masm_, 2 * Assembler::kInstrSize);
+  __ Call(isolate->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
+  __ bind(&ok);
+}
+
+
 // Generate code for a JS function.  On entry to the function the receiver
 // and arguments have been pushed on the stack left to right.  The actual
 // argument count matches the formal parameter count expected by the
@@ -179,20 +198,28 @@ void FullCodeGenerator::Generate() {
     // Generators allocate locals, if any, in context slots.
     ASSERT(!info->function()->is_generator() || locals_count == 0);
     if (locals_count > 0) {
-      // Emit a loop to initialize stack cells for locals when optimizing for
-      // size. Otherwise, unroll the loop for maximum performance.
+      if (locals_count >= 128) {
+        EmitStackCheck(masm_, r2, locals_count, r9);
+      }
       __ LoadRoot(r9, Heap::kUndefinedValueRootIndex);
-      if (FLAG_optimize_for_size && locals_count > 4) {
-        Label loop;
-        __ mov(r2, Operand(locals_count));
-        __ bind(&loop);
-        __ sub(r2, r2, Operand(1), SetCC);
-        __ push(r9);
-        __ b(&loop, ne);
-      } else {
-        for (int i = 0; i < locals_count; i++) {
+      int kMaxPushes = FLAG_optimize_for_size ? 4 : 32;
+      if (locals_count >= kMaxPushes) {
+        int loop_iterations = locals_count / kMaxPushes;
+        __ mov(r2, Operand(loop_iterations));
+        Label loop_header;
+        __ bind(&loop_header);
+        // Do pushes.
+        for (int i = 0; i < kMaxPushes; i++) {
           __ push(r9);
         }
+        // Continue loop if not done.
+        __ sub(r2, r2, Operand(1), SetCC);
+        __ b(&loop_header, ne);
+      }
+      int remaining = locals_count % kMaxPushes;
+      // Emit the remaining pushes.
+      for (int i  = 0; i < remaining; i++) {
+        __ push(r9);
       }
     }
   }
@@ -303,13 +330,7 @@ void FullCodeGenerator::Generate() {
 
     { Comment cmnt(masm_, "[ Stack check");
       PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
-      Label ok;
-      __ LoadRoot(ip, Heap::kStackLimitRootIndex);
-      __ cmp(sp, Operand(ip));
-      __ b(hs, &ok);
-      PredictableCodeSizeScope predictable(masm_, 2 * Assembler::kInstrSize);
-      __ Call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
-      __ bind(&ok);
+      EmitStackCheck(masm_, ip);
     }
 
     { Comment cmnt(masm_, "[ Body");
index 8aa7e37..272e1c7 100644 (file)
@@ -110,6 +110,25 @@ class JumpPatchSite BASE_EMBEDDED {
 };
 
 
+static void EmitStackCheck(MacroAssembler* masm_,
+                           int pointers = 0,
+                           Register scratch = jssp) {
+  Isolate* isolate = masm_->isolate();
+  Label ok;
+  ASSERT(jssp.Is(__ StackPointer()));
+  ASSERT(scratch.Is(jssp) == (pointers == 0));
+  if (pointers != 0) {
+    __ Sub(scratch, jssp, pointers * kPointerSize);
+  }
+  __ CompareRoot(scratch, Heap::kStackLimitRootIndex);
+  __ B(hs, &ok);
+  PredictableCodeSizeScope predictable(masm_,
+                                       Assembler::kCallSizeWithRelocation);
+  __ Call(isolate->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
+  __ Bind(&ok);
+}
+
+
 // Generate code for a JS function. On entry to the function the receiver
 // and arguments have been pushed on the stack left to right. The actual
 // argument count matches the formal parameter count expected by the
@@ -182,8 +201,28 @@ void FullCodeGenerator::Generate() {
     ASSERT(!info->function()->is_generator() || locals_count == 0);
 
     if (locals_count > 0) {
+      if (locals_count >= 128) {
+        EmitStackCheck(masm_, locals_count, x10);
+      }
       __ LoadRoot(x10, Heap::kUndefinedValueRootIndex);
-      __ PushMultipleTimes(x10, locals_count);
+      if (FLAG_optimize_for_size) {
+        __ PushMultipleTimes(x10 , locals_count);
+      } else {
+        const int kMaxPushes = 32;
+        if (locals_count >= kMaxPushes) {
+          int loop_iterations = locals_count / kMaxPushes;
+          __ Mov(x3, loop_iterations);
+          Label loop_header;
+          __ Bind(&loop_header);
+          // Do pushes.
+          __ PushMultipleTimes(x10 , kMaxPushes);
+          __ Subs(x3, x3, 1);
+          __ B(ne, &loop_header);
+        }
+        int remaining = locals_count % kMaxPushes;
+        // Emit the remaining pushes.
+        __ PushMultipleTimes(x10 , remaining);
+      }
     }
   }
 
@@ -291,14 +330,7 @@ void FullCodeGenerator::Generate() {
 
   { Comment cmnt(masm_, "[ Stack check");
     PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
-    Label ok;
-    ASSERT(jssp.Is(__ StackPointer()));
-    __ CompareRoot(jssp, Heap::kStackLimitRootIndex);
-    __ B(hs, &ok);
-    PredictableCodeSizeScope predictable(masm_,
-                                         Assembler::kCallSizeWithRelocation);
-    __ Call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
-    __ Bind(&ok);
+    EmitStackCheck(masm_);
   }
 
   { Comment cmnt(masm_, "[ Body");
index 9feba6e..64376c7 100644 (file)
@@ -2860,7 +2860,7 @@ T Simulator::FPAdd(T op1, T op2) {
   // NaNs should be handled elsewhere.
   ASSERT(!std::isnan(op1) && !std::isnan(op2));
 
-  if (isinf(op1) && isinf(op2) && (op1 != op2)) {
+  if (std::isinf(op1) && std::isinf(op2) && (op1 != op2)) {
     // inf + -inf returns the default NaN.
     return FPDefaultNaN<T>();
   } else {
@@ -2875,7 +2875,7 @@ T Simulator::FPDiv(T op1, T op2) {
   // NaNs should be handled elsewhere.
   ASSERT(!std::isnan(op1) && !std::isnan(op2));
 
-  if ((isinf(op1) && isinf(op2)) || ((op1 == 0.0) && (op2 == 0.0))) {
+  if ((std::isinf(op1) && std::isinf(op2)) || ((op1 == 0.0) && (op2 == 0.0))) {
     // inf / inf and 0.0 / 0.0 return the default NaN.
     return FPDefaultNaN<T>();
   } else {
@@ -2936,7 +2936,7 @@ T Simulator::FPMinNM(T a, T b) {
   }
 
   T result = FPProcessNaNs(a, b);
-  return isnan(result) ? result : FPMin(a, b);
+  return std::isnan(result) ? result : FPMin(a, b);
 }
 
 
@@ -2945,7 +2945,7 @@ T Simulator::FPMul(T op1, T op2) {
   // NaNs should be handled elsewhere.
   ASSERT(!std::isnan(op1) && !std::isnan(op2));
 
-  if ((isinf(op1) && (op2 == 0.0)) || (isinf(op2) && (op1 == 0.0))) {
+  if ((std::isinf(op1) && (op2 == 0.0)) || (std::isinf(op2) && (op1 == 0.0))) {
     // inf * 0.0 returns the default NaN.
     return FPDefaultNaN<T>();
   } else {
@@ -3017,7 +3017,7 @@ T Simulator::FPSub(T op1, T op2) {
   // NaNs should be handled elsewhere.
   ASSERT(!std::isnan(op1) && !std::isnan(op2));
 
-  if (isinf(op1) && isinf(op2) && (op1 == op2)) {
+  if (std::isinf(op1) && std::isinf(op2) && (op1 == op2)) {
     // inf - inf returns the default NaN.
     return FPDefaultNaN<T>();
   } else {
index 16c3294..7764ece 100644 (file)
@@ -101,6 +101,25 @@ class JumpPatchSite BASE_EMBEDDED {
 };
 
 
+static void EmitStackCheck(MacroAssembler* masm_,
+                           int pointers = 0,
+                           Register scratch = esp) {
+    Label ok;
+    Isolate* isolate = masm_->isolate();
+    ExternalReference stack_limit =
+        ExternalReference::address_of_stack_limit(isolate);
+    ASSERT(scratch.is(esp) == (pointers == 0));
+    if (pointers != 0) {
+      __ mov(scratch, esp);
+      __ sub(scratch, Immediate(pointers * kPointerSize));
+    }
+    __ cmp(scratch, Operand::StaticVariable(stack_limit));
+    __ j(above_equal, &ok, Label::kNear);
+    __ call(isolate->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
+    __ bind(&ok);
+}
+
+
 // Generate code for a JS function.  On entry to the function the receiver
 // and arguments have been pushed on the stack left to right, with the
 // return address on top of them.  The actual argument count matches the
@@ -171,8 +190,26 @@ void FullCodeGenerator::Generate() {
     if (locals_count == 1) {
       __ push(Immediate(isolate()->factory()->undefined_value()));
     } else if (locals_count > 1) {
+      if (locals_count >= 128) {
+        EmitStackCheck(masm_, locals_count, ecx);
+      }
       __ mov(eax, Immediate(isolate()->factory()->undefined_value()));
-      for (int i = 0; i < locals_count; i++) {
+      const int kMaxPushes = 32;
+      if (locals_count >= kMaxPushes) {
+        int loop_iterations = locals_count / kMaxPushes;
+        __ mov(ecx, loop_iterations);
+        Label loop_header;
+        __ bind(&loop_header);
+        // Do pushes.
+        for (int i = 0; i < kMaxPushes; i++) {
+          __ push(eax);
+        }
+        __ dec(ecx);
+        __ j(not_zero, &loop_header, Label::kNear);
+      }
+      int remaining = locals_count % kMaxPushes;
+      // Emit the remaining pushes.
+      for (int i  = 0; i < remaining; i++) {
         __ push(eax);
       }
     }
@@ -285,13 +322,7 @@ void FullCodeGenerator::Generate() {
 
     { Comment cmnt(masm_, "[ Stack check");
       PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
-      Label ok;
-      ExternalReference stack_limit =
-          ExternalReference::address_of_stack_limit(isolate());
-      __ cmp(esp, Operand::StaticVariable(stack_limit));
-      __ j(above_equal, &ok, Label::kNear);
-      __ call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
-      __ bind(&ok);
+      EmitStackCheck(masm_);
     }
 
     { Comment cmnt(masm_, "[ Body");
index 137622e..dcecadf 100644 (file)
@@ -101,6 +101,23 @@ class JumpPatchSite BASE_EMBEDDED {
 };
 
 
+static void EmitStackCheck(MacroAssembler* masm_,
+                             int pointers = 0,
+                             Register scratch = rsp) {
+    Isolate* isolate = masm_->isolate();
+    Label ok;
+    ASSERT(scratch.is(rsp) == (pointers == 0));
+    if (pointers != 0) {
+      __ movq(scratch, rsp);
+      __ subq(scratch, Immediate(pointers * kPointerSize));
+    }
+    __ CompareRoot(scratch, Heap::kStackLimitRootIndex);
+    __ j(above_equal, &ok, Label::kNear);
+    __ call(isolate->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
+    __ bind(&ok);
+}
+
+
 // Generate code for a JS function.  On entry to the function the receiver
 // and arguments have been pushed on the stack left to right, with the
 // return address on top of them.  The actual argument count matches the
@@ -171,8 +188,27 @@ void FullCodeGenerator::Generate() {
     if (locals_count == 1) {
       __ PushRoot(Heap::kUndefinedValueRootIndex);
     } else if (locals_count > 1) {
+      if (locals_count >= 128) {
+        EmitStackCheck(masm_, locals_count, rcx);
+      }
       __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
-      for (int i = 0; i < locals_count; i++) {
+      const int kMaxPushes = 32;
+      if (locals_count >= kMaxPushes) {
+        int loop_iterations = locals_count / kMaxPushes;
+        __ movq(rcx, Immediate(loop_iterations));
+        Label loop_header;
+        __ bind(&loop_header);
+        // Do pushes.
+        for (int i = 0; i < kMaxPushes; i++) {
+          __ Push(rdx);
+        }
+        // Continue loop if not done.
+        __ decq(rcx);
+        __ j(not_zero, &loop_header, Label::kNear);
+      }
+      int remaining = locals_count % kMaxPushes;
+      // Emit the remaining pushes.
+      for (int i  = 0; i < remaining; i++) {
         __ Push(rdx);
       }
     }
@@ -284,11 +320,7 @@ void FullCodeGenerator::Generate() {
 
     { Comment cmnt(masm_, "[ Stack check");
       PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
-      Label ok;
-      __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
-      __ j(above_equal, &ok, Label::kNear);
-      __ call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
-      __ bind(&ok);
+      EmitStackCheck(masm_);
     }
 
     { Comment cmnt(masm_, "[ Body");
index edb050e..a473fa8 100644 (file)
@@ -10154,7 +10154,7 @@ TEST(process_nan_float) {
 
 
 static void ProcessNaNsHelper(double n, double m, double expected) {
-  ASSERT(isnan(n) || isnan(m));
+  ASSERT(std::isnan(n) || std::isnan(m));
   ASSERT(isnan(expected));
 
   SETUP();
@@ -10226,7 +10226,7 @@ TEST(process_nans_double) {
 
 
 static void ProcessNaNsHelper(float n, float m, float expected) {
-  ASSERT(isnan(n) || isnan(m));
+  ASSERT(std::isnan(n) || std::isnan(m));
   ASSERT(isnan(expected));
 
   SETUP();
@@ -10298,10 +10298,10 @@ TEST(process_nans_float) {
 
 
 static void DefaultNaNHelper(float n, float m, float a) {
-  ASSERT(isnan(n) || isnan(m) || isnan(a));
+  ASSERT(std::isnan(n) || std::isnan(m) || isnan(a));
 
-  bool test_1op = isnan(n);
-  bool test_2op = isnan(n) || isnan(m);
+  bool test_1op = std::isnan(n);
+  bool test_2op = std::isnan(n) || std::isnan(m);
 
   SETUP();
   START();
@@ -10426,10 +10426,10 @@ TEST(default_nan_float) {
 
 
 static void DefaultNaNHelper(double n, double m, double a) {
-  ASSERT(isnan(n) || isnan(m) || isnan(a));
+  ASSERT(std::isnan(n) || std::isnan(m) || isnan(a));
 
-  bool test_1op = isnan(n);
-  bool test_2op = isnan(n) || isnan(m);
+  bool test_1op = std::isnan(n);
+  bool test_2op = std::isnan(n) || std::isnan(m);
 
   SETUP();
   START();