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
This commit is contained in:
dcarney@chromium.org 2014-03-24 08:17:06 +00:00
parent db8196ae63
commit 493c6b3543
6 changed files with 170 additions and 54 deletions

View 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");

View 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");

View 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 {

View 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");

View 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");

View 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();