Revision: 5026
Author: [email protected]
Date: Tue Jul 6 05:56:55 2010
Log: Simplify the transitions in the Binary Op ICs. Now a single call
to the runtime will both patch in the more specialized binary op
stub and calculate the answer. This eliminates the need to call
both the rest of the binary op and the patching runtime call. The
runtime routines are altered to be more agressive in returning
Smis so we don't get spurious heap numbers as inputs to binary ops
while we are patching the binary op ICs.
Review URL: http://codereview.chromium.org/2843049
http://code.google.com/p/v8/source/detail?r=5026
Added:
/branches/bleeding_edge/test/mjsunit/value-of.js
Modified:
/branches/bleeding_edge/src/arm/codegen-arm.cc
/branches/bleeding_edge/src/ia32/codegen-ia32.cc
/branches/bleeding_edge/src/ic.cc
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/x64/codegen-x64.cc
/branches/bleeding_edge/test/mjsunit/math-min-max.js
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/value-of.js Tue Jul 6 05:56:55
2010
@@ -0,0 +1,33 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+function MyException() { }
+
+var o = new Object();
+o.valueOf = function() { throw new MyException(); }
+
+assertThrows(function() { o + 1 }, MyException);
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc Mon Jul 5 04:03:16 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc Tue Jul 6 05:56:55 2010
@@ -7647,9 +7647,11 @@
if (lhs.is(r0)) {
__ Swap(r0, r1, ip);
}
+
+ // The type transition also calculates the answer.
+ bool generate_code_to_calculate_answer = true;
if (ShouldGenerateFPCode()) {
- Label r0_is_smi, r1_is_smi, finished_loading_r0, finished_loading_r1;
if (runtime_operands_type_ == BinaryOpIC::DEFAULT) {
switch (op_) {
@@ -7657,179 +7659,186 @@
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);
- }
- } 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);
- }
- } 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);
+ 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);
+ }
+
+ // 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);
+ }
+ } 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);
}
- __ 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 (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 {
- 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 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)) {
__ b(&slow);
@@ -8752,29 +8761,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);
}
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Mon Jul 5 04:03:16
2010
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Tue Jul 6 05:56:55
2010
@@ -9866,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;
@@ -10213,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();
-
- // 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.
+ __ pop(ecx); // Save 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.
-
- // Patch the caller to an appropriate specialized stub
- // and return the operation result.
+ __ push(ecx); // Push return address.
+
+ // 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);
}
=======================================
--- /branches/bleeding_edge/src/ic.cc Fri Jul 2 07:15:04 2010
+++ /branches/bleeding_edge/src/ic.cc Tue Jul 6 05:56:55 2010
@@ -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;
}
=======================================
--- /branches/bleeding_edge/src/runtime.cc Tue Jul 6 05:22:19 2010
+++ /branches/bleeding_edge/src/runtime.cc Tue Jul 6 05:56:55 2010
@@ -5575,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);
}
@@ -5585,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);
}
@@ -5595,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);
}
@@ -5604,7 +5604,7 @@
ASSERT(args.length() == 1);
CONVERT_DOUBLE_CHECKED(x, args[0]);
- return Heap::AllocateHeapNumber(-x);
+ return Heap::NumberFromDouble(-x);
}
@@ -6206,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]);
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc Mon Jul 5 04:03:16 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc Tue Jul 6 05:56:55 2010
@@ -10611,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;
@@ -10928,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()));
@@ -10963,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);
}
=======================================
--- /branches/bleeding_edge/test/mjsunit/math-min-max.js Tue Dec 8
02:18:28 2009
+++ /branches/bleeding_edge/test/mjsunit/math-min-max.js Tue Jul 6
05:56:55 2010
@@ -42,7 +42,16 @@
// Prepare a non-Smi zero value.
function returnsNonSmi(){ return 0.25; }
-var ZERO = returnsNonSmi() - returnsNonSmi();
+var ZERO = (function() {
+ var z;
+ // We have to have a loop here because the first time we get a Smi from
the
+ // runtime system. After a while the binary op IC settles down and we
get
+ // a non-Smi from the generated code.
+ for (var i = 0; i < 10; i++) {
+ z = returnsNonSmi() - returnsNonSmi();
+ }
+ return z;
+})();
assertEquals(0, ZERO);
assertEquals(Infinity, 1/ZERO);
assertEquals(-Infinity, 1/-ZERO);
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev