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;