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
This commit is contained in:
parent
2883c03037
commit
3135110af8
@ -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) {
|
||||
VirtualFrame::SpilledScope spilled_scope;
|
||||
ASSERT(args->length() == 2);
|
||||
|
@ -393,6 +393,10 @@ class CodeGenerator: public AstVisitor {
|
||||
// Fast support for number to string.
|
||||
void GenerateNumberToString(ZoneList<Expression*>* args);
|
||||
|
||||
// Fast call to sine function.
|
||||
void GenerateMathSin(ZoneList<Expression*>* args);
|
||||
void GenerateMathCos(ZoneList<Expression*>* args);
|
||||
|
||||
// Simple condition analysis.
|
||||
enum ConditionAnalysis {
|
||||
ALWAYS_TRUE,
|
||||
|
@ -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() {
|
||||
return ExternalReference(KeyedLookupCache::keys_address());
|
||||
}
|
||||
|
@ -400,6 +400,7 @@ class ExternalReference BASE_EMBEDDED {
|
||||
|
||||
static ExternalReference perform_gc_function();
|
||||
static ExternalReference random_positive_smi_function();
|
||||
static ExternalReference transcendental_cache_array_address();
|
||||
|
||||
// Static data in the keyed lookup cache.
|
||||
static ExternalReference keyed_lookup_cache_keys();
|
||||
|
@ -48,6 +48,7 @@ namespace internal {
|
||||
V(FastNewClosure) \
|
||||
V(FastNewContext) \
|
||||
V(FastCloneShallowArray) \
|
||||
V(TranscendentalCache) \
|
||||
V(GenericUnaryOp) \
|
||||
V(RevertToNumber) \
|
||||
V(ToBoolean) \
|
||||
|
@ -379,6 +379,8 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
|
||||
{&CodeGenerator::GenerateStringCompare, "_StringCompare"},
|
||||
{&CodeGenerator::GenerateRegExpExec, "_RegExpExec"},
|
||||
{&CodeGenerator::GenerateNumberToString, "_NumberToString"},
|
||||
{&CodeGenerator::GenerateMathSin, "_Math_sin"},
|
||||
{&CodeGenerator::GenerateMathCos, "_Math_cos"},
|
||||
};
|
||||
|
||||
|
||||
|
13
src/heap.h
13
src/heap.h
@ -1610,6 +1610,7 @@ class TranscendentalCache {
|
||||
if (e.in[0] == c.integers[0] &&
|
||||
e.in[1] == c.integers[1]) {
|
||||
ASSERT(e.output != NULL);
|
||||
Counters::transcendental_cache_hit.Increment();
|
||||
return e.output;
|
||||
}
|
||||
double answer = Calculate(input);
|
||||
@ -1619,6 +1620,7 @@ class TranscendentalCache {
|
||||
elements_[hash].in[1] = c.integers[1];
|
||||
elements_[hash].output = heap_number;
|
||||
}
|
||||
Counters::transcendental_cache_miss.Increment();
|
||||
return heap_number;
|
||||
}
|
||||
|
||||
@ -1659,6 +1661,17 @@ class TranscendentalCache {
|
||||
hash ^= hash >> 8;
|
||||
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];
|
||||
Element elements_[kCacheSize];
|
||||
Type type_;
|
||||
|
@ -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() {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
@ -1645,6 +1652,14 @@ void Assembler::fld1() {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::fldpi() {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
EMIT(0xD9);
|
||||
EMIT(0xEB);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::fldz() {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
@ -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) {
|
||||
EnsureSpace ensure_space(this);
|
||||
last_pc_ = pc_;
|
||||
|
@ -668,6 +668,7 @@ class Assembler : public Malloced {
|
||||
void call(Label* L);
|
||||
void call(byte* entry, RelocInfo::Mode rmode);
|
||||
void call(const Operand& adr);
|
||||
void call(const ExternalReference& target);
|
||||
void call(Handle<Code> code, RelocInfo::Mode rmode);
|
||||
|
||||
// Jumps
|
||||
@ -683,15 +684,18 @@ class Assembler : public Malloced {
|
||||
|
||||
// Floating-point operations
|
||||
void fld(int i);
|
||||
void fstp(int i);
|
||||
|
||||
void fld1();
|
||||
void fldz();
|
||||
void fldpi();
|
||||
|
||||
void fld_s(const Operand& adr);
|
||||
void fld_d(const Operand& adr);
|
||||
|
||||
void fstp_s(const Operand& adr);
|
||||
void fstp_d(const Operand& adr);
|
||||
void fst_d(const Operand& adr);
|
||||
|
||||
void fild_s(const Operand& adr);
|
||||
void fild_d(const Operand& adr);
|
||||
|
@ -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) {
|
||||
if (CheckForInlineRuntimeCall(node)) {
|
||||
return;
|
||||
@ -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
|
||||
// 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
|
||||
|
@ -588,6 +588,10 @@ class CodeGenerator: public AstVisitor {
|
||||
// Fast support for number to string.
|
||||
void GenerateNumberToString(ZoneList<Expression*>* args);
|
||||
|
||||
// Fast call to transcendental functions.
|
||||
void GenerateMathSin(ZoneList<Expression*>* args);
|
||||
void GenerateMathCos(ZoneList<Expression*>* args);
|
||||
|
||||
// Simple condition analysis.
|
||||
enum ConditionAnalysis {
|
||||
ALWAYS_TRUE,
|
||||
@ -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.
|
||||
enum GenericBinaryFlags {
|
||||
NO_GENERIC_BINARY_FLAGS = 0,
|
||||
|
@ -679,6 +679,7 @@ int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
|
||||
|
||||
case 0xDD: switch (regop) {
|
||||
case 0: mnem = "fld_d"; break;
|
||||
case 2: mnem = "fstp"; break;
|
||||
case 3: mnem = "fstp_d"; break;
|
||||
default: UnimplementedInstruction();
|
||||
}
|
||||
@ -720,6 +721,7 @@ int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
|
||||
case 0xE1: mnem = "fabs"; break;
|
||||
case 0xE4: mnem = "ftst"; break;
|
||||
case 0xE8: mnem = "fld1"; break;
|
||||
case 0xEB: mnem = "fldpi"; break;
|
||||
case 0xEE: mnem = "fldz"; break;
|
||||
case 0xF5: mnem = "fprem1"; break;
|
||||
case 0xF7: mnem = "fincstp"; break;
|
||||
|
@ -84,7 +84,7 @@ function MathCeil(x) {
|
||||
// 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
|
||||
@ -176,7 +176,7 @@ function MathRound(x) {
|
||||
// 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
|
||||
|
@ -4638,6 +4638,7 @@ static Object* Runtime_StringCompare(Arguments args) {
|
||||
static Object* Runtime_Math_abs(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
Counters::math_abs.Increment();
|
||||
|
||||
CONVERT_DOUBLE_CHECKED(x, args[0]);
|
||||
return Heap::AllocateHeapNumber(fabs(x));
|
||||
@ -4647,6 +4648,7 @@ static Object* Runtime_Math_abs(Arguments args) {
|
||||
static Object* Runtime_Math_acos(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
Counters::math_acos.Increment();
|
||||
|
||||
CONVERT_DOUBLE_CHECKED(x, args[0]);
|
||||
return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
|
||||
@ -4656,6 +4658,7 @@ static Object* Runtime_Math_acos(Arguments args) {
|
||||
static Object* Runtime_Math_asin(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
Counters::math_asin.Increment();
|
||||
|
||||
CONVERT_DOUBLE_CHECKED(x, args[0]);
|
||||
return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
|
||||
@ -4665,6 +4668,7 @@ static Object* Runtime_Math_asin(Arguments args) {
|
||||
static Object* Runtime_Math_atan(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
Counters::math_atan.Increment();
|
||||
|
||||
CONVERT_DOUBLE_CHECKED(x, args[0]);
|
||||
return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
|
||||
@ -4674,6 +4678,7 @@ static Object* Runtime_Math_atan(Arguments args) {
|
||||
static Object* Runtime_Math_atan2(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 2);
|
||||
Counters::math_atan2.Increment();
|
||||
|
||||
CONVERT_DOUBLE_CHECKED(x, args[0]);
|
||||
CONVERT_DOUBLE_CHECKED(y, args[1]);
|
||||
@ -4697,6 +4702,7 @@ static Object* Runtime_Math_atan2(Arguments args) {
|
||||
static Object* Runtime_Math_ceil(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
Counters::math_ceil.Increment();
|
||||
|
||||
CONVERT_DOUBLE_CHECKED(x, args[0]);
|
||||
return Heap::NumberFromDouble(ceiling(x));
|
||||
@ -4706,6 +4712,7 @@ static Object* Runtime_Math_ceil(Arguments args) {
|
||||
static Object* Runtime_Math_cos(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
Counters::math_cos.Increment();
|
||||
|
||||
CONVERT_DOUBLE_CHECKED(x, args[0]);
|
||||
return TranscendentalCache::Get(TranscendentalCache::COS, x);
|
||||
@ -4715,6 +4722,7 @@ static Object* Runtime_Math_cos(Arguments args) {
|
||||
static Object* Runtime_Math_exp(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
Counters::math_exp.Increment();
|
||||
|
||||
CONVERT_DOUBLE_CHECKED(x, args[0]);
|
||||
return TranscendentalCache::Get(TranscendentalCache::EXP, x);
|
||||
@ -4724,6 +4732,7 @@ static Object* Runtime_Math_exp(Arguments args) {
|
||||
static Object* Runtime_Math_floor(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
Counters::math_floor.Increment();
|
||||
|
||||
CONVERT_DOUBLE_CHECKED(x, args[0]);
|
||||
return Heap::NumberFromDouble(floor(x));
|
||||
@ -4733,6 +4742,7 @@ static Object* Runtime_Math_floor(Arguments args) {
|
||||
static Object* Runtime_Math_log(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
Counters::math_log.Increment();
|
||||
|
||||
CONVERT_DOUBLE_CHECKED(x, args[0]);
|
||||
return TranscendentalCache::Get(TranscendentalCache::LOG, x);
|
||||
@ -4773,6 +4783,7 @@ static double powi(double x, int y) {
|
||||
static Object* Runtime_Math_pow(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 2);
|
||||
Counters::math_pow.Increment();
|
||||
|
||||
CONVERT_DOUBLE_CHECKED(x, args[0]);
|
||||
|
||||
@ -4811,6 +4822,7 @@ static Object* Runtime_Math_pow(Arguments args) {
|
||||
static Object* Runtime_Math_round(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
Counters::math_round.Increment();
|
||||
|
||||
CONVERT_DOUBLE_CHECKED(x, args[0]);
|
||||
if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
|
||||
@ -4823,6 +4835,7 @@ static Object* Runtime_Math_round(Arguments args) {
|
||||
static Object* Runtime_Math_sin(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
Counters::math_sin.Increment();
|
||||
|
||||
CONVERT_DOUBLE_CHECKED(x, args[0]);
|
||||
return TranscendentalCache::Get(TranscendentalCache::SIN, x);
|
||||
@ -4832,6 +4845,7 @@ static Object* Runtime_Math_sin(Arguments args) {
|
||||
static Object* Runtime_Math_sqrt(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
Counters::math_sqrt.Increment();
|
||||
|
||||
CONVERT_DOUBLE_CHECKED(x, args[0]);
|
||||
return Heap::AllocateHeapNumber(sqrt(x));
|
||||
@ -4841,6 +4855,7 @@ static Object* Runtime_Math_sqrt(Arguments args) {
|
||||
static Object* Runtime_Math_tan(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 1);
|
||||
Counters::math_tan.Increment();
|
||||
|
||||
CONVERT_DOUBLE_CHECKED(x, args[0]);
|
||||
return TranscendentalCache::Get(TranscendentalCache::TAN, x);
|
||||
|
@ -432,6 +432,10 @@ void ExternalReferenceTable::PopulateTable() {
|
||||
UNCLASSIFIED,
|
||||
24,
|
||||
"KeyedLookupCache::field_offsets()");
|
||||
Add(ExternalReference::transcendental_cache_array_address().address(),
|
||||
UNCLASSIFIED,
|
||||
25,
|
||||
"TranscendentalCache::caches()");
|
||||
}
|
||||
|
||||
|
||||
|
@ -169,7 +169,24 @@ namespace internal {
|
||||
SC(regexp_entry_runtime, V8.RegExpEntryRuntime) \
|
||||
SC(regexp_entry_native, V8.RegExpEntryNative) \
|
||||
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.
|
||||
class Counters : AllStatic {
|
||||
|
@ -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) {
|
||||
ASSERT_EQ(2, args->length());
|
||||
|
||||
|
@ -572,7 +572,11 @@ class CodeGenerator: public AstVisitor {
|
||||
// Fast support for number to string.
|
||||
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 {
|
||||
ALWAYS_TRUE,
|
||||
ALWAYS_FALSE,
|
||||
|
Loading…
Reference in New Issue
Block a user