Commit 3135110a authored by lrn@chromium.org's avatar lrn@chromium.org

IA32: Native access to TranscendentalCache for sin/cos.

Review URL: http://codereview.chromium.org/652041

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3929 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 2883c030
...@@ -3628,6 +3628,24 @@ void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) { ...@@ -3628,6 +3628,24 @@ void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
} }
void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 1);
// Load the argument on the stack and jump to the runtime.
Load(args->at(0));
frame_->CallRuntime(Runtime::kMath_sin, 1);
frame_->EmitPush(r0);
}
void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 1);
// Load the argument on the stack and jump to the runtime.
Load(args->at(0));
frame_->CallRuntime(Runtime::kMath_cos, 1);
frame_->EmitPush(r0);
}
void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
VirtualFrame::SpilledScope spilled_scope; VirtualFrame::SpilledScope spilled_scope;
ASSERT(args->length() == 2); ASSERT(args->length() == 2);
......
...@@ -393,6 +393,10 @@ class CodeGenerator: public AstVisitor { ...@@ -393,6 +393,10 @@ class CodeGenerator: public AstVisitor {
// Fast support for number to string. // Fast support for number to string.
void GenerateNumberToString(ZoneList<Expression*>* args); void GenerateNumberToString(ZoneList<Expression*>* args);
// Fast call to sine function.
void GenerateMathSin(ZoneList<Expression*>* args);
void GenerateMathCos(ZoneList<Expression*>* args);
// Simple condition analysis. // Simple condition analysis.
enum ConditionAnalysis { enum ConditionAnalysis {
ALWAYS_TRUE, ALWAYS_TRUE,
......
...@@ -579,6 +579,11 @@ ExternalReference ExternalReference::random_positive_smi_function() { ...@@ -579,6 +579,11 @@ ExternalReference ExternalReference::random_positive_smi_function() {
} }
ExternalReference ExternalReference::transcendental_cache_array_address() {
return ExternalReference(TranscendentalCache::cache_array_address());
}
ExternalReference ExternalReference::keyed_lookup_cache_keys() { ExternalReference ExternalReference::keyed_lookup_cache_keys() {
return ExternalReference(KeyedLookupCache::keys_address()); return ExternalReference(KeyedLookupCache::keys_address());
} }
......
...@@ -400,6 +400,7 @@ class ExternalReference BASE_EMBEDDED { ...@@ -400,6 +400,7 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference perform_gc_function(); static ExternalReference perform_gc_function();
static ExternalReference random_positive_smi_function(); static ExternalReference random_positive_smi_function();
static ExternalReference transcendental_cache_array_address();
// Static data in the keyed lookup cache. // Static data in the keyed lookup cache.
static ExternalReference keyed_lookup_cache_keys(); static ExternalReference keyed_lookup_cache_keys();
......
...@@ -48,6 +48,7 @@ namespace internal { ...@@ -48,6 +48,7 @@ namespace internal {
V(FastNewClosure) \ V(FastNewClosure) \
V(FastNewContext) \ V(FastNewContext) \
V(FastCloneShallowArray) \ V(FastCloneShallowArray) \
V(TranscendentalCache) \
V(GenericUnaryOp) \ V(GenericUnaryOp) \
V(RevertToNumber) \ V(RevertToNumber) \
V(ToBoolean) \ V(ToBoolean) \
......
...@@ -379,6 +379,8 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = { ...@@ -379,6 +379,8 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
{&CodeGenerator::GenerateStringCompare, "_StringCompare"}, {&CodeGenerator::GenerateStringCompare, "_StringCompare"},
{&CodeGenerator::GenerateRegExpExec, "_RegExpExec"}, {&CodeGenerator::GenerateRegExpExec, "_RegExpExec"},
{&CodeGenerator::GenerateNumberToString, "_NumberToString"}, {&CodeGenerator::GenerateNumberToString, "_NumberToString"},
{&CodeGenerator::GenerateMathSin, "_Math_sin"},
{&CodeGenerator::GenerateMathCos, "_Math_cos"},
}; };
......
...@@ -1610,6 +1610,7 @@ class TranscendentalCache { ...@@ -1610,6 +1610,7 @@ class TranscendentalCache {
if (e.in[0] == c.integers[0] && if (e.in[0] == c.integers[0] &&
e.in[1] == c.integers[1]) { e.in[1] == c.integers[1]) {
ASSERT(e.output != NULL); ASSERT(e.output != NULL);
Counters::transcendental_cache_hit.Increment();
return e.output; return e.output;
} }
double answer = Calculate(input); double answer = Calculate(input);
...@@ -1619,6 +1620,7 @@ class TranscendentalCache { ...@@ -1619,6 +1620,7 @@ class TranscendentalCache {
elements_[hash].in[1] = c.integers[1]; elements_[hash].in[1] = c.integers[1];
elements_[hash].output = heap_number; elements_[hash].output = heap_number;
} }
Counters::transcendental_cache_miss.Increment();
return heap_number; return heap_number;
} }
...@@ -1659,6 +1661,17 @@ class TranscendentalCache { ...@@ -1659,6 +1661,17 @@ class TranscendentalCache {
hash ^= hash >> 8; hash ^= hash >> 8;
return (hash & (kCacheSize - 1)); return (hash & (kCacheSize - 1));
} }
static Address cache_array_address() {
// Used to create an external reference.
return reinterpret_cast<Address>(caches_);
}
// Allow access to the caches_ array as an ExternalReference.
friend class ExternalReference;
// Inline implementation of the caching.
friend class TranscendentalCacheStub;
static TranscendentalCache* caches_[kNumberOfCaches]; static TranscendentalCache* caches_[kNumberOfCaches];
Element elements_[kCacheSize]; Element elements_[kCacheSize];
Type type_; Type type_;
......
...@@ -1637,6 +1637,13 @@ void Assembler::fld(int i) { ...@@ -1637,6 +1637,13 @@ void Assembler::fld(int i) {
} }
void Assembler::fstp(int i) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit_farith(0xDD, 0xD8, i);
}
void Assembler::fld1() { void Assembler::fld1() {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
last_pc_ = pc_; last_pc_ = pc_;
...@@ -1645,6 +1652,14 @@ void Assembler::fld1() { ...@@ -1645,6 +1652,14 @@ void Assembler::fld1() {
} }
void Assembler::fldpi() {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xD9);
EMIT(0xEB);
}
void Assembler::fldz() { void Assembler::fldz() {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
last_pc_ = pc_; last_pc_ = pc_;
...@@ -1685,6 +1700,14 @@ void Assembler::fstp_d(const Operand& adr) { ...@@ -1685,6 +1700,14 @@ void Assembler::fstp_d(const Operand& adr) {
} }
void Assembler::fst_d(const Operand& adr) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xDD);
emit_operand(edx, adr);
}
void Assembler::fild_s(const Operand& adr) { void Assembler::fild_s(const Operand& adr) {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
last_pc_ = pc_; last_pc_ = pc_;
......
...@@ -668,6 +668,7 @@ class Assembler : public Malloced { ...@@ -668,6 +668,7 @@ class Assembler : public Malloced {
void call(Label* L); void call(Label* L);
void call(byte* entry, RelocInfo::Mode rmode); void call(byte* entry, RelocInfo::Mode rmode);
void call(const Operand& adr); void call(const Operand& adr);
void call(const ExternalReference& target);
void call(Handle<Code> code, RelocInfo::Mode rmode); void call(Handle<Code> code, RelocInfo::Mode rmode);
// Jumps // Jumps
...@@ -683,15 +684,18 @@ class Assembler : public Malloced { ...@@ -683,15 +684,18 @@ class Assembler : public Malloced {
// Floating-point operations // Floating-point operations
void fld(int i); void fld(int i);
void fstp(int i);
void fld1(); void fld1();
void fldz(); void fldz();
void fldpi();
void fld_s(const Operand& adr); void fld_s(const Operand& adr);
void fld_d(const Operand& adr); void fld_d(const Operand& adr);
void fstp_s(const Operand& adr); void fstp_s(const Operand& adr);
void fstp_d(const Operand& adr); void fstp_d(const Operand& adr);
void fst_d(const Operand& adr);
void fild_s(const Operand& adr); void fild_s(const Operand& adr);
void fild_d(const Operand& adr); void fild_d(const Operand& adr);
......
...@@ -5825,6 +5825,24 @@ void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) { ...@@ -5825,6 +5825,24 @@ void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
} }
void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 1);
Load(args->at(0));
TranscendentalCacheStub stub(TranscendentalCache::SIN);
Result result = frame_->CallStub(&stub, 1);
frame_->Push(&result);
}
void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 1);
Load(args->at(0));
TranscendentalCacheStub stub(TranscendentalCache::COS);
Result result = frame_->CallStub(&stub, 1);
frame_->Push(&result);
}
void CodeGenerator::VisitCallRuntime(CallRuntime* node) { void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
if (CheckForInlineRuntimeCall(node)) { if (CheckForInlineRuntimeCall(node)) {
return; return;
...@@ -8123,6 +8141,212 @@ void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) { ...@@ -8123,6 +8141,212 @@ void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) {
} }
void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
// Input on stack:
// esp[4]: argument (should be number).
// esp[0]: return address.
// Test that eax is a number.
Label runtime_call;
Label runtime_call_clear_stack;
Label input_not_smi;
Label loaded;
__ mov(eax, Operand(esp, kPointerSize));
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, &input_not_smi);
// Input is a smi. Untag and load it onto the FPU stack.
// Then load the low and high words of the double into ebx, edx.
ASSERT_EQ(1, kSmiTagSize);
__ sar(eax, 1);
__ sub(Operand(esp), Immediate(2 * kPointerSize));
__ mov(Operand(esp, 0), eax);
__ fild_s(Operand(esp, 0));
__ fst_d(Operand(esp, 0));
__ pop(edx);
__ pop(ebx);
__ jmp(&loaded);
__ bind(&input_not_smi);
// Check if input is a HeapNumber.
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
__ cmp(Operand(ebx), Immediate(Factory::heap_number_map()));
__ j(not_equal, &runtime_call);
// Input is a HeapNumber. Push it on the FPU stack and load its
// low and high words into ebx, edx.
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset));
__ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset));
__ bind(&loaded);
// ST[0] == double value
// ebx = low 32 bits of double value
// edx = high 32 bits of double value
// Compute hash:
// h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
__ mov(ecx, ebx);
__ xor_(ecx, Operand(edx));
__ mov(eax, ecx);
__ sar(eax, 16);
__ xor_(ecx, Operand(eax));
__ mov(eax, ecx);
__ sar(eax, 8);
__ xor_(ecx, Operand(eax));
ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize));
__ and_(Operand(ecx), Immediate(TranscendentalCache::kCacheSize - 1));
// ST[0] == double value.
// ebx = low 32 bits of double value.
// edx = high 32 bits of double value.
// ecx = TranscendentalCache::hash(double value).
__ mov(eax,
Immediate(ExternalReference::transcendental_cache_array_address()));
// Eax points to cache array.
__ mov(eax, Operand(eax, type_ * sizeof(TranscendentalCache::caches_[0])));
// Eax points to the cache for the type type_.
// If NULL, the cache hasn't been initialized yet, so go through runtime.
__ test(eax, Operand(eax));
__ j(zero, &runtime_call_clear_stack);
#ifdef DEBUG
// Check that the layout of cache elements match expectations.
{ // NOLINT - doesn't like a single brace on a line.
TranscendentalCache::Element test_elem[2];
char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
CHECK_EQ(0, elem_in0 - elem_start);
CHECK_EQ(kIntSize, elem_in1 - elem_start);
CHECK_EQ(2 * kIntSize, elem_out - elem_start);
}
#endif
// Find the address of the ecx'th entry in the cache, i.e., &eax[ecx*12].
__ lea(ecx, Operand(ecx, ecx, times_2, 0));
__ lea(ecx, Operand(eax, ecx, times_4, 0));
// Check if cache matches: Double value is stored in uint32_t[2] array.
Label cache_miss;
__ cmp(ebx, Operand(ecx, 0));
__ j(not_equal, &cache_miss);
__ cmp(edx, Operand(ecx, kIntSize));
__ j(not_equal, &cache_miss);
// Cache hit!
__ mov(eax, Operand(ecx, 2 * kIntSize));
__ fstp(0);
__ ret(kPointerSize);
__ bind(&cache_miss);
// Update cache with new value.
// We are short on registers, so use no_reg as scratch.
// This gives slightly larger code.
__ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack);
GenerateOperation(masm);
__ mov(Operand(ecx, 0), ebx);
__ mov(Operand(ecx, kIntSize), edx);
__ mov(Operand(ecx, 2 * kIntSize), eax);
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ ret(kPointerSize);
__ bind(&runtime_call_clear_stack);
__ fstp(0);
__ bind(&runtime_call);
__ TailCallRuntime(ExternalReference(RuntimeFunction()), 1, 1);
}
Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
switch (type_) {
// Add more cases when necessary.
case TranscendentalCache::SIN: return Runtime::kMath_sin;
case TranscendentalCache::COS: return Runtime::kMath_cos;
default:
UNIMPLEMENTED();
return Runtime::kAbort;
}
}
void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
// Only free register is edi.
Label done;
ASSERT(type_ == TranscendentalCache::SIN ||
type_ == TranscendentalCache::COS);
// More transcendental types can be added later.
// Both fsin and fcos require arguments in the range +/-2^63 and
// return NaN for infinities and NaN. They can share all code except
// the actual fsin/fcos operation.
Label in_range;
// If argument is outside the range -2^63..2^63, fsin/cos doesn't
// work. We must reduce it to the appropriate range.
__ mov(edi, edx);
__ and_(Operand(edi), Immediate(0x7ff00000)); // Exponent only.
int supported_exponent_limit =
(63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift;
__ cmp(Operand(edi), Immediate(supported_exponent_limit));
__ j(below, &in_range, taken);
// Check for infinity and NaN. Both return NaN for sin.
__ cmp(Operand(edi), Immediate(0x7ff00000));
Label non_nan_result;
__ j(not_equal, &non_nan_result, taken);
// Input is +/-Infinity or NaN. Result is NaN.
__ fstp(0);
// NaN is represented by 0x7ff8000000000000.
__ push(Immediate(0x7ff80000));
__ push(Immediate(0));
__ fld_d(Operand(esp, 0));
__ add(Operand(esp), Immediate(2 * kPointerSize));
__ jmp(&done);
__ bind(&non_nan_result);
// Use fpmod to restrict argument to the range +/-2*PI.
__ mov(edi, eax); // Save eax before using fnstsw_ax.
__ fldpi();
__ fadd(0);
__ fld(1);
// FPU Stack: input, 2*pi, input.
{
Label no_exceptions;
__ fwait();
__ fnstsw_ax();
// Clear if Illegal Operand or Zero Division exceptions are set.
__ test(Operand(eax), Immediate(5));
__ j(zero, &no_exceptions);
__ fnclex();
__ bind(&no_exceptions);
}
// Compute st(0) % st(1)
{
Label partial_remainder_loop;
__ bind(&partial_remainder_loop);
__ fprem1();
__ fwait();
__ fnstsw_ax();
__ test(Operand(eax), Immediate(0x400 /* C2 */));
// If C2 is set, computation only has partial result. Loop to
// continue computation.
__ j(not_zero, &partial_remainder_loop);
}
// FPU Stack: input, 2*pi, input % 2*pi
__ fstp(2);
__ fstp(0);
__ mov(eax, edi); // Restore eax (allocated HeapNumber pointer).
// FPU Stack: input % 2*pi
__ bind(&in_range);
switch (type_) {
case TranscendentalCache::SIN:
__ fsin();
break;
case TranscendentalCache::COS:
__ fcos();
break;
default:
UNREACHABLE();
}
__ bind(&done);
}
// Get the integer part of a heap number. Surprisingly, all this bit twiddling // Get the integer part of a heap number. Surprisingly, all this bit twiddling
// is faster than using the built-in instructions on floating point registers. // is faster than using the built-in instructions on floating point registers.
// Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the
......
...@@ -588,6 +588,10 @@ class CodeGenerator: public AstVisitor { ...@@ -588,6 +588,10 @@ class CodeGenerator: public AstVisitor {
// Fast support for number to string. // Fast support for number to string.
void GenerateNumberToString(ZoneList<Expression*>* args); void GenerateNumberToString(ZoneList<Expression*>* args);
// Fast call to transcendental functions.
void GenerateMathSin(ZoneList<Expression*>* args);
void GenerateMathCos(ZoneList<Expression*>* args);
// Simple condition analysis. // Simple condition analysis.
enum ConditionAnalysis { enum ConditionAnalysis {
ALWAYS_TRUE, ALWAYS_TRUE,
...@@ -655,6 +659,22 @@ class CodeGenerator: public AstVisitor { ...@@ -655,6 +659,22 @@ class CodeGenerator: public AstVisitor {
}; };
// Compute a transcendental math function natively, or call the
// TranscendentalCache runtime function.
class TranscendentalCacheStub: public CodeStub {
public:
explicit TranscendentalCacheStub(TranscendentalCache::Type type)
: type_(type) {}
void Generate(MacroAssembler* masm);
private:
TranscendentalCache::Type type_;
Major MajorKey() { return TranscendentalCache; }
int MinorKey() { return type_; }
Runtime::FunctionId RuntimeFunction();
void GenerateOperation(MacroAssembler* masm);
};
// Flag that indicates how to generate code for the stub GenericBinaryOpStub. // Flag that indicates how to generate code for the stub GenericBinaryOpStub.
enum GenericBinaryFlags { enum GenericBinaryFlags {
NO_GENERIC_BINARY_FLAGS = 0, NO_GENERIC_BINARY_FLAGS = 0,
......
...@@ -679,6 +679,7 @@ int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode, ...@@ -679,6 +679,7 @@ int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
case 0xDD: switch (regop) { case 0xDD: switch (regop) {
case 0: mnem = "fld_d"; break; case 0: mnem = "fld_d"; break;
case 2: mnem = "fstp"; break;
case 3: mnem = "fstp_d"; break; case 3: mnem = "fstp_d"; break;
default: UnimplementedInstruction(); default: UnimplementedInstruction();
} }
...@@ -720,6 +721,7 @@ int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode, ...@@ -720,6 +721,7 @@ int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
case 0xE1: mnem = "fabs"; break; case 0xE1: mnem = "fabs"; break;
case 0xE4: mnem = "ftst"; break; case 0xE4: mnem = "ftst"; break;
case 0xE8: mnem = "fld1"; break; case 0xE8: mnem = "fld1"; break;
case 0xEB: mnem = "fldpi"; break;
case 0xEE: mnem = "fldz"; break; case 0xEE: mnem = "fldz"; break;
case 0xF5: mnem = "fprem1"; break; case 0xF5: mnem = "fprem1"; break;
case 0xF7: mnem = "fincstp"; break; case 0xF7: mnem = "fincstp"; break;
......
...@@ -84,7 +84,7 @@ function MathCeil(x) { ...@@ -84,7 +84,7 @@ function MathCeil(x) {
// ECMA 262 - 15.8.2.7 // ECMA 262 - 15.8.2.7
function MathCos(x) { function MathCos(x) {
if (!IS_NUMBER(x)) x = ToNumber(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.8
...@@ -176,7 +176,7 @@ function MathRound(x) { ...@@ -176,7 +176,7 @@ function MathRound(x) {
// ECMA 262 - 15.8.2.16 // ECMA 262 - 15.8.2.16
function MathSin(x) { function MathSin(x) {
if (!IS_NUMBER(x)) x = ToNumber(x); if (!IS_NUMBER(x)) x = ToNumber(x);
return %Math_sin(x); return %_Math_sin(x);
} }
// ECMA 262 - 15.8.2.17 // ECMA 262 - 15.8.2.17
......
...@@ -4638,6 +4638,7 @@ static Object* Runtime_StringCompare(Arguments args) { ...@@ -4638,6 +4638,7 @@ static Object* Runtime_StringCompare(Arguments args) {
static Object* Runtime_Math_abs(Arguments args) { static Object* Runtime_Math_abs(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
Counters::math_abs.Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(x, args[0]);
return Heap::AllocateHeapNumber(fabs(x)); return Heap::AllocateHeapNumber(fabs(x));
...@@ -4647,6 +4648,7 @@ static Object* Runtime_Math_abs(Arguments args) { ...@@ -4647,6 +4648,7 @@ static Object* Runtime_Math_abs(Arguments args) {
static Object* Runtime_Math_acos(Arguments args) { static Object* Runtime_Math_acos(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
Counters::math_acos.Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(x, args[0]);
return TranscendentalCache::Get(TranscendentalCache::ACOS, x); return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
...@@ -4656,6 +4658,7 @@ static Object* Runtime_Math_acos(Arguments args) { ...@@ -4656,6 +4658,7 @@ static Object* Runtime_Math_acos(Arguments args) {
static Object* Runtime_Math_asin(Arguments args) { static Object* Runtime_Math_asin(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
Counters::math_asin.Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(x, args[0]);
return TranscendentalCache::Get(TranscendentalCache::ASIN, x); return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
...@@ -4665,6 +4668,7 @@ static Object* Runtime_Math_asin(Arguments args) { ...@@ -4665,6 +4668,7 @@ static Object* Runtime_Math_asin(Arguments args) {
static Object* Runtime_Math_atan(Arguments args) { static Object* Runtime_Math_atan(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
Counters::math_atan.Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(x, args[0]);
return TranscendentalCache::Get(TranscendentalCache::ATAN, x); return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
...@@ -4674,6 +4678,7 @@ static Object* Runtime_Math_atan(Arguments args) { ...@@ -4674,6 +4678,7 @@ static Object* Runtime_Math_atan(Arguments args) {
static Object* Runtime_Math_atan2(Arguments args) { static Object* Runtime_Math_atan2(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
Counters::math_atan2.Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(x, args[0]);
CONVERT_DOUBLE_CHECKED(y, args[1]); CONVERT_DOUBLE_CHECKED(y, args[1]);
...@@ -4697,6 +4702,7 @@ static Object* Runtime_Math_atan2(Arguments args) { ...@@ -4697,6 +4702,7 @@ static Object* Runtime_Math_atan2(Arguments args) {
static Object* Runtime_Math_ceil(Arguments args) { static Object* Runtime_Math_ceil(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
Counters::math_ceil.Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(x, args[0]);
return Heap::NumberFromDouble(ceiling(x)); return Heap::NumberFromDouble(ceiling(x));
...@@ -4706,6 +4712,7 @@ static Object* Runtime_Math_ceil(Arguments args) { ...@@ -4706,6 +4712,7 @@ static Object* Runtime_Math_ceil(Arguments args) {
static Object* Runtime_Math_cos(Arguments args) { static Object* Runtime_Math_cos(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
Counters::math_cos.Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(x, args[0]);
return TranscendentalCache::Get(TranscendentalCache::COS, x); return TranscendentalCache::Get(TranscendentalCache::COS, x);
...@@ -4715,6 +4722,7 @@ static Object* Runtime_Math_cos(Arguments args) { ...@@ -4715,6 +4722,7 @@ static Object* Runtime_Math_cos(Arguments args) {
static Object* Runtime_Math_exp(Arguments args) { static Object* Runtime_Math_exp(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
Counters::math_exp.Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(x, args[0]);
return TranscendentalCache::Get(TranscendentalCache::EXP, x); return TranscendentalCache::Get(TranscendentalCache::EXP, x);
...@@ -4724,6 +4732,7 @@ static Object* Runtime_Math_exp(Arguments args) { ...@@ -4724,6 +4732,7 @@ static Object* Runtime_Math_exp(Arguments args) {
static Object* Runtime_Math_floor(Arguments args) { static Object* Runtime_Math_floor(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
Counters::math_floor.Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(x, args[0]);
return Heap::NumberFromDouble(floor(x)); return Heap::NumberFromDouble(floor(x));
...@@ -4733,6 +4742,7 @@ static Object* Runtime_Math_floor(Arguments args) { ...@@ -4733,6 +4742,7 @@ static Object* Runtime_Math_floor(Arguments args) {
static Object* Runtime_Math_log(Arguments args) { static Object* Runtime_Math_log(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
Counters::math_log.Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(x, args[0]);
return TranscendentalCache::Get(TranscendentalCache::LOG, x); return TranscendentalCache::Get(TranscendentalCache::LOG, x);
...@@ -4773,6 +4783,7 @@ static double powi(double x, int y) { ...@@ -4773,6 +4783,7 @@ static double powi(double x, int y) {
static Object* Runtime_Math_pow(Arguments args) { static Object* Runtime_Math_pow(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
Counters::math_pow.Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(x, args[0]);
...@@ -4811,6 +4822,7 @@ static Object* Runtime_Math_pow(Arguments args) { ...@@ -4811,6 +4822,7 @@ static Object* Runtime_Math_pow(Arguments args) {
static Object* Runtime_Math_round(Arguments args) { static Object* Runtime_Math_round(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
Counters::math_round.Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(x, args[0]);
if (signbit(x) && x >= -0.5) return Heap::minus_zero_value(); if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
...@@ -4823,6 +4835,7 @@ static Object* Runtime_Math_round(Arguments args) { ...@@ -4823,6 +4835,7 @@ static Object* Runtime_Math_round(Arguments args) {
static Object* Runtime_Math_sin(Arguments args) { static Object* Runtime_Math_sin(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
Counters::math_sin.Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(x, args[0]);
return TranscendentalCache::Get(TranscendentalCache::SIN, x); return TranscendentalCache::Get(TranscendentalCache::SIN, x);
...@@ -4832,6 +4845,7 @@ static Object* Runtime_Math_sin(Arguments args) { ...@@ -4832,6 +4845,7 @@ static Object* Runtime_Math_sin(Arguments args) {
static Object* Runtime_Math_sqrt(Arguments args) { static Object* Runtime_Math_sqrt(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
Counters::math_sqrt.Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(x, args[0]);
return Heap::AllocateHeapNumber(sqrt(x)); return Heap::AllocateHeapNumber(sqrt(x));
...@@ -4841,6 +4855,7 @@ static Object* Runtime_Math_sqrt(Arguments args) { ...@@ -4841,6 +4855,7 @@ static Object* Runtime_Math_sqrt(Arguments args) {
static Object* Runtime_Math_tan(Arguments args) { static Object* Runtime_Math_tan(Arguments args) {
NoHandleAllocation ha; NoHandleAllocation ha;
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
Counters::math_tan.Increment();
CONVERT_DOUBLE_CHECKED(x, args[0]); CONVERT_DOUBLE_CHECKED(x, args[0]);
return TranscendentalCache::Get(TranscendentalCache::TAN, x); return TranscendentalCache::Get(TranscendentalCache::TAN, x);
......
...@@ -432,6 +432,10 @@ void ExternalReferenceTable::PopulateTable() { ...@@ -432,6 +432,10 @@ void ExternalReferenceTable::PopulateTable() {
UNCLASSIFIED, UNCLASSIFIED,
24, 24,
"KeyedLookupCache::field_offsets()"); "KeyedLookupCache::field_offsets()");
Add(ExternalReference::transcendental_cache_array_address().address(),
UNCLASSIFIED,
25,
"TranscendentalCache::caches()");
} }
......
...@@ -169,7 +169,24 @@ namespace internal { ...@@ -169,7 +169,24 @@ namespace internal {
SC(regexp_entry_runtime, V8.RegExpEntryRuntime) \ SC(regexp_entry_runtime, V8.RegExpEntryRuntime) \
SC(regexp_entry_native, V8.RegExpEntryNative) \ SC(regexp_entry_native, V8.RegExpEntryNative) \
SC(number_to_string_native, V8.NumberToStringNative) \ SC(number_to_string_native, V8.NumberToStringNative) \
SC(number_to_string_runtime, V8.NumberToStringRuntime) SC(number_to_string_runtime, V8.NumberToStringRuntime) \
SC(math_abs, V8.MathAbs) \
SC(math_acos, V8.MathAcos) \
SC(math_asin, V8.MathAsin) \
SC(math_atan, V8.MathAtan) \
SC(math_atan2, V8.MathAtan2) \
SC(math_ceil, V8.MathCeil) \
SC(math_cos, V8.MathCos) \
SC(math_exp, V8.MathExp) \
SC(math_floor, V8.MathFloor) \
SC(math_log, V8.MathLog) \
SC(math_pow, V8.MathPow) \
SC(math_round, V8.MathRound) \
SC(math_sin, V8.MathSin) \
SC(math_sqrt, V8.MathSqrt) \
SC(math_tan, V8.MathTan) \
SC(transcendental_cache_hit, V8.TranscendentalCacheHit) \
SC(transcendental_cache_miss, V8.TranscendentalCacheMiss)
// This file contains all the v8 counters that are in use. // This file contains all the v8 counters that are in use.
class Counters : AllStatic { class Counters : AllStatic {
......
...@@ -4004,6 +4004,24 @@ void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) { ...@@ -4004,6 +4004,24 @@ void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
} }
void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 1);
// Load the argument on the stack and jump to the runtime.
Load(args->at(0));
Result answer = frame_->CallRuntime(Runtime::kMath_sin, 1);
frame_->Push(&answer);
}
void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 1);
// Load the argument on the stack and jump to the runtime.
Load(args->at(0));
Result answer = frame_->CallRuntime(Runtime::kMath_cos, 1);
frame_->Push(&answer);
}
void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) { void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) {
ASSERT_EQ(2, args->length()); ASSERT_EQ(2, args->length());
......
...@@ -572,7 +572,11 @@ class CodeGenerator: public AstVisitor { ...@@ -572,7 +572,11 @@ class CodeGenerator: public AstVisitor {
// Fast support for number to string. // Fast support for number to string.
void GenerateNumberToString(ZoneList<Expression*>* args); void GenerateNumberToString(ZoneList<Expression*>* args);
// Simple condition analysis. // Fast call to math functions.
void GenerateMathSin(ZoneList<Expression*>* args);
void GenerateMathCos(ZoneList<Expression*>* args);
// Simple condition analysis.
enum ConditionAnalysis { enum ConditionAnalysis {
ALWAYS_TRUE, ALWAYS_TRUE,
ALWAYS_FALSE, ALWAYS_FALSE,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment