diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc index 76a610b7be..b42d627b9c 100644 --- a/src/arm/code-stubs-arm.cc +++ b/src/arm/code-stubs-arm.cc @@ -2290,6 +2290,7 @@ Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { // Add more cases when necessary. case TranscendentalCache::SIN: return Runtime::kMath_sin; case TranscendentalCache::COS: return Runtime::kMath_cos; + case TranscendentalCache::LOG: return Runtime::kMath_log; default: UNIMPLEMENTED(); return Runtime::kAbort; diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index 27e14df481..ea57d2d4e5 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -5750,6 +5750,20 @@ void CodeGenerator::GenerateMathCos(ZoneList* args) { } +void CodeGenerator::GenerateMathLog(ZoneList* args) { + ASSERT_EQ(args->length(), 1); + Load(args->at(0)); + if (CpuFeatures::IsSupported(VFP3)) { + TranscendentalCacheStub stub(TranscendentalCache::LOG); + frame_->SpillAllButCopyTOSToR0(); + frame_->CallStub(&stub, 1); + } else { + frame_->CallRuntime(Runtime::kMath_log, 1); + } + frame_->EmitPush(r0); +} + + void CodeGenerator::GenerateObjectEquals(ZoneList* args) { ASSERT(args->length() == 2); diff --git a/src/arm/codegen-arm.h b/src/arm/codegen-arm.h index 1930f5e1a4..4e672b2528 100644 --- a/src/arm/codegen-arm.h +++ b/src/arm/codegen-arm.h @@ -516,6 +516,7 @@ class CodeGenerator: public AstVisitor { void GenerateMathSin(ZoneList* args); void GenerateMathCos(ZoneList* args); void GenerateMathSqrt(ZoneList* args); + void GenerateMathLog(ZoneList* args); void GenerateIsRegExpEquivalent(ZoneList* args); diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 1a55efa45c..633b5b4d1f 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -2617,6 +2617,15 @@ void FullCodeGenerator::EmitMathSqrt(ZoneList* args) { } +void FullCodeGenerator::EmitMathLog(ZoneList* args) { + // Load the argument on the stack and call the runtime function. + ASSERT(args->length() == 1); + VisitForStackValue(args->at(0)); + __ CallRuntime(Runtime::kMath_log, 1); + context()->Plug(r0); +} + + void FullCodeGenerator::EmitCallFunction(ZoneList* args) { ASSERT(args->length() >= 2); diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc index 125f503bec..8687f2eb60 100644 --- a/src/ia32/assembler-ia32.cc +++ b/src/ia32/assembler-ia32.cc @@ -1772,6 +1772,14 @@ void Assembler::fldz() { } +void Assembler::fldln2() { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + EMIT(0xD9); + EMIT(0xED); +} + + void Assembler::fld_s(const Operand& adr) { EnsureSpace ensure_space(this); last_pc_ = pc_; @@ -1902,6 +1910,14 @@ void Assembler::fsin() { } +void Assembler::fyl2x() { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + EMIT(0xD9); + EMIT(0xF1); +} + + void Assembler::fadd(int i) { EnsureSpace ensure_space(this); last_pc_ = pc_; diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h index 79637a1901..681bcf9970 100644 --- a/src/ia32/assembler-ia32.h +++ b/src/ia32/assembler-ia32.h @@ -720,6 +720,7 @@ class Assembler : public Malloced { void fld1(); void fldz(); void fldpi(); + void fldln2(); void fld_s(const Operand& adr); void fld_d(const Operand& adr); @@ -744,6 +745,7 @@ class Assembler : public Malloced { void fchs(); void fcos(); void fsin(); + void fyl2x(); void fadd(int i); void fsub(int i); diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc index 5975ad27db..6cf6d12bc2 100644 --- a/src/ia32/code-stubs-ia32.cc +++ b/src/ia32/code-stubs-ia32.cc @@ -1330,6 +1330,7 @@ Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { // Add more cases when necessary. case TranscendentalCache::SIN: return Runtime::kMath_sin; case TranscendentalCache::COS: return Runtime::kMath_cos; + case TranscendentalCache::LOG: return Runtime::kMath_log; default: UNIMPLEMENTED(); return Runtime::kAbort; @@ -1339,85 +1340,90 @@ Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) { // Only free register is edi. + // Input value is on FP stack, and also in ebx/edx. Address of result + // (a newly allocated HeapNumber) is in eax. NearLabel done; - ASSERT(type_ == TranscendentalCache::SIN || - type_ == TranscendentalCache::COS); - // More transcendental types can be added later. + if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) { + // 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. + NearLabel 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)); + NearLabel 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); - // 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. - NearLabel 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)); - NearLabel 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); - __ 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. + { + NearLabel 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); + } - // 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. - { - NearLabel 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) + { + NearLabel 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); + } else { + ASSERT(type_ == TranscendentalCache::LOG); + __ fldln2(); + __ fxch(); + __ fyl2x(); } - - // Compute st(0) % st(1) - { - NearLabel 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); } diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index f5ab357ff1..a791ed5ea3 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -7995,6 +7995,15 @@ void CodeGenerator::GenerateMathCos(ZoneList* args) { } +void CodeGenerator::GenerateMathLog(ZoneList* args) { + ASSERT_EQ(args->length(), 1); + Load(args->at(0)); + TranscendentalCacheStub stub(TranscendentalCache::LOG); + Result result = frame_->CallStub(&stub, 1); + frame_->Push(&result); +} + + // Generates the Math.sqrt method. Please note - this function assumes that // the callsite has executed ToNumber on the argument. void CodeGenerator::GenerateMathSqrt(ZoneList* args) { diff --git a/src/ia32/codegen-ia32.h b/src/ia32/codegen-ia32.h index d1a2036cb7..1030856c98 100644 --- a/src/ia32/codegen-ia32.h +++ b/src/ia32/codegen-ia32.h @@ -705,8 +705,9 @@ class CodeGenerator: public AstVisitor { void GenerateMathSin(ZoneList* args); void GenerateMathCos(ZoneList* args); void GenerateMathSqrt(ZoneList* args); + void GenerateMathLog(ZoneList* args); - // Check whether two RegExps are equivalent + // Check whether two RegExps are equivalent. void GenerateIsRegExpEquivalent(ZoneList* args); void GenerateHasCachedArrayIndex(ZoneList* args); diff --git a/src/ia32/disasm-ia32.cc b/src/ia32/disasm-ia32.cc index 52c2b3848a..437c741b36 100644 --- a/src/ia32/disasm-ia32.cc +++ b/src/ia32/disasm-ia32.cc @@ -733,7 +733,9 @@ int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode, case 0xE4: mnem = "ftst"; break; case 0xE8: mnem = "fld1"; break; case 0xEB: mnem = "fldpi"; break; + case 0xED: mnem = "fldln2"; break; case 0xEE: mnem = "fldz"; break; + case 0xF1: mnem = "fyl2x"; break; case 0xF5: mnem = "fprem1"; break; case 0xF7: mnem = "fincstp"; break; case 0xF8: mnem = "fprem"; break; diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 09dd59afbb..d175b9cecd 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -2917,6 +2917,16 @@ void FullCodeGenerator::EmitMathCos(ZoneList* args) { } +void FullCodeGenerator::EmitMathLog(ZoneList* args) { + // Load the argument on the stack and call the stub. + TranscendentalCacheStub stub(TranscendentalCache::LOG); + ASSERT(args->length() == 1); + VisitForStackValue(args->at(0)); + __ CallStub(&stub); + context()->Plug(eax); +} + + void FullCodeGenerator::EmitMathSqrt(ZoneList* args) { // Load the argument on the stack and call the runtime function. ASSERT(args->length() == 1); diff --git a/src/math.js b/src/math.js index fc3b132fff..90667d76cf 100644 --- a/src/math.js +++ b/src/math.js @@ -113,7 +113,7 @@ function MathFloor(x) { // ECMA 262 - 15.8.2.10 function MathLog(x) { if (!IS_NUMBER(x)) x = ToNumber(x); - return %Math_log(x); + return %_MathLog(x); } // ECMA 262 - 15.8.2.11 diff --git a/src/runtime.h b/src/runtime.h index 98782b1e4a..8b6f9886a3 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -417,6 +417,7 @@ namespace internal { F(MathSin, 1, 1) \ F(MathCos, 1, 1) \ F(MathSqrt, 1, 1) \ + F(MathLog, 1, 1) \ F(IsRegExpEquivalent, 2, 1) \ F(HasCachedArrayIndex, 1, 1) \ F(GetCachedArrayIndex, 1, 1) \ diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc index caed7c8aa9..05bf19545d 100644 --- a/src/x64/assembler-x64.cc +++ b/src/x64/assembler-x64.cc @@ -2217,6 +2217,14 @@ void Assembler::fldpi() { } +void Assembler::fldln2() { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit(0xD9); + emit(0xED); +} + + void Assembler::fld_s(const Operand& adr) { EnsureSpace ensure_space(this); last_pc_ = pc_; @@ -2358,6 +2366,14 @@ void Assembler::fsin() { } +void Assembler::fyl2x() { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit(0xD9); + emit(0xF1); +} + + void Assembler::fadd(int i) { EnsureSpace ensure_space(this); last_pc_ = pc_; diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h index c7f763222e..549d94c224 100644 --- a/src/x64/assembler-x64.h +++ b/src/x64/assembler-x64.h @@ -1046,6 +1046,7 @@ class Assembler : public Malloced { void fld1(); void fldz(); void fldpi(); + void fldln2(); void fld_s(const Operand& adr); void fld_d(const Operand& adr); @@ -1100,6 +1101,7 @@ class Assembler : public Malloced { void fsin(); void fcos(); + void fyl2x(); void frndint(); diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc index 14e352731f..9bd28bc5cd 100644 --- a/src/x64/code-stubs-x64.cc +++ b/src/x64/code-stubs-x64.cc @@ -1107,6 +1107,7 @@ Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { // Add more cases when necessary. case TranscendentalCache::SIN: return Runtime::kMath_sin; case TranscendentalCache::COS: return Runtime::kMath_cos; + case TranscendentalCache::LOG: return Runtime::kMath_log; default: UNIMPLEMENTED(); return Runtime::kAbort; @@ -1121,73 +1122,76 @@ void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm, // rcx: Pointer to cache entry. Must be preserved. // st(0): Input double Label done; - ASSERT(type_ == TranscendentalCache::SIN || - type_ == TranscendentalCache::COS); - // More transcendental types can be added later. + if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) { + // 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. + __ movq(rdi, rbx); + // Move exponent and sign bits to low bits. + __ shr(rdi, Immediate(HeapNumber::kMantissaBits)); + // Remove sign bit. + __ andl(rdi, Immediate((1 << HeapNumber::kExponentBits) - 1)); + int supported_exponent_limit = (63 + HeapNumber::kExponentBias); + __ cmpl(rdi, Immediate(supported_exponent_limit)); + __ j(below, &in_range); + // Check for infinity and NaN. Both return NaN for sin. + __ cmpl(rdi, Immediate(0x7ff)); + __ j(equal, on_nan_result); - // 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. - __ movq(rdi, rbx); - // Move exponent and sign bits to low bits. - __ shr(rdi, Immediate(HeapNumber::kMantissaBits)); - // Remove sign bit. - __ andl(rdi, Immediate((1 << HeapNumber::kExponentBits) - 1)); - int supported_exponent_limit = (63 + HeapNumber::kExponentBias); - __ cmpl(rdi, Immediate(supported_exponent_limit)); - __ j(below, &in_range); - // Check for infinity and NaN. Both return NaN for sin. - __ cmpl(rdi, Immediate(0x7ff)); - __ j(equal, on_nan_result); + // Use fpmod to restrict argument to the range +/-2*PI. + __ 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. + __ testl(rax, Immediate(5)); // #IO and #ZD flags of FPU status word. + __ j(zero, &no_exceptions); + __ fnclex(); + __ bind(&no_exceptions); + } - // Use fpmod to restrict argument to the range +/-2*PI. - __ 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. - __ testl(rax, Immediate(5)); // #IO and #ZD flags of FPU status word. - __ j(zero, &no_exceptions); - __ fnclex(); - __ bind(&no_exceptions); + // Compute st(0) % st(1) + { + NearLabel partial_remainder_loop; + __ bind(&partial_remainder_loop); + __ fprem1(); + __ fwait(); + __ fnstsw_ax(); + __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word. + // If C2 is set, computation only has partial result. Loop to + // continue computation. + __ j(not_zero, &partial_remainder_loop); } - - // Compute st(0) % st(1) - { - NearLabel partial_remainder_loop; - __ bind(&partial_remainder_loop); - __ fprem1(); - __ fwait(); - __ fnstsw_ax(); - __ testl(rax, Immediate(0x400)); // Check C2 bit of FPU status word. - // 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); + // FPU Stack: input % 2*pi, 2*pi, + __ fstp(0); + // FPU Stack: input % 2*pi + __ bind(&in_range); + switch (type_) { + case TranscendentalCache::SIN: + __ fsin(); + break; + case TranscendentalCache::COS: + __ fcos(); + break; + default: + UNREACHABLE(); + } + __ bind(&done); + } else { + ASSERT(type_ == TranscendentalCache::LOG); + __ fldln2(); + __ fxch(); + __ fyl2x(); } - // FPU Stack: input, 2*pi, input % 2*pi - __ fstp(2); - // FPU Stack: input % 2*pi, 2*pi, - __ fstp(0); - // FPU Stack: input % 2*pi - __ bind(&in_range); - switch (type_) { - case TranscendentalCache::SIN: - __ fsin(); - break; - case TranscendentalCache::COS: - __ fcos(); - break; - default: - UNREACHABLE(); - } - __ bind(&done); } diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index 5abf3c838c..765a570b4a 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -7111,6 +7111,15 @@ void CodeGenerator::GenerateMathCos(ZoneList* args) { } +void CodeGenerator::GenerateMathLog(ZoneList* args) { + ASSERT_EQ(args->length(), 1); + Load(args->at(0)); + TranscendentalCacheStub stub(TranscendentalCache::LOG); + Result result = frame_->CallStub(&stub, 1); + frame_->Push(&result); +} + + // Generates the Math.sqrt method. Please note - this function assumes that // the callsite has executed ToNumber on the argument. void CodeGenerator::GenerateMathSqrt(ZoneList* args) { diff --git a/src/x64/codegen-x64.h b/src/x64/codegen-x64.h index 1a5e7df31c..e38bf29f21 100644 --- a/src/x64/codegen-x64.h +++ b/src/x64/codegen-x64.h @@ -664,14 +664,16 @@ class CodeGenerator: public AstVisitor { void GenerateMathSin(ZoneList* args); void GenerateMathCos(ZoneList* args); void GenerateMathSqrt(ZoneList* args); + void GenerateMathLog(ZoneList* args); + // Check whether two RegExps are equivalent. void GenerateIsRegExpEquivalent(ZoneList* args); void GenerateHasCachedArrayIndex(ZoneList* args); void GenerateGetCachedArrayIndex(ZoneList* args); void GenerateFastAsciiArrayJoin(ZoneList* args); -// Simple condition analysis. + // Simple condition analysis. enum ConditionAnalysis { ALWAYS_TRUE, ALWAYS_FALSE, diff --git a/src/x64/disasm-x64.cc b/src/x64/disasm-x64.cc index 4213912b91..7502d6182c 100644 --- a/src/x64/disasm-x64.cc +++ b/src/x64/disasm-x64.cc @@ -906,7 +906,9 @@ int DisassemblerX64::RegisterFPUInstruction(int escape_opcode, case 0xE4: mnem = "ftst"; break; case 0xE8: mnem = "fld1"; break; case 0xEB: mnem = "fldpi"; break; + case 0xED: mnem = "fldln2"; break; case 0xEE: mnem = "fldz"; break; + case 0xF1: mnem = "fyl2x"; break; case 0xF5: mnem = "fprem1"; break; case 0xF7: mnem = "fincstp"; break; case 0xF8: mnem = "fprem"; break; diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 2a1ad244fc..6007d7e984 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -2623,6 +2623,16 @@ void FullCodeGenerator::EmitMathCos(ZoneList* args) { } +void FullCodeGenerator::EmitMathLog(ZoneList* args) { + // Load the argument on the stack and call the stub. + TranscendentalCacheStub stub(TranscendentalCache::LOG); + ASSERT(args->length() == 1); + VisitForStackValue(args->at(0)); + __ CallStub(&stub); + context()->Plug(rax); +} + + void FullCodeGenerator::EmitMathSqrt(ZoneList* args) { // Load the argument on the stack and call the runtime function. ASSERT(args->length() == 1);