Version 2.2.23
API change: Convert Unicode code points outside the basic multilingual
plane to the replacement character. Previous behavior was to silently
truncate the value to 16 bits.
Fixed crash: handle all flat string types in regexp replace.
Prevent invalid pre-parsing data passed in through the API from
crashing V8.
Performance improvements on all platforms.
Review URL: http://codereview.chromium.org/2814050
git-svn-id: http://v8.googlecode.com/svn/trunk@5033 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index 4d18727..fa6efcd 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -5423,9 +5423,13 @@
frame_->EmitPush(r0); // r0 has result
} else {
- bool overwrite =
+ bool can_overwrite =
(node->expression()->AsBinaryOperation() != NULL &&
node->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
+
+ bool no_negative_zero = node->expression()->no_negative_zero();
Load(node->expression());
switch (op) {
case Token::NOT:
@@ -5436,7 +5440,10 @@
case Token::SUB: {
frame_->PopToR0();
- GenericUnaryOpStub stub(Token::SUB, overwrite);
+ GenericUnaryOpStub stub(
+ Token::SUB,
+ overwrite,
+ no_negative_zero ? kIgnoreNegativeZero : kStrictNegativeZero);
frame_->CallStub(&stub, 0);
frame_->EmitPush(r0); // r0 has result
break;
@@ -7641,187 +7648,195 @@
__ Swap(r0, r1, ip);
}
- if (ShouldGenerateFPCode()) {
- Label r0_is_smi, r1_is_smi, finished_loading_r0, finished_loading_r1;
+ // The type transition also calculates the answer.
+ bool generate_code_to_calculate_answer = true;
+ if (ShouldGenerateFPCode()) {
if (runtime_operands_type_ == BinaryOpIC::DEFAULT) {
switch (op_) {
case Token::ADD:
case Token::SUB:
case Token::MUL:
case Token::DIV:
- GenerateTypeTransition(masm);
+ GenerateTypeTransition(masm); // Tail call.
+ generate_code_to_calculate_answer = false;
break;
default:
break;
}
- // Restore heap number map register.
- __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
}
- if (mode_ == NO_OVERWRITE) {
- // In the case where there is no chance of an overwritable float we may as
- // well do the allocation immediately while r0 and r1 are untouched.
- __ AllocateHeapNumber(r5, r3, r7, heap_number_map, &slow);
- }
-
- // Move r0 to a double in r2-r3.
- __ tst(r0, Operand(kSmiTagMask));
- __ b(eq, &r0_is_smi); // It's a Smi so don't check it's a heap number.
- __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
- __ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
- __ cmp(r4, heap_number_map);
- __ b(ne, &slow);
- if (mode_ == OVERWRITE_RIGHT) {
- __ mov(r5, Operand(r0)); // Overwrite this heap number.
- }
- if (use_fp_registers) {
- CpuFeatures::Scope scope(VFP3);
- // Load the double from tagged HeapNumber r0 to d7.
- __ sub(r7, r0, Operand(kHeapObjectTag));
- __ vldr(d7, r7, HeapNumber::kValueOffset);
- } else {
- // Calling convention says that second double is in r2 and r3.
- __ Ldrd(r2, r3, FieldMemOperand(r0, HeapNumber::kValueOffset));
- }
- __ jmp(&finished_loading_r0);
- __ bind(&r0_is_smi);
- if (mode_ == OVERWRITE_RIGHT) {
- // We can't overwrite a Smi so get address of new heap number into r5.
- __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow);
- }
-
- if (CpuFeatures::IsSupported(VFP3)) {
- CpuFeatures::Scope scope(VFP3);
- // Convert smi in r0 to double in d7.
- __ mov(r7, Operand(r0, ASR, kSmiTagSize));
- __ vmov(s15, r7);
- __ vcvt_f64_s32(d7, s15);
- if (!use_fp_registers) {
- __ vmov(r2, r3, d7);
+ if (generate_code_to_calculate_answer) {
+ Label r0_is_smi, r1_is_smi, finished_loading_r0, finished_loading_r1;
+ if (mode_ == NO_OVERWRITE) {
+ // In the case where there is no chance of an overwritable float we may
+ // as well do the allocation immediately while r0 and r1 are untouched.
+ __ AllocateHeapNumber(r5, r3, r7, heap_number_map, &slow);
}
- } else {
- // Write Smi from r0 to r3 and r2 in double format.
- __ mov(r7, Operand(r0));
- ConvertToDoubleStub stub3(r3, r2, r7, r4);
- __ push(lr);
- __ Call(stub3.GetCode(), RelocInfo::CODE_TARGET);
- __ pop(lr);
- }
- // HEAP_NUMBERS stub is slower than GENERIC on a pair of smis.
- // r0 is known to be a smi. If r1 is also a smi then switch to GENERIC.
- Label r1_is_not_smi;
- if (runtime_operands_type_ == BinaryOpIC::HEAP_NUMBERS) {
- __ tst(r1, Operand(kSmiTagMask));
- __ b(ne, &r1_is_not_smi);
- GenerateTypeTransition(masm);
- // Restore heap number map register.
- __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
- __ jmp(&r1_is_smi);
- }
-
- __ bind(&finished_loading_r0);
-
- // Move r1 to a double in r0-r1.
- __ tst(r1, Operand(kSmiTagMask));
- __ b(eq, &r1_is_smi); // It's a Smi so don't check it's a heap number.
- __ bind(&r1_is_not_smi);
- __ ldr(r4, FieldMemOperand(r1, HeapNumber::kMapOffset));
- __ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
- __ cmp(r4, heap_number_map);
- __ b(ne, &slow);
- if (mode_ == OVERWRITE_LEFT) {
- __ mov(r5, Operand(r1)); // Overwrite this heap number.
- }
- if (use_fp_registers) {
- CpuFeatures::Scope scope(VFP3);
- // Load the double from tagged HeapNumber r1 to d6.
- __ sub(r7, r1, Operand(kHeapObjectTag));
- __ vldr(d6, r7, HeapNumber::kValueOffset);
- } else {
- // Calling convention says that first double is in r0 and r1.
- __ Ldrd(r0, r1, FieldMemOperand(r1, HeapNumber::kValueOffset));
- }
- __ jmp(&finished_loading_r1);
- __ bind(&r1_is_smi);
- if (mode_ == OVERWRITE_LEFT) {
- // We can't overwrite a Smi so get address of new heap number into r5.
- __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow);
- }
-
- if (CpuFeatures::IsSupported(VFP3)) {
- CpuFeatures::Scope scope(VFP3);
- // Convert smi in r1 to double in d6.
- __ mov(r7, Operand(r1, ASR, kSmiTagSize));
- __ vmov(s13, r7);
- __ vcvt_f64_s32(d6, s13);
- if (!use_fp_registers) {
- __ vmov(r0, r1, d6);
+ // Move r0 to a double in r2-r3.
+ __ tst(r0, Operand(kSmiTagMask));
+ __ b(eq, &r0_is_smi); // It's a Smi so don't check it's a heap number.
+ __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset));
+ __ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
+ __ cmp(r4, heap_number_map);
+ __ b(ne, &slow);
+ if (mode_ == OVERWRITE_RIGHT) {
+ __ mov(r5, Operand(r0)); // Overwrite this heap number.
}
- } else {
- // Write Smi from r1 to r1 and r0 in double format.
- __ mov(r7, Operand(r1));
- ConvertToDoubleStub stub4(r1, r0, r7, r9);
- __ push(lr);
- __ Call(stub4.GetCode(), RelocInfo::CODE_TARGET);
- __ pop(lr);
- }
-
- __ bind(&finished_loading_r1);
-
- __ bind(&do_the_call);
- // If we are inlining the operation using VFP3 instructions for
- // add, subtract, multiply, or divide, the arguments are in d6 and d7.
- if (use_fp_registers) {
- CpuFeatures::Scope scope(VFP3);
- // ARMv7 VFP3 instructions to implement
- // double precision, add, subtract, multiply, divide.
-
- if (Token::MUL == op_) {
- __ vmul(d5, d6, d7);
- } else if (Token::DIV == op_) {
- __ vdiv(d5, d6, d7);
- } else if (Token::ADD == op_) {
- __ vadd(d5, d6, d7);
- } else if (Token::SUB == op_) {
- __ vsub(d5, d6, d7);
+ if (use_fp_registers) {
+ CpuFeatures::Scope scope(VFP3);
+ // Load the double from tagged HeapNumber r0 to d7.
+ __ sub(r7, r0, Operand(kHeapObjectTag));
+ __ vldr(d7, r7, HeapNumber::kValueOffset);
} else {
- UNREACHABLE();
+ // Calling convention says that second double is in r2 and r3.
+ __ Ldrd(r2, r3, FieldMemOperand(r0, HeapNumber::kValueOffset));
}
- __ sub(r0, r5, Operand(kHeapObjectTag));
- __ vstr(d5, r0, HeapNumber::kValueOffset);
- __ add(r0, r0, Operand(kHeapObjectTag));
- __ mov(pc, lr);
- } else {
- // If we did not inline the operation, then the arguments are in:
- // r0: Left value (least significant part of mantissa).
- // r1: Left value (sign, exponent, top of mantissa).
- // r2: Right value (least significant part of mantissa).
- // r3: Right value (sign, exponent, top of mantissa).
- // r5: Address of heap number for result.
+ __ jmp(&finished_loading_r0);
+ __ bind(&r0_is_smi);
+ if (mode_ == OVERWRITE_RIGHT) {
+ // We can't overwrite a Smi so get address of new heap number into r5.
+ __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow);
+ }
- __ push(lr); // For later.
- __ PrepareCallCFunction(4, r4); // Two doubles count as 4 arguments.
- // Call C routine that may not cause GC or other trouble. r5 is callee
- // save.
- __ CallCFunction(ExternalReference::double_fp_operation(op_), 4);
- // Store answer in the overwritable heap number.
- #if !defined(USE_ARM_EABI)
- // Double returned in fp coprocessor register 0 and 1, encoded as register
- // cr8. Offsets must be divisible by 4 for coprocessor so we need to
- // substract the tag from r5.
- __ sub(r4, r5, Operand(kHeapObjectTag));
- __ stc(p1, cr8, MemOperand(r4, HeapNumber::kValueOffset));
- #else
- // Double returned in registers 0 and 1.
- __ Strd(r0, r1, FieldMemOperand(r5, HeapNumber::kValueOffset));
- #endif
- __ mov(r0, Operand(r5));
- // And we are done.
- __ pop(pc);
+ if (CpuFeatures::IsSupported(VFP3)) {
+ CpuFeatures::Scope scope(VFP3);
+ // Convert smi in r0 to double in d7.
+ __ mov(r7, Operand(r0, ASR, kSmiTagSize));
+ __ vmov(s15, r7);
+ __ vcvt_f64_s32(d7, s15);
+ if (!use_fp_registers) {
+ __ vmov(r2, r3, d7);
+ }
+ } else {
+ // Write Smi from r0 to r3 and r2 in double format.
+ __ mov(r7, Operand(r0));
+ ConvertToDoubleStub stub3(r3, r2, r7, r4);
+ __ push(lr);
+ __ Call(stub3.GetCode(), RelocInfo::CODE_TARGET);
+ __ pop(lr);
+ }
+
+ // HEAP_NUMBERS stub is slower than GENERIC on a pair of smis.
+ // r0 is known to be a smi. If r1 is also a smi then switch to GENERIC.
+ Label r1_is_not_smi;
+ if (runtime_operands_type_ == BinaryOpIC::HEAP_NUMBERS) {
+ __ tst(r1, Operand(kSmiTagMask));
+ __ b(ne, &r1_is_not_smi);
+ GenerateTypeTransition(masm); // Tail call.
+ }
+
+ __ bind(&finished_loading_r0);
+
+ // Move r1 to a double in r0-r1.
+ __ tst(r1, Operand(kSmiTagMask));
+ __ b(eq, &r1_is_smi); // It's a Smi so don't check it's a heap number.
+ __ bind(&r1_is_not_smi);
+ __ ldr(r4, FieldMemOperand(r1, HeapNumber::kMapOffset));
+ __ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
+ __ cmp(r4, heap_number_map);
+ __ b(ne, &slow);
+ if (mode_ == OVERWRITE_LEFT) {
+ __ mov(r5, Operand(r1)); // Overwrite this heap number.
+ }
+ if (use_fp_registers) {
+ CpuFeatures::Scope scope(VFP3);
+ // Load the double from tagged HeapNumber r1 to d6.
+ __ sub(r7, r1, Operand(kHeapObjectTag));
+ __ vldr(d6, r7, HeapNumber::kValueOffset);
+ } else {
+ // Calling convention says that first double is in r0 and r1.
+ __ Ldrd(r0, r1, FieldMemOperand(r1, HeapNumber::kValueOffset));
+ }
+ __ jmp(&finished_loading_r1);
+ __ bind(&r1_is_smi);
+ if (mode_ == OVERWRITE_LEFT) {
+ // We can't overwrite a Smi so get address of new heap number into r5.
+ __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow);
+ }
+
+ if (CpuFeatures::IsSupported(VFP3)) {
+ CpuFeatures::Scope scope(VFP3);
+ // Convert smi in r1 to double in d6.
+ __ mov(r7, Operand(r1, ASR, kSmiTagSize));
+ __ vmov(s13, r7);
+ __ vcvt_f64_s32(d6, s13);
+ if (!use_fp_registers) {
+ __ vmov(r0, r1, d6);
+ }
+ } else {
+ // Write Smi from r1 to r1 and r0 in double format.
+ __ mov(r7, Operand(r1));
+ ConvertToDoubleStub stub4(r1, r0, r7, r9);
+ __ push(lr);
+ __ Call(stub4.GetCode(), RelocInfo::CODE_TARGET);
+ __ pop(lr);
+ }
+
+ __ bind(&finished_loading_r1);
}
+
+ if (generate_code_to_calculate_answer || do_the_call.is_linked()) {
+ __ bind(&do_the_call);
+ // If we are inlining the operation using VFP3 instructions for
+ // add, subtract, multiply, or divide, the arguments are in d6 and d7.
+ if (use_fp_registers) {
+ CpuFeatures::Scope scope(VFP3);
+ // ARMv7 VFP3 instructions to implement
+ // double precision, add, subtract, multiply, divide.
+
+ if (Token::MUL == op_) {
+ __ vmul(d5, d6, d7);
+ } else if (Token::DIV == op_) {
+ __ vdiv(d5, d6, d7);
+ } else if (Token::ADD == op_) {
+ __ vadd(d5, d6, d7);
+ } else if (Token::SUB == op_) {
+ __ vsub(d5, d6, d7);
+ } else {
+ UNREACHABLE();
+ }
+ __ sub(r0, r5, Operand(kHeapObjectTag));
+ __ vstr(d5, r0, HeapNumber::kValueOffset);
+ __ add(r0, r0, Operand(kHeapObjectTag));
+ __ mov(pc, lr);
+ } else {
+ // If we did not inline the operation, then the arguments are in:
+ // r0: Left value (least significant part of mantissa).
+ // r1: Left value (sign, exponent, top of mantissa).
+ // r2: Right value (least significant part of mantissa).
+ // r3: Right value (sign, exponent, top of mantissa).
+ // r5: Address of heap number for result.
+
+ __ push(lr); // For later.
+ __ PrepareCallCFunction(4, r4); // Two doubles count as 4 arguments.
+ // Call C routine that may not cause GC or other trouble. r5 is callee
+ // save.
+ __ CallCFunction(ExternalReference::double_fp_operation(op_), 4);
+ // Store answer in the overwritable heap number.
+ #if !defined(USE_ARM_EABI)
+ // Double returned in fp coprocessor register 0 and 1, encoded as
+ // register cr8. Offsets must be divisible by 4 for coprocessor so we
+ // need to substract the tag from r5.
+ __ sub(r4, r5, Operand(kHeapObjectTag));
+ __ stc(p1, cr8, MemOperand(r4, HeapNumber::kValueOffset));
+ #else
+ // Double returned in registers 0 and 1.
+ __ Strd(r0, r1, FieldMemOperand(r5, HeapNumber::kValueOffset));
+ #endif
+ __ mov(r0, Operand(r5));
+ // And we are done.
+ __ pop(pc);
+ }
+ }
+ }
+
+ if (!generate_code_to_calculate_answer &&
+ !slow_reverse.is_linked() &&
+ !slow.is_linked()) {
+ return;
}
if (lhs.is(r0)) {
@@ -8745,29 +8760,15 @@
__ Push(r1, r0);
- // Internal frame is necessary to handle exceptions properly.
- __ EnterInternalFrame();
- // Call the stub proper to get the result in r0.
- __ Call(&get_result);
- __ LeaveInternalFrame();
-
- __ push(r0);
-
- __ mov(r0, Operand(Smi::FromInt(MinorKey())));
- __ push(r0);
- __ mov(r0, Operand(Smi::FromInt(op_)));
- __ push(r0);
+ __ mov(r2, Operand(Smi::FromInt(MinorKey())));
+ __ mov(r1, Operand(Smi::FromInt(op_)));
__ mov(r0, Operand(Smi::FromInt(runtime_operands_type_)));
- __ push(r0);
+ __ Push(r2, r1, r0);
__ TailCallExternalReference(
ExternalReference(IC_Utility(IC::kBinaryOp_Patch)),
- 6,
+ 5,
1);
-
- // The entry point for the result calculation is assumed to be immediately
- // after this sequence.
- __ bind(&get_result);
}
@@ -8899,16 +8900,23 @@
// Go slow case if the value of the expression is zero
// to make sure that we switch between 0 and -0.
- __ cmp(r0, Operand(0));
- __ b(eq, &slow);
-
- // The value of the expression is a smi that is not zero. Try
- // optimistic subtraction '0 - value'.
- __ rsb(r1, r0, Operand(0), SetCC);
- __ b(vs, &slow);
-
- __ mov(r0, Operand(r1)); // Set r0 to result.
- __ b(&done);
+ if (negative_zero_ == kStrictNegativeZero) {
+ // If we have to check for zero, then we can check for the max negative
+ // smi while we are at it.
+ __ bic(ip, r0, Operand(0x80000000), SetCC);
+ __ b(eq, &slow);
+ __ rsb(r0, r0, Operand(0));
+ __ StubReturn(1);
+ } else {
+ // The value of the expression is a smi and 0 is OK for -0. Try
+ // optimistic subtraction '0 - value'.
+ __ rsb(r0, r0, Operand(0), SetCC);
+ __ StubReturn(1, vc);
+ // We don't have to reverse the optimistic neg since the only case
+ // where we fall through is the minimum negative Smi, which is the case
+ // where the neg leaves the register unchanged.
+ __ jmp(&slow); // Go slow on max negative Smi.
+ }
__ bind(&try_float);
__ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
@@ -8916,7 +8924,7 @@
__ cmp(r1, heap_number_map);
__ b(ne, &slow);
// r0 is a heap number. Get a new heap number in r1.
- if (overwrite_) {
+ if (overwrite_ == UNARY_OVERWRITE) {
__ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
__ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign.
__ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
@@ -8949,7 +8957,7 @@
__ b(&done);
__ bind(&try_float);
- if (!overwrite_) {
+ if (!overwrite_ == UNARY_OVERWRITE) {
// Allocate a fresh heap number, but don't overwrite r0 until
// we're sure we can do it without going through the slow case
// that needs the value in r0.
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 6732873..080cb83 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -2736,9 +2736,11 @@
case Token::SUB: {
Comment cmt(masm_, "[ UnaryOperation (SUB)");
- bool overwrite =
+ bool can_overwrite =
(expr->expression()->AsBinaryOperation() != NULL &&
expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::SUB, overwrite);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register r0.
@@ -2750,9 +2752,11 @@
case Token::BIT_NOT: {
Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
- bool overwrite =
+ bool can_overwrite =
(expr->expression()->AsBinaryOperation() != NULL &&
expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register r0.
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 81fc11e..2896cc9 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -1372,12 +1372,12 @@
}
-void MacroAssembler::StubReturn(int argc) {
+void MacroAssembler::StubReturn(int argc, Condition cond) {
ASSERT(argc >= 1 && generating_stub());
if (argc > 1) {
- add(sp, sp, Operand((argc - 1) * kPointerSize));
+ add(sp, sp, Operand((argc - 1) * kPointerSize), LeaveCC, cond);
}
- Ret();
+ Ret(cond);
}
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index d57c565..f1f7de7 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -537,7 +537,7 @@
void TailCallStub(CodeStub* stub, Condition cond = al);
// Return from a code stub after popping its arguments.
- void StubReturn(int argc);
+ void StubReturn(int argc, Condition cond = al);
// Call a runtime routine.
void CallRuntime(Runtime::Function* f, int num_arguments);
diff --git a/src/codegen.cc b/src/codegen.cc
index 686e173..8864c95 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -460,11 +460,17 @@
const char* GenericUnaryOpStub::GetName() {
switch (op_) {
case Token::SUB:
- return overwrite_
- ? "GenericUnaryOpStub_SUB_Overwrite"
- : "GenericUnaryOpStub_SUB_Alloc";
+ if (negative_zero_ == kStrictNegativeZero) {
+ return overwrite_ == UNARY_OVERWRITE
+ ? "GenericUnaryOpStub_SUB_Overwrite_Strict0"
+ : "GenericUnaryOpStub_SUB_Alloc_Strict0";
+ } else {
+ return overwrite_ == UNARY_OVERWRITE
+ ? "GenericUnaryOpStub_SUB_Overwrite_Ignore0"
+ : "GenericUnaryOpStub_SUB_Alloc_Ignore0";
+ }
case Token::BIT_NOT:
- return overwrite_
+ return overwrite_ == UNARY_OVERWRITE
? "GenericUnaryOpStub_BIT_NOT_Overwrite"
: "GenericUnaryOpStub_BIT_NOT_Alloc";
default:
diff --git a/src/codegen.h b/src/codegen.h
index 0576fbb..783bef0 100644
--- a/src/codegen.h
+++ b/src/codegen.h
@@ -75,6 +75,7 @@
// Mode to overwrite BinaryExpression values.
enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
+enum UnaryOverwriteMode { UNARY_OVERWRITE, UNARY_NO_OVERWRITE };
// Types of uncatchable exceptions.
enum UncatchableExceptionType { OUT_OF_MEMORY, TERMINATION };
@@ -414,21 +415,33 @@
};
+enum NegativeZeroHandling {
+ kStrictNegativeZero,
+ kIgnoreNegativeZero
+};
+
+
class GenericUnaryOpStub : public CodeStub {
public:
- GenericUnaryOpStub(Token::Value op, bool overwrite)
- : op_(op), overwrite_(overwrite) { }
+ GenericUnaryOpStub(Token::Value op,
+ UnaryOverwriteMode overwrite,
+ NegativeZeroHandling negative_zero = kStrictNegativeZero)
+ : op_(op), overwrite_(overwrite), negative_zero_(negative_zero) { }
private:
Token::Value op_;
- bool overwrite_;
+ UnaryOverwriteMode overwrite_;
+ NegativeZeroHandling negative_zero_;
- class OverwriteField: public BitField<int, 0, 1> {};
- class OpField: public BitField<Token::Value, 1, kMinorBits - 1> {};
+ class OverwriteField: public BitField<UnaryOverwriteMode, 0, 1> {};
+ class NegativeZeroField: public BitField<NegativeZeroHandling, 1, 1> {};
+ class OpField: public BitField<Token::Value, 2, kMinorBits - 2> {};
Major MajorKey() { return GenericUnaryOp; }
int MinorKey() {
- return OpField::encode(op_) | OverwriteField::encode(overwrite_);
+ return OpField::encode(op_) |
+ OverwriteField::encode(overwrite_) |
+ NegativeZeroField::encode(negative_zero_);
}
void Generate(MacroAssembler* masm);
diff --git a/src/date.js b/src/date.js
index 83fca27..9c42a04 100644
--- a/src/date.js
+++ b/src/date.js
@@ -453,111 +453,6 @@
});
-// Helper functions.
-function GetTimeFrom(aDate) {
- return DATE_VALUE(aDate);
-}
-
-function GetMillisecondsFrom(aDate) {
- var t = DATE_VALUE(aDate);
- if (NUMBER_IS_NAN(t)) return t;
- return MS_FROM_TIME(LocalTimeNoCheck(t));
-}
-
-
-function GetUTCMillisecondsFrom(aDate) {
- var t = DATE_VALUE(aDate);
- if (NUMBER_IS_NAN(t)) return t;
- return MS_FROM_TIME(t);
-}
-
-
-function GetSecondsFrom(aDate) {
- var t = DATE_VALUE(aDate);
- if (NUMBER_IS_NAN(t)) return t;
- return SEC_FROM_TIME(LocalTimeNoCheck(t));
-}
-
-
-function GetUTCSecondsFrom(aDate) {
- var t = DATE_VALUE(aDate);
- if (NUMBER_IS_NAN(t)) return t;
- return SEC_FROM_TIME(t);
-}
-
-
-function GetMinutesFrom(aDate) {
- var t = DATE_VALUE(aDate);
- if (NUMBER_IS_NAN(t)) return t;
- return MIN_FROM_TIME(LocalTimeNoCheck(t));
-}
-
-
-function GetUTCMinutesFrom(aDate) {
- var t = DATE_VALUE(aDate);
- if (NUMBER_IS_NAN(t)) return t;
- return MIN_FROM_TIME(t);
-}
-
-
-function GetHoursFrom(aDate) {
- var t = DATE_VALUE(aDate);
- if (NUMBER_IS_NAN(t)) return t;
- return HOUR_FROM_TIME(LocalTimeNoCheck(t));
-}
-
-
-function GetUTCHoursFrom(aDate) {
- var t = DATE_VALUE(aDate);
- if (NUMBER_IS_NAN(t)) return t;
- return HOUR_FROM_TIME(t);
-}
-
-
-function GetFullYearFrom(aDate) {
- var t = DATE_VALUE(aDate);
- if (NUMBER_IS_NAN(t)) return t;
- var cache = Date_cache;
- if (cache.time === t) return cache.year;
- return YEAR_FROM_TIME(LocalTimeNoCheck(t));
-}
-
-
-function GetUTCFullYearFrom(aDate) {
- var t = DATE_VALUE(aDate);
- if (NUMBER_IS_NAN(t)) return t;
- return YEAR_FROM_TIME(t);
-}
-
-
-function GetMonthFrom(aDate) {
- var t = DATE_VALUE(aDate);
- if (NUMBER_IS_NAN(t)) return t;
- return MONTH_FROM_TIME(LocalTimeNoCheck(t));
-}
-
-
-function GetUTCMonthFrom(aDate) {
- var t = DATE_VALUE(aDate);
- if (NUMBER_IS_NAN(t)) return t;
- return MONTH_FROM_TIME(t);
-}
-
-
-function GetDateFrom(aDate) {
- var t = DATE_VALUE(aDate);
- if (NUMBER_IS_NAN(t)) return t;
- return DATE_FROM_TIME(LocalTimeNoCheck(t));
-}
-
-
-function GetUTCDateFrom(aDate) {
- var t = DATE_VALUE(aDate);
- if (NUMBER_IS_NAN(t)) return t;
- return DATE_FROM_TIME(t);
-}
-
-
%FunctionSetPrototype($Date, new $Date($NaN));
@@ -737,37 +632,50 @@
// ECMA 262 - 15.9.5.10
function DateGetFullYear() {
- return GetFullYearFrom(this)
+ var t = DATE_VALUE(this);
+ if (NUMBER_IS_NAN(t)) return t;
+ var cache = Date_cache;
+ if (cache.time === t) return cache.year;
+ return YEAR_FROM_TIME(LocalTimeNoCheck(t));
}
// ECMA 262 - 15.9.5.11
function DateGetUTCFullYear() {
- return GetUTCFullYearFrom(this)
+ var t = DATE_VALUE(this);
+ if (NUMBER_IS_NAN(t)) return t;
+ return YEAR_FROM_TIME(t);
}
// ECMA 262 - 15.9.5.12
function DateGetMonth() {
- return GetMonthFrom(this);
+ var t = DATE_VALUE(this);
+ if (NUMBER_IS_NAN(t)) return t;
+ return MONTH_FROM_TIME(LocalTimeNoCheck(t));
}
// ECMA 262 - 15.9.5.13
function DateGetUTCMonth() {
- return GetUTCMonthFrom(this);
+ var t = DATE_VALUE(this);
+ if (NUMBER_IS_NAN(t)) return t;
+ return MONTH_FROM_TIME(t);
}
// ECMA 262 - 15.9.5.14
function DateGetDate() {
- return GetDateFrom(this);
+ var t = DATE_VALUE(this);
+ if (NUMBER_IS_NAN(t)) return t;
+ return DATE_FROM_TIME(LocalTimeNoCheck(t));
}
// ECMA 262 - 15.9.5.15
function DateGetUTCDate() {
- return GetUTCDateFrom(this);
+ var t = DATE_VALUE(this);
+ return NAN_OR_DATE_FROM_TIME(t);
}
@@ -789,49 +697,62 @@
// ECMA 262 - 15.9.5.18
function DateGetHours() {
- return GetHoursFrom(this);
+ var t = DATE_VALUE(this);
+ if (NUMBER_IS_NAN(t)) return t;
+ return HOUR_FROM_TIME(LocalTimeNoCheck(t));
}
// ECMA 262 - 15.9.5.19
function DateGetUTCHours() {
- return GetUTCHoursFrom(this);
+ var t = DATE_VALUE(this);
+ if (NUMBER_IS_NAN(t)) return t;
+ return HOUR_FROM_TIME(t);
}
// ECMA 262 - 15.9.5.20
function DateGetMinutes() {
- return GetMinutesFrom(this);
+ var t = DATE_VALUE(this);
+ if (NUMBER_IS_NAN(t)) return t;
+ return MIN_FROM_TIME(LocalTimeNoCheck(t));
}
// ECMA 262 - 15.9.5.21
function DateGetUTCMinutes() {
- return GetUTCMinutesFrom(this);
+ var t = DATE_VALUE(this);
+ return NAN_OR_MIN_FROM_TIME(t);
}
// ECMA 262 - 15.9.5.22
function DateGetSeconds() {
- return GetSecondsFrom(this);
+ var t = DATE_VALUE(this);
+ if (NUMBER_IS_NAN(t)) return t;
+ return SEC_FROM_TIME(LocalTimeNoCheck(t));
}
// ECMA 262 - 15.9.5.23
function DateGetUTCSeconds() {
- return GetUTCSecondsFrom(this);
+ var t = DATE_VALUE(this);
+ return NAN_OR_SEC_FROM_TIME(t);
}
// ECMA 262 - 15.9.5.24
function DateGetMilliseconds() {
- return GetMillisecondsFrom(this);
+ var t = DATE_VALUE(this);
+ if (NUMBER_IS_NAN(t)) return t;
+ return MS_FROM_TIME(LocalTimeNoCheck(t));
}
// ECMA 262 - 15.9.5.25
function DateGetUTCMilliseconds() {
- return GetUTCMillisecondsFrom(this);
+ var t = DATE_VALUE(this);
+ return NAN_OR_MS_FROM_TIME(t);
}
@@ -872,7 +793,7 @@
function DateSetSeconds(sec, ms) {
var t = LocalTime(DATE_VALUE(this));
sec = ToNumber(sec);
- ms = %_ArgumentsLength() < 2 ? GetMillisecondsFrom(this) : ToNumber(ms);
+ ms = %_ArgumentsLength() < 2 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), sec, ms);
return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
}
@@ -882,7 +803,7 @@
function DateSetUTCSeconds(sec, ms) {
var t = DATE_VALUE(this);
sec = ToNumber(sec);
- ms = %_ArgumentsLength() < 2 ? GetUTCMillisecondsFrom(this) : ToNumber(ms);
+ ms = %_ArgumentsLength() < 2 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
var time = MakeTime(HOUR_FROM_TIME(t), MIN_FROM_TIME(t), sec, ms);
return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
}
@@ -893,8 +814,8 @@
var t = LocalTime(DATE_VALUE(this));
min = ToNumber(min);
var argc = %_ArgumentsLength();
- sec = argc < 2 ? GetSecondsFrom(this) : ToNumber(sec);
- ms = argc < 3 ? GetMillisecondsFrom(this) : ToNumber(ms);
+ sec = argc < 2 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
+ ms = argc < 3 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
var time = MakeTime(HOUR_FROM_TIME(t), min, sec, ms);
return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
}
@@ -905,8 +826,8 @@
var t = DATE_VALUE(this);
min = ToNumber(min);
var argc = %_ArgumentsLength();
- sec = argc < 2 ? GetUTCSecondsFrom(this) : ToNumber(sec);
- ms = argc < 3 ? GetUTCMillisecondsFrom(this) : ToNumber(ms);
+ sec = argc < 2 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
+ ms = argc < 3 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
var time = MakeTime(HOUR_FROM_TIME(t), min, sec, ms);
return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
}
@@ -917,9 +838,9 @@
var t = LocalTime(DATE_VALUE(this));
hour = ToNumber(hour);
var argc = %_ArgumentsLength();
- min = argc < 2 ? GetMinutesFrom(this) : ToNumber(min);
- sec = argc < 3 ? GetSecondsFrom(this) : ToNumber(sec);
- ms = argc < 4 ? GetMillisecondsFrom(this) : ToNumber(ms);
+ min = argc < 2 ? NAN_OR_MIN_FROM_TIME(t) : ToNumber(min);
+ sec = argc < 3 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
+ ms = argc < 4 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
var time = MakeTime(hour, min, sec, ms);
return %_SetValueOf(this, TimeClip(UTC(MakeDate(DAY(t), time))));
}
@@ -930,9 +851,9 @@
var t = DATE_VALUE(this);
hour = ToNumber(hour);
var argc = %_ArgumentsLength();
- min = argc < 2 ? GetUTCMinutesFrom(this) : ToNumber(min);
- sec = argc < 3 ? GetUTCSecondsFrom(this) : ToNumber(sec);
- ms = argc < 4 ? GetUTCMillisecondsFrom(this) : ToNumber(ms);
+ min = argc < 2 ? NAN_OR_MIN_FROM_TIME(t) : ToNumber(min);
+ sec = argc < 3 ? NAN_OR_SEC_FROM_TIME(t) : ToNumber(sec);
+ ms = argc < 4 ? NAN_OR_MS_FROM_TIME(t) : ToNumber(ms);
var time = MakeTime(hour, min, sec, ms);
return %_SetValueOf(this, TimeClip(MakeDate(DAY(t), time)));
}
@@ -960,7 +881,7 @@
function DateSetMonth(month, date) {
var t = LocalTime(DATE_VALUE(this));
month = ToNumber(month);
- date = %_ArgumentsLength() < 2 ? GetDateFrom(this) : ToNumber(date);
+ date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
var day = MakeDay(YEAR_FROM_TIME(t), month, date);
return %_SetValueOf(this, TimeClip(UTC(MakeDate(day, TimeWithinDay(t)))));
}
@@ -970,7 +891,7 @@
function DateSetUTCMonth(month, date) {
var t = DATE_VALUE(this);
month = ToNumber(month);
- date = %_ArgumentsLength() < 2 ? GetUTCDateFrom(this) : ToNumber(date);
+ date = %_ArgumentsLength() < 2 ? NAN_OR_DATE_FROM_TIME(t) : ToNumber(date);
var day = MakeDay(YEAR_FROM_TIME(t), month, date);
return %_SetValueOf(this, TimeClip(MakeDate(day, TimeWithinDay(t))));
}
diff --git a/src/debug.cc b/src/debug.cc
index 1dc6275..b8e0252 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -472,8 +472,9 @@
RelocInfo::Mode mode = rmode();
if (RelocInfo::IsCodeTarget(mode)) {
+ AssertNoAllocation nogc;
Address target = original_rinfo()->target_address();
- Handle<Code> code(Code::GetCodeFromTargetAddress(target));
+ Code* code = Code::GetCodeFromTargetAddress(target);
// Restore the inlined version of keyed stores to get back to the
// fast case. We need to patch back the keyed store because no
diff --git a/src/factory.cc b/src/factory.cc
index f6b93b0..39e881a 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -96,6 +96,12 @@
}
+Handle<String> Factory::NewRawAsciiString(int length,
+ PretenureFlag pretenure) {
+ CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(length, pretenure), String);
+}
+
+
Handle<String> Factory::NewRawTwoByteString(int length,
PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(length, pretenure), String);
diff --git a/src/factory.h b/src/factory.h
index b0a0571..56deda5 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -95,12 +95,16 @@
Vector<const char> str,
PretenureFlag pretenure = NOT_TENURED);
- static Handle<String> NewStringFromTwoByte(Vector<const uc16> str,
+ static Handle<String> NewStringFromTwoByte(
+ Vector<const uc16> str,
PretenureFlag pretenure = NOT_TENURED);
- // Allocates and partially initializes a TwoByte String. The characters of
- // the string are uninitialized. Currently used in regexp code only, where
- // they are pretenured.
+ // Allocates and partially initializes an ASCII or TwoByte String. The
+ // characters of the string are uninitialized. Currently used in regexp code
+ // only, where they are pretenured.
+ static Handle<String> NewRawAsciiString(
+ int length,
+ PretenureFlag pretenure = NOT_TENURED);
static Handle<String> NewRawTwoByteString(
int length,
PretenureFlag pretenure = NOT_TENURED);
diff --git a/src/frames.cc b/src/frames.cc
index 9cf83c9..67a20d3 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -542,7 +542,7 @@
Address pc = this->pc();
if (code != NULL && code->kind() == Code::FUNCTION &&
- pc >= code->instruction_start() && pc < code->relocation_start()) {
+ pc >= code->instruction_start() && pc < code->instruction_end()) {
int source_pos = code->SourcePosition(pc);
int line = GetScriptLineNumberSafe(script, source_pos) + 1;
accumulator->Add(":%d", line);
diff --git a/src/heap.cc b/src/heap.cc
index 6ae46f2..1b62589 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -2351,8 +2351,13 @@
ZoneScopeInfo* sinfo,
Code::Flags flags,
Handle<Object> self_reference) {
+ // Allocate ByteArray before the Code object, so that we do not risk
+ // leaving uninitialized Code object (and breaking the heap).
+ Object* reloc_info = AllocateByteArray(desc.reloc_size, TENURED);
+ if (reloc_info->IsFailure()) return reloc_info;
+
// Compute size
- int body_size = RoundUp(desc.instr_size + desc.reloc_size, kObjectAlignment);
+ int body_size = RoundUp(desc.instr_size, kObjectAlignment);
int sinfo_size = 0;
if (sinfo != NULL) sinfo_size = sinfo->Serialize(NULL);
int obj_size = Code::SizeFor(body_size, sinfo_size);
@@ -2371,7 +2376,7 @@
Code* code = Code::cast(result);
ASSERT(!CodeRange::exists() || CodeRange::contains(code->address()));
code->set_instruction_size(desc.instr_size);
- code->set_relocation_size(desc.reloc_size);
+ code->set_relocation_info(ByteArray::cast(reloc_info));
code->set_sinfo_size(sinfo_size);
code->set_flags(flags);
// Allow self references to created code object by patching the handle to
@@ -2419,8 +2424,12 @@
Object* Heap::CopyCode(Code* code, Vector<byte> reloc_info) {
- int new_body_size = RoundUp(code->instruction_size() + reloc_info.length(),
- kObjectAlignment);
+ // Allocate ByteArray before the Code object, so that we do not risk
+ // leaving uninitialized Code object (and breaking the heap).
+ Object* reloc_info_array = AllocateByteArray(reloc_info.length(), TENURED);
+ if (reloc_info_array->IsFailure()) return reloc_info_array;
+
+ int new_body_size = RoundUp(code->instruction_size(), kObjectAlignment);
int sinfo_size = code->sinfo_size();
@@ -2429,7 +2438,7 @@
Address old_addr = code->address();
size_t relocation_offset =
- static_cast<size_t>(code->relocation_start() - old_addr);
+ static_cast<size_t>(code->instruction_end() - old_addr);
Object* result;
if (new_obj_size > MaxObjectSizeInPagedSpace()) {
@@ -2446,14 +2455,11 @@
// Copy header and instructions.
memcpy(new_addr, old_addr, relocation_offset);
- // Copy patched rinfo.
- memcpy(new_addr + relocation_offset,
- reloc_info.start(),
- reloc_info.length());
-
Code* new_code = Code::cast(result);
- new_code->set_relocation_size(reloc_info.length());
+ new_code->set_relocation_info(ByteArray::cast(reloc_info_array));
+ // Copy patched rinfo.
+ memcpy(new_code->relocation_start(), reloc_info.start(), reloc_info.length());
// Copy sinfo.
memcpy(new_code->sinfo_start(), code->sinfo_start(), code->sinfo_size());
@@ -2866,6 +2872,8 @@
Object* Heap::AllocateStringFromUtf8(Vector<const char> string,
PretenureFlag pretenure) {
+ // V8 only supports characters in the Basic Multilingual Plane.
+ const uc32 kMaxSupportedChar = 0xFFFF;
// Count the number of characters in the UTF-8 string and check if
// it is an ASCII string.
Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder());
@@ -2890,6 +2898,7 @@
decoder->Reset(string.start(), string.length());
for (int i = 0; i < chars; i++) {
uc32 r = decoder->GetNext();
+ if (r > kMaxSupportedChar) { r = unibrow::Utf8::kBadChar; }
string_result->Set(i, r);
}
return result;
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index fa09dd8..0f72074 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -7583,9 +7583,12 @@
frame_->Push(&value);
} else {
Load(node->expression());
- bool overwrite =
+ bool can_overwrite =
(node->expression()->AsBinaryOperation() != NULL &&
node->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
+ bool no_negative_zero = node->expression()->no_negative_zero();
switch (op) {
case Token::NOT:
case Token::DELETE:
@@ -7594,7 +7597,10 @@
break;
case Token::SUB: {
- GenericUnaryOpStub stub(Token::SUB, overwrite);
+ GenericUnaryOpStub stub(
+ Token::SUB,
+ overwrite,
+ no_negative_zero ? kIgnoreNegativeZero : kStrictNegativeZero);
Result operand = frame_->Pop();
Result answer = frame_->CallStub(&stub, &operand);
answer.set_type_info(TypeInfo::Number());
@@ -9860,6 +9866,7 @@
// the four basic operations. The stub stays in the DEFAULT state
// forever for all other operations (also if smi code is skipped).
GenerateTypeTransition(masm);
+ break;
}
Label not_floats;
@@ -10207,51 +10214,28 @@
void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
- Label get_result;
-
- // Keep a copy of operands on the stack and make sure they are also in
- // edx, eax.
+ // Ensure the operands are on the stack.
if (HasArgsInRegisters()) {
GenerateRegisterArgsPush(masm);
- } else {
- GenerateLoadArguments(masm);
}
- // Internal frame is necessary to handle exceptions properly.
- __ EnterInternalFrame();
+ __ pop(ecx); // Save return address.
- // Push arguments on stack if the stub expects them there.
- if (!HasArgsInRegisters()) {
- __ push(edx);
- __ push(eax);
- }
- // Call the stub proper to get the result in eax.
- __ call(&get_result);
- __ LeaveInternalFrame();
-
- __ pop(ecx); // Return address.
// Left and right arguments are now on top.
- // Push the operation result. The tail call to BinaryOp_Patch will
- // return it to the original caller.
- __ push(eax);
// Push this stub's key. Although the operation and the type info are
// encoded into the key, the encoding is opaque, so push them too.
__ push(Immediate(Smi::FromInt(MinorKey())));
__ push(Immediate(Smi::FromInt(op_)));
__ push(Immediate(Smi::FromInt(runtime_operands_type_)));
- __ push(ecx); // Return address.
+ __ push(ecx); // Push return address.
- // Patch the caller to an appropriate specialized stub
- // and return the operation result.
+ // Patch the caller to an appropriate specialized stub and return the
+ // operation result to the caller of the stub.
__ TailCallExternalReference(
ExternalReference(IC_Utility(IC::kBinaryOp_Patch)),
- 6,
+ 5,
1);
-
- // The entry point for the result calculation is assumed to be immediately
- // after this sequence.
- __ bind(&get_result);
}
@@ -10934,10 +10918,12 @@
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, &try_float, not_taken);
- // Go slow case if the value of the expression is zero
- // to make sure that we switch between 0 and -0.
- __ test(eax, Operand(eax));
- __ j(zero, &slow, not_taken);
+ if (negative_zero_ == kStrictNegativeZero) {
+ // Go slow case if the value of the expression is zero
+ // to make sure that we switch between 0 and -0.
+ __ test(eax, Operand(eax));
+ __ j(zero, &slow, not_taken);
+ }
// The value of the expression is a smi that is not zero. Try
// optimistic subtraction '0 - value'.
@@ -10945,11 +10931,7 @@
__ mov(edx, Operand(eax));
__ Set(eax, Immediate(0));
__ sub(eax, Operand(edx));
- __ j(overflow, &undo, not_taken);
-
- // If result is a smi we are done.
- __ test(eax, Immediate(kSmiTagMask));
- __ j(zero, &done, taken);
+ __ j(no_overflow, &done, taken);
// Restore eax and go slow case.
__ bind(&undo);
@@ -10961,7 +10943,7 @@
__ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
__ cmp(edx, Factory::heap_number_map());
__ j(not_equal, &slow);
- if (overwrite_) {
+ if (overwrite_ == UNARY_OVERWRITE) {
__ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset));
__ xor_(edx, HeapNumber::kSignMask); // Flip sign.
__ mov(FieldOperand(eax, HeapNumber::kExponentOffset), edx);
@@ -11002,7 +10984,7 @@
// Try to store the result in a heap number.
__ bind(&try_float);
- if (!overwrite_) {
+ if (overwrite_ == UNARY_NO_OVERWRITE) {
// Allocate a fresh heap number, but don't overwrite eax until
// we're sure we can do it without going through the slow case
// that needs the value in eax.
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 13173e2..2ca1105 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -2813,9 +2813,11 @@
case Token::SUB: {
Comment cmt(masm_, "[ UnaryOperation (SUB)");
- bool overwrite =
+ bool can_overwrite =
(expr->expression()->AsBinaryOperation() != NULL &&
expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::SUB, overwrite);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register eax.
@@ -2827,9 +2829,11 @@
case Token::BIT_NOT: {
Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
- bool overwrite =
+ bool can_overwrite =
(expr->expression()->AsBinaryOperation() != NULL &&
expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register eax.
diff --git a/src/ic.cc b/src/ic.cc
index cdb06ac..12332f9 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1639,16 +1639,15 @@
Object* BinaryOp_Patch(Arguments args) {
- ASSERT(args.length() == 6);
+ ASSERT(args.length() == 5);
Handle<Object> left = args.at<Object>(0);
Handle<Object> right = args.at<Object>(1);
- Handle<Object> result = args.at<Object>(2);
- int key = Smi::cast(args[3])->value();
+ int key = Smi::cast(args[2])->value();
+ Token::Value op = static_cast<Token::Value>(Smi::cast(args[3])->value());
#ifdef DEBUG
- Token::Value op = static_cast<Token::Value>(Smi::cast(args[4])->value());
BinaryOpIC::TypeInfo prev_type_info =
- static_cast<BinaryOpIC::TypeInfo>(Smi::cast(args[5])->value());
+ static_cast<BinaryOpIC::TypeInfo>(Smi::cast(args[4])->value());
#endif // DEBUG
{ HandleScope scope;
BinaryOpIC::TypeInfo type_info = BinaryOpIC::GetTypeInfo(*left, *right);
@@ -1667,6 +1666,61 @@
}
}
+ HandleScope scope;
+ Handle<JSBuiltinsObject> builtins = Top::builtins();
+
+ Object* builtin = NULL; // Initialization calms down the compiler.
+
+ switch (op) {
+ case Token::ADD:
+ builtin = builtins->javascript_builtin(Builtins::ADD);
+ break;
+ case Token::SUB:
+ builtin = builtins->javascript_builtin(Builtins::SUB);
+ break;
+ case Token::MUL:
+ builtin = builtins->javascript_builtin(Builtins::MUL);
+ break;
+ case Token::DIV:
+ builtin = builtins->javascript_builtin(Builtins::DIV);
+ break;
+ case Token::MOD:
+ builtin = builtins->javascript_builtin(Builtins::MOD);
+ break;
+ case Token::BIT_AND:
+ builtin = builtins->javascript_builtin(Builtins::BIT_AND);
+ break;
+ case Token::BIT_OR:
+ builtin = builtins->javascript_builtin(Builtins::BIT_OR);
+ break;
+ case Token::BIT_XOR:
+ builtin = builtins->javascript_builtin(Builtins::BIT_XOR);
+ break;
+ case Token::SHR:
+ builtin = builtins->javascript_builtin(Builtins::SHR);
+ break;
+ case Token::SAR:
+ builtin = builtins->javascript_builtin(Builtins::SAR);
+ break;
+ case Token::SHL:
+ builtin = builtins->javascript_builtin(Builtins::SHL);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ Handle<JSFunction> builtin_function(JSFunction::cast(builtin));
+
+ bool caught_exception;
+ Object** builtin_args[] = { right.location() };
+ Handle<Object> result = Execution::Call(builtin_function,
+ left,
+ ARRAY_SIZE(builtin_args),
+ builtin_args,
+ &caught_exception);
+ if (caught_exception) {
+ return Failure::Exception();
+ }
return *result;
}
diff --git a/src/macros.py b/src/macros.py
index 32c9651..b4be15b 100644
--- a/src/macros.py
+++ b/src/macros.py
@@ -146,11 +146,15 @@
macro DAY(time) = ($floor(time / 86400000));
macro MONTH_FROM_TIME(time) = (MonthFromTime(time));
macro DATE_FROM_TIME(time) = (DateFromTime(time));
+macro NAN_OR_DATE_FROM_TIME(time) = (NUMBER_IS_NAN(time) ? time : DATE_FROM_TIME(time));
macro YEAR_FROM_TIME(time) = (YearFromTime(time));
macro HOUR_FROM_TIME(time) = (Modulo($floor(time / 3600000), 24));
macro MIN_FROM_TIME(time) = (Modulo($floor(time / 60000), 60));
+macro NAN_OR_MIN_FROM_TIME(time) = (NUMBER_IS_NAN(time) ? time : MIN_FROM_TIME(time));
macro SEC_FROM_TIME(time) = (Modulo($floor(time / 1000), 60));
+macro NAN_OR_SEC_FROM_TIME(time) = (NUMBER_IS_NAN(time) ? time : SEC_FROM_TIME(time));
macro MS_FROM_TIME(time) = (Modulo(time, 1000));
+macro NAN_OR_MS_FROM_TIME(time) = (NUMBER_IS_NAN(time) ? time : MS_FROM_TIME(time));
# Last input and last subject of regexp matches.
macro LAST_SUBJECT(array) = ((array)[1]);
diff --git a/src/messages.js b/src/messages.js
index 7bac3b2..99ba454 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -197,7 +197,8 @@
obj_ctor_property_non_object: "Object.%0 called on non-object",
array_indexof_not_defined: "Array.getIndexOf: Argument undefined",
object_not_extensible: "Can't add property %0, object is not extensible",
- illegal_access: "illegal access"
+ illegal_access: "Illegal access",
+ invalid_preparser_data: "Invalid preparser data for function %0"
};
}
var format = kMessages[message.type];
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 79f2c97..0e45550 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2807,7 +2807,7 @@
INT_ACCESSORS(Code, instruction_size, kInstructionSizeOffset)
-INT_ACCESSORS(Code, relocation_size, kRelocationSizeOffset)
+ACCESSORS(Code, relocation_info, ByteArray, kRelocationInfoOffset)
INT_ACCESSORS(Code, sinfo_size, kSInfoSizeOffset)
@@ -2816,13 +2816,28 @@
}
+byte* Code::instruction_end() {
+ return instruction_start() + instruction_size();
+}
+
+
int Code::body_size() {
- return RoundUp(instruction_size() + relocation_size(), kObjectAlignment);
+ return RoundUp(instruction_size(), kObjectAlignment);
+}
+
+
+ByteArray* Code::unchecked_relocation_info() {
+ return reinterpret_cast<ByteArray*>(READ_FIELD(this, kRelocationInfoOffset));
}
byte* Code::relocation_start() {
- return FIELD_ADDR(this, kHeaderSize + instruction_size());
+ return unchecked_relocation_info()->GetDataStartAddress();
+}
+
+
+int Code::relocation_size() {
+ return unchecked_relocation_info()->length();
}
diff --git a/src/objects.cc b/src/objects.cc
index 8288f63..e79a550 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -5314,7 +5314,15 @@
RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
- for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
+ // Use the relocation info pointer before it is visited by
+ // the heap compaction in the next statement.
+ RelocIterator it(this, mode_mask);
+
+ IteratePointers(v,
+ kRelocationInfoOffset,
+ kRelocationInfoOffset + kPointerSize);
+
+ for (; !it.done(); it.next()) {
it.rinfo()->Visit(v);
}
@@ -5334,14 +5342,6 @@
// copy code
memmove(instruction_start(), desc.buffer, desc.instr_size);
- // fill gap with zero bytes
- { byte* p = instruction_start() + desc.instr_size;
- byte* q = relocation_start();
- while (p < q) {
- *p++ = 0;
- }
- }
-
// copy reloc info
memmove(relocation_start(),
desc.buffer + desc.buffer_size - desc.reloc_size,
diff --git a/src/objects.h b/src/objects.h
index 15cfd5c..4a7dee6 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -2736,9 +2736,13 @@
inline int instruction_size();
inline void set_instruction_size(int value);
- // [relocation_size]: Size of relocation information.
+ // [relocation_info]: Code relocation information
+ DECL_ACCESSORS(relocation_info, ByteArray)
+
+ // Unchecked accessor to be used during GC.
+ inline ByteArray* unchecked_relocation_info();
+
inline int relocation_size();
- inline void set_relocation_size(int value);
// [sinfo_size]: Size of scope information.
inline int sinfo_size();
@@ -2797,6 +2801,9 @@
// Returns the address of the first instruction.
inline byte* instruction_start();
+ // Returns the address right after the last instruction.
+ inline byte* instruction_end();
+
// Returns the size of the instructions, padding, and relocation information.
inline int body_size();
@@ -2857,8 +2864,8 @@
// Layout description.
static const int kInstructionSizeOffset = HeapObject::kHeaderSize;
- static const int kRelocationSizeOffset = kInstructionSizeOffset + kIntSize;
- static const int kSInfoSizeOffset = kRelocationSizeOffset + kIntSize;
+ static const int kRelocationInfoOffset = kInstructionSizeOffset + kIntSize;
+ static const int kSInfoSizeOffset = kRelocationInfoOffset + kPointerSize;
static const int kFlagsOffset = kSInfoSizeOffset + kIntSize;
static const int kKindSpecificFlagsOffset = kFlagsOffset + kIntSize;
// Add padding to align the instruction start following right after
@@ -4406,6 +4413,8 @@
// Each character in the AsciiString is an ascii character.
class SeqAsciiString: public SeqString {
public:
+ static const bool kHasAsciiEncoding = true;
+
// Dispatched behavior.
inline uint16_t SeqAsciiStringGet(int index);
inline void SeqAsciiStringSet(int index, uint16_t value);
@@ -4455,6 +4464,8 @@
// Each character in the TwoByteString is a two-byte uint16_t.
class SeqTwoByteString: public SeqString {
public:
+ static const bool kHasAsciiEncoding = false;
+
// Dispatched behavior.
inline uint16_t SeqTwoByteStringGet(int index);
inline void SeqTwoByteStringSet(int index, uint16_t value);
@@ -4587,6 +4598,8 @@
// ASCII string.
class ExternalAsciiString: public ExternalString {
public:
+ static const bool kHasAsciiEncoding = true;
+
typedef v8::String::ExternalAsciiStringResource Resource;
// The underlying resource.
@@ -4619,6 +4632,8 @@
// encoded string.
class ExternalTwoByteString: public ExternalString {
public:
+ static const bool kHasAsciiEncoding = false;
+
typedef v8::String::ExternalStringResource Resource;
// The underlying string resource.
diff --git a/src/parser.cc b/src/parser.cc
index 31bac91..fb58cfa 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -134,6 +134,7 @@
// Report syntax error
void ReportUnexpectedToken(Token::Value token);
+ void ReportInvalidPreparseData(Handle<String> name, bool* ok);
Handle<Script> script_;
Scanner scanner_;
@@ -3263,6 +3264,15 @@
}
+void Parser::ReportInvalidPreparseData(Handle<String> name, bool* ok) {
+ SmartPointer<char> name_string = name->ToCString(DISALLOW_NULLS);
+ const char* element[1] = { *name_string };
+ ReportMessage("invalid_preparser_data",
+ Vector<const char*>(element, 1));
+ *ok = false;
+}
+
+
Expression* Parser::ParsePrimaryExpression(bool* ok) {
// PrimaryExpression ::
// 'this'
@@ -3810,7 +3820,14 @@
Handle<FixedArray> this_property_assignments;
if (is_lazily_compiled && pre_data() != NULL) {
FunctionEntry entry = pre_data()->GetFunctionEnd(start_pos);
+ if (!entry.is_valid()) {
+ ReportInvalidPreparseData(name, CHECK_OK);
+ }
int end_pos = entry.end_pos();
+ if (end_pos <= start_pos) {
+ // End position greater than end of stream is safe, and hard to check.
+ ReportInvalidPreparseData(name, CHECK_OK);
+ }
Counters::total_preparse_skipped.Increment(end_pos - start_pos);
scanner_.SeekForward(end_pos);
materialized_literal_count = entry.literal_count();
diff --git a/src/runtime.cc b/src/runtime.cc
index a3eb09f..4a0fe7a 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -2285,6 +2285,134 @@
}
+template <typename ResultSeqString>
+static Object* StringReplaceRegExpWithEmptyString(String* subject,
+ JSRegExp* regexp,
+ JSArray* last_match_info) {
+ ASSERT(subject->IsFlat());
+
+ HandleScope handles;
+
+ Handle<String> subject_handle(subject);
+ Handle<JSRegExp> regexp_handle(regexp);
+ Handle<JSArray> last_match_info_handle(last_match_info);
+ Handle<Object> match = RegExpImpl::Exec(regexp_handle,
+ subject_handle,
+ 0,
+ last_match_info_handle);
+ if (match.is_null()) return Failure::Exception();
+ if (match->IsNull()) return *subject_handle;
+
+ ASSERT(last_match_info_handle->HasFastElements());
+
+ HandleScope loop_scope;
+ int start, end;
+ {
+ AssertNoAllocation match_info_array_is_not_in_a_handle;
+ FixedArray* match_info_array =
+ FixedArray::cast(last_match_info_handle->elements());
+
+ start = RegExpImpl::GetCapture(match_info_array, 0);
+ end = RegExpImpl::GetCapture(match_info_array, 1);
+ }
+
+ int length = subject->length();
+ int new_length = length - (end - start);
+ if (new_length == 0) {
+ return Heap::empty_string();
+ }
+ Handle<ResultSeqString> answer;
+ if (ResultSeqString::kHasAsciiEncoding) {
+ answer =
+ Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
+ } else {
+ answer =
+ Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
+ }
+
+ // If the regexp isn't global, only match once.
+ if (!regexp_handle->GetFlags().is_global()) {
+ if (start > 0) {
+ String::WriteToFlat(*subject_handle,
+ answer->GetChars(),
+ 0,
+ start);
+ }
+ if (end < length) {
+ String::WriteToFlat(*subject_handle,
+ answer->GetChars() + start,
+ end,
+ length);
+ }
+ return *answer;
+ }
+
+ int prev = 0; // Index of end of last match.
+ int next = 0; // Start of next search (prev unless last match was empty).
+ int position = 0;
+
+ do {
+ if (prev < start) {
+ // Add substring subject[prev;start] to answer string.
+ String::WriteToFlat(*subject_handle,
+ answer->GetChars() + position,
+ prev,
+ start);
+ position += start - prev;
+ }
+ prev = end;
+ next = end;
+ // Continue from where the match ended, unless it was an empty match.
+ if (start == end) {
+ next++;
+ if (next > length) break;
+ }
+ match = RegExpImpl::Exec(regexp_handle,
+ subject_handle,
+ next,
+ last_match_info_handle);
+ if (match.is_null()) return Failure::Exception();
+ if (match->IsNull()) break;
+
+ ASSERT(last_match_info_handle->HasFastElements());
+ HandleScope loop_scope;
+ {
+ AssertNoAllocation match_info_array_is_not_in_a_handle;
+ FixedArray* match_info_array =
+ FixedArray::cast(last_match_info_handle->elements());
+ start = RegExpImpl::GetCapture(match_info_array, 0);
+ end = RegExpImpl::GetCapture(match_info_array, 1);
+ }
+ } while (true);
+
+ if (prev < length) {
+ // Add substring subject[prev;length] to answer string.
+ String::WriteToFlat(*subject_handle,
+ answer->GetChars() + position,
+ prev,
+ length);
+ position += length - prev;
+ }
+
+ if (position == 0) {
+ return Heap::empty_string();
+ }
+
+ // Shorten string and fill
+ int string_size = ResultSeqString::SizeFor(position);
+ int allocated_string_size = ResultSeqString::SizeFor(new_length);
+ int delta = allocated_string_size - string_size;
+
+ answer->set_length(position);
+ if (delta == 0) return *answer;
+
+ Address end_of_string = answer->address() + string_size;
+ Heap::CreateFillerObjectAt(end_of_string, delta);
+
+ return *answer;
+}
+
+
static Object* Runtime_StringReplaceRegExpWithString(Arguments args) {
ASSERT(args.length() == 4);
@@ -2311,6 +2439,16 @@
ASSERT(last_match_info->HasFastElements());
+ if (replacement->length() == 0) {
+ if (subject->HasOnlyAsciiChars()) {
+ return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
+ subject, regexp, last_match_info);
+ } else {
+ return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
+ subject, regexp, last_match_info);
+ }
+ }
+
return StringReplaceRegExpWithString(subject,
regexp,
replacement,
@@ -5437,7 +5575,7 @@
CONVERT_DOUBLE_CHECKED(x, args[0]);
CONVERT_DOUBLE_CHECKED(y, args[1]);
- return Heap::AllocateHeapNumber(x + y);
+ return Heap::NumberFromDouble(x + y);
}
@@ -5447,7 +5585,7 @@
CONVERT_DOUBLE_CHECKED(x, args[0]);
CONVERT_DOUBLE_CHECKED(y, args[1]);
- return Heap::AllocateHeapNumber(x - y);
+ return Heap::NumberFromDouble(x - y);
}
@@ -5457,7 +5595,7 @@
CONVERT_DOUBLE_CHECKED(x, args[0]);
CONVERT_DOUBLE_CHECKED(y, args[1]);
- return Heap::AllocateHeapNumber(x * y);
+ return Heap::NumberFromDouble(x * y);
}
@@ -5466,7 +5604,7 @@
ASSERT(args.length() == 1);
CONVERT_DOUBLE_CHECKED(x, args[0]);
- return Heap::AllocateHeapNumber(-x);
+ return Heap::NumberFromDouble(-x);
}
@@ -6068,7 +6206,7 @@
// custom powi() function than the generic pow().
if (args[1]->IsSmi()) {
int y = Smi::cast(args[1])->value();
- return Heap::AllocateHeapNumber(powi(x, y));
+ return Heap::NumberFromDouble(powi(x, y));
}
CONVERT_DOUBLE_CHECKED(y, args[1]);
diff --git a/src/spaces.cc b/src/spaces.cc
index 3c495ba..ca4b66a 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -2305,8 +2305,8 @@
}
ASSERT(code->instruction_start() <= prev_pc &&
- prev_pc <= code->relocation_start());
- delta += static_cast<int>(code->relocation_start() - prev_pc);
+ prev_pc <= code->instruction_end());
+ delta += static_cast<int>(code->instruction_end() - prev_pc);
EnterComment("NoComment", delta);
}
}
diff --git a/src/version.cc b/src/version.cc
index db604e0..d930c8d 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 2
#define MINOR_VERSION 2
-#define BUILD_NUMBER 22
+#define BUILD_NUMBER 23
#define PATCH_LEVEL 0
#define CANDIDATE_VERSION false
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index 3b1aeae..7e04c20 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -3373,9 +3373,12 @@
}
} else {
- bool overwrite =
+ bool can_overwrite =
(node->expression()->AsBinaryOperation() != NULL &&
node->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
+ bool no_negative_zero = node->expression()->no_negative_zero();
Load(node->expression());
switch (op) {
case Token::NOT:
@@ -3385,7 +3388,10 @@
break;
case Token::SUB: {
- GenericUnaryOpStub stub(Token::SUB, overwrite);
+ GenericUnaryOpStub stub(
+ Token::SUB,
+ overwrite,
+ no_negative_zero ? kIgnoreNegativeZero : kStrictNegativeZero);
Result operand = frame_->Pop();
Result answer = frame_->CallStub(&stub, &operand);
answer.set_type_info(TypeInfo::Number());
@@ -8506,6 +8512,11 @@
Label try_float;
__ JumpIfNotSmi(rax, &try_float);
+ if (negative_zero_ == kIgnoreNegativeZero) {
+ __ SmiCompare(rax, Smi::FromInt(0));
+ __ j(equal, &done);
+ }
+
// Enter runtime system if the value of the smi is zero
// to make sure that we switch between 0 and -0.
// Also enter it if the value of the smi is Smi::kMinValue.
@@ -8513,10 +8524,14 @@
// Either zero or Smi::kMinValue, neither of which become a smi when
// negated.
- __ SmiCompare(rax, Smi::FromInt(0));
- __ j(not_equal, &slow);
- __ Move(rax, Factory::minus_zero_value());
- __ jmp(&done);
+ if (negative_zero_ == kStrictNegativeZero) {
+ __ SmiCompare(rax, Smi::FromInt(0));
+ __ j(not_equal, &slow);
+ __ Move(rax, Factory::minus_zero_value());
+ __ jmp(&done);
+ } else {
+ __ jmp(&slow);
+ }
// Try floating point case.
__ bind(&try_float);
@@ -8529,7 +8544,7 @@
__ shl(kScratchRegister, Immediate(63));
__ xor_(rdx, kScratchRegister); // Flip sign.
// rdx is value to store.
- if (overwrite_) {
+ if (overwrite_ == UNARY_OVERWRITE) {
__ movq(FieldOperand(rax, HeapNumber::kValueOffset), rdx);
} else {
__ AllocateHeapNumber(rcx, rbx, &slow);
@@ -10596,6 +10611,7 @@
// the four basic operations. The stub stays in the DEFAULT state
// forever for all other operations (also if smi code is skipped).
GenerateTypeTransition(masm);
+ break;
}
Label not_floats;
@@ -10913,31 +10929,13 @@
void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
Label get_result;
- // Keep a copy of operands on the stack and make sure they are also in
- // rdx, rax.
+ // Ensure the operands are on the stack.
if (HasArgsInRegisters()) {
GenerateRegisterArgsPush(masm);
- } else {
- GenerateLoadArguments(masm);
}
- // Internal frame is necessary to handle exceptions properly.
- __ EnterInternalFrame();
-
- // Push arguments on stack if the stub expects them there.
- if (!HasArgsInRegisters()) {
- __ push(rdx);
- __ push(rax);
- }
- // Call the stub proper to get the result in rax.
- __ call(&get_result);
- __ LeaveInternalFrame();
-
// Left and right arguments are already on stack.
- __ pop(rcx);
- // Push the operation result. The tail call to BinaryOp_Patch will
- // return it to the original caller..
- __ push(rax);
+ __ pop(rcx); // Save the return address.
// Push this stub's key.
__ Push(Smi::FromInt(MinorKey()));
@@ -10948,17 +10946,13 @@
__ Push(Smi::FromInt(runtime_operands_type_));
- __ push(rcx);
+ __ push(rcx); // The return address.
// Perform patching to an appropriate fast case and return the result.
__ TailCallExternalReference(
ExternalReference(IC_Utility(IC::kBinaryOp_Patch)),
- 6,
+ 5,
1);
-
- // The entry point for the result calculation is assumed to be immediately
- // after this sequence.
- __ bind(&get_result);
}
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index e3f74f6..c6be503 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -2807,9 +2807,11 @@
case Token::SUB: {
Comment cmt(masm_, "[ UnaryOperation (SUB)");
- bool overwrite =
+ bool can_overwrite =
(expr->expression()->AsBinaryOperation() != NULL &&
expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::SUB, overwrite);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register rax.
@@ -2821,9 +2823,11 @@
case Token::BIT_NOT: {
Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
- bool overwrite =
+ bool can_overwrite =
(expr->expression()->AsBinaryOperation() != NULL &&
expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ UnaryOverwriteMode overwrite =
+ can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
// GenericUnaryOpStub expects the argument to be in the
// accumulator register rax.