[JSC] Add a node for Math.log()
https://bugs.webkit.org/show_bug.cgi?id=142126

Patch by Benjamin Poulain <bpoulain@apple.com> on 2015-03-04
Reviewed by Geoffrey Garen.

This patch adds the DFG node ArithLog for LogIntrinsic.

Having a direct call to log has very little value by itself, the implementation
in DFG and FTL is a simple function call.

What is useful in ArithLog is that we know the operation is pure.
This allow us to hoist it out of loops when the argument is independent
is an invariant of the loop.

Perf wise, this patch gives:
-Kraken's imaging-darkroom: definitely 1.2372x faster.
-AsmBench's Towers.c: definitely 1.0261x faster.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsic):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
(JSC::DFG::PredictionPropagationPhase::doDoubleVoting):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArithLog):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLIntrinsicRepository.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileArithLog):
* ftl/FTLOutput.h:
(JSC::FTL::Output::doubleLog):
* tests/stress/math-log-basics.js: Added.
* tests/stress/math-log-with-constants.js: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@181035 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 30dea39..80fad33 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,57 @@
+2015-03-04  Benjamin Poulain  <bpoulain@apple.com>
+
+        [JSC] Add a node for Math.log()
+        https://bugs.webkit.org/show_bug.cgi?id=142126
+
+        Reviewed by Geoffrey Garen.
+
+        This patch adds the DFG node ArithLog for LogIntrinsic.
+
+        Having a direct call to log has very little value by itself, the implementation
+        in DFG and FTL is a simple function call.
+
+        What is useful in ArithLog is that we know the operation is pure.
+        This allow us to hoist it out of loops when the argument is independent
+        is an invariant of the loop.
+
+        Perf wise, this patch gives:
+        -Kraken's imaging-darkroom: definitely 1.2372x faster.
+        -AsmBench's Towers.c: definitely 1.0261x faster.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsic):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        (JSC::DFG::PredictionPropagationPhase::doDoubleVoting):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileArithLog):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLIntrinsicRepository.h:
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileNode):
+        (JSC::FTL::LowerDFGToLLVM::compileArithLog):
+        * ftl/FTLOutput.h:
+        (JSC::FTL::Output::doubleLog):
+        * tests/stress/math-log-basics.js: Added.
+        * tests/stress/math-log-with-constants.js: Added.
+
 2015-03-04  Filip Pizlo  <fpizlo@apple.com>
 
         Only Heap should be in charge of deciding how to select a subspace for a type
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index 90f98aa..c015ad0 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -794,6 +794,16 @@
         forNode(node).setType(typeOfDoubleUnaryOp(forNode(node->child1()).m_type));
         break;
     }
+
+    case ArithLog: {
+        JSValue child = forNode(node->child1()).value();
+        if (child && child.isNumber()) {
+            setConstant(node, jsDoubleNumber(log(child.asNumber())));
+            break;
+        }
+        forNode(node).setType(typeOfDoubleUnaryOp(forNode(node->child1()).m_type));
+        break;
+    }
             
     case LogicalNot: {
         switch (booleanResult(node, forNode(node->child1()))) {
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 443eb13..2874cc3 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -1834,10 +1834,11 @@
         
     case MaxIntrinsic:
         return handleMinMax(resultOperand, ArithMax, registerOffset, argumentCountIncludingThis, insertChecks);
-        
+
     case SqrtIntrinsic:
     case CosIntrinsic:
-    case SinIntrinsic: {
+    case SinIntrinsic:
+    case LogIntrinsic: {
         if (argumentCountIncludingThis == 1) {
             insertChecks();
             set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_constantNaN)));
@@ -1859,6 +1860,11 @@
             insertChecks();
             set(VirtualRegister(resultOperand), addToGraph(ArithSin, get(virtualRegisterForArgument(1, registerOffset))));
             return true;
+
+        case LogIntrinsic:
+            insertChecks();
+            set(VirtualRegister(resultOperand), addToGraph(ArithLog, get(virtualRegisterForArgument(1, registerOffset))));
+            return true;
             
         default:
             RELEASE_ASSERT_NOT_REACHED();
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index c2f1635..58b7fbc 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -133,6 +133,7 @@
     case ArithFRound:
     case ArithSin:
     case ArithCos:
+    case ArithLog:
     case GetScope:
     case SkipScope:
     case StringCharCodeAt:
diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
index 96ebe8f..61204df 100644
--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
@@ -85,6 +85,7 @@
     case ArithFRound:
     case ArithSin:
     case ArithCos:
+    case ArithLog:
     case ValueAdd:
     case GetById:
     case GetByIdFlush:
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 17681dd..838670c 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -356,7 +356,8 @@
         case ArithSqrt:
         case ArithFRound:
         case ArithSin:
-        case ArithCos: {
+        case ArithCos:
+        case ArithLog: {
             fixDoubleOrBooleanEdge(node->child1());
             node->setResult(NodeResultDouble);
             break;
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 35dcb54..bda8184 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -140,6 +140,7 @@
     macro(ArithSqrt, NodeResultNumber) \
     macro(ArithSin, NodeResultNumber) \
     macro(ArithCos, NodeResultNumber) \
+    macro(ArithLog, NodeResultNumber) \
     \
     /* Add of values may either be arithmetic, or result in string concatenation. */\
     macro(ValueAdd, NodeResultJS | NodeMustGenerate) \
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index 676c987..8401f5d 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -334,7 +334,8 @@
         case ArithSqrt:
         case ArithFRound:
         case ArithSin:
-        case ArithCos: {
+        case ArithCos:
+        case ArithLog: {
             changed |= setPrediction(SpecBytecodeDouble);
             break;
         }
@@ -783,6 +784,7 @@
         case ArithSqrt:
         case ArithCos:
         case ArithSin:
+        case ArithLog:
             if (node->child1()->shouldSpeculateNumber())
                 m_graph.voteNode(node->child1(), VoteDouble, weight);
             else
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index e9c030d..5199ee2 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -155,6 +155,7 @@
     case ArithFRound:
     case ArithSin:
     case ArithCos:
+    case ArithLog:
     case ValueAdd:
     case GetById:
     case GetByIdFlush:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 6f5a6ea..34e7320 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -3626,6 +3626,16 @@
     doubleResult(resultFpr, node);
 }
 
+void SpeculativeJIT::compileArithLog(Node* node)
+{
+    SpeculateDoubleOperand op1(this, node->child1());
+    FPRReg op1FPR = op1.fpr();
+    flushRegisters();
+    FPRResult result(this);
+    callOperation(log, result.fpr(), op1FPR);
+    doubleResult(result.fpr(), node);
+}
+
 // Returns true if the compare is fused with a subsequent branch.
 bool SpeculativeJIT::compare(Node* node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_JITOperation_EJJ operation)
 {
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 19d5bee..0e5d03d 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -2174,6 +2174,7 @@
     void compileArithMod(Node*);
     void compileArithPow(Node*);
     void compileArithSqrt(Node*);
+    void compileArithLog(Node*);
     void compileConstantStoragePointer(Node*);
     void compileGetIndexedPropertyStorage(Node*);
     JITCompiler::Jump jumpForTypedArrayOutOfBounds(Node*, GPRReg baseGPR, GPRReg indexGPR);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 700b194..c2d18a1 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -2220,6 +2220,10 @@
         break;
     }
 
+    case ArithLog:
+        compileArithLog(node);
+        break;
+
     case LogicalNot:
         compileLogicalNot(node);
         break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 07d4635..1d1bccb 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -2353,6 +2353,10 @@
         break;
     }
 
+    case ArithLog:
+        compileArithLog(node);
+        break;
+
     case LogicalNot:
         compileLogicalNot(node);
         break;
diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
index 2f56a74..77d098f 100644
--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
@@ -91,6 +91,7 @@
     case ArithCos:
     case ArithPow:
     case ArithSqrt:
+    case ArithLog:
     case ArithFRound:
     case ArithNegate:
     case UInt32ToNumber:
diff --git a/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h b/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
index 4f36029..8f0b274 100644
--- a/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
+++ b/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h
@@ -43,6 +43,7 @@
     macro(doublePow, "llvm.pow.f64", functionType(doubleType, doubleType, doubleType)) \
     macro(doublePowi, "llvm.powi.f64", functionType(doubleType, doubleType, int32)) \
     macro(doubleSqrt, "llvm.sqrt.f64", functionType(doubleType, doubleType)) \
+    macro(doubleLog, "llvm.log.f64", functionType(doubleType, doubleType)) \
     macro(frameAddress, "llvm.frameaddress", functionType(pointerType(int8), int32)) \
     macro(mulWithOverflow32, "llvm.smul.with.overflow.i32", functionType(structType(m_context, int32, boolean), int32, int32)) \
     macro(mulWithOverflow64, "llvm.smul.with.overflow.i64", functionType(structType(m_context, int64, boolean), int64, int64)) \
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
index c1a24e0..1a290c5 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
@@ -510,6 +510,9 @@
         case ArithSqrt:
             compileArithSqrt();
             break;
+        case ArithLog:
+            compileArithLog();
+            break;
         case ArithFRound:
             compileArithFRound();
             break;
@@ -1718,6 +1721,8 @@
     }
 
     void compileArithSqrt() { setDouble(m_out.doubleSqrt(lowDouble(m_node->child1()))); }
+
+    void compileArithLog() { setDouble(m_out.doubleLog(lowDouble(m_node->child1()))); }
     
     void compileArithFRound()
     {
diff --git a/Source/JavaScriptCore/ftl/FTLOutput.h b/Source/JavaScriptCore/ftl/FTLOutput.h
index 27febd3..cd3751e 100644
--- a/Source/JavaScriptCore/ftl/FTLOutput.h
+++ b/Source/JavaScriptCore/ftl/FTLOutput.h
@@ -192,6 +192,11 @@
         return call(doubleSqrtIntrinsic(), value);
     }
 
+    LValue doubleLog(LValue value)
+    {
+        return call(doubleLogIntrinsic(), value);
+    }
+
     static bool hasSensibleDoubleToInt() { return isX86(); }
     LValue sensibleDoubleToInt(LValue);
     
diff --git a/Source/JavaScriptCore/tests/stress/math-log-basics.js b/Source/JavaScriptCore/tests/stress/math-log-basics.js
new file mode 100644
index 0000000..d6d1d14
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/math-log-basics.js
@@ -0,0 +1,128 @@
+// Basic cases of Math.log().
+
+// log(NaN).
+function logNaN(antilogarithm) {
+    return Math.log(antilogarithm);
+}
+noInline(logNaN);
+
+function testLogNaN() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = logNaN(NaN);
+        if (!isNaN(result))
+            throw "logNaN(NaN) = " + result + ", expected NaN";
+    }
+}
+testLogNaN();
+
+
+// log(0).
+function logZero(antilogarithm) {
+    return Math.log(antilogarithm);
+}
+noInline(logZero);
+
+function testLogZero() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = logZero(0);
+        if (result !== -Infinity)
+            throw "logZero(0) = " + result + ", expected -Infinity";
+    }
+}
+testLogZero();
+
+
+// log(1).
+function logOne(antilogarithm) {
+    return Math.log(antilogarithm);
+}
+noInline(logOne);
+
+function testLogOne() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = logOne(1);
+        if (result !== 0)
+            throw "logOne(1) = " + result + ", expected 0";
+    }
+}
+testLogOne();
+
+
+// log(-1).
+function logMinusOne(antilogarithm) {
+    return Math.log(antilogarithm);
+}
+noInline(logMinusOne);
+
+function testLogMinusOne() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = logMinusOne(-1);
+        if (!isNaN(result))
+            throw "logMinusOne(-1) = " + result + ", expected NaN";
+    }
+}
+testLogMinusOne();
+
+
+// log(Infinity).
+function logInfinity(antilogarithm) {
+    return Math.log(antilogarithm);
+}
+noInline(logInfinity);
+
+function testLogInfinity() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = logInfinity(Infinity);
+        if (result !== Infinity)
+            throw "logInfinity(Infinity) = " + result + ", expected Infinity";
+    }
+}
+testLogInfinity();
+
+
+// log(-Infinity).
+function logMinusInfinity(antilogarithm) {
+    return Math.log(antilogarithm);
+}
+noInline(logMinusInfinity);
+
+function testLogMinusInfinity() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = logMinusInfinity(-Infinity);
+        if (!isNaN(result))
+            throw "logMinusInfinity(-Infinity) = " + result + ", expected NaN";
+    }
+}
+testLogMinusInfinity();
+
+
+// log(integer).
+function logInteger(antilogarithm) {
+    return Math.log(antilogarithm);
+}
+noInline(logInteger);
+
+function testLogInteger() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = logInteger(42);
+        if (result !== 3.7376696182833684)
+            throw "logInteger(42) = " + result + ", expected 3.7376696182833684";
+    }
+}
+testLogInteger();
+
+
+// log(double).
+function logDouble(antilogarithm) {
+    return Math.log(antilogarithm);
+}
+noInline(logDouble);
+
+function testLogDouble() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = logDouble(Math.PI);
+        if (result !== 1.1447298858494002)
+            throw "logDouble(Math.PI) = " + result + ", expected 1.1447298858494002";
+    }
+}
+testLogDouble();
\ No newline at end of file
diff --git a/Source/JavaScriptCore/tests/stress/math-log-with-constants.js b/Source/JavaScriptCore/tests/stress/math-log-with-constants.js
new file mode 100644
index 0000000..c05a075
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/math-log-with-constants.js
@@ -0,0 +1,128 @@
+// Basic cases of Math.log() when the value passed are constants.
+
+// log(NaN).
+function logNaN() {
+    return Math.log(NaN);
+}
+noInline(logNaN);
+
+function testLogNaN() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = logNaN();
+        if (!isNaN(result))
+            throw "logNaN() = " + result + ", expected NaN";
+    }
+}
+testLogNaN();
+
+
+// log(0).
+function logZero() {
+    return Math.log(0);
+}
+noInline(logZero);
+
+function testLogZero() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = logZero();
+        if (result !== -Infinity)
+            throw "logZero() = " + result + ", expected -Infinity";
+    }
+}
+testLogZero();
+
+
+// log(1).
+function logOne() {
+    return Math.log(1);
+}
+noInline(logOne);
+
+function testLogOne() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = logOne();
+        if (result !== 0)
+            throw "logOne(1) = " + result + ", expected 0";
+    }
+}
+testLogOne();
+
+
+// log(-1).
+function logMinusOne() {
+    return Math.log(-1);
+}
+noInline(logMinusOne);
+
+function testLogMinusOne() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = logMinusOne();
+        if (!isNaN(result))
+            throw "logMinusOne() = " + result + ", expected NaN";
+    }
+}
+testLogMinusOne();
+
+
+// log(Infinity).
+function logInfinity() {
+    return Math.log(Infinity);
+}
+noInline(logInfinity);
+
+function testLogInfinity() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = logInfinity();
+        if (result !== Infinity)
+            throw "logInfinity() = " + result + ", expected Infinity";
+    }
+}
+testLogInfinity();
+
+
+// log(-Infinity).
+function logMinusInfinity() {
+    return Math.log(-Infinity);
+}
+noInline(logMinusInfinity);
+
+function testLogMinusInfinity() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = logMinusInfinity();
+        if (!isNaN(result))
+            throw "logMinusInfinity() = " + result + ", expected NaN";
+    }
+}
+testLogMinusInfinity();
+
+
+// log(integer).
+function logInteger() {
+    return Math.log(42);
+}
+noInline(logInteger);
+
+function testLogInteger() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = logInteger();
+        if (result !== 3.7376696182833684)
+            throw "logInteger() = " + result + ", expected 3.7376696182833684";
+    }
+}
+testLogInteger();
+
+
+// log(double).
+function logDouble() {
+    return Math.log(Math.PI);
+}
+noInline(logDouble);
+
+function testLogDouble() {
+    for (var i = 0; i < 10000; ++i) {
+        var result = logDouble();
+        if (result !== 1.1447298858494002)
+            throw "logDouble() = " + result + ", expected 1.1447298858494002";
+    }
+}
+testLogDouble();
\ No newline at end of file