Changeset 202680 in webkit


Ignore:
Timestamp:
Jun 30, 2016 8:26:47 AM (8 years ago)
Author:
Yusuke Suzuki
Message:

[JSC] Implement isFinite / isNaN in JS and make DFG ToNumber accept non number values
https://bugs.webkit.org/show_bug.cgi?id=154022

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

We aim at optimizing @toInteger operation.
While it still has an unoptimized part[1], this patch should be a first step.

We introduce the @toNumber builtin intrinsic operation.
This converts the given value to the JS number by emitting op_to_number bytecode.
Previously @toInteger called C++ @Number constructor for that purpose.

And in DFG, op_to_number is converted to DFG ToNumber node.
During DFG, we attempt to convert this to edge filtering and Identity, but if we fail,
we just fall back to calling the C++ function.

To utilize ToNumber in user-land side, we add a path attempting to convert Number constructor calls
to ToNumber DFG nodes. This conversion is useful because Number(value) is used to convert a value to a number in JS.

Before this patch, we emit simple edge filtering (NumberUse) instead of emitting DFG node like ToNumber for op_to_number.
But emitting ToNumber is useful, because in the case of Number(value), considering value may not be a number is reasonable.

By leveraging @toNumber operation, we rewrite Number.{isFinite, isNaN}, global.{isFinite, isNaN} and @toInteger.

ToNumber DFG node has a value profiling. This profiling is leveraged to determine the result number type of the ToNumber operation.
This value profiling is provided from either NumberConstructor's call operation or op_to_number.

The results (with the added performance tests) show that, while existing cases are performance neutral, the newly added cases gain the performance benefit.
And ASMBench/n-body.c also shows stable ~2% progression.

[1]: https://bugs.webkit.org/show_bug.cgi?id=153738

  • CMakeLists.txt:
  • DerivedSources.make:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • builtins/BuiltinNames.h:
  • builtins/GlobalObject.js:

(globalPrivate.isFinite):
(globalPrivate.isNaN):
(globalPrivate.toInteger): Deleted.
(globalPrivate.toLength): Deleted.
(globalPrivate.isDictionary): Deleted.
(globalPrivate.speciesGetter): Deleted.
(globalPrivate.speciesConstructor): Deleted.

  • builtins/GlobalOperations.js: Copied from Source/JavaScriptCore/builtins/GlobalObject.js.

(globalPrivate.toInteger):
(globalPrivate.toLength):
(globalPrivate.isDictionary):
(globalPrivate.speciesGetter):
(globalPrivate.speciesConstructor):

  • builtins/NumberConstructor.js: Added.

(isFinite):
(isNaN):

  • bytecode/BytecodeIntrinsicRegistry.cpp:

(JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry):

  • bytecode/BytecodeIntrinsicRegistry.h:
  • bytecode/BytecodeList.json:
  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::finishCreation):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitUnaryOp):
(JSC::BytecodeGenerator::emitUnaryOpProfiled):

  • bytecompiler/BytecodeGenerator.h:

(JSC::BytecodeGenerator::emitToNumber):

  • bytecompiler/NodesCodegen.cpp:

(JSC::BytecodeIntrinsicNode::emit_intrinsic_toNumber):
(JSC::UnaryPlusNode::emitBytecode):

  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGBackwardsPropagationPhase.cpp:

(JSC::DFG::BackwardsPropagationPhase::propagate):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::attemptToInlineCall):
(JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
(JSC::DFG::ByteCodeParser::parseBlock):
We use getPrediction() to retrieve the heap prediction from the to_number bytecode.
According to the benchmark results, choosing getPredictionWithoutOSRExit() causes performance regression (1.5%) in kraken stanford-crypto-aes.

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGConstantFoldingPhase.cpp:

(JSC::DFG::ConstantFoldingPhase::foldConstants):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixupToNumber):

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasHeapPrediction):

  • dfg/DFGNodeType.h:
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:

Always on the heap prediction.

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):
As of 64bit version, we carefully manage the register reuse. The largest difference between 32bit and 64bit is
branchIfNotNumber() requires the temporary register. We should not use the result registers for that since
it may be reuse the argument registers and it can break the argument registers before using them to call the operation.
Currently, we allocate the additional temporary register for that scratch register.

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):
Reuse the argument register for the result if possible. And manually decrement the use count in the middle of the node.
This is similar technique used in ToPrimitive. Typically, the child of ToNumber is only used by this ToNumber node since
we would like to perform the type conversion onto this child node here. So this careful register reuse effectively removes
the spills to call the operation. The example of the actually emitted code is the following.

76:<!2:loc11> ToNumber(Untyped:@68, JS|MustGen|UseAsOther, DoubleimpurenanTopEmpty, R:World, W:Heap, Exits, ClobbersExit, bc#48) predicting DoubleimpurenanTopEmpty

0x7f986d5fe693: test %rax, %r14
0x7f986d5fe696: jz 0x7f986d5fe6a1
0x7f986d5fe69c: jmp 0x7f986d5fe6d1
0x7f986d5fe6a1: mov %rax, %rsi
0x7f986d5fe6a4: mov %rbp, %rdi
0x7f986d5fe6a7: mov $0x2, 0x24(%rbp)
0x7f986d5fe6ae: mov $0x7f98711ea5f0, %r11
0x7f986d5fe6b8: call *%r11
0x7f986d5fe6bb: mov $0x7f982d3f72d0, %r11
0x7f986d5fe6c5: mov (%r11), %r11
0x7f986d5fe6c8: test %r11, %r11
0x7f986d5fe6cb: jnz 0x7f986d5fe88c

It effectively removes the unnecessary spill to call the operation!

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileToNumber):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):

  • jit/AssemblyHelpers.h:

(JSC::AssemblyHelpers::branchIfNumber):
(JSC::AssemblyHelpers::branchIfNotNumber):

  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_to_number):

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_to_number):

  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • parser/Nodes.h:

(JSC::UnaryOpNode::opcodeID):

  • runtime/CommonSlowPaths.cpp:

(JSC::SLOW_PATH_DECL):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::globalFuncIsNaN): Deleted.
(JSC::globalFuncIsFinite): Deleted.

  • runtime/JSGlobalObjectFunctions.h:
  • runtime/MathCommon.h:

(JSC::maxSafeInteger):
(JSC::minSafeInteger):

  • runtime/NumberConstructor.cpp:

(JSC::NumberConstructor::finishCreation):
(JSC::numberConstructorFuncIsFinite): Deleted.
(JSC::numberConstructorFuncIsNaN): Deleted.

  • runtime/NumberConstructor.h:
  • tests/stress/Number-isNaN-basics.js: Added.

(numberIsNaNOnInteger):
(testNumberIsNaNOnIntegers):
(verifyNumberIsNaNOnIntegerWithOtherTypes):
(numberIsNaNOnDouble):
(testNumberIsNaNOnDoubles):
(verifyNumberIsNaNOnDoublesWithOtherTypes):
(numberIsNaNNoArguments):
(numberIsNaNTooManyArguments):
(testNumberIsNaNOnConstants):
(numberIsNaNStructTransition):
(Number.isNaN):

  • tests/stress/global-is-finite.js: Added.

(shouldBe):

  • tests/stress/global-is-nan.js: Added.

(shouldBe):

  • tests/stress/global-isNaN-basics.js: Added.

(isNaNOnInteger):
(testIsNaNOnIntegers):
(verifyIsNaNOnIntegerWithOtherTypes):
(isNaNOnDouble):
(testIsNaNOnDoubles):
(verifyIsNaNOnDoublesWithOtherTypes):
(verifyIsNaNOnCoercedTypes):
(isNaNNoArguments):
(isNaNTooManyArguments):
(testIsNaNOnConstants):
(isNaNTypeCoercionSideEffects):
(i.value.isNaNTypeCoercionSideEffects.valueOf):
(isNaNStructTransition):
(isNaN):

  • tests/stress/number-is-finite.js: Added.

(shouldBe):
(test2):
(test3):

  • tests/stress/number-is-nan.js: Added.

(shouldBe):
(test2):
(test3):

  • tests/stress/to-number-basics.js: Added.

(shouldBe):

  • tests/stress/to-number-convert-identity-without-execution.js: Added.

(shouldBe):
(object.valueOf):
(valueOf):

  • tests/stress/to-number-int52.js: Added.

(shouldBe):
(object.valueOf):

  • tests/stress/to-number-intrinsic-convert-to-identity-without-execution.js: Added.

(shouldBe):
(object.valueOf):
(valueOf):

  • tests/stress/to-number-intrinsic-int52.js: Added.

(shouldBe):
(object.valueOf):

  • tests/stress/to-number-intrinsic-object-without-execution.js: Added.

(shouldBe):
(object.valueOf):

  • tests/stress/to-number-intrinsic-value-profiling.js: Added.

(shouldBe):
(object.valueOf):

  • tests/stress/to-number-object-without-execution.js: Added.

(shouldBe):
(object.valueOf):

  • tests/stress/to-number-object.js: Added.

(shouldBe):
(test12):
(object1.valueOf):
(test2):
(test22):
(object2.valueOf):
(test3):
(test32):
(object3.valueOf):

  • tests/stress/to-number-value-profiling.js: Added.

(shouldBe):
(object.valueOf):

LayoutTests:

  • js/regress/Number-isNaN-expected.txt: Added.
  • js/regress/Number-isNaN.html: Added.
  • js/regress/global-isNaN-expected.txt: Added.
  • js/regress/global-isNaN.html: Added.
  • js/regress/script-tests/Number-isNaN.js: Added.
  • js/regress/script-tests/global-isNaN.js: Added.
  • js/regress/script-tests/many-foreach-calls.js:

(i.4.forEach):
(i.array.forEach): Deleted.

  • js/regress/script-tests/to-number-constructor-number-string-number-string.js: Added.

(test):

  • js/regress/script-tests/to-number-constructor-only-number.js: Added.

(test):

  • js/regress/script-tests/to-number-constructor-only-string.js: Added.

(test):

  • js/regress/script-tests/to-number-constructor-string-number-string-number.js: Added.

(test):

  • js/regress/script-tests/to-number-number-string-number-string.js: Added.

(test):

  • js/regress/script-tests/to-number-only-number.js: Added.

(test):

  • js/regress/script-tests/to-number-only-string.js: Added.

(test):

  • js/regress/script-tests/to-number-string-number-string-number.js: Added.

(test):

  • js/regress/to-number-constructor-number-string-number-string-expected.txt: Added.
  • js/regress/to-number-constructor-number-string-number-string.html: Added.
  • js/regress/to-number-constructor-only-number-expected.txt: Added.
  • js/regress/to-number-constructor-only-number.html: Added.
  • js/regress/to-number-constructor-only-string-expected.txt: Added.
  • js/regress/to-number-constructor-only-string.html: Added.
  • js/regress/to-number-constructor-string-number-string-number-expected.txt: Added.
  • js/regress/to-number-constructor-string-number-string-number.html: Added.
  • js/regress/to-number-number-string-number-string-expected.txt: Added.
  • js/regress/to-number-number-string-number-string.html: Added.
  • js/regress/to-number-only-number-expected.txt: Added.
  • js/regress/to-number-only-number.html: Added.
  • js/regress/to-number-only-string-expected.txt: Added.
  • js/regress/to-number-only-string.html: Added.
  • js/regress/to-number-string-number-string-number-expected.txt: Added.
  • js/regress/to-number-string-number-string-number.html: Added.
Location:
trunk
Files:
47 added
45 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r202679 r202680  
     12016-06-30  Joseph Pecoraro  <pecoraro@apple.com> and Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] Implement isFinite / isNaN in JS and make DFG ToNumber accept non number values
     4        https://bugs.webkit.org/show_bug.cgi?id=154022
     5
     6        Reviewed by Filip Pizlo.
     7
     8        * js/regress/Number-isNaN-expected.txt: Added.
     9        * js/regress/Number-isNaN.html: Added.
     10        * js/regress/global-isNaN-expected.txt: Added.
     11        * js/regress/global-isNaN.html: Added.
     12        * js/regress/script-tests/Number-isNaN.js: Added.
     13        * js/regress/script-tests/global-isNaN.js: Added.
     14        * js/regress/script-tests/many-foreach-calls.js:
     15        (i.4.forEach):
     16        (i.array.forEach): Deleted.
     17        * js/regress/script-tests/to-number-constructor-number-string-number-string.js: Added.
     18        (test):
     19        * js/regress/script-tests/to-number-constructor-only-number.js: Added.
     20        (test):
     21        * js/regress/script-tests/to-number-constructor-only-string.js: Added.
     22        (test):
     23        * js/regress/script-tests/to-number-constructor-string-number-string-number.js: Added.
     24        (test):
     25        * js/regress/script-tests/to-number-number-string-number-string.js: Added.
     26        (test):
     27        * js/regress/script-tests/to-number-only-number.js: Added.
     28        (test):
     29        * js/regress/script-tests/to-number-only-string.js: Added.
     30        (test):
     31        * js/regress/script-tests/to-number-string-number-string-number.js: Added.
     32        (test):
     33        * js/regress/to-number-constructor-number-string-number-string-expected.txt: Added.
     34        * js/regress/to-number-constructor-number-string-number-string.html: Added.
     35        * js/regress/to-number-constructor-only-number-expected.txt: Added.
     36        * js/regress/to-number-constructor-only-number.html: Added.
     37        * js/regress/to-number-constructor-only-string-expected.txt: Added.
     38        * js/regress/to-number-constructor-only-string.html: Added.
     39        * js/regress/to-number-constructor-string-number-string-number-expected.txt: Added.
     40        * js/regress/to-number-constructor-string-number-string-number.html: Added.
     41        * js/regress/to-number-number-string-number-string-expected.txt: Added.
     42        * js/regress/to-number-number-string-number-string.html: Added.
     43        * js/regress/to-number-only-number-expected.txt: Added.
     44        * js/regress/to-number-only-number.html: Added.
     45        * js/regress/to-number-only-string-expected.txt: Added.
     46        * js/regress/to-number-only-string.html: Added.
     47        * js/regress/to-number-string-number-string-number-expected.txt: Added.
     48        * js/regress/to-number-string-number-string-number.html: Added.
     49
    1502016-06-30  Antoine Quint  <graouts@apple.com>
    251
  • trunk/LayoutTests/js/regress/script-tests/many-foreach-calls.js

    r202435 r202680  
    1 var sum = 0;
    2 var array = [1, 2, 3];
    3 for (var i = 0; i < 1e5; ++i) {
    4     array.forEach(function (value) {
     1for (var i = 0; i < 1e4; ++i) {
     2    var sum = 0;
     3    [1, 2, 3, 4].forEach(function (value) {
    54        sum += value;
    65    });
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r202659 r202680  
    12191219    ${JAVASCRIPTCORE_DIR}/builtins/GeneratorPrototype.js
    12201220    ${JAVASCRIPTCORE_DIR}/builtins/GlobalObject.js
     1221    ${JAVASCRIPTCORE_DIR}/builtins/GlobalOperations.js
    12211222    ${JAVASCRIPTCORE_DIR}/builtins/InspectorInstrumentationObject.js
    12221223    ${JAVASCRIPTCORE_DIR}/builtins/InternalPromiseConstructor.js
     
    12241225    ${JAVASCRIPTCORE_DIR}/builtins/MapPrototype.js
    12251226    ${JAVASCRIPTCORE_DIR}/builtins/ModuleLoaderObject.js
     1227    ${JAVASCRIPTCORE_DIR}/builtins/NumberConstructor.js
    12261228    ${JAVASCRIPTCORE_DIR}/builtins/NumberPrototype.js
    12271229    ${JAVASCRIPTCORE_DIR}/builtins/ObjectConstructor.js
  • trunk/Source/JavaScriptCore/ChangeLog

    r202673 r202680  
     12016-06-30  Joseph Pecoraro  <pecoraro@apple.com> and Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] Implement isFinite / isNaN in JS and make DFG ToNumber accept non number values
     4        https://bugs.webkit.org/show_bug.cgi?id=154022
     5
     6        Reviewed by Filip Pizlo.
     7
     8        We aim at optimizing @toInteger operation.
     9        While it still has an unoptimized part[1], this patch should be a first step.
     10
     11        We introduce the @toNumber builtin intrinsic operation.
     12        This converts the given value to the JS number by emitting op_to_number bytecode.
     13        Previously @toInteger called C++ @Number constructor for that purpose.
     14
     15        And in DFG, op_to_number is converted to DFG ToNumber node.
     16        During DFG, we attempt to convert this to edge filtering and Identity, but if we fail,
     17        we just fall back to calling the C++ function.
     18
     19        To utilize ToNumber in user-land side, we add a path attempting to convert Number constructor calls
     20        to ToNumber DFG nodes. This conversion is useful because `Number(value)` is used to convert a value to a number in JS.
     21
     22        Before this patch, we emit simple edge filtering (NumberUse) instead of emitting DFG node like ToNumber for op_to_number.
     23        But emitting ToNumber is useful, because in the case of `Number(value)`, considering `value` may not be a number is reasonable.
     24
     25        By leveraging @toNumber operation, we rewrite Number.{isFinite, isNaN}, global.{isFinite, isNaN} and @toInteger.
     26
     27        ToNumber DFG node has a value profiling. This profiling is leveraged to determine the result number type of the ToNumber operation.
     28        This value profiling is provided from either NumberConstructor's call operation or op_to_number.
     29
     30        The results (with the added performance tests) show that, while existing cases are performance neutral, the newly added cases gain the performance benefit.
     31        And ASMBench/n-body.c also shows stable ~2% progression.
     32
     33        [1]: https://bugs.webkit.org/show_bug.cgi?id=153738
     34
     35        * CMakeLists.txt:
     36        * DerivedSources.make:
     37        * JavaScriptCore.xcodeproj/project.pbxproj:
     38        * builtins/BuiltinNames.h:
     39        * builtins/GlobalObject.js:
     40        (globalPrivate.isFinite):
     41        (globalPrivate.isNaN):
     42        (globalPrivate.toInteger): Deleted.
     43        (globalPrivate.toLength): Deleted.
     44        (globalPrivate.isDictionary): Deleted.
     45        (globalPrivate.speciesGetter): Deleted.
     46        (globalPrivate.speciesConstructor): Deleted.
     47        * builtins/GlobalOperations.js: Copied from Source/JavaScriptCore/builtins/GlobalObject.js.
     48        (globalPrivate.toInteger):
     49        (globalPrivate.toLength):
     50        (globalPrivate.isDictionary):
     51        (globalPrivate.speciesGetter):
     52        (globalPrivate.speciesConstructor):
     53        * builtins/NumberConstructor.js: Added.
     54        (isFinite):
     55        (isNaN):
     56        * bytecode/BytecodeIntrinsicRegistry.cpp:
     57        (JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry):
     58        * bytecode/BytecodeIntrinsicRegistry.h:
     59        * bytecode/BytecodeList.json:
     60        * bytecode/CodeBlock.cpp:
     61        (JSC::CodeBlock::dumpBytecode):
     62        (JSC::CodeBlock::finishCreation):
     63        * bytecompiler/BytecodeGenerator.cpp:
     64        (JSC::BytecodeGenerator::emitUnaryOp):
     65        (JSC::BytecodeGenerator::emitUnaryOpProfiled):
     66        * bytecompiler/BytecodeGenerator.h:
     67        (JSC::BytecodeGenerator::emitToNumber):
     68        * bytecompiler/NodesCodegen.cpp:
     69        (JSC::BytecodeIntrinsicNode::emit_intrinsic_toNumber):
     70        (JSC::UnaryPlusNode::emitBytecode):
     71        * dfg/DFGAbstractInterpreterInlines.h:
     72        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     73        * dfg/DFGBackwardsPropagationPhase.cpp:
     74        (JSC::DFG::BackwardsPropagationPhase::propagate):
     75        * dfg/DFGByteCodeParser.cpp:
     76        (JSC::DFG::ByteCodeParser::attemptToInlineCall):
     77        (JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
     78        (JSC::DFG::ByteCodeParser::parseBlock):
     79        We use `getPrediction()` to retrieve the heap prediction from the to_number bytecode.
     80        According to the benchmark results, choosing `getPredictionWithoutOSRExit()` causes performance regression (1.5%) in kraken stanford-crypto-aes.
     81
     82        * dfg/DFGClobberize.h:
     83        (JSC::DFG::clobberize):
     84        * dfg/DFGConstantFoldingPhase.cpp:
     85        (JSC::DFG::ConstantFoldingPhase::foldConstants):
     86        * dfg/DFGDoesGC.cpp:
     87        (JSC::DFG::doesGC):
     88        * dfg/DFGFixupPhase.cpp:
     89        (JSC::DFG::FixupPhase::fixupNode):
     90        (JSC::DFG::FixupPhase::fixupToNumber):
     91        * dfg/DFGNode.h:
     92        (JSC::DFG::Node::hasHeapPrediction):
     93        * dfg/DFGNodeType.h:
     94        * dfg/DFGOperations.cpp:
     95        * dfg/DFGOperations.h:
     96        * dfg/DFGPredictionPropagationPhase.cpp:
     97        Always on the heap prediction.
     98
     99        * dfg/DFGSafeToExecute.h:
     100        (JSC::DFG::safeToExecute):
     101        * dfg/DFGSpeculativeJIT32_64.cpp:
     102        (JSC::DFG::SpeculativeJIT::compile):
     103        As of 64bit version, we carefully manage the register reuse. The largest difference between 32bit and 64bit is
     104        `branchIfNotNumber()` requires the temporary register. We should not use the result registers for that since
     105        it may be reuse the argument registers and it can break the argument registers before using them to call the operation.
     106        Currently, we allocate the additional temporary register for that scratch register.
     107
     108        * dfg/DFGSpeculativeJIT64.cpp:
     109        (JSC::DFG::SpeculativeJIT::compile):
     110        Reuse the argument register for the result if possible. And manually decrement the use count in the middle of the node.
     111        This is similar technique used in ToPrimitive. Typically, the child of ToNumber is only used by this ToNumber node since
     112        we would like to perform the type conversion onto this child node here. So this careful register reuse effectively removes
     113        the spills to call the operation. The example of the actually emitted code is the following.
     114
     115        76:<!2:loc11>     ToNumber(Untyped:@68, JS|MustGen|UseAsOther, DoubleimpurenanTopEmpty, R:World, W:Heap, Exits, ClobbersExit, bc#48)  predicting DoubleimpurenanTopEmpty
     116            0x7f986d5fe693: test %rax, %r14
     117            0x7f986d5fe696: jz 0x7f986d5fe6a1
     118            0x7f986d5fe69c: jmp 0x7f986d5fe6d1
     119            0x7f986d5fe6a1: mov %rax, %rsi
     120            0x7f986d5fe6a4: mov %rbp, %rdi
     121            0x7f986d5fe6a7: mov $0x2, 0x24(%rbp)
     122            0x7f986d5fe6ae: mov $0x7f98711ea5f0, %r11
     123            0x7f986d5fe6b8: call *%r11
     124            0x7f986d5fe6bb: mov $0x7f982d3f72d0, %r11
     125            0x7f986d5fe6c5: mov (%r11), %r11
     126            0x7f986d5fe6c8: test %r11, %r11
     127            0x7f986d5fe6cb: jnz 0x7f986d5fe88c
     128
     129        It effectively removes the unnecessary spill to call the operation!
     130
     131        * ftl/FTLCapabilities.cpp:
     132        (JSC::FTL::canCompile):
     133        * ftl/FTLLowerDFGToB3.cpp:
     134        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     135        (JSC::FTL::DFG::LowerDFGToB3::compileToNumber):
     136        (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
     137        * jit/AssemblyHelpers.h:
     138        (JSC::AssemblyHelpers::branchIfNumber):
     139        (JSC::AssemblyHelpers::branchIfNotNumber):
     140        * jit/JITOpcodes.cpp:
     141        (JSC::JIT::emit_op_to_number):
     142        * jit/JITOpcodes32_64.cpp:
     143        (JSC::JIT::emit_op_to_number):
     144        * llint/LowLevelInterpreter32_64.asm:
     145        * llint/LowLevelInterpreter64.asm:
     146        * parser/Nodes.h:
     147        (JSC::UnaryOpNode::opcodeID):
     148        * runtime/CommonSlowPaths.cpp:
     149        (JSC::SLOW_PATH_DECL):
     150        * runtime/JSGlobalObject.cpp:
     151        (JSC::JSGlobalObject::init):
     152        * runtime/JSGlobalObjectFunctions.cpp:
     153        (JSC::globalFuncIsNaN): Deleted.
     154        (JSC::globalFuncIsFinite): Deleted.
     155        * runtime/JSGlobalObjectFunctions.h:
     156        * runtime/MathCommon.h:
     157        (JSC::maxSafeInteger):
     158        (JSC::minSafeInteger):
     159        * runtime/NumberConstructor.cpp:
     160        (JSC::NumberConstructor::finishCreation):
     161        (JSC::numberConstructorFuncIsFinite): Deleted.
     162        (JSC::numberConstructorFuncIsNaN): Deleted.
     163        * runtime/NumberConstructor.h:
     164        * tests/stress/Number-isNaN-basics.js: Added.
     165        (numberIsNaNOnInteger):
     166        (testNumberIsNaNOnIntegers):
     167        (verifyNumberIsNaNOnIntegerWithOtherTypes):
     168        (numberIsNaNOnDouble):
     169        (testNumberIsNaNOnDoubles):
     170        (verifyNumberIsNaNOnDoublesWithOtherTypes):
     171        (numberIsNaNNoArguments):
     172        (numberIsNaNTooManyArguments):
     173        (testNumberIsNaNOnConstants):
     174        (numberIsNaNStructTransition):
     175        (Number.isNaN):
     176        * tests/stress/global-is-finite.js: Added.
     177        (shouldBe):
     178        * tests/stress/global-is-nan.js: Added.
     179        (shouldBe):
     180        * tests/stress/global-isNaN-basics.js: Added.
     181        (isNaNOnInteger):
     182        (testIsNaNOnIntegers):
     183        (verifyIsNaNOnIntegerWithOtherTypes):
     184        (isNaNOnDouble):
     185        (testIsNaNOnDoubles):
     186        (verifyIsNaNOnDoublesWithOtherTypes):
     187        (verifyIsNaNOnCoercedTypes):
     188        (isNaNNoArguments):
     189        (isNaNTooManyArguments):
     190        (testIsNaNOnConstants):
     191        (isNaNTypeCoercionSideEffects):
     192        (i.value.isNaNTypeCoercionSideEffects.valueOf):
     193        (isNaNStructTransition):
     194        (isNaN):
     195        * tests/stress/number-is-finite.js: Added.
     196        (shouldBe):
     197        (test2):
     198        (test3):
     199        * tests/stress/number-is-nan.js: Added.
     200        (shouldBe):
     201        (test2):
     202        (test3):
     203        * tests/stress/to-number-basics.js: Added.
     204        (shouldBe):
     205        * tests/stress/to-number-convert-identity-without-execution.js: Added.
     206        (shouldBe):
     207        (object.valueOf):
     208        (valueOf):
     209        * tests/stress/to-number-int52.js: Added.
     210        (shouldBe):
     211        (object.valueOf):
     212        * tests/stress/to-number-intrinsic-convert-to-identity-without-execution.js: Added.
     213        (shouldBe):
     214        (object.valueOf):
     215        (valueOf):
     216        * tests/stress/to-number-intrinsic-int52.js: Added.
     217        (shouldBe):
     218        (object.valueOf):
     219        * tests/stress/to-number-intrinsic-object-without-execution.js: Added.
     220        (shouldBe):
     221        (object.valueOf):
     222        * tests/stress/to-number-intrinsic-value-profiling.js: Added.
     223        (shouldBe):
     224        (object.valueOf):
     225        * tests/stress/to-number-object-without-execution.js: Added.
     226        (shouldBe):
     227        (object.valueOf):
     228        * tests/stress/to-number-object.js: Added.
     229        (shouldBe):
     230        (test12):
     231        (object1.valueOf):
     232        (test2):
     233        (test22):
     234        (object2.valueOf):
     235        (test3):
     236        (test32):
     237        (object3.valueOf):
     238        * tests/stress/to-number-value-profiling.js: Added.
     239        (shouldBe):
     240        (object.valueOf):
     241
    12422016-06-29  Benjamin Poulain  <benjamin@webkit.org>
    2243
     
    11081349        (JSC::DFG::FixupPhase::fixupNode):
    11091350        (JSC::DFG::FixupPhase::fixupToNumber):
     1351        ToNumber tells its predicted type by its heap prediction. So the fixup phase need to consider about it.
     1352        If the heap prediction is Int32, we should attempt to convert the child value to Int32.
     1353        Without this, misc-bugs-847389-jpeg2000 in assorted tests poses 53% regression.
     1354
    11101355        * dfg/DFGNode.h:
    11111356        (JSC::DFG::Node::hasHeapPrediction):
  • trunk/Source/JavaScriptCore/DerivedSources.make

    r202435 r202680  
    8989    $(JavaScriptCore)/builtins/GeneratorPrototype.js \
    9090    $(JavaScriptCore)/builtins/GlobalObject.js \
     91    $(JavaScriptCore)/builtins/GlobalOperations.js \
    9192    $(JavaScriptCore)/builtins/InspectorInstrumentationObject.js \
    9293    $(JavaScriptCore)/builtins/InternalPromiseConstructor.js \
     
    9495    $(JavaScriptCore)/builtins/MapPrototype.js \
    9596    $(JavaScriptCore)/builtins/ModuleLoaderObject.js \
     97    $(JavaScriptCore)/builtins/NumberConstructor.js \
    9698    $(JavaScriptCore)/builtins/NumberPrototype.js \
    9799    $(JavaScriptCore)/builtins/ObjectConstructor.js \
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r202659 r202680  
    37773777                A514B2C0185A684400F3C7CB /* InjectedScriptBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedScriptBase.cpp; sourceTree = "<group>"; };
    37783778                A514B2C1185A684400F3C7CB /* InjectedScriptBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectedScriptBase.h; sourceTree = "<group>"; };
     3779                A52704851D027C8800354C37 /* GlobalOperations.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = GlobalOperations.js; sourceTree = "<group>"; };
     3780                A52704861D027C8800354C37 /* NumberConstructor.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = NumberConstructor.js; sourceTree = "<group>"; };
    37793781                A5311C341C77CEAC00E6B1B6 /* HeapSnapshotBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapSnapshotBuilder.cpp; sourceTree = "<group>"; };
    37803782                A5311C351C77CEAC00E6B1B6 /* HeapSnapshotBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapSnapshotBuilder.h; sourceTree = "<group>"; };
     
    68966898                                70B7918F1C0244EC002481E2 /* GeneratorPrototype.js */,
    68976899                                7CF9BC5A1B65D9A3009DB1EF /* GlobalObject.js */,
     6900                                A52704851D027C8800354C37 /* GlobalOperations.js */,
    68986901                                E35E03611B7AB4850073AD2A /* InspectorInstrumentationObject.js */,
    68996902                                E33F50881B844A1A00413856 /* InternalPromiseConstructor.js */,
     
    69016904                                7035587C1C418419004BD7BF /* MapPrototype.js */,
    69026905                                E30677971B8BC6F5003F87F0 /* ModuleLoaderObject.js */,
     6906                                A52704861D027C8800354C37 /* NumberConstructor.js */,
    69036907                                A15DE5C51C0FBF8D0089133D /* NumberPrototype.js */,
    69046908                                7CF9BC5C1B65D9B1009DB1EF /* ObjectConstructor.js */,
  • trunk/Source/JavaScriptCore/builtins/BuiltinNames.h

    r202435 r202680  
    6565    macro(floor) \
    6666    macro(trunc) \
    67     macro(isFinite) \
    68     macro(isNaN) \
    6967    macro(create) \
    7068    macro(defineProperty) \
  • trunk/Source/JavaScriptCore/builtins/GlobalObject.js

    r202435 r202680  
    11/*
    2  * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
     2 * Copyright (C) 2015-2016 Yusuke Suzuki <utatane.tea@gmail.com>.
    33 * Copyright (C) 2016 Apple Inc. All rights reserved.
    44 *
     
    2525 */
    2626
    27 // @internal
    28 
    2927@globalPrivate
    30 function toInteger(target)
     28function isFinite(value)
    3129{
    3230    "use strict";
    3331
    34     var numberValue = @Number(target);
    35 
    36     // isNaN(numberValue)
     32    var numberValue = @toNumber(value);
     33    // Return false if numberValue is |NaN|.
    3734    if (numberValue !== numberValue)
    38         return 0;
    39     return @trunc(numberValue);
     35        return false;
     36    return numberValue !== @Infinity && numberValue !== -@Infinity;
    4037}
    4138
    4239@globalPrivate
    43 function toLength(target)
     40function isNaN(value)
    4441{
    4542    "use strict";
    4643
    47     var maxSafeInteger = 0x1FFFFFFFFFFFFF;
    48     var length = @toInteger(target);
    49     // originally Math.min(Math.max(length, 0), maxSafeInteger));
    50     return length > 0 ? (length < maxSafeInteger ? length : maxSafeInteger) : 0;
     44    var numberValue = @toNumber(value);
     45    return numberValue !== numberValue;
    5146}
    52 
    53 @globalPrivate
    54 function isDictionary(object)
    55 {
    56     "use strict";
    57 
    58     return object === @undefined || object == null || typeof object === "object";
    59 }
    60 
    61 // FIXME: this needs to have it's name changed to "get [Symbol.species]".
    62 // see: https://bugs.webkit.org/show_bug.cgi?id=151363
    63 @globalPrivate
    64 function speciesGetter()
    65 {
    66     return this;
    67 }
    68 
    69 @globalPrivate
    70 function speciesConstructor(obj, defaultConstructor)
    71 {
    72     var constructor = obj.constructor;
    73     if (constructor === @undefined)
    74         return defaultConstructor;
    75     if (!@isObject(constructor))
    76         throw new @TypeError("|this|.constructor is not an Object or undefined");
    77     constructor = constructor.@speciesSymbol;
    78     if (constructor == null)
    79         return defaultConstructor;
    80     if (@isConstructor(constructor))
    81         return constructor;
    82     throw new @TypeError("|this|.constructor[Symbol.species] is not a constructor");
    83 }
  • trunk/Source/JavaScriptCore/builtins/GlobalOperations.js

    r202679 r202680  
    11/*
    2  * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
    3  * Copyright (C) 2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com>.
    43 *
    54 * Redistribution and use in source and binary forms, with or without
     
    4544    "use strict";
    4645
    47     var maxSafeInteger = 0x1FFFFFFFFFFFFF;
    4846    var length = @toInteger(target);
    4947    // originally Math.min(Math.max(length, 0), maxSafeInteger));
    50     return length > 0 ? (length < maxSafeInteger ? length : maxSafeInteger) : 0;
     48    return length > 0 ? (length < @MAX_SAFE_INTEGER? length : @MAX_SAFE_INTEGER) : 0;
     49
    5150}
    5251
     
    5655    "use strict";
    5756
    58     return object === @undefined || object == null || typeof object === "object";
     57    return object == null || typeof object === "object";
    5958}
    6059
  • trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp

    r202435 r202680  
    5555    m_arrayIterationKindKeyValue.set(m_vm, jsNumber(ArrayIterateKeyValue));
    5656    m_MAX_STRING_LENGTH.set(m_vm, jsNumber(JSString::MaxLength));
    57     m_MAX_SAFE_INTEGER.set(m_vm, jsDoubleNumber(9007199254740991.0)); // 2 ^ 53 - 1
     57    m_MAX_SAFE_INTEGER.set(m_vm, jsDoubleNumber(maxSafeInteger()));
    5858    m_ModuleFetch.set(m_vm, jsNumber(static_cast<unsigned>(ModuleLoaderObject::Status::Fetch)));
    5959    m_ModuleTranslate.set(m_vm, jsNumber(static_cast<unsigned>(ModuleLoaderObject::Status::Translate)));
  • trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h

    r202435 r202680  
    4848    macro(tryGetById) \
    4949    macro(putByValDirect) \
     50    macro(toNumber) \
    5051    macro(toString)
    5152
  • trunk/Source/JavaScriptCore/bytecode/BytecodeList.json

    r202633 r202680  
    3232            { "name" : "op_inc", "length" : 2 },
    3333            { "name" : "op_dec", "length" : 2 },
    34             { "name" : "op_to_number", "length" : 3 },
     34            { "name" : "op_to_number", "length" : 4 },
    3535            { "name" : "op_to_string", "length" : 3 },
    3636            { "name" : "op_negate", "length" : 3 },
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r202659 r202680  
    993993        case op_to_number: {
    994994            printUnaryOp(out, exec, location, it, "to_number");
     995            dumpValueProfiling(out, it, hasPrintedProfiling);
    995996            break;
    996997        }
     
    20942095        case op_get_direct_pname:
    20952096        case op_get_by_id:
    2096         case op_get_from_arguments: {
     2097        case op_get_from_arguments:
     2098        case op_to_number: {
    20972099            ValueProfile* profile = &m_valueProfiles[pc[opLength - 1].u.operand];
    20982100            ASSERT(profile->m_bytecodeOffset == -1);
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r202608 r202680  
    15261526RegisterID* BytecodeGenerator::emitUnaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src)
    15271527{
     1528    ASSERT_WITH_MESSAGE(op_to_number != opcodeID, "op_to_number is profiled.");
    15281529    emitOpcode(opcodeID);
    15291530    instructions().append(dst->index());
    15301531    instructions().append(src->index());
     1532    return dst;
     1533}
     1534
     1535RegisterID* BytecodeGenerator::emitUnaryOpProfiled(OpcodeID opcodeID, RegisterID* dst, RegisterID* src)
     1536{
     1537    UnlinkedValueProfile profile = emitProfiledOpcode(opcodeID);
     1538    instructions().append(dst->index());
     1539    instructions().append(src->index());
     1540    instructions().append(profile);
    15311541    return dst;
    15321542}
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r202608 r202680  
    512512
    513513        RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src);
     514        RegisterID* emitUnaryOpProfiled(OpcodeID, RegisterID* dst, RegisterID* src);
    514515        RegisterID* emitBinaryOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes);
    515516        RegisterID* emitEqualityOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2);
     
    538539        RegisterID* emitMove(RegisterID* dst, RegisterID* src);
    539540
    540         RegisterID* emitToNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_number, dst, src); }
     541        RegisterID* emitToNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOpProfiled(op_to_number, dst, src); }
    541542        RegisterID* emitToString(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_string, dst, src); }
    542543        RegisterID* emitInc(RegisterID* srcDst);
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r202654 r202680  
    919919    RefPtr<RegisterID> finalDest = generator.finalDestination(dst);
    920920    return generator.emitTryGetById(finalDest.get(), base.get(), ident);
     921}
     922
     923RegisterID* BytecodeIntrinsicNode::emit_intrinsic_toNumber(BytecodeGenerator& generator, RegisterID* dst)
     924{
     925    ArgumentListNode* node = m_args->m_listNode;
     926    RefPtr<RegisterID> src = generator.emitNode(node);
     927    ASSERT(!node->m_next);
     928
     929    return generator.moveToDestinationIfNeeded(dst, generator.emitToNumber(generator.tempDestination(dst), src.get()));
    921930}
    922931
     
    15521561}
    15531562
     1563// ------------------------------ UnaryPlusNode -----------------------------------
     1564
     1565RegisterID* UnaryPlusNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
     1566{
     1567    ASSERT(opcodeID() == op_to_number);
     1568    RefPtr<RegisterID> src = generator.emitNode(expr());
     1569    generator.emitExpressionInfo(position(), position(), position());
     1570    return generator.emitToNumber(generator.finalDestination(dst), src.get());
     1571}
     1572
    15541573// ------------------------------ BitwiseNotNode -----------------------------------
    15551574 
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r202435 r202680  
    18281828        ASSERT(node->child1().useKind() == UntypedUse);
    18291829       
    1830         if (!forNode(node->child1()).m_type) {
    1831             m_state.setIsValid(false);
    1832             break;
    1833         }
    1834        
    18351830        if (!(forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString | SpecSymbol))) {
    18361831            m_state.setFoundConstants(true);
     
    18421837       
    18431838        forNode(node).setType(m_graph, SpecHeapTop & ~SpecObject);
     1839        break;
     1840    }
     1841
     1842    case ToNumber: {
     1843        JSValue childConst = forNode(node->child1()).value();
     1844        if (childConst && childConst.isNumber()) {
     1845            setConstant(node, childConst);
     1846            break;
     1847        }
     1848
     1849        ASSERT(node->child1().useKind() == UntypedUse);
     1850
     1851        if (!(forNode(node->child1()).m_type & ~SpecBytecodeNumber)) {
     1852            m_state.setFoundConstants(true);
     1853            forNode(node) = forNode(node->child1());
     1854            break;
     1855        }
     1856
     1857        clobberWorld(node->origin.semantic, clobberLimit);
     1858        forNode(node).setType(m_graph, SpecBytecodeNumber);
    18441859        break;
    18451860    }
  • trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp

    r198770 r202680  
    361361        }
    362362           
    363         case ToPrimitive: {
     363        case ToPrimitive:
     364        case ToNumber: {
    364365            node->child1()->mergeFlags(flags);
    365366            break;
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r202633 r202680  
    4343#include "GetByIdStatus.h"
    4444#include "Heap.h"
     45#include "JSCInlines.h"
    4546#include "JSLexicalEnvironment.h"
    46 #include "JSCInlines.h"
    4747#include "JSModuleEnvironment.h"
     48#include "NumberConstructor.h"
    4849#include "ObjectConstructor.h"
    4950#include "PreciseJumpTargets.h"
     
    216217    bool handleTypedArrayConstructor(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, TypedArrayType, const ChecksFunctor& insertChecks);
    217218    template<typename ChecksFunctor>
    218     bool handleConstantInternalFunction(Node* callTargetNode, int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind, const ChecksFunctor& insertChecks);
     219    bool handleConstantInternalFunction(Node* callTargetNode, int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind, SpeculatedType, const ChecksFunctor& insertChecks);
    219220    Node* handlePutByOffset(Node* base, unsigned identifier, PropertyOffset, const InferredType::Descriptor&, Node* value);
    220221    Node* handleGetByOffset(SpeculatedType, Node* base, unsigned identifierNumber, PropertyOffset, const InferredType::Descriptor&, NodeType = GetByOffset);
     
    16521653   
    16531654        if (InternalFunction* function = callee.internalFunction()) {
    1654             if (handleConstantInternalFunction(callTargetNode, resultOperand, function, registerOffset, argumentCountIncludingThis, specializationKind, insertChecksWithAccounting)) {
     1655            if (handleConstantInternalFunction(callTargetNode, resultOperand, function, registerOffset, argumentCountIncludingThis, specializationKind, prediction, insertChecksWithAccounting)) {
    16551656                RELEASE_ASSERT(didInsertChecks);
    16561657                addToGraph(Phantom, callTargetNode);
     
    26382639bool ByteCodeParser::handleConstantInternalFunction(
    26392640    Node* callTargetNode, int resultOperand, InternalFunction* function, int registerOffset,
    2640     int argumentCountIncludingThis, CodeSpecializationKind kind, const ChecksFunctor& insertChecks)
     2641    int argumentCountIncludingThis, CodeSpecializationKind kind, SpeculatedType prediction, const ChecksFunctor& insertChecks)
    26412642{
    26422643    if (verbose)
     
    26672668        set(VirtualRegister(resultOperand),
    26682669            addToGraph(Node::VarArg, NewArray, OpInfo(ArrayWithUndecided), OpInfo(0)));
     2670        return true;
     2671    }
     2672
     2673    if (function->classInfo() == NumberConstructor::info()) {
     2674        if (kind == CodeForConstruct)
     2675            return false;
     2676
     2677        insertChecks();
     2678        if (argumentCountIncludingThis <= 1)
     2679            set(VirtualRegister(resultOperand), jsConstant(jsNumber(0)));
     2680        else
     2681            set(VirtualRegister(resultOperand), addToGraph(ToNumber, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(1, registerOffset))));
     2682
    26692683        return true;
    26702684    }
     
    50515065
    50525066        case op_to_number: {
    5053             Node* node = get(VirtualRegister(currentInstruction[2].u.operand));
    5054             addToGraph(Phantom, Edge(node, NumberUse));
    5055             set(VirtualRegister(currentInstruction[1].u.operand), node);
     5067            SpeculatedType prediction = getPrediction();
     5068            Node* value = get(VirtualRegister(currentInstruction[2].u.operand));
     5069            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(ToNumber, OpInfo(0), OpInfo(prediction), value));
    50565070            NEXT_OPCODE(op_to_number);
    50575071        }
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r202435 r202680  
    11741174        write(Heap);
    11751175        return;
     1176
     1177    case ToNumber: {
     1178        read(World);
     1179        write(Heap);
     1180        return;
     1181    }
    11761182       
    11771183    case ToString:
  • trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp

    r202435 r202680  
    567567            }
    568568
     569            case ToNumber: {
     570                if (m_state.forNode(node->child1()).m_type & ~SpecBytecodeNumber)
     571                    break;
     572
     573                node->convertToIdentity();
     574                changed = true;
     575                break;
     576            }
     577
    569578            case Check: {
    570579                alreadyHandled = true;
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r202435 r202680  
    170170    case LogicalNot:
    171171    case ToPrimitive:
     172    case ToNumber:
    172173    case ToString:
    173174    case CallStringConstructor:
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r202435 r202680  
    988988        case ToPrimitive: {
    989989            fixupToPrimitive(node);
     990            break;
     991        }
     992
     993        case ToNumber: {
     994            fixupToNumber(node);
    990995            break;
    991996        }
     
    17991804        }
    18001805    }
     1806
     1807    void fixupToNumber(Node* node)
     1808    {
     1809        // If the prediction of the child is Number, we attempt to convert ToNumber to Identity.
     1810        if (node->child1()->shouldSpeculateNumber()) {
     1811            if (isInt32Speculation(node->getHeapPrediction())) {
     1812                // If the both predictions of this node and the child is Int32, we just convert ToNumber to Identity, that's simple.
     1813                if (node->child1()->shouldSpeculateInt32()) {
     1814                    fixEdge<Int32Use>(node->child1());
     1815                    node->convertToIdentity();
     1816                    return;
     1817                }
     1818
     1819                // The another case is that the predicted type of the child is Int32, but the heap prediction tell the users that this will produce non Int32 values.
     1820                // In that case, let's receive the child value as a Double value and convert it to Int32. This case happens in misc-bugs-847389-jpeg2000.
     1821                fixEdge<DoubleRepUse>(node->child1());
     1822                node->setOp(DoubleAsInt32);
     1823                if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
     1824                    node->setArithMode(Arith::CheckOverflow);
     1825                else
     1826                    node->setArithMode(Arith::CheckOverflowAndNegativeZero);
     1827                return;
     1828            }
     1829
     1830            fixEdge<DoubleRepUse>(node->child1());
     1831            node->convertToIdentity();
     1832            node->setResult(NodeResultDouble);
     1833            return;
     1834        }
     1835
     1836        fixEdge<UntypedUse>(node->child1());
     1837        node->setResult(NodeResultJS);
     1838    }
    18011839   
    18021840    void fixupToStringOrCallStringConstructor(Node* node)
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r202435 r202680  
    14401440        case StringReplace:
    14411441        case StringReplaceRegExp:
     1442        case ToNumber:
    14421443            return true;
    14431444        default:
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r202435 r202680  
    323323    macro(ToPrimitive, NodeResultJS | NodeMustGenerate) \
    324324    macro(ToString, NodeResultJS | NodeMustGenerate) \
     325    macro(ToNumber, NodeResultJS | NodeMustGenerate) \
    325326    macro(CallObjectConstructor, NodeResultJS) \
    326327    macro(CallStringConstructor, NodeResultJS | NodeMustGenerate) \
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r202588 r202680  
    732732}
    733733
     734EncodedJSValue JIT_OPERATION operationToNumber(ExecState* exec, EncodedJSValue value)
     735{
     736    VM* vm = &exec->vm();
     737    NativeCallFrameTracer tracer(vm, exec);
     738
     739    return JSValue::encode(jsNumber(JSValue::decode(value).toNumber(exec)));
     740}
     741
    734742EncodedJSValue JIT_OPERATION operationGetByIdWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, UniquedStringImpl* impl)
    735743{
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r202435 r202680  
    5959EncodedJSValue JIT_OPERATION operationGetByValStringInt(ExecState*, JSString*, int32_t) WTF_INTERNAL;
    6060EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState*, EncodedJSValue) WTF_INTERNAL;
     61EncodedJSValue JIT_OPERATION operationToNumber(ExecState*, EncodedJSValue) WTF_INTERNAL;
    6162EncodedJSValue JIT_OPERATION operationGetByIdWithThis(ExecState*, EncodedJSValue, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
    6263EncodedJSValue JIT_OPERATION operationGetByValWithThis(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r202435 r202680  
    713713        case GetGlobalLexicalVariable:
    714714        case GetClosureVar:
    715         case GetFromArguments: {
     715        case GetFromArguments:
     716        case ToNumber: {
    716717            setPrediction(m_currentNode->getHeapPrediction());
    717718            break;
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r202435 r202680  
    273273    case ToPrimitive:
    274274    case ToString:
     275    case ToNumber:
    275276    case SetFunctionName:
    276277    case StrCat:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r202435 r202680  
    35683568    case ToPrimitive: {
    35693569        RELEASE_ASSERT(node->child1().useKind() == UntypedUse);
    3570         JSValueOperand op1(this, node->child1());
    3571         GPRTemporary resultTag(this, Reuse, op1, TagWord);
    3572         GPRTemporary resultPayload(this, Reuse, op1, PayloadWord);
    3573        
    3574         GPRReg op1TagGPR = op1.tagGPR();
    3575         GPRReg op1PayloadGPR = op1.payloadGPR();
     3570        JSValueOperand argument(this, node->child1());
     3571        GPRTemporary resultTag(this, Reuse, argument, TagWord);
     3572        GPRTemporary resultPayload(this, Reuse, argument, PayloadWord);
     3573       
     3574        GPRReg argumentTagGPR = argument.tagGPR();
     3575        GPRReg argumentPayloadGPR = argument.payloadGPR();
    35763576        GPRReg resultTagGPR = resultTag.gpr();
    35773577        GPRReg resultPayloadGPR = resultPayload.gpr();
    35783578       
    3579         op1.use();
    3580        
    3581         MacroAssembler::Jump alreadyPrimitive = m_jit.branchIfNotCell(op1.jsValueRegs());
    3582         MacroAssembler::Jump notPrimitive = m_jit.branchIfObject(op1PayloadGPR);
     3579        argument.use();
     3580       
     3581        MacroAssembler::Jump alreadyPrimitive = m_jit.branchIfNotCell(argument.jsValueRegs());
     3582        MacroAssembler::Jump notPrimitive = m_jit.branchIfObject(argumentPayloadGPR);
    35833583       
    35843584        alreadyPrimitive.link(&m_jit);
    3585         m_jit.move(op1TagGPR, resultTagGPR);
    3586         m_jit.move(op1PayloadGPR, resultPayloadGPR);
     3585        m_jit.move(argumentTagGPR, resultTagGPR);
     3586        m_jit.move(argumentPayloadGPR, resultPayloadGPR);
    35873587       
    35883588        addSlowPathGenerator(
    35893589            slowPathCall(
    35903590                notPrimitive, this, operationToPrimitive,
    3591                 JSValueRegs(resultTagGPR, resultPayloadGPR), op1TagGPR, op1PayloadGPR));
     3591                JSValueRegs(resultTagGPR, resultPayloadGPR), argumentTagGPR, argumentPayloadGPR));
    35923592       
    35933593        jsValueResult(resultTagGPR, resultPayloadGPR, node, UseChildrenCalledExplicitly);
     3594        break;
     3595    }
     3596
     3597    case ToNumber: {
     3598        JSValueOperand argument(this, node->child1());
     3599        GPRTemporary resultTag(this, Reuse, argument, TagWord);
     3600        GPRTemporary resultPayload(this, Reuse, argument, PayloadWord);
     3601
     3602        GPRReg argumentPayloadGPR = argument.payloadGPR();
     3603        GPRReg argumentTagGPR = argument.tagGPR();
     3604        JSValueRegs resultRegs(resultTag.gpr(), resultPayload.gpr());
     3605
     3606        argument.use();
     3607
     3608        // We have several attempts to remove ToNumber. But ToNumber still exists.
     3609        // It means that converting non-numbers to numbers by this ToNumber is not rare.
     3610        // Instead of the slow path generator, we emit callOperation here.
     3611        if (!(m_state.forNode(node->child1()).m_type & SpecBytecodeNumber)) {
     3612            flushRegisters();
     3613            callOperation(operationToNumber, resultRegs, argumentTagGPR, argumentPayloadGPR);
     3614            m_jit.exceptionCheck();
     3615        } else {
     3616            MacroAssembler::Jump notNumber;
     3617            {
     3618                GPRTemporary scratch(this);
     3619                notNumber = m_jit.branchIfNotNumber(argument.jsValueRegs(), scratch.gpr());
     3620            }
     3621            m_jit.move(argumentTagGPR, resultRegs.tagGPR());
     3622            m_jit.move(argumentPayloadGPR, resultRegs.payloadGPR());
     3623            MacroAssembler::Jump done = m_jit.jump();
     3624
     3625            notNumber.link(&m_jit);
     3626            silentSpillAllRegisters(resultRegs);
     3627            callOperation(operationToNumber, resultRegs, argumentTagGPR, argumentPayloadGPR);
     3628            silentFillAllRegisters(resultRegs);
     3629            m_jit.exceptionCheck();
     3630
     3631            done.link(&m_jit);
     3632        }
     3633
     3634        jsValueResult(resultRegs.tagGPR(), resultRegs.payloadGPR(), node, UseChildrenCalledExplicitly);
    35943635        break;
    35953636    }
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r202435 r202680  
    35213521    case ToPrimitive: {
    35223522        DFG_ASSERT(m_jit.graph(), node, node->child1().useKind() == UntypedUse);
    3523         JSValueOperand op1(this, node->child1());
    3524         GPRTemporary result(this, Reuse, op1);
    3525        
    3526         GPRReg op1GPR = op1.gpr();
     3523        JSValueOperand argument(this, node->child1());
     3524        GPRTemporary result(this, Reuse, argument);
     3525       
     3526        GPRReg argumentGPR = argument.gpr();
    35273527        GPRReg resultGPR = result.gpr();
    35283528       
    3529         op1.use();
    3530        
    3531         MacroAssembler::Jump alreadyPrimitive = m_jit.branchIfNotCell(JSValueRegs(op1GPR));
    3532         MacroAssembler::Jump notPrimitive = m_jit.branchIfObject(op1GPR);
     3529        argument.use();
     3530       
     3531        MacroAssembler::Jump alreadyPrimitive = m_jit.branchIfNotCell(JSValueRegs(argumentGPR));
     3532        MacroAssembler::Jump notPrimitive = m_jit.branchIfObject(argumentGPR);
    35333533       
    35343534        alreadyPrimitive.link(&m_jit);
    3535         m_jit.move(op1GPR, resultGPR);
     3535        m_jit.move(argumentGPR, resultGPR);
    35363536       
    35373537        addSlowPathGenerator(
    3538             slowPathCall(notPrimitive, this, operationToPrimitive, resultGPR, op1GPR));
    3539        
     3538            slowPathCall(notPrimitive, this, operationToPrimitive, resultGPR, argumentGPR));
     3539       
     3540        jsValueResult(resultGPR, node, UseChildrenCalledExplicitly);
     3541        break;
     3542    }
     3543
     3544    case ToNumber: {
     3545        JSValueOperand argument(this, node->child1());
     3546        GPRTemporary result(this, Reuse, argument);
     3547
     3548        GPRReg argumentGPR = argument.gpr();
     3549        GPRReg resultGPR = result.gpr();
     3550
     3551        argument.use();
     3552
     3553        // We have several attempts to remove ToNumber. But ToNumber still exists.
     3554        // It means that converting non-numbers to numbers by this ToNumber is not rare.
     3555        // Instead of the slow path generator, we emit callOperation here.
     3556        if (!(m_state.forNode(node->child1()).m_type & SpecBytecodeNumber)) {
     3557            flushRegisters();
     3558            callOperation(operationToNumber, resultGPR, argumentGPR);
     3559            m_jit.exceptionCheck();
     3560        } else {
     3561            MacroAssembler::Jump notNumber = m_jit.branchIfNotNumber(argumentGPR);
     3562            m_jit.move(argumentGPR, resultGPR);
     3563            MacroAssembler::Jump done = m_jit.jump();
     3564
     3565            notNumber.link(&m_jit);
     3566            silentSpillAllRegisters(resultGPR);
     3567            callOperation(operationToNumber, resultGPR, argumentGPR);
     3568            silentFillAllRegisters(resultGPR);
     3569            m_jit.exceptionCheck();
     3570
     3571            done.link(&m_jit);
     3572        }
     3573
    35403574        jsValueResult(resultGPR, node, UseChildrenCalledExplicitly);
    35413575        break;
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r202435 r202680  
    162162    case GetCallee:
    163163    case GetArgumentCountIncludingThis:
     164    case ToNumber:
     165    case ToString:
    164166    case CallObjectConstructor:
    165     case ToString:
    166167    case CallStringConstructor:
    167168    case MakeRope:
     
    404405            break;
    405406        if (node->isBinaryUseKind(BooleanUse))
     407            break;
     408        if (node->isBinaryUseKind(UntypedUse))
    406409            break;
    407410        if (node->isBinaryUseKind(SymbolUse))
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r202519 r202680  
    723723        case ReallocatePropertyStorage:
    724724            compileReallocatePropertyStorage();
     725            break;
     726        case ToNumber:
     727            compileToNumber();
    725728            break;
    726729        case ToString:
     
    40954098                object, oldStorage, transition->previous, transition->next));
    40964099    }
     4100
     4101    void compileToNumber()
     4102    {
     4103        LValue value = lowJSValue(m_node->child1());
     4104
     4105        if (!(abstractValue(m_node->child1()).m_type & SpecBytecodeNumber))
     4106            setJSValue(vmCall(m_out.int64, m_out.operation(operationToNumber), m_callFrame, value));
     4107        else {
     4108            LBasicBlock notNumber = m_out.newBlock();
     4109            LBasicBlock continuation = m_out.newBlock();
     4110
     4111            ValueFromBlock fastResult = m_out.anchor(value);
     4112            m_out.branch(isNumber(value, provenType(m_node->child1())), unsure(continuation), unsure(notNumber));
     4113
     4114            // notNumber case.
     4115            LBasicBlock lastNext = m_out.appendTo(notNumber, continuation);
     4116            // We have several attempts to remove ToNumber. But ToNumber still exists.
     4117            // It means that converting non-numbers to numbers by this ToNumber is not rare.
     4118            // Instead of the lazy slow path generator, we call the operation here.
     4119            ValueFromBlock slowResult = m_out.anchor(vmCall(m_out.int64, m_out.operation(operationToNumber), m_callFrame, value));
     4120            m_out.jump(continuation);
     4121
     4122            // continuation case.
     4123            m_out.appendTo(continuation, lastNext);
     4124            setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
     4125        }
     4126    }
    40974127   
    40984128    void compileToStringOrCallStringConstructor()
     
    48824912            setBoolean(
    48834913                m_out.equal(lowBoolean(m_node->child1()), lowBoolean(m_node->child2())));
     4914            return;
     4915        }
     4916
     4917        if (m_node->isBinaryUseKind(UntypedUse)) {
     4918            nonSpeculativeCompare(
     4919                [&] (LValue left, LValue right) {
     4920                    return m_out.equal(left, right);
     4921                },
     4922                operationCompareStrictEq);
    48844923            return;
    48854924        }
  • trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h

    r202435 r202680  
    756756#if USE(JSVALUE64)
    757757        UNUSED_PARAM(tempGPR);
    758         if (mode == HaveTagRegisters)
    759             return branchTest64(NonZero, regs.gpr(), GPRInfo::tagTypeNumberRegister);
    760         return branchTest64(NonZero, regs.gpr(), TrustedImm64(TagTypeNumber));
     758        return branchIfNumber(regs.gpr(), mode);
    761759#else
    762760        UNUSED_PARAM(mode);
     
    765763#endif
    766764    }
     765
     766#if USE(JSVALUE64)
     767    Jump branchIfNumber(GPRReg reg, TagRegistersMode mode = HaveTagRegisters)
     768    {
     769        if (mode == HaveTagRegisters)
     770            return branchTest64(NonZero, reg, GPRInfo::tagTypeNumberRegister);
     771        return branchTest64(NonZero, reg, TrustedImm64(TagTypeNumber));
     772    }
     773#endif
    767774   
    768775    // Note that the tempGPR is not used in 64-bit mode.
     
    771778#if USE(JSVALUE64)
    772779        UNUSED_PARAM(tempGPR);
    773         if (mode == HaveTagRegisters)
    774             return branchTest64(Zero, regs.gpr(), GPRInfo::tagTypeNumberRegister);
    775         return branchTest64(Zero, regs.gpr(), TrustedImm64(TagTypeNumber));
     780        return branchIfNotNumber(regs.gpr(), mode);
    776781#else
    777782        UNUSED_PARAM(mode);
     
    780785#endif
    781786    }
     787
     788#if USE(JSVALUE64)
     789    Jump branchIfNotNumber(GPRReg reg, TagRegistersMode mode = HaveTagRegisters)
     790    {
     791        if (mode == HaveTagRegisters)
     792            return branchTest64(Zero, reg, GPRInfo::tagTypeNumberRegister);
     793        return branchTest64(Zero, reg, TrustedImm64(TagTypeNumber));
     794    }
     795#endif
    782796
    783797    Jump branchIfNotDoubleKnownNotInt32(JSValueRegs regs, TagRegistersMode mode = HaveTagRegisters)
  • trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp

    r202435 r202680  
    517517void JIT::emit_op_to_number(Instruction* currentInstruction)
    518518{
     519    int dstVReg = currentInstruction[1].u.operand;
    519520    int srcVReg = currentInstruction[2].u.operand;
    520521    emitGetVirtualRegister(srcVReg, regT0);
     
    522523    addSlowCase(emitJumpIfNotNumber(regT0));
    523524
    524     emitPutVirtualRegister(currentInstruction[1].u.operand);
     525    emitValueProfilingSite();
     526    if (srcVReg != dstVReg)
     527        emitPutVirtualRegister(dstVReg);
    525528}
    526529
  • trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp

    r202435 r202680  
    829829    isInt32.link(this);
    830830
     831    emitValueProfilingSite();
    831832    if (src != dst)
    832833        emitStore(dst, regT1, regT0);
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm

    r202633 r202680  
    956956    storei t2, TagOffset[cfr, t1, 8]
    957957    storei t3, PayloadOffset[cfr, t1, 8]
    958     dispatch(3)
     958    valueProfile(t2, t3, 12, t1)
     959    dispatch(4)
    959960
    960961.opToNumberSlow:
    961962    callOpcodeSlowPath(_slow_path_to_number)
    962     dispatch(3)
     963    dispatch(4)
    963964
    964965
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

    r202633 r202680  
    835835.opToNumberIsImmediate:
    836836    storeq t2, [cfr, t1, 8]
    837     dispatch(3)
     837    valueProfile(t2, 3, t0)
     838    dispatch(4)
    838839
    839840.opToNumberSlow:
    840841    callOpcodeSlowPath(_slow_path_to_number)
    841     dispatch(3)
     842    dispatch(4)
    842843
    843844
  • trunk/Source/JavaScriptCore/parser/Nodes.h

    r202435 r202680  
    968968        ExpressionNode* expr() { return m_expr; }
    969969        const ExpressionNode* expr() const { return m_expr; }
    970 
    971     private:
    972         RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
    973 
    974970        OpcodeID opcodeID() const { return m_opcodeID; }
     971
     972    private:
     973        RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
    975974
    976975        ExpressionNode* m_expr;
     
    983982
    984983    private:
     984        RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
     985
    985986        ExpressionNode* stripUnaryPlus() override { return expr(); }
    986987    };
  • trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

    r202435 r202680  
    347347}
    348348
    349 SLOW_PATH_DECL(slow_path_to_number)
    350 {
    351     BEGIN();
    352     RETURN(jsNumber(OP_C(2).jsValue().toNumber(exec)));
    353 }
    354 
    355349SLOW_PATH_DECL(slow_path_to_string)
    356350{
     
    398392static void updateResultProfileForBinaryArithOp(ExecState*, Instruction*, JSValue, JSValue, JSValue) { }
    399393#endif
     394
     395SLOW_PATH_DECL(slow_path_to_number)
     396{
     397    BEGIN();
     398    JSValue argument = OP_C(2).jsValue();
     399    JSValue result = jsNumber(argument.toNumber(exec));
     400    RETURN_PROFILED(op_to_number, result);
     401}
    400402
    401403SLOW_PATH_DECL(slow_path_add)
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r202631 r202680  
    212212@begin globalObjectTable
    213213  parseFloat            globalFuncParseFloat                         DontEnum|Function 1
    214   isNaN                 globalFuncIsNaN                              DontEnum|Function 1
    215   isFinite              globalFuncIsFinite                           DontEnum|Function 1
     214  isNaN                 JSBuiltin                                    DontEnum|Function 1
     215  isFinite              JSBuiltin                                    DontEnum|Function 1
    216216  escape                globalFuncEscape                             DontEnum|Function 1
    217217  unescape              globalFuncUnescape                           DontEnum|Function 1
     
    407407
    408408    m_speciesGetterSetter.set(vm, this, GetterSetter::create(vm, this));
    409     m_speciesGetterSetter->setGetter(vm, this, JSFunction::createBuiltinFunction(vm, globalObjectSpeciesGetterCodeGenerator(vm), this, "get [Symbol.species]"));
     409    m_speciesGetterSetter->setGetter(vm, this, JSFunction::createBuiltinFunction(vm, globalOperationsSpeciesGetterCodeGenerator(vm), this, "get [Symbol.species]"));
    410410
    411411    m_typedArrayProto.initLater(
     
    652652    JSFunction* privateFuncAbs = JSFunction::create(vm, this, 0, String(), mathProtoFuncAbs, AbsIntrinsic);
    653653    JSFunction* privateFuncFloor = JSFunction::create(vm, this, 0, String(), mathProtoFuncFloor, FloorIntrinsic);
    654     JSFunction* privateFuncIsFinite = JSFunction::create(vm, this, 0, String(), globalFuncIsFinite);
    655     JSFunction* privateFuncIsNaN = JSFunction::create(vm, this, 0, String(), globalFuncIsNaN);
    656654    JSFunction* privateFuncTrunc = JSFunction::create(vm, this, 0, String(), mathProtoFuncTrunc, TruncIntrinsic);
    657655
     
    720718        GlobalPropertyInfo(vm.propertyNames->builtinNames().floorPrivateName(), privateFuncFloor, DontEnum | DontDelete | ReadOnly),
    721719        GlobalPropertyInfo(vm.propertyNames->builtinNames().truncPrivateName(), privateFuncTrunc, DontEnum | DontDelete | ReadOnly),
    722         GlobalPropertyInfo(vm.propertyNames->builtinNames().isFinitePrivateName(), privateFuncIsFinite, DontEnum | DontDelete | ReadOnly),
    723         GlobalPropertyInfo(vm.propertyNames->builtinNames().isNaNPrivateName(), privateFuncIsNaN, DontEnum | DontDelete | ReadOnly),
    724720        GlobalPropertyInfo(vm.propertyNames->builtinNames().PromisePrivateName(), promiseConstructor, DontEnum | DontDelete | ReadOnly),
    725721        GlobalPropertyInfo(vm.propertyNames->builtinNames().ReflectPrivateName(), reflectObject, DontEnum | DontDelete | ReadOnly),
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

    r202435 r202680  
    707707}
    708708
    709 EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState* exec)
    710 {
    711     return JSValue::encode(jsBoolean(std::isnan(exec->argument(0).toNumber(exec))));
    712 }
    713 
    714 EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState* exec)
    715 {
    716     double n = exec->argument(0).toNumber(exec);
    717     return JSValue::encode(jsBoolean(std::isfinite(n)));
    718 }
    719 
    720709EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec)
    721710{
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h

    r202435 r202680  
    4141EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState*);
    4242EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState*);
    43 EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState*);
    44 EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState*);
    4543EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState*);
    4644EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState*);
  • trunk/Source/JavaScriptCore/runtime/MathCommon.h

    r202435 r202680  
    3535double JIT_OPERATION operationMathPow(double x, double y) WTF_INTERNAL;
    3636int32_t JIT_OPERATION operationToInt32(double) WTF_INTERNAL;
     37
     38inline constexpr double maxSafeInteger()
     39{
     40    // 2 ^ 53 - 1
     41    return 9007199254740991.0;
     42}
     43
     44inline constexpr double minSafeInteger()
     45{
     46    // -(2 ^ 53 - 1)
     47    return -9007199254740991.0;
     48}
    3749
    3850inline int clz32(uint32_t number)
  • trunk/Source/JavaScriptCore/runtime/NumberConstructor.cpp

    r202435 r202680  
    3232namespace JSC {
    3333
    34 static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsFinite(ExecState*);
    3534static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsInteger(ExecState*);
    36 static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsNaN(ExecState*);
    3735static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsSafeInteger(ExecState*);
    3836
    3937} // namespace JSC
     38
     39#include "NumberConstructor.lut.h"
    4040
    4141namespace JSC {
     
    4343STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(NumberConstructor);
    4444
    45 const ClassInfo NumberConstructor::s_info = { "Function", &InternalFunction::s_info, 0, CREATE_METHOD_TABLE(NumberConstructor) };
     45const ClassInfo NumberConstructor::s_info = { "Function", &InternalFunction::s_info, &numberConstructorTable, CREATE_METHOD_TABLE(NumberConstructor) };
     46
     47/* Source for NumberConstructor.lut.h
     48@begin numberConstructorTable
     49  isFinite       JSBuiltin                           DontEnum|Function 1
     50  isInteger      numberConstructorFuncIsInteger      DontEnum|Function 1
     51  isNaN          JSBuiltin                           DontEnum|Function 1
     52  isSafeInteger  numberConstructorFuncIsSafeInteger  DontEnum|Function 1
     53  parseFloat     globalFuncParseFloat                DontEnum|Function 1
     54@end
     55*/
    4656
    4757NumberConstructor::NumberConstructor(VM& vm, Structure* structure)
     
    6474    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "MAX_VALUE"), jsDoubleNumber(1.7976931348623157E+308), DontDelete | DontEnum | ReadOnly);
    6575    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "MIN_VALUE"), jsDoubleNumber(5E-324), DontDelete | DontEnum | ReadOnly);
    66     putDirectWithoutTransition(vm, Identifier::fromString(&vm, "MAX_SAFE_INTEGER"), jsDoubleNumber(9007199254740991.0), DontDelete | DontEnum | ReadOnly);
    67     putDirectWithoutTransition(vm, Identifier::fromString(&vm, "MIN_SAFE_INTEGER"), jsDoubleNumber(-9007199254740991.0), DontDelete | DontEnum | ReadOnly);
     76    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "MAX_SAFE_INTEGER"), jsDoubleNumber(maxSafeInteger()), DontDelete | DontEnum | ReadOnly);
     77    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "MIN_SAFE_INTEGER"), jsDoubleNumber(minSafeInteger()), DontDelete | DontEnum | ReadOnly);
    6878    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "NEGATIVE_INFINITY"), jsDoubleNumber(-std::numeric_limits<double>::infinity()), DontDelete | DontEnum | ReadOnly);
    6979    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "POSITIVE_INFINITY"), jsDoubleNumber(std::numeric_limits<double>::infinity()), DontDelete | DontEnum | ReadOnly);
    7080    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "NaN"), jsNaN(), DontDelete | DontEnum | ReadOnly);
    7181
    72     putDirectNativeFunctionWithoutTransition(vm, numberPrototype->globalObject(), Identifier::fromString(&vm, "isFinite"), 1, numberConstructorFuncIsFinite, NoIntrinsic, DontEnum);
    73     putDirectNativeFunctionWithoutTransition(vm, numberPrototype->globalObject(), Identifier::fromString(&vm, "isInteger"), 1, numberConstructorFuncIsInteger, NoIntrinsic, DontEnum);
    74     putDirectNativeFunctionWithoutTransition(vm, numberPrototype->globalObject(), Identifier::fromString(&vm, "isNaN"), 1, numberConstructorFuncIsNaN, NoIntrinsic, DontEnum);
    75     putDirectNativeFunctionWithoutTransition(vm, numberPrototype->globalObject(), Identifier::fromString(&vm, "isSafeInteger"), 1, numberConstructorFuncIsSafeInteger, NoIntrinsic, DontEnum);
    76     putDirectNativeFunctionWithoutTransition(vm, numberPrototype->globalObject(), Identifier::fromString(&vm, "parseFloat"), 1, globalFuncParseFloat, NoIntrinsic, DontEnum);
    7782    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "parseInt"), numberPrototype->globalObject()->parseIntFunction(), DontEnum);
    7883}
     
    109114}
    110115
    111 // ECMA-262 20.1.2.2
    112 static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsFinite(ExecState* exec)
    113 {
    114     JSValue argument = exec->argument(0);
    115     return JSValue::encode(jsBoolean(argument.isNumber() && (argument.isInt32() || std::isfinite(argument.asDouble()))));
    116 }
    117 
    118116// ECMA-262 20.1.2.3
    119117static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsInteger(ExecState* exec)
     
    130128    }
    131129    return JSValue::encode(jsBoolean(isInteger));
    132 }
    133 
    134 // ECMA-262 20.1.2.4
    135 static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsNaN(ExecState* exec)
    136 {
    137     JSValue argument = exec->argument(0);
    138     return JSValue::encode(jsBoolean(argument.isDouble() && std::isnan(argument.asDouble())));
    139130}
    140131
  • trunk/Source/JavaScriptCore/runtime/NumberConstructor.h

    r202435 r202680  
    3232public:
    3333    typedef InternalFunction Base;
    34     static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | ImplementsHasInstance | ImplementsDefaultHasInstance;
     34    static const unsigned StructureFlags = Base::StructureFlags | ImplementsHasInstance | HasStaticPropertyTable;
    3535
    3636    static NumberConstructor* create(VM& vm, Structure* structure, NumberPrototype* numberPrototype, GetterSetter*)
Note: See TracChangeset for help on using the changeset viewer.