void DeferredCode::Jump() { __ jmp(&entry_label_); }
void DeferredCode::Branch(Condition cc) { __ b(cc, &entry_label_); }
+void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
+ GenerateFastMathOp(SIN, args);
+}
+
+
+void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
+ GenerateFastMathOp(COS, args);
+}
+
+
#undef __
} } // namespace v8::internal
}
+void CodeGenerator::GenerateFastMathOp(MathOp op, ZoneList<Expression*>* args) {
+ VirtualFrame::SpilledScope spilled_scope;
+ Load(args->at(0));
+ switch (op) {
+ case SIN:
+ __ CallRuntime(Runtime::kMath_sin, 1);
+ break;
+ case COS:
+ __ CallRuntime(Runtime::kMath_cos, 1);
+ break;
+ }
+ frame_->EmitPush(r0);
+}
+
+
void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
VirtualFrame::SpilledScope spilled_scope;
ASSERT(args->length() == 2);
// Fast support for Math.random().
void GenerateRandomPositiveSmi(ZoneList<Expression*>* args);
+ // Fast support for Math.sin and Math.cos.
+ enum MathOp { SIN, COS };
+ void GenerateFastMathOp(MathOp op, ZoneList<Expression*>* args);
+ inline void GenerateMathSin(ZoneList<Expression*>* args);
+ inline void GenerateMathCos(ZoneList<Expression*>* args);
+
// Methods and constants for fast case switch statement support.
//
// Only allow fast-case switch if the range of labels is at most
{&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"},
{&CodeGenerator::GenerateObjectEquals, "_ObjectEquals"},
{&CodeGenerator::GenerateLog, "_Log"},
- {&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"}
+ {&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"},
+ {&CodeGenerator::GenerateMathSin, "_Math_sin"},
+ {&CodeGenerator::GenerateMathCos, "_Math_cos"}
};
}
+void Assembler::fcos() {
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ EMIT(0xD9);
+ EMIT(0xFF);
+}
+
+
+void Assembler::fsin() {
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ EMIT(0xD9);
+ EMIT(0xFE);
+}
+
+
void Assembler::fadd(int i) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
void fabs();
void fchs();
+ void fcos();
+ void fsin();
void fadd(int i);
void fsub(int i);
void DeferredCode::Jump() { __ jmp(&entry_label_); }
void DeferredCode::Branch(Condition cc) { __ j(cc, &entry_label_); }
+void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
+ GenerateFastMathOp(SIN, args);
+}
+
+
+void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
+ GenerateFastMathOp(COS, args);
+}
+
+
#undef __
} } // namespace v8::internal
class FloatingPointHelper : public AllStatic {
public:
+ // Code pattern for loading a floating point value. Input value must
+ // be either a smi or a heap number object (fp value). Requirements:
+ // operand on TOS+1. Returns operand as floating point number on FPU
+ // stack.
+ static void LoadFloatOperand(MacroAssembler* masm, Register scratch);
// Code pattern for loading floating point values. Input values must
// be either smi or heap number objects (fp values). Requirements:
// operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as
static void AllocateHeapNumber(MacroAssembler* masm,
Label* need_gc,
Register scratch1,
- Register scratch2);
+ Register scratch2,
+ Register result);
};
}
+void CodeGenerator::GenerateFastMathOp(MathOp op, ZoneList<Expression*>* args) {
+ JumpTarget done;
+ JumpTarget call_runtime;
+ ASSERT(args->length() == 1);
+
+ // Load number and duplicate it.
+ Load(args->at(0));
+ frame_->Dup();
+
+ // Get the number into an unaliased register and load it onto the
+ // floating point stack still leaving one copy on the frame.
+ Result number = frame_->Pop();
+ number.ToRegister();
+ frame_->Spill(number.reg());
+ FloatingPointHelper::LoadFloatOperand(masm_, number.reg());
+ number.Unuse();
+
+ // Perform the operation on the number.
+ switch (op) {
+ case SIN:
+ __ fsin();
+ break;
+ case COS:
+ __ fcos();
+ break;
+ }
+
+ // Go slow case if argument to operation is out of range.
+ __ fnstsw_ax();
+ __ sahf();
+ call_runtime.Branch(parity_even, not_taken);
+
+ // Allocate heap number for result if possible.
+ Result scratch1 = allocator()->Allocate();
+ Result scratch2 = allocator()->Allocate();
+ Result heap_number = allocator()->Allocate();
+ FloatingPointHelper::AllocateHeapNumber(masm_,
+ call_runtime.entry_label(),
+ scratch1.reg(),
+ scratch2.reg(),
+ heap_number.reg());
+ scratch1.Unuse();
+ scratch2.Unuse();
+
+ // Store the result in the allocated heap number.
+ __ fstp_d(FieldOperand(heap_number.reg(), HeapNumber::kValueOffset));
+ // Pop the extra copy of the argument.
+ frame_->Pop();
+ // Push the result on the frame.
+ frame_->Push(&heap_number);
+ heap_number.Unuse();
+ done.Jump();
+
+ call_runtime.Bind();
+ // Free ST(0) which was not popped before calling into the runtime.
+ __ ffree(0);
+ Result answer;
+ switch (op) {
+ case SIN:
+ answer = frame_->CallRuntime(Runtime::kMath_sin, 1);
+ break;
+ case COS:
+ answer = frame_->CallRuntime(Runtime::kMath_cos, 1);
+ break;
+ }
+ frame_->Push(&answer);
+ done.Bind();
+}
+
+
void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
if (CheckForInlineRuntimeCall(node)) {
return;
FloatingPointHelper::AllocateHeapNumber(masm,
&call_runtime,
ecx,
- edx);
+ edx,
+ eax);
__ bind(&skip_allocation);
break;
default: UNREACHABLE();
// Fall through!
case NO_OVERWRITE:
FloatingPointHelper::AllocateHeapNumber(masm, &call_runtime,
- ecx, edx);
+ ecx, edx, eax);
__ bind(&skip_allocation);
break;
default: UNREACHABLE();
void FloatingPointHelper::AllocateHeapNumber(MacroAssembler* masm,
Label* need_gc,
Register scratch1,
- Register scratch2) {
+ Register scratch2,
+ Register result) {
ExternalReference allocation_top =
ExternalReference::new_space_allocation_top_address();
ExternalReference allocation_limit =
ExternalReference::new_space_allocation_limit_address();
__ mov(Operand(scratch1), Immediate(allocation_top));
- __ mov(eax, Operand(scratch1, 0));
- __ lea(scratch2, Operand(eax, HeapNumber::kSize)); // scratch2: new top
+ __ mov(result, Operand(scratch1, 0));
+ __ lea(scratch2, Operand(result, HeapNumber::kSize)); // scratch2: new top
__ cmp(scratch2, Operand::StaticVariable(allocation_limit));
__ j(above, need_gc, not_taken);
__ mov(Operand(scratch1, 0), scratch2); // store new top
- __ mov(Operand(eax, HeapObject::kMapOffset),
+ __ mov(Operand(result, HeapObject::kMapOffset),
Immediate(Factory::heap_number_map()));
// Tag old top and use as result.
- __ add(Operand(eax), Immediate(kHeapObjectTag));
+ __ add(Operand(result), Immediate(kHeapObjectTag));
+}
+
+
+void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
+ Register scratch) {
+ Label load_smi, done;
+
+ __ test(scratch, Immediate(kSmiTagMask));
+ __ j(zero, &load_smi, not_taken);
+ __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset));
+ __ jmp(&done);
+
+ __ bind(&load_smi);
+ __ sar(scratch, kSmiTagSize);
+ __ push(scratch);
+ __ fild_s(Operand(esp, 0));
+ __ pop(scratch);
+
+ __ bind(&done);
}
} else {
__ mov(edx, Operand(eax));
// edx: operand
- FloatingPointHelper::AllocateHeapNumber(masm, &undo, ebx, ecx);
+ FloatingPointHelper::AllocateHeapNumber(masm, &undo, ebx, ecx, eax);
// eax: allocated 'empty' number
__ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset));
__ xor_(ecx, HeapNumber::kSignMask); // Flip sign.
// Fast support for Math.random().
void GenerateRandomPositiveSmi(ZoneList<Expression*>* args);
+ // Fast support for Math.sin and Math.cos.
+ enum MathOp { SIN, COS };
+ void GenerateFastMathOp(MathOp op, ZoneList<Expression*>* args);
+ inline void GenerateMathSin(ZoneList<Expression*>* args);
+ inline void GenerateMathCos(ZoneList<Expression*>* args);
+
// Methods and constants for fast case switch statement support.
//
// Only allow fast-case switch if the range of labels is at most
// ECMA 262 - 15.8.2.7
function MathCos(x) {
if (!IS_NUMBER(x)) x = ToNumber(x);
- return %Math_cos(x);
+ return %_Math_cos(x);
}
// ECMA 262 - 15.8.2.8
// ECMA 262 - 15.8.2.16
function MathSin(x) {
if (!IS_NUMBER(x)) x = ToNumber(x);
- return %Math_sin(x);
+ return %_Math_sin(x);
}
// ECMA 262 - 15.8.2.17
void DeferredCode::Jump() { UNIMPLEMENTED(); }
void DeferredCode::Branch(Condition cc) { UNIMPLEMENTED(); }
+
+void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
+ GenerateFastMathOp(SIN, args);
+}
+
+
+void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
+ GenerateFastMathOp(COS, args);
+}
+
+
} } // namespace v8::internal
#endif // V8_X64_CODEGEN_X64_INL_H_
UNIMPLEMENTED();
}
+void CodeGenerator::GenerateFastMathOp(MathOp op, ZoneList<Expression*>* args) {
+ UNIMPLEMENTED();
+}
+
void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
// Fast support for Math.random().
void GenerateRandomPositiveSmi(ZoneList<Expression*>* args);
+ // Fast support for Math.sin and Math.cos.
+ enum MathOp { SIN, COS };
+ void GenerateFastMathOp(MathOp op, ZoneList<Expression*>* args);
+ inline void GenerateMathSin(ZoneList<Expression*>* args);
+ inline void GenerateMathCos(ZoneList<Expression*>* args);
+
// Methods and constants for fast case switch statement support.
//
// Only allow fast-case switch if the range of labels is at most
--- /dev/null
+// Copyright 2009 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.
+
+// Test Math.sin and Math.cos.
+
+var input_sin = [0, Math.PI, Math.PI / 6, Math.PI / 2, Math.pow(2, 70)];
+var input_cos = [0, Math.PI, Math.PI / 6, Math.PI / 2, Math.pow(2, 70)];
+
+var output_sin = input_sin.map(Math.sin);
+var output_cos = input_sin.map(Math.cos);
+
+var expected_sin = [0,
+ 1.2246063538223773e-16,
+ 0.49999999999999994,
+ 1,
+ -0.9983193022079332];
+
+var expected_cos = [1,
+ -1,
+ 0.8660254037844387,
+ 6.123031769111886e-17,
+ 0.05795317798935058];
+
+assertArrayEquals(expected_sin, output_sin, "sine");
+assertArrayEquals(expected_cos, output_cos, "cosine");