From: dcarney@chromium.org Date: Mon, 24 Mar 2014 08:17:06 +0000 (+0000) Subject: Do stack checks while pushing locals X-Git-Tag: upstream/4.7.83~10077 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=493c6b35433287a7c9b903e6dee785361f4c8dd8;p=platform%2Fupstream%2Fv8.git Do stack checks while pushing locals 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 --- diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index eec910a..e2753a8 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -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"); diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc index 8aa7e37..272e1c7 100644 --- a/src/arm64/full-codegen-arm64.cc +++ b/src/arm64/full-codegen-arm64.cc @@ -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"); diff --git a/src/arm64/simulator-arm64.cc b/src/arm64/simulator-arm64.cc index 9feba6e..64376c7 100644 --- a/src/arm64/simulator-arm64.cc +++ b/src/arm64/simulator-arm64.cc @@ -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(); } 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(); } 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(); } 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(); } else { diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 16c3294..7764ece 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -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"); diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 137622e..dcecadf 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -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"); diff --git a/test/cctest/test-assembler-arm64.cc b/test/cctest/test-assembler-arm64.cc index edb050e..a473fa8 100644 --- a/test/cctest/test-assembler-arm64.cc +++ b/test/cctest/test-assembler-arm64.cc @@ -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();