Title: [183358] trunk
Revision
183358
Author
[email protected]
Date
2015-04-26 12:55:18 -0700 (Sun, 26 Apr 2015)

Log Message

[JSC] Implement Math.clz32(), remove Number.clz()
https://bugs.webkit.org/show_bug.cgi?id=144205

Reviewed by Michael Saboff.

Source/_javascript_Core:

This patch adds the ES6 function Math.clz32(), and remove the non-standard
Number.clz(). Number.clz() probably came from an older draft.

The new function has a corresponding instrinsic: Clz32Intrinsic,
and a corresponding DFG node: ArithClz32, optimized all the way to LLVM.

* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::countLeadingZeros32):
* assembler/X86Assembler.h:
(JSC::X86Assembler::bsr_rr):
The x86 assembler did not have countLeadingZeros32() because there is
no native CLZ instruction on that architecture.

I have added the version with bsr + branches for the case of zero.
An other popular version uses cmov to handle the case of zero. I kept
it simple since the Assembler has no support for cmov.

It is unlikely to matter much. If the code is hot enough, LLVM picks
something good based on the surrounding code.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
Constant handling + effect propagation. The node only produces integer (between 0 and 32).

* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::propagate):
Thanks to the definition of toUint32(), we can ignore plenty of details
from doubles.

* 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):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArithClz32):
* 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::compileArithClz32):
* ftl/FTLOutput.h:
(JSC::FTL::Output::ctlz32):
* jit/ThunkGenerators.cpp:
(JSC::clz32ThunkGenerator):
* jit/ThunkGenerators.h:
* runtime/Intrinsic.h:
* runtime/MathCommon.h:
(JSC::clz32):
Fun fact: InstCombine does not recognize this pattern to eliminate
the branch which makes our FTL version better than the C version.

* runtime/MathObject.cpp:
(JSC::MathObject::finishCreation):
(JSC::mathProtoFuncClz32):
* runtime/NumberPrototype.cpp:
(JSC::clz): Deleted.
(JSC::numberProtoFuncClz): Deleted.
* runtime/VM.cpp:
(JSC::thunkGeneratorForIntrinsic):
* tests/stress/math-clz32-basics.js: Added.
(mathClz32OnInteger):
(testMathClz32OnIntegers):
(verifyMathClz32OnIntegerWithOtherTypes):
(mathClz32OnDouble):
(testMathClz32OnDoubles):
(verifyMathClz32OnDoublesWithOtherTypes):
(mathClz32NoArguments):
(mathClz32TooManyArguments):
(testMathClz32OnConstants):
(mathClz32StructTransition):
(Math.clz32):

LayoutTests:

Basic conformance tests.

* js/Object-getOwnPropertyNames-expected.txt:
* js/math-clz32-expected.txt: Added.
* js/math-clz32.html: Renamed from LayoutTests/js/number-clz.html.
* js/number-clz-expected.txt: Removed.
* js/script-tests/Object-getOwnPropertyNames.js:
* js/script-tests/math-clz32.js: Added.
(objectConvertToString.toString):
(objectRecordToStringCall.toString):
(objectThrowOnToString.toString):
(objectWithValueOf.valueOf):
(objectThrowOnValueOf.valueOf):
(objectThrowOnValueOf.toString):
(objectRecordValueOfCall.valueOf):
(objectRecordConversionCalls.toString):
(objectRecordConversionCalls.valueOf):
* js/script-tests/number-clz.js: Removed.

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (183357 => 183358)


--- trunk/LayoutTests/ChangeLog	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/LayoutTests/ChangeLog	2015-04-26 19:55:18 UTC (rev 183358)
@@ -1,3 +1,29 @@
+2015-04-26  Benjamin Poulain  <[email protected]>
+
+        [JSC] Implement Math.clz32(), remove Number.clz()
+        https://bugs.webkit.org/show_bug.cgi?id=144205
+
+        Reviewed by Michael Saboff.
+
+        Basic conformance tests.
+
+        * js/Object-getOwnPropertyNames-expected.txt:
+        * js/math-clz32-expected.txt: Added.
+        * js/math-clz32.html: Renamed from LayoutTests/js/number-clz.html.
+        * js/number-clz-expected.txt: Removed.
+        * js/script-tests/Object-getOwnPropertyNames.js:
+        * js/script-tests/math-clz32.js: Added.
+        (objectConvertToString.toString):
+        (objectRecordToStringCall.toString):
+        (objectThrowOnToString.toString):
+        (objectWithValueOf.valueOf):
+        (objectThrowOnValueOf.valueOf):
+        (objectThrowOnValueOf.toString):
+        (objectRecordValueOfCall.valueOf):
+        (objectRecordConversionCalls.toString):
+        (objectRecordConversionCalls.valueOf):
+        * js/script-tests/number-clz.js: Removed.
+
 2015-04-26  Yusuke Suzuki  <[email protected]>
 
         [ES6] Array.from need to accept iterables

Modified: trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt (183357 => 183358)


--- trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt	2015-04-26 19:55:18 UTC (rev 183358)
@@ -52,14 +52,14 @@
 PASS getSortedOwnPropertyNames(Boolean) is ['length', 'name', 'prototype']
 PASS getSortedOwnPropertyNames(Boolean.prototype) is ['constructor', 'toString', 'valueOf']
 PASS getSortedOwnPropertyNames(Number) is ['EPSILON', 'MAX_SAFE_INTEGER', 'MAX_VALUE', 'MIN_SAFE_INTEGER', 'MIN_VALUE', 'NEGATIVE_INFINITY', 'NaN', 'POSITIVE_INFINITY', 'isFinite', 'isInteger', 'isNaN', 'isSafeInteger', 'length', 'name', 'parseFloat', 'parseInt', 'prototype']
-PASS getSortedOwnPropertyNames(Number.prototype) is ['clz', 'constructor', 'toExponential', 'toFixed', 'toLocaleString', 'toPrecision', 'toString', 'valueOf']
+PASS getSortedOwnPropertyNames(Number.prototype) is ['constructor', 'toExponential', 'toFixed', 'toLocaleString', 'toPrecision', 'toString', 'valueOf']
 PASS getSortedOwnPropertyNames(Date) is ['UTC', 'length', 'name', 'now', 'parse', 'prototype']
 PASS getSortedOwnPropertyNames(Date.prototype) is ['constructor', 'getDate', 'getDay', 'getFullYear', 'getHours', 'getMilliseconds', 'getMinutes', 'getMonth', 'getSeconds', 'getTime', 'getTimezoneOffset', 'getUTCDate', 'getUTCDay', 'getUTCFullYear', 'getUTCHours', 'getUTCMilliseconds', 'getUTCMinutes', 'getUTCMonth', 'getUTCSeconds', 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds', 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear', 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds', 'setYear', 'toDateString', 'toGMTString', 'toISOString', 'toJSON', 'toLocaleDateString', 'toLocaleString', 'toLocaleTimeString', 'toString', 'toTimeString', 'toUTCString', 'valueOf']
 PASS getSortedOwnPropertyNames(RegExp) is ['$&', "$'", '$*', '$+', '$1', '$2', '$3', '$4', '$5', '$6', '$7', '$8', '$9', '$_', '$`', 'input', 'lastMatch', 'lastParen', 'leftContext', 'length', 'multiline', 'name', 'prototype', 'rightContext']
 PASS getSortedOwnPropertyNames(RegExp.prototype) is ['compile', 'constructor', 'exec', 'global', 'ignoreCase', 'lastIndex', 'multiline', 'source', 'test', 'toString']
 PASS getSortedOwnPropertyNames(Error) is ['length', 'name', 'prototype']
 PASS getSortedOwnPropertyNames(Error.prototype) is ['constructor', 'message', 'name', 'toString']
-PASS getSortedOwnPropertyNames(Math) is ['E','LN10','LN2','LOG10E','LOG2E','PI','SQRT1_2','SQRT2','abs','acos','acosh','asin','asinh','atan','atan2','atanh','cbrt','ceil','cos','cosh','exp','expm1','floor','fround','hypot','imul','log','log10','log1p','log2','max','min','pow','random','round','sign','sin','sinh','sqrt','tan','tanh','trunc']
+PASS getSortedOwnPropertyNames(Math) is ['E','LN10','LN2','LOG10E','LOG2E','PI','SQRT1_2','SQRT2','abs','acos','acosh','asin','asinh','atan','atan2','atanh','cbrt','ceil','clz32','cos','cosh','exp','expm1','floor','fround','hypot','imul','log','log10','log1p','log2','max','min','pow','random','round','sign','sin','sinh','sqrt','tan','tanh','trunc']
 PASS getSortedOwnPropertyNames(JSON) is ['parse', 'stringify']
 PASS getSortedOwnPropertyNames(Symbol) is ['for', 'iterator', 'keyFor', 'length', 'name', 'prototype', 'unscopables']
 PASS getSortedOwnPropertyNames(Symbol.prototype) is ['constructor', 'toString', 'valueOf']

Added: trunk/LayoutTests/js/math-clz32-expected.txt (0 => 183358)


--- trunk/LayoutTests/js/math-clz32-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/math-clz32-expected.txt	2015-04-26 19:55:18 UTC (rev 183358)
@@ -0,0 +1,49 @@
+Test the basic behaviors of Math.clz32()
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Math.hasOwnProperty("clz32") is true
+PASS typeof Math.clz32 is "function"
+PASS Object.getPrototypeOf(Math).clz32 is undefined
+PASS Math.clz32.length is 1
+PASS Math.clz32.name is "clz32"
+PASS Object.getOwnPropertyDescriptor(Math, "clz32").configurable is true
+PASS Object.getOwnPropertyDescriptor(Math, "clz32").enumerable is false
+PASS Object.getOwnPropertyDescriptor(Math, "clz32").writable is true
+PASS Math.clz32(0) is 32
+PASS Math.clz32(-0) is 32
+PASS Math.clz32(1) is 31
+PASS Math.clz32(-1) is 0
+PASS Math.clz32(42) is 26
+PASS Math.clz32(-2147483648) is 0
+PASS Math.clz32(2147483647) is 1
+PASS Math.clz32(Number.MAX_VALUE) is 32
+PASS Math.clz32(Number.MIN_VALUE) is 32
+PASS Math.clz32(Number.MAX_SAFE_INTEGER) is 0
+PASS Math.clz32(Number.MIN_SAFE_INTEGER) is 31
+PASS Math.clz32(Math.PI) is 30
+PASS Math.clz32(Math.E) is 30
+PASS Math.clz32(NaN) is 32
+PASS Math.clz32(Number.POSITIVE_INFINITI) is 32
+PASS Math.clz32(Number.NEGATIVE_INFINITI) is 32
+PASS Math.clz32() is 32
+PASS Math.clz32(undefined) is 32
+PASS Math.clz32(null) is 32
+PASS Math.clz32("WebKit") is 32
+PASS Math.clz32(Symbol("WebKit")) threw exception TypeError: Type error.
+PASS Math.clz32({ webkit: "awesome" }) is 32
+PASS Math.clz32(objectConvertToString) is 25
+PASS Math.clz32(objectRecordToStringCall) is 28
+PASS objectRecordToStringCall.toStringCallCount is 1
+PASS Math.clz32(objectThrowOnToString) threw exception No!.
+PASS Math.clz32(objectWithValueOf) is 15
+PASS Math.clz32(objectThrowOnValueOf) threw exception Nope!.
+PASS Math.clz32(objectRecordValueOfCall) is 23
+PASS objectRecordValueOfCall.valueOfCallCount is 1
+PASS Math.clz32(objectRecordConversionCalls) is 15
+PASS objectRecordConversionCalls.callList.toString() is "valueOf"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/math-clz32.html (0 => 183358)


--- trunk/LayoutTests/js/math-clz32.html	                        (rev 0)
+++ trunk/LayoutTests/js/math-clz32.html	2015-04-26 19:55:18 UTC (rev 183358)
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<meta charset="utf-8">
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+</body>
+</html>

Deleted: trunk/LayoutTests/js/number-clz-expected.txt (183357 => 183358)


--- trunk/LayoutTests/js/number-clz-expected.txt	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/LayoutTests/js/number-clz-expected.txt	2015-04-26 19:55:18 UTC (rev 183358)
@@ -1,15 +0,0 @@
-PASS Number(Infinity).clz() is Infinity
-PASS Number(-Infinity).clz() is -Infinity
-PASS Number(NaN).clz() is NaN
-PASS Number(0).clz() is 32
-PASS Number(1).clz() is 31
-PASS Number(2147483648).clz() is 0
-PASS Number(2147483647).clz() is 1
-PASS Number(1073741824).clz() is 1
-PASS Number(1073741823).clz() is 2
-PASS Number(32768).clz() is 16
-PASS Number(32767).clz() is 17
-PASS successfullyParsed is true
-
-TEST COMPLETE
-

Deleted: trunk/LayoutTests/js/number-clz.html (183357 => 183358)


--- trunk/LayoutTests/js/number-clz.html	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/LayoutTests/js/number-clz.html	2015-04-26 19:55:18 UTC (rev 183358)
@@ -1,10 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src=""
-</head>
-<body>
-<script src=""
-<script src=""
-</body>
-</html>

Modified: trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js (183357 => 183358)


--- trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js	2015-04-26 19:55:18 UTC (rev 183358)
@@ -61,14 +61,14 @@
     "Boolean": "['length', 'name', 'prototype']",
     "Boolean.prototype": "['constructor', 'toString', 'valueOf']",
     "Number": "['EPSILON', 'MAX_SAFE_INTEGER', 'MAX_VALUE', 'MIN_SAFE_INTEGER', 'MIN_VALUE', 'NEGATIVE_INFINITY', 'NaN', 'POSITIVE_INFINITY', 'isFinite', 'isInteger', 'isNaN', 'isSafeInteger', 'length', 'name', 'parseFloat', 'parseInt', 'prototype']",
-    "Number.prototype": "['clz', 'constructor', 'toExponential', 'toFixed', 'toLocaleString', 'toPrecision', 'toString', 'valueOf']",
+    "Number.prototype": "['constructor', 'toExponential', 'toFixed', 'toLocaleString', 'toPrecision', 'toString', 'valueOf']",
     "Date": "['UTC', 'length', 'name', 'now', 'parse', 'prototype']",
     "Date.prototype": "['constructor', 'getDate', 'getDay', 'getFullYear', 'getHours', 'getMilliseconds', 'getMinutes', 'getMonth', 'getSeconds', 'getTime', 'getTimezoneOffset', 'getUTCDate', 'getUTCDay', 'getUTCFullYear', 'getUTCHours', 'getUTCMilliseconds', 'getUTCMinutes', 'getUTCMonth', 'getUTCSeconds', 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds', 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear', 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds', 'setYear', 'toDateString', 'toGMTString', 'toISOString', 'toJSON', 'toLocaleDateString', 'toLocaleString', 'toLocaleTimeString', 'toString', 'toTimeString', 'toUTCString', 'valueOf']",
     "RegExp": "['$&', \"$'\", '$*', '$+', '$1', '$2', '$3', '$4', '$5', '$6', '$7', '$8', '$9', '$_', '$`', 'input', 'lastMatch', 'lastParen', 'leftContext', 'length', 'multiline', 'name', 'prototype', 'rightContext']",
     "RegExp.prototype": "['compile', 'constructor', 'exec', 'global', 'ignoreCase', 'lastIndex', 'multiline', 'source', 'test', 'toString']",
     "Error": "['length', 'name', 'prototype']",
     "Error.prototype": "['constructor', 'message', 'name', 'toString']",
-    "Math": "['E','LN10','LN2','LOG10E','LOG2E','PI','SQRT1_2','SQRT2','abs','acos','acosh','asin','asinh','atan','atan2','atanh','cbrt','ceil','cos','cosh','exp','expm1','floor','fround','hypot','imul','log','log10','log1p','log2','max','min','pow','random','round','sign','sin','sinh','sqrt','tan','tanh','trunc']",
+    "Math": "['E','LN10','LN2','LOG10E','LOG2E','PI','SQRT1_2','SQRT2','abs','acos','acosh','asin','asinh','atan','atan2','atanh','cbrt','ceil','clz32','cos','cosh','exp','expm1','floor','fround','hypot','imul','log','log10','log1p','log2','max','min','pow','random','round','sign','sin','sinh','sqrt','tan','tanh','trunc']",
     "JSON": "['parse', 'stringify']",
     "Symbol": "['for', 'iterator', 'keyFor', 'length', 'name', 'prototype', 'unscopables']",
     "Symbol.prototype": "['constructor', 'toString', 'valueOf']"

Added: trunk/LayoutTests/js/script-tests/math-clz32.js (0 => 183358)


--- trunk/LayoutTests/js/script-tests/math-clz32.js	                        (rev 0)
+++ trunk/LayoutTests/js/script-tests/math-clz32.js	2015-04-26 19:55:18 UTC (rev 183358)
@@ -0,0 +1,75 @@
+description("Test the basic behaviors of Math.clz32()");
+
+shouldBeTrue('Math.hasOwnProperty("clz32")');
+shouldBeEqualToString('typeof Math.clz32', 'function');
+shouldBe('Object.getPrototypeOf(Math).clz32', 'undefined');
+
+// Function properties.
+shouldBe('Math.clz32.length', '1');
+shouldBeEqualToString('Math.clz32.name', 'clz32')
+shouldBe('Object.getOwnPropertyDescriptor(Math, "clz32").configurable', 'true');
+shouldBe('Object.getOwnPropertyDescriptor(Math, "clz32").enumerable', 'false');
+shouldBe('Object.getOwnPropertyDescriptor(Math, "clz32").writable', 'true');
+
+// Some simple cases.
+shouldBe('Math.clz32(0)', '32');
+shouldBe('Math.clz32(-0)', '32');
+shouldBe('Math.clz32(1)', '31');
+shouldBe('Math.clz32(-1)', '0');
+shouldBe('Math.clz32(42)', '26');
+shouldBe('Math.clz32(-2147483648)', '0');
+shouldBe('Math.clz32(2147483647)', '1');
+
+shouldBe('Math.clz32(Number.MAX_VALUE)', '32');
+shouldBe('Math.clz32(Number.MIN_VALUE)', '32');
+shouldBe('Math.clz32(Number.MAX_SAFE_INTEGER)', '0');
+shouldBe('Math.clz32(Number.MIN_SAFE_INTEGER)', '31');
+
+shouldBe('Math.clz32(Math.PI)', '30');
+shouldBe('Math.clz32(Math.E)', '30');
+shouldBe('Math.clz32(NaN)', '32');
+shouldBe('Math.clz32(Number.POSITIVE_INFINITI)', '32');
+shouldBe('Math.clz32(Number.NEGATIVE_INFINITI)', '32');
+
+shouldBe('Math.clz32()', '32');
+shouldBe('Math.clz32(undefined)', '32');
+shouldBe('Math.clz32(null)', '32');
+shouldBe('Math.clz32("WebKit")', '32');
+shouldThrow('Math.clz32(Symbol("WebKit"))');
+shouldBe('Math.clz32({ webkit: "awesome" })', '32');
+
+// Type conversion.
+var objectConvertToString = { toString: function() { return "66"; } };
+shouldBe('Math.clz32(objectConvertToString)', '25');
+
+var objectRecordToStringCall = { toStringCallCount: 0, toString: function() { this.toStringCallCount += 1; return "9"; } };
+shouldBe('Math.clz32(objectRecordToStringCall)', '28');
+shouldBe('objectRecordToStringCall.toStringCallCount', '1');
+
+var objectThrowOnToString = { toString: function() { throw "No!"; } };
+shouldThrow('Math.clz32(objectThrowOnToString)');
+
+var objectWithValueOf = { valueOf: function() { return 95014; } };
+shouldBe('Math.clz32(objectWithValueOf)', '15');
+
+var objectThrowOnValueOf = { valueOf: function() { throw "Nope!" }, toString: function() { return 5; } };
+shouldThrow('Math.clz32(objectThrowOnValueOf)');
+
+
+var objectRecordValueOfCall = { valueOfCallCount: 0, valueOf: function() { ++this.valueOfCallCount; return 436; } }
+shouldBe('Math.clz32(objectRecordValueOfCall)', '23');
+shouldBe('objectRecordValueOfCall.valueOfCallCount', '1');
+
+var objectRecordConversionCalls = {
+    callList: [],
+    toString: function() {
+        this.callList.push("toString");
+        return "Uh?";
+    },
+    valueOf: function() {
+        this.callList.push("valueOf");
+        return 87665;
+    }
+};
+shouldBe('Math.clz32(objectRecordConversionCalls)', '15');
+shouldBe('objectRecordConversionCalls.callList.toString()', '"valueOf"');
\ No newline at end of file

Deleted: trunk/LayoutTests/js/script-tests/number-clz.js (183357 => 183358)


--- trunk/LayoutTests/js/script-tests/number-clz.js	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/LayoutTests/js/script-tests/number-clz.js	2015-04-26 19:55:18 UTC (rev 183358)
@@ -1,11 +0,0 @@
-shouldBe("Number(Infinity).clz()","Infinity");
-shouldBe("Number(-Infinity).clz()","-Infinity");
-shouldBe("Number(NaN).clz()","NaN");
-shouldBe("Number(0).clz()","32");
-shouldBe("Number(1).clz()","31");
-shouldBe("Number(2147483648).clz()","0");
-shouldBe("Number(2147483647).clz()","1");
-shouldBe("Number(1073741824).clz()","1");
-shouldBe("Number(1073741823).clz()","2");
-shouldBe("Number(32768).clz()","16");
-shouldBe("Number(32767).clz()","17");

Modified: trunk/Source/_javascript_Core/ChangeLog (183357 => 183358)


--- trunk/Source/_javascript_Core/ChangeLog	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-04-26 19:55:18 UTC (rev 183358)
@@ -1,3 +1,97 @@
+2015-04-26  Benjamin Poulain  <[email protected]>
+
+        [JSC] Implement Math.clz32(), remove Number.clz()
+        https://bugs.webkit.org/show_bug.cgi?id=144205
+
+        Reviewed by Michael Saboff.
+
+        This patch adds the ES6 function Math.clz32(), and remove the non-standard
+        Number.clz(). Number.clz() probably came from an older draft.
+
+        The new function has a corresponding instrinsic: Clz32Intrinsic,
+        and a corresponding DFG node: ArithClz32, optimized all the way to LLVM.
+
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::countLeadingZeros32):
+        * assembler/X86Assembler.h:
+        (JSC::X86Assembler::bsr_rr):
+        The x86 assembler did not have countLeadingZeros32() because there is
+        no native CLZ instruction on that architecture.
+
+        I have added the version with bsr + branches for the case of zero.
+        An other popular version uses cmov to handle the case of zero. I kept
+        it simple since the Assembler has no support for cmov.
+
+        It is unlikely to matter much. If the code is hot enough, LLVM picks
+        something good based on the surrounding code.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        Constant handling + effect propagation. The node only produces integer (between 0 and 32).
+
+        * dfg/DFGBackwardsPropagationPhase.cpp:
+        (JSC::DFG::BackwardsPropagationPhase::propagate):
+        Thanks to the definition of toUint32(), we can ignore plenty of details
+        from doubles.
+
+        * 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):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileArithClz32):
+        * 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::compileArithClz32):
+        * ftl/FTLOutput.h:
+        (JSC::FTL::Output::ctlz32):
+        * jit/ThunkGenerators.cpp:
+        (JSC::clz32ThunkGenerator):
+        * jit/ThunkGenerators.h:
+        * runtime/Intrinsic.h:
+        * runtime/MathCommon.h:
+        (JSC::clz32):
+        Fun fact: InstCombine does not recognize this pattern to eliminate
+        the branch which makes our FTL version better than the C version.
+
+        * runtime/MathObject.cpp:
+        (JSC::MathObject::finishCreation):
+        (JSC::mathProtoFuncClz32):
+        * runtime/NumberPrototype.cpp:
+        (JSC::clz): Deleted.
+        (JSC::numberProtoFuncClz): Deleted.
+        * runtime/VM.cpp:
+        (JSC::thunkGeneratorForIntrinsic):
+        * tests/stress/math-clz32-basics.js: Added.
+        (mathClz32OnInteger):
+        (testMathClz32OnIntegers):
+        (verifyMathClz32OnIntegerWithOtherTypes):
+        (mathClz32OnDouble):
+        (testMathClz32OnDoubles):
+        (verifyMathClz32OnDoublesWithOtherTypes):
+        (mathClz32NoArguments):
+        (mathClz32TooManyArguments):
+        (testMathClz32OnConstants):
+        (mathClz32StructTransition):
+        (Math.clz32):
+
 2015-04-26  Yusuke Suzuki  <[email protected]>
 
         [ES6] Array.from need to accept iterables

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h (183357 => 183358)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h	2015-04-26 19:55:18 UTC (rev 183358)
@@ -183,6 +183,18 @@
         and32(imm, dest);
     }
 
+    void countLeadingZeros32(RegisterID src, RegisterID dst)
+    {
+        m_assembler.bsr_rr(src, dst);
+        Jump srcIsNonZero = m_assembler.jCC(x86Condition(NonZero));
+        move(TrustedImm32(32), dst);
+
+        Jump skipNonZeroCase = jump();
+        srcIsNonZero.link(this);
+        xor32(TrustedImm32(0x1f), dst);
+        skipNonZeroCase.link(this);
+    }
+
     void lshift32(RegisterID shift_amount, RegisterID dest)
     {
         ASSERT(shift_amount != dest);

Modified: trunk/Source/_javascript_Core/assembler/X86Assembler.h (183357 => 183358)


--- trunk/Source/_javascript_Core/assembler/X86Assembler.h	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/assembler/X86Assembler.h	2015-04-26 19:55:18 UTC (rev 183358)
@@ -263,6 +263,7 @@
         OP2_3BYTE_ESCAPE    = 0xAE,
         OP2_IMUL_GvEv       = 0xAF,
         OP2_MOVZX_GvEb      = 0xB6,
+        OP2_BSR             = 0xBD,
         OP2_MOVSX_GvEb      = 0xBE,
         OP2_MOVZX_GvEw      = 0xB7,
         OP2_MOVSX_GvEw      = 0xBF,
@@ -820,6 +821,11 @@
 
 #endif
 
+    void bsr_rr(RegisterID src, RegisterID dst)
+    {
+        m_formatter.twoByteOp(OP2_BSR, dst, src);
+    }
+
     void sarl_i8r(int imm, RegisterID dst)
     {
         if (imm == 1)

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (183357 => 183358)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2015-04-26 19:55:18 UTC (rev 183358)
@@ -425,7 +425,18 @@
         }
         break;
     }
-        
+
+    case ArithClz32: {
+        JSValue operand = forNode(node->child1()).value();
+        if (operand && operand.isNumber()) {
+            uint32_t value = toUInt32(operand.asNumber());
+            setConstant(node, jsNumber(clz32(value)));
+            break;
+        }
+        forNode(node).setType(SpecInt32);
+        break;
+    }
+
     case MakeRope: {
         forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
         break;

Modified: trunk/Source/_javascript_Core/dfg/DFGBackwardsPropagationPhase.cpp (183357 => 183358)


--- trunk/Source/_javascript_Core/dfg/DFGBackwardsPropagationPhase.cpp	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/dfg/DFGBackwardsPropagationPhase.cpp	2015-04-26 19:55:18 UTC (rev 183358)
@@ -259,7 +259,14 @@
             node->child2()->mergeFlags(flags);
             break;
         }
-            
+
+        case ArithClz32: {
+            flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther | ~NodeBytecodeUsesAsArrayIndex);
+            flags |= NodeBytecodeUsesAsInt;
+            node->child1()->mergeFlags(flags);
+            break;
+        }
+
         case ArithSub: {
             if (isNotNegZero(node->child1().node()) || isNotPosZero(node->child2().node()))
                 flags &= ~NodeBytecodeNeedsNegZero;

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (183357 => 183358)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2015-04-26 19:55:18 UTC (rev 183358)
@@ -2000,6 +2000,16 @@
         set(VirtualRegister(resultOperand), charCode);
         return true;
     }
+    case Clz32Intrinsic: {
+        insertChecks();
+        if (argumentCountIncludingThis == 1)
+            set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_graph.freeze(jsNumber(32)))));
+        else {
+            Node* operand = get(virtualRegisterForArgument(1, registerOffset));
+            set(VirtualRegister(resultOperand), addToGraph(ArithClz32, operand));
+        }
+        return true;
+    }
     case FromCharCodeIntrinsic: {
         if (argumentCountIncludingThis != 2)
             return false;

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (183357 => 183358)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2015-04-26 19:55:18 UTC (rev 183358)
@@ -129,6 +129,7 @@
     case BitURShift:
     case ArithIMul:
     case ArithAbs:
+    case ArithClz32:
     case ArithMin:
     case ArithMax:
     case ArithPow:

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (183357 => 183358)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2015-04-26 19:55:18 UTC (rev 183358)
@@ -72,6 +72,7 @@
     case UInt32ToNumber:
     case DoubleAsInt32:
     case ArithAdd:
+    case ArithClz32:
     case ArithSub:
     case ArithNegate:
     case ArithMul:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (183357 => 183358)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2015-04-26 19:55:18 UTC (rev 183358)
@@ -119,6 +119,12 @@
             node->child2().setUseKind(Int32Use);
             break;
         }
+
+        case ArithClz32: {
+            fixIntConvertingEdge(node->child1());
+            node->setArithMode(Arith::Unchecked);
+            break;
+        }
             
         case UInt32ToNumber: {
             fixIntConvertingEdge(node->child1());

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (183357 => 183358)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2015-04-26 19:55:18 UTC (rev 183358)
@@ -132,6 +132,7 @@
     \
     /* Nodes for arithmetic operations. */\
     macro(ArithAdd, NodeResultNumber) \
+    macro(ArithClz32, NodeResultInt32) \
     macro(ArithSub, NodeResultNumber) \
     macro(ArithNegate, NodeResultNumber) \
     macro(ArithMul, NodeResultNumber) \

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (183357 => 183358)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2015-04-26 19:55:18 UTC (rev 183358)
@@ -178,7 +178,8 @@
         case BitRShift:
         case BitLShift:
         case BitURShift:
-        case ArithIMul: {
+        case ArithIMul:
+        case ArithClz32: {
             changed |= setPrediction(SpecInt32);
             break;
         }

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (183357 => 183358)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2015-04-26 19:55:18 UTC (rev 183358)
@@ -142,6 +142,7 @@
     case UInt32ToNumber:
     case DoubleAsInt32:
     case ArithAdd:
+    case ArithClz32:
     case ArithSub:
     case ArithNegate:
     case ArithMul:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (183357 => 183358)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2015-04-26 19:55:18 UTC (rev 183358)
@@ -2821,6 +2821,17 @@
     cellResult(resultGPR, node);
 }
 
+void SpeculativeJIT::compileArithClz32(Node* node)
+{
+    ASSERT_WITH_MESSAGE(node->child1().useKind() == Int32Use || node->child1().useKind() == KnownInt32Use, "The Fixup phase should have enforced a Int32 operand.");
+    SpeculateInt32Operand value(this, node->child1());
+    GPRTemporary result(this, Reuse, value);
+    GPRReg valueReg = value.gpr();
+    GPRReg resultReg = result.gpr();
+    m_jit.countLeadingZeros32(valueReg, resultReg);
+    int32Result(resultReg, node);
+}
+
 void SpeculativeJIT::compileArithSub(Node* node)
 {
     switch (node->binaryUseKind()) {

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (183357 => 183358)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2015-04-26 19:55:18 UTC (rev 183358)
@@ -2182,6 +2182,7 @@
     void compileDoubleAsInt32(Node*);
     void compileAdd(Node*);
     void compileMakeRope(Node*);
+    void compileArithClz32(Node*);
     void compileArithSub(Node*);
     void compileArithNegate(Node*);
     void compileArithMul(Node*);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (183357 => 183358)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2015-04-26 19:55:18 UTC (rev 183358)
@@ -2011,6 +2011,10 @@
         compileAdd(node);
         break;
 
+    case ArithClz32:
+        compileArithClz32(node);
+        break;
+
     case MakeRope:
         compileMakeRope(node);
         break;

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (183357 => 183358)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2015-04-26 19:55:18 UTC (rev 183358)
@@ -2153,6 +2153,10 @@
     case ArithAdd:
         compileAdd(node);
         break;
+
+    case ArithClz32:
+        compileArithClz32(node);
+        break;
         
     case MakeRope:
         compileMakeRope(node);

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (183357 => 183358)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2015-04-26 19:55:18 UTC (rev 183358)
@@ -79,6 +79,7 @@
     case PutGlobalVar:
     case ValueAdd:
     case ArithAdd:
+    case ArithClz32:
     case ArithSub:
     case ArithMul:
     case ArithDiv:

Modified: trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h (183357 => 183358)


--- trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/ftl/FTLIntrinsicRepository.h	2015-04-26 19:55:18 UTC (rev 183358)
@@ -35,6 +35,7 @@
 namespace JSC { namespace FTL {
 
 #define FOR_EACH_FTL_INTRINSIC(macro) \
+    macro(ctlz32, "llvm.ctlz.i32", functionType(int32, int32, boolean)) \
     macro(addWithOverflow32, "llvm.sadd.with.overflow.i32", functionType(structType(m_context, int32, boolean), int32, int32)) \
     macro(addWithOverflow64, "llvm.sadd.with.overflow.i64", functionType(structType(m_context, int64, boolean), int64, int64)) \
     macro(doubleAbs, "llvm.fabs.f64", functionType(doubleType, doubleType)) \

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (183357 => 183358)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-04-26 19:55:18 UTC (rev 183358)
@@ -478,6 +478,9 @@
         case ArithSub:
             compileArithAddOrSub();
             break;
+        case ArithClz32:
+            compileArithClz32();
+            break;
         case ArithMul:
             compileArithMul();
             break;
@@ -1319,6 +1322,13 @@
             break;
         }
     }
+
+    void compileArithClz32()
+    {
+        LValue operand = lowInt32(m_node->child1());
+        LValue isZeroUndef = m_out.booleanFalse;
+        setInt32(m_out.ctlz32(operand, isZeroUndef));
+    }
     
     void compileArithMul()
     {

Modified: trunk/Source/_javascript_Core/ftl/FTLOutput.h (183357 => 183358)


--- trunk/Source/_javascript_Core/ftl/FTLOutput.h	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/ftl/FTLOutput.h	2015-04-26 19:55:18 UTC (rev 183358)
@@ -138,7 +138,11 @@
     LValue bitNot(LValue value) { return buildNot(m_builder, value); }
     
     LValue insertElement(LValue vector, LValue element, LValue index) { return buildInsertElement(m_builder, vector, element, index); }
-    
+
+    LValue ctlz32(LValue xOperand, LValue yOperand)
+    {
+        return call(ctlz32Intrinsic(), xOperand, yOperand);
+    }
     LValue addWithOverflow32(LValue left, LValue right)
     {
         return call(addWithOverflow32Intrinsic(), left, right);

Modified: trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp (183357 => 183358)


--- trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp	2015-04-26 19:55:18 UTC (rev 183358)
@@ -646,6 +646,27 @@
     return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "fromCharCode");
 }
 
+MacroAssemblerCodeRef clz32ThunkGenerator(VM* vm)
+{
+    SpecializedThunkJIT jit(vm, 1);
+    MacroAssembler::Jump nonIntArgJump;
+    jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntArgJump);
+
+    SpecializedThunkJIT::Label convertedArgumentReentry(&jit);
+    jit.countLeadingZeros32(SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1);
+    jit.returnInt32(SpecializedThunkJIT::regT1);
+
+    if (jit.supportsFloatingPointTruncate()) {
+        nonIntArgJump.link(&jit);
+        jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
+        jit.branchTruncateDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::BranchIfTruncateSuccessful).linkTo(convertedArgumentReentry, &jit);
+        jit.appendFailure(jit.jump());
+    } else
+        jit.appendFailure(nonIntArgJump);
+
+    return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "clz32");
+}
+
 MacroAssemblerCodeRef sqrtThunkGenerator(VM* vm)
 {
     SpecializedThunkJIT jit(vm, 1);

Modified: trunk/Source/_javascript_Core/jit/ThunkGenerators.h (183357 => 183358)


--- trunk/Source/_javascript_Core/jit/ThunkGenerators.h	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/jit/ThunkGenerators.h	2015-04-26 19:55:18 UTC (rev 183358)
@@ -120,6 +120,7 @@
 
 MacroAssemblerCodeRef charCodeAtThunkGenerator(VM*);
 MacroAssemblerCodeRef charAtThunkGenerator(VM*);
+MacroAssemblerCodeRef clz32ThunkGenerator(VM*);
 MacroAssemblerCodeRef fromCharCodeThunkGenerator(VM*);
 MacroAssemblerCodeRef absThunkGenerator(VM*);
 MacroAssemblerCodeRef ceilThunkGenerator(VM*);

Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.h (183357 => 183358)


--- trunk/Source/_javascript_Core/runtime/Intrinsic.h	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.h	2015-04-26 19:55:18 UTC (rev 183358)
@@ -35,6 +35,7 @@
     MaxIntrinsic,
     SqrtIntrinsic,
     SinIntrinsic,
+    Clz32Intrinsic,
     CosIntrinsic,
     ArrayPushIntrinsic,
     ArrayPopIntrinsic,

Modified: trunk/Source/_javascript_Core/runtime/MathCommon.h (183357 => 183358)


--- trunk/Source/_javascript_Core/runtime/MathCommon.h	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/runtime/MathCommon.h	2015-04-26 19:55:18 UTC (rev 183358)
@@ -34,6 +34,26 @@
 
 namespace JSC {
 double JIT_OPERATION operationMathPow(double x, double y) WTF_INTERNAL;
+
+inline int clz32(uint32_t number)
+{
+#if COMPILER(GCC) || COMPILER(CLANG)
+    int zeroCount = 32;
+    if (number)
+        zeroCount = __builtin_clz(number);
+    return zeroCount;
+#else
+    int zeroCount = 0;
+    for (int i = 31; i >= 0; i--) {
+        if (!(number >> i))
+            zeroCount++;
+        else
+            break;
+    }
+    return zeroCount;
+#endif
 }
 
+}
+
 #endif // MathCommon_h

Modified: trunk/Source/_javascript_Core/runtime/MathObject.cpp (183357 => 183358)


--- trunk/Source/_javascript_Core/runtime/MathObject.cpp	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/runtime/MathObject.cpp	2015-04-26 19:55:18 UTC (rev 183358)
@@ -46,6 +46,7 @@
 EncodedJSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState*);
 EncodedJSValue JSC_HOST_CALL mathProtoFuncCbrt(ExecState*);
 EncodedJSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState*);
+EncodedJSValue JSC_HOST_CALL mathProtoFuncClz32(ExecState*);
 EncodedJSValue JSC_HOST_CALL mathProtoFuncCos(ExecState*);
 EncodedJSValue JSC_HOST_CALL mathProtoFuncCosh(ExecState*);
 EncodedJSValue JSC_HOST_CALL mathProtoFuncExp(ExecState*);
@@ -106,6 +107,7 @@
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "atan2"), 2, mathProtoFuncATan2, NoIntrinsic, DontEnum | Function);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "cbrt"), 1, mathProtoFuncCbrt, NoIntrinsic, DontEnum | Function);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "ceil"), 1, mathProtoFuncCeil, CeilIntrinsic, DontEnum | Function);
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "clz32"), 1, mathProtoFuncClz32, Clz32Intrinsic, DontEnum | Function);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "cos"), 1, mathProtoFuncCos, CosIntrinsic, DontEnum | Function);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "cosh"), 1, mathProtoFuncCosh, NoIntrinsic, DontEnum | Function);
     putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, "exp"), 1, mathProtoFuncExp, ExpIntrinsic, DontEnum | Function);
@@ -166,6 +168,14 @@
     return JSValue::encode(jsNumber(ceil(exec->argument(0).toNumber(exec))));
 }
 
+EncodedJSValue JSC_HOST_CALL mathProtoFuncClz32(ExecState* exec)
+{
+    uint32_t value = exec->argument(0).toUInt32(exec);
+    if (exec->hadException())
+        return JSValue::encode(jsNull());
+    return JSValue::encode(JSValue(clz32(value)));
+}
+
 EncodedJSValue JSC_HOST_CALL mathProtoFuncCos(ExecState* exec)
 {
     return JSValue::encode(jsDoubleNumber(cos(exec->argument(0).toNumber(exec))));

Modified: trunk/Source/_javascript_Core/runtime/NumberPrototype.cpp (183357 => 183358)


--- trunk/Source/_javascript_Core/runtime/NumberPrototype.cpp	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/runtime/NumberPrototype.cpp	2015-04-26 19:55:18 UTC (rev 183358)
@@ -48,7 +48,6 @@
 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState*);
 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState*);
 static EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*);
-static EncodedJSValue JSC_HOST_CALL numberProtoFuncClz(ExecState*);
 
 }
 
@@ -66,7 +65,6 @@
   toFixed           numberProtoFuncToFixed          DontEnum|Function 1
   toExponential     numberProtoFuncToExponential    DontEnum|Function 1
   toPrecision       numberProtoFuncToPrecision      DontEnum|Function 1
-  clz               numberProtoFuncClz              DontEnum|Function 1
 @end
 */
 
@@ -452,41 +450,6 @@
     return JSValue::encode(jsString(exec, String(numberToFixedPrecisionString(x, significantFigures, buffer))));
 }
 
-#if !COMPILER(GCC) && !COMPILER(CLANG)
-static inline int clz(uint32_t number)
-{
-    int zeroCount = 0;
-    for (int i = 31; i >= 0; i--) {
-        if (!(number >> i))
-            zeroCount++;
-        else
-            break;
-    }
-    return zeroCount;
-}
-#endif
-
-EncodedJSValue JSC_HOST_CALL numberProtoFuncClz(ExecState* exec)
-{
-    double x;
-    if (!toThisNumber(exec->thisValue(), x))
-        return throwVMTypeError(exec);
-
-    if (!std::isfinite(x))
-        return JSValue::encode(JSValue(x));
-
-    uint32_t number = toUInt32(x);
-#if COMPILER(GCC) || COMPILER(CLANG)
-    int zeroCount = 32;
-    if (number)
-        zeroCount = __builtin_clz(number);
-
-    return JSValue::encode(JSValue(zeroCount));
-#else
-    return JSValue::encode(JSValue(clz(number)));
-#endif
-}
-
 static inline int32_t extractRadixFromArgs(ExecState* exec)
 {
     JSValue radixValue = exec->argument(0);

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (183357 => 183358)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2015-04-26 19:52:33 UTC (rev 183357)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2015-04-26 19:55:18 UTC (rev 183358)
@@ -379,6 +379,8 @@
         return charCodeAtThunkGenerator;
     case CharAtIntrinsic:
         return charAtThunkGenerator;
+    case Clz32Intrinsic:
+        return clz32ThunkGenerator;
     case FromCharCodeIntrinsic:
         return fromCharCodeThunkGenerator;
     case SqrtIntrinsic:

Added: trunk/Source/_javascript_Core/tests/stress/math-clz32-basics.js (0 => 183358)


--- trunk/Source/_javascript_Core/tests/stress/math-clz32-basics.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/math-clz32-basics.js	2015-04-26 19:55:18 UTC (rev 183358)
@@ -0,0 +1,222 @@
+function mathClz32OnInteger(value)
+{
+    return Math.clz32(value);
+}
+noInline(mathClz32OnInteger);
+
+// *** Test simple cases on integers. ***
+function testMathClz32OnIntegers()
+{
+    // Bounds.
+    var clzZero = mathClz32OnInteger(0);
+    if (clzZero != 32)
+        throw "mathClz32OnInteger(0) = " + clzZero;
+
+    var clzIntMin = mathClz32OnInteger(-2147483648);
+    if (clzIntMin != 0)
+        throw "mathClz32OnInteger(-2147483648) = " + clzIntMin;
+
+    var clzIntMax = mathClz32OnInteger(2147483647);
+    if (clzIntMax != 1)
+        throw "mathClz32OnInteger(2147483647) = " + clzIntMax;
+
+    // Simple values.
+    var clzMinusOne = mathClz32OnInteger(-1);
+    if (clzMinusOne != 0)
+        throw "mathClz32OnInteger(-1) = " + clzMinusOne;
+
+    var clzUltimateAnswer = mathClz32OnInteger(42);
+    if (clzUltimateAnswer != 26)
+        throw "mathClz32OnInteger(42) = " + clzUltimateAnswer;
+
+    var clzMinusUltimateAnswer = mathClz32OnInteger(-42);
+    if (clzMinusUltimateAnswer != 0)
+        throw "mathClz32OnInteger(-42) = " + clzMinusUltimateAnswer;
+}
+noInline(testMathClz32OnIntegers);
+
+for (var i = 0; i < 1e4; ++i) {
+    testMathClz32OnIntegers();
+}
+
+// Make sure we don't do anything stupid when the type is unexpected.
+function verifyMathClz32OnIntegerWithOtherTypes()
+{
+    var clzPi = mathClz32OnInteger(Math.PI);
+    if (clzPi != 30)
+        throw "mathClz32OnInteger(Math.PI) = " + clzPi;
+
+    var clzString = mathClz32OnInteger("42");
+    if (clzString != 26)
+        throw "mathClz32OnInteger(\"42\") = " + clzString;
+
+    var clzString = mathClz32OnInteger("WebKit");
+    if (clzString != 32)
+        throw "mathClz32OnInteger(\"WebKit\") = " + clzString;
+
+    var clzMinusZero = mathClz32OnInteger(-0);
+    if (clzMinusZero != 32)
+        throw "mathClz32OnInteger(\"-0\") = " + clzMinusZero;
+}
+noInline(verifyMathClz32OnIntegerWithOtherTypes);
+
+for (var i = 0; i < 1e4; ++i) {
+    verifyMathClz32OnIntegerWithOtherTypes();
+}
+
+
+// *** Test simple cases on doubles. ***
+function mathClz32OnDouble(value)
+{
+    return Math.clz32(value);
+}
+noInline(mathClz32OnInteger);
+
+// Test simple cases on integers.
+function testMathClz32OnDoubles()
+{
+    var value = mathClz32OnDouble(Math.PI);
+    if (value != 30)
+        throw "mathClz32OnDouble(Math.PI) = " + value;
+
+    var value = mathClz32OnDouble(Math.E);
+    if (value != 30)
+        throw "mathClz32OnDouble(Math.E) = " + value;
+
+    var value = mathClz32OnDouble(Math.LN2);
+    if (value != 32)
+        throw "mathClz32OnDouble(Math.LN2) = " + value;
+
+    var value = mathClz32OnDouble(-0);
+    if (value != 32)
+        throw "mathClz32OnDouble(0) = " + value;
+
+    var value = mathClz32OnDouble(NaN);
+    if (value != 32)
+        throw "mathClz32OnDouble(NaN) = " + value;
+
+    var value = mathClz32OnDouble(Number.POSITIVE_INFINITI);
+    if (value != 32)
+        throw "mathClz32OnDouble(Number.POSITIVE_INFINITI) = " + value;
+
+    var value = mathClz32OnDouble(Number.NEGATIVE_INFINITI);
+    if (value != 32)
+        throw "mathClz32OnDouble(Number.NEGATIVE_INFINITI) = " + value;
+}
+noInline(testMathClz32OnDoubles);
+
+for (var i = 0; i < 1e4; ++i) {
+    testMathClz32OnDoubles();
+}
+
+// Make sure we don't do anything stupid when the type is unexpected.
+function verifyMathClz32OnDoublesWithOtherTypes()
+{
+    var clzOne = mathClz32OnDouble(1);
+    if (clzOne != 31)
+        throw "mathClz32OnDouble(1) = " + clzOne;
+
+    var clzString = mathClz32OnDouble("42");
+    if (clzString != 26)
+        throw "mathClz32OnDouble(\"42\") = " + clzString;
+
+    var clzString = mathClz32OnDouble("WebKit");
+    if (clzString != 32)
+        throw "mathClz32OnDouble(\"WebKit\") = " + clzString;
+
+    var clzMinusZero = mathClz32OnDouble({});
+    if (clzMinusZero != 32)
+        throw "mathClz32OnDouble({}) = " + clzMinusZero;
+}
+noInline(verifyMathClz32OnDoublesWithOtherTypes);
+
+for (var i = 0; i < 1e4; ++i) {
+    verifyMathClz32OnDoublesWithOtherTypes();
+}
+
+
+// *** Unusual arguments. ***
+function mathClz32NoArguments()
+{
+    return Math.clz32();
+}
+noInline(mathClz32NoArguments);
+
+function mathClz32TooManyArguments(a, b, c)
+{
+    return Math.clz32(a, b, c);
+}
+noInline(mathClz32TooManyArguments);
+
+
+for (var i = 0; i < 1e4; ++i) {
+    var value = mathClz32NoArguments();
+    if (value !== 32)
+        throw "mathClz32NoArguments() = " + value;
+
+    var value = mathClz32TooManyArguments(2, 3, 5);
+    if (value !== 30)
+        throw "mathClz32TooManyArguments() = " + value;
+
+}
+
+
+// *** Constant as arguments. ***
+function testMathClz32OnConstants()
+{
+    var value = Math.clz32(0);
+    if (value !== 32)
+        throw "Math.clz32(0) = " + value;
+    var value = Math.clz32(-0);
+    if (value !== 32)
+        throw "Math.clz32(-0) = " + value;
+    var value = Math.clz32(1);
+    if (value !== 31)
+        throw "Math.clz32(1) = " + value;
+    var value = Math.clz32(-1);
+    if (value !== 0)
+        throw "Math.clz32(-1) = " + value;
+    var value = Math.clz32(42);
+    if (value !== 26)
+        throw "Math.clz32(42) = " + value;
+    var value = Math.clz32(-42);
+    if (value !== 0)
+        throw "Math.clz32(-42) = " + value;
+    var value = Math.clz32(NaN);
+    if (value !== 32)
+        throw "Math.clz32(NaN) = " + value;
+    var value = Math.clz32(Number.POSITIVE_INFINITI);
+    if (value !== 32)
+        throw "Math.clz32(Number.POSITIVE_INFINITI) = " + value;
+    var value = Math.clz32(Number.NEGATIVE_INFINITI);
+    if (value !== 32)
+        throw "Math.clz32(Number.NEGATIVE_INFINITI) = " + value;
+    var value = Math.clz32(Math.E);
+    if (value !== 30)
+        throw "Math.clz32(Math.E) = " + value;
+}
+noInline(testMathClz32OnConstants);
+
+for (var i = 0; i < 1e4; ++i) {
+    testMathClz32OnConstants();
+}
+
+
+// *** Struct transition. ***
+function mathClz32StructTransition(value)
+{
+    return Math.clz32(value);
+}
+noInline(mathClz32StructTransition);
+
+for (var i = 0; i < 1e4; ++i) {
+    var value = mathClz32StructTransition(42);
+    if (value !== 26)
+        throw "mathClz32StructTransition(42) = " + value;
+}
+
+Math.clz32 = function() { return arguments[0] + 5; }
+
+var value = mathClz32StructTransition(42);
+if (value !== 47)
+    throw "mathClz32StructTransition(42) after transition = " + value;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to