Changeset 202413 in webkit


Ignore:
Timestamp:
Jun 23, 2016 8:41:52 PM (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/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:

Alway rely 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
44 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r202412 r202413  
     12016-06-23  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-23  Simon Fraser  <simon.fraser@apple.com>
    251
  • trunk/LayoutTests/js/regress/script-tests/many-foreach-calls.js

    r198981 r202413  
    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

    r202280 r202413  
    12181218    ${JAVASCRIPTCORE_DIR}/builtins/GeneratorPrototype.js
    12191219    ${JAVASCRIPTCORE_DIR}/builtins/GlobalObject.js
     1220    ${JAVASCRIPTCORE_DIR}/builtins/GlobalOperations.js
    12201221    ${JAVASCRIPTCORE_DIR}/builtins/InspectorInstrumentationObject.js
    12211222    ${JAVASCRIPTCORE_DIR}/builtins/InternalPromiseConstructor.js
     
    12231224    ${JAVASCRIPTCORE_DIR}/builtins/MapPrototype.js
    12241225    ${JAVASCRIPTCORE_DIR}/builtins/ModuleLoaderObject.js
     1226    ${JAVASCRIPTCORE_DIR}/builtins/NumberConstructor.js
    12251227    ${JAVASCRIPTCORE_DIR}/builtins/NumberPrototype.js
    12261228    ${JAVASCRIPTCORE_DIR}/builtins/ObjectConstructor.js
  • trunk/Source/JavaScriptCore/ChangeLog

    r202402 r202413  
     12016-06-23  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/DFGByteCodeParser.cpp:
     74        (JSC::DFG::ByteCodeParser::attemptToInlineCall):
     75        (JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
     76        (JSC::DFG::ByteCodeParser::parseBlock):
     77        We use `getPrediction()` to retrieve the heap prediction from the to_number bytecode.
     78        According to the benchmark results, choosing `getPredictionWithoutOSRExit()` causes performance regression (1.5%) in kraken stanford-crypto-aes.
     79
     80        * dfg/DFGClobberize.h:
     81        (JSC::DFG::clobberize):
     82        * dfg/DFGConstantFoldingPhase.cpp:
     83        (JSC::DFG::ConstantFoldingPhase::foldConstants):
     84        * dfg/DFGDoesGC.cpp:
     85        (JSC::DFG::doesGC):
     86        * dfg/DFGFixupPhase.cpp:
     87        (JSC::DFG::FixupPhase::fixupNode):
     88        (JSC::DFG::FixupPhase::fixupToNumber):
     89        * dfg/DFGNode.h:
     90        (JSC::DFG::Node::hasHeapPrediction):
     91        * dfg/DFGNodeType.h:
     92        * dfg/DFGOperations.cpp:
     93        * dfg/DFGOperations.h:
     94        * dfg/DFGPredictionPropagationPhase.cpp:
     95        Alway rely on the heap prediction.
     96
     97        * dfg/DFGSafeToExecute.h:
     98        (JSC::DFG::safeToExecute):
     99        * dfg/DFGSpeculativeJIT32_64.cpp:
     100        (JSC::DFG::SpeculativeJIT::compile):
     101        As of 64bit version, we carefully manage the register reuse. The largest difference between 32bit and 64bit is
     102        `branchIfNotNumber()` requires the temporary register. We should not use the result registers for that since
     103        it may be reuse the argument registers and it can break the argument registers before using them to call the operation.
     104        Currently, we allocate the additional temporary register for that scratch register.
     105
     106        * dfg/DFGSpeculativeJIT64.cpp:
     107        (JSC::DFG::SpeculativeJIT::compile):
     108        Reuse the argument register for the result if possible. And manually decrement the use count in the middle of the node.
     109        This is similar technique used in ToPrimitive. Typically, the child of ToNumber is only used by this ToNumber node since
     110        we would like to perform the type conversion onto this child node here. So this careful register reuse effectively removes
     111        the spills to call the operation. The example of the actually emitted code is the following.
     112
     113        76:<!2:loc11>     ToNumber(Untyped:@68, JS|MustGen|UseAsOther, DoubleimpurenanTopEmpty, R:World, W:Heap, Exits, ClobbersExit, bc#48)  predicting DoubleimpurenanTopEmpty
     114            0x7f986d5fe693: test %rax, %r14
     115            0x7f986d5fe696: jz 0x7f986d5fe6a1
     116            0x7f986d5fe69c: jmp 0x7f986d5fe6d1
     117            0x7f986d5fe6a1: mov %rax, %rsi
     118            0x7f986d5fe6a4: mov %rbp, %rdi
     119            0x7f986d5fe6a7: mov $0x2, 0x24(%rbp)
     120            0x7f986d5fe6ae: mov $0x7f98711ea5f0, %r11
     121            0x7f986d5fe6b8: call *%r11
     122            0x7f986d5fe6bb: mov $0x7f982d3f72d0, %r11
     123            0x7f986d5fe6c5: mov (%r11), %r11
     124            0x7f986d5fe6c8: test %r11, %r11
     125            0x7f986d5fe6cb: jnz 0x7f986d5fe88c
     126
     127        It effectively removes the unnecessary spill to call the operation!
     128
     129        * ftl/FTLCapabilities.cpp:
     130        (JSC::FTL::canCompile):
     131        * ftl/FTLLowerDFGToB3.cpp:
     132        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     133        (JSC::FTL::DFG::LowerDFGToB3::compileToNumber):
     134        (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
     135        * jit/AssemblyHelpers.h:
     136        (JSC::AssemblyHelpers::branchIfNumber):
     137        (JSC::AssemblyHelpers::branchIfNotNumber):
     138        * jit/JITOpcodes.cpp:
     139        (JSC::JIT::emit_op_to_number):
     140        * jit/JITOpcodes32_64.cpp:
     141        (JSC::JIT::emit_op_to_number):
     142        * llint/LowLevelInterpreter32_64.asm:
     143        * llint/LowLevelInterpreter64.asm:
     144        * parser/Nodes.h:
     145        (JSC::UnaryOpNode::opcodeID):
     146        * runtime/CommonSlowPaths.cpp:
     147        (JSC::SLOW_PATH_DECL):
     148        * runtime/JSGlobalObject.cpp:
     149        (JSC::JSGlobalObject::init):
     150        * runtime/JSGlobalObjectFunctions.cpp:
     151        (JSC::globalFuncIsNaN): Deleted.
     152        (JSC::globalFuncIsFinite): Deleted.
     153        * runtime/JSGlobalObjectFunctions.h:
     154        * runtime/MathCommon.h:
     155        (JSC::maxSafeInteger):
     156        (JSC::minSafeInteger):
     157        * runtime/NumberConstructor.cpp:
     158        (JSC::NumberConstructor::finishCreation):
     159        (JSC::numberConstructorFuncIsFinite): Deleted.
     160        (JSC::numberConstructorFuncIsNaN): Deleted.
     161        * runtime/NumberConstructor.h:
     162        * tests/stress/Number-isNaN-basics.js: Added.
     163        (numberIsNaNOnInteger):
     164        (testNumberIsNaNOnIntegers):
     165        (verifyNumberIsNaNOnIntegerWithOtherTypes):
     166        (numberIsNaNOnDouble):
     167        (testNumberIsNaNOnDoubles):
     168        (verifyNumberIsNaNOnDoublesWithOtherTypes):
     169        (numberIsNaNNoArguments):
     170        (numberIsNaNTooManyArguments):
     171        (testNumberIsNaNOnConstants):
     172        (numberIsNaNStructTransition):
     173        (Number.isNaN):
     174        * tests/stress/global-is-finite.js: Added.
     175        (shouldBe):
     176        * tests/stress/global-is-nan.js: Added.
     177        (shouldBe):
     178        * tests/stress/global-isNaN-basics.js: Added.
     179        (isNaNOnInteger):
     180        (testIsNaNOnIntegers):
     181        (verifyIsNaNOnIntegerWithOtherTypes):
     182        (isNaNOnDouble):
     183        (testIsNaNOnDoubles):
     184        (verifyIsNaNOnDoublesWithOtherTypes):
     185        (verifyIsNaNOnCoercedTypes):
     186        (isNaNNoArguments):
     187        (isNaNTooManyArguments):
     188        (testIsNaNOnConstants):
     189        (isNaNTypeCoercionSideEffects):
     190        (i.value.isNaNTypeCoercionSideEffects.valueOf):
     191        (isNaNStructTransition):
     192        (isNaN):
     193        * tests/stress/number-is-finite.js: Added.
     194        (shouldBe):
     195        (test2):
     196        (test3):
     197        * tests/stress/number-is-nan.js: Added.
     198        (shouldBe):
     199        (test2):
     200        (test3):
     201        * tests/stress/to-number-basics.js: Added.
     202        (shouldBe):
     203        * tests/stress/to-number-convert-identity-without-execution.js: Added.
     204        (shouldBe):
     205        (object.valueOf):
     206        (valueOf):
     207        * tests/stress/to-number-int52.js: Added.
     208        (shouldBe):
     209        (object.valueOf):
     210        * tests/stress/to-number-intrinsic-convert-to-identity-without-execution.js: Added.
     211        (shouldBe):
     212        (object.valueOf):
     213        (valueOf):
     214        * tests/stress/to-number-intrinsic-int52.js: Added.
     215        (shouldBe):
     216        (object.valueOf):
     217        * tests/stress/to-number-intrinsic-object-without-execution.js: Added.
     218        (shouldBe):
     219        (object.valueOf):
     220        * tests/stress/to-number-intrinsic-value-profiling.js: Added.
     221        (shouldBe):
     222        (object.valueOf):
     223        * tests/stress/to-number-object-without-execution.js: Added.
     224        (shouldBe):
     225        (object.valueOf):
     226        * tests/stress/to-number-object.js: Added.
     227        (shouldBe):
     228        (test12):
     229        (object1.valueOf):
     230        (test2):
     231        (test22):
     232        (object2.valueOf):
     233        (test3):
     234        (test32):
     235        (object3.valueOf):
     236        * tests/stress/to-number-value-profiling.js: Added.
     237        (shouldBe):
     238        (object.valueOf):
     239
    12402016-06-23  Saam Barati  <sbarati@apple.com>
    2241
  • trunk/Source/JavaScriptCore/DerivedSources.make

    r201542 r202413  
    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

    r202287 r202413  
    37733773                A514B2C0185A684400F3C7CB /* InjectedScriptBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedScriptBase.cpp; sourceTree = "<group>"; };
    37743774                A514B2C1185A684400F3C7CB /* InjectedScriptBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectedScriptBase.h; sourceTree = "<group>"; };
     3775                A52704851D027C8800354C37 /* GlobalOperations.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = GlobalOperations.js; sourceTree = "<group>"; };
     3776                A52704861D027C8800354C37 /* NumberConstructor.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = NumberConstructor.js; sourceTree = "<group>"; };
    37753777                A5311C341C77CEAC00E6B1B6 /* HeapSnapshotBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapSnapshotBuilder.cpp; sourceTree = "<group>"; };
    37763778                A5311C351C77CEAC00E6B1B6 /* HeapSnapshotBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapSnapshotBuilder.h; sourceTree = "<group>"; };
     
    68846886                                70B7918F1C0244EC002481E2 /* GeneratorPrototype.js */,
    68856887                                7CF9BC5A1B65D9A3009DB1EF /* GlobalObject.js */,
     6888                                A52704851D027C8800354C37 /* GlobalOperations.js */,
    68866889                                E35E03611B7AB4850073AD2A /* InspectorInstrumentationObject.js */,
    68876890                                E33F50881B844A1A00413856 /* InternalPromiseConstructor.js */,
     
    68896892                                7035587C1C418419004BD7BF /* MapPrototype.js */,
    68906893                                E30677971B8BC6F5003F87F0 /* ModuleLoaderObject.js */,
     6894                                A52704861D027C8800354C37 /* NumberConstructor.js */,
    68916895                                A15DE5C51C0FBF8D0089133D /* NumberPrototype.js */,
    68926896                                7CF9BC5C1B65D9B1009DB1EF /* ObjectConstructor.js */,
  • trunk/Source/JavaScriptCore/builtins/BuiltinNames.h

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

    r202280 r202413  
    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

    r202412 r202413  
    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
  • trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp

    r202280 r202413  
    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

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

    r202125 r202413  
    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

    r202397 r202413  
    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

    r202280 r202413  
    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

    r202125 r202413  
    511511
    512512        RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src);
     513        RegisterID* emitUnaryOpProfiled(OpcodeID, RegisterID* dst, RegisterID* src);
    513514        RegisterID* emitBinaryOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes);
    514515        RegisterID* emitEqualityOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2);
     
    537538        RegisterID* emitMove(RegisterID* dst, RegisterID* src);
    538539
    539         RegisterID* emitToNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_number, dst, src); }
     540        RegisterID* emitToNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOpProfiled(op_to_number, dst, src); }
    540541        RegisterID* emitToString(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_string, dst, src); }
    541542        RegisterID* emitInc(RegisterID* srcDst);
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r202280 r202413  
    917917    RefPtr<RegisterID> finalDest = generator.finalDestination(dst);
    918918    return generator.emitTryGetById(finalDest.get(), base.get(), ident);
     919}
     920
     921RegisterID* BytecodeIntrinsicNode::emit_intrinsic_toNumber(BytecodeGenerator& generator, RegisterID* dst)
     922{
     923    ArgumentListNode* node = m_args->m_listNode;
     924    RefPtr<RegisterID> src = generator.emitNode(node);
     925    ASSERT(!node->m_next);
     926
     927    return generator.moveToDestinationIfNeeded(dst, generator.emitToNumber(generator.tempDestination(dst), src.get()));
    919928}
    920929
     
    15501559}
    15511560
     1561// ------------------------------ UnaryPlusNode -----------------------------------
     1562
     1563RegisterID* UnaryPlusNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
     1564{
     1565    ASSERT(opcodeID() == op_to_number);
     1566    RefPtr<RegisterID> src = generator.emitNode(expr());
     1567    generator.emitExpressionInfo(position(), position(), position());
     1568    return generator.emitToNumber(generator.finalDestination(dst), src.get());
     1569}
     1570
    15521571// ------------------------------ BitwiseNotNode -----------------------------------
    15531572 
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r202363 r202413  
    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/DFGByteCodeParser.cpp

    r202397 r202413  
    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    }
     
    50475061
    50485062        case op_to_number: {
    5049             Node* node = get(VirtualRegister(currentInstruction[2].u.operand));
    5050             addToGraph(Phantom, Edge(node, NumberUse));
    5051             set(VirtualRegister(currentInstruction[1].u.operand), node);
     5063            SpeculatedType prediction = getPrediction();
     5064            Node* value = get(VirtualRegister(currentInstruction[2].u.operand));
     5065            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(ToNumber, OpInfo(0), OpInfo(prediction), value));
    50525066            NEXT_OPCODE(op_to_number);
    50535067        }
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r202363 r202413  
    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

    r201900 r202413  
    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

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

    r202364 r202413  
    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 (node->child1()->shouldSpeculateInt32()) {
     1810            fixEdge<Int32Use>(node->child1());
     1811            node->convertToIdentity();
     1812            return;
     1813        }
     1814
     1815        if (enableInt52() && node->child1()->shouldSpeculateAnyInt()) {
     1816            fixEdge<Int52RepUse>(node->child1());
     1817            node->convertToIdentity();
     1818            node->setResult(NodeResultInt52);
     1819            return;
     1820        }
     1821
     1822        if (node->child1()->shouldSpeculateNumber()) {
     1823            fixEdge<DoubleRepUse>(node->child1());
     1824            node->convertToIdentity();
     1825            node->setResult(NodeResultDouble);
     1826            return;
     1827        }
     1828
     1829        fixEdge<UntypedUse>(node->child1());
     1830        node->setResult(NodeResultJS);
     1831    }
    18011832   
    18021833    void fixupToStringOrCallStringConstructor(Node* node)
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

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

    r202363 r202413  
    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

    r202402 r202413  
    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

    r202125 r202413  
    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

    r202363 r202413  
    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

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

    r202363 r202413  
    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

    r202363 r202413  
    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

    r202363 r202413  
    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

    r202363 r202413  
    728728        case ReallocatePropertyStorage:
    729729            compileReallocatePropertyStorage();
     730            break;
     731        case ToNumber:
     732            compileToNumber();
    730733            break;
    731734        case ToString:
     
    41004103                object, oldStorage, transition->previous, transition->next));
    41014104    }
     4105
     4106    void compileToNumber()
     4107    {
     4108        LValue value = lowJSValue(m_node->child1());
     4109
     4110        if (!(abstractValue(m_node->child1()).m_type & SpecBytecodeNumber))
     4111            setJSValue(vmCall(m_out.int64, m_out.operation(operationToNumber), m_callFrame, value));
     4112        else {
     4113            LBasicBlock notNumber = m_out.newBlock();
     4114            LBasicBlock continuation = m_out.newBlock();
     4115
     4116            ValueFromBlock fastResult = m_out.anchor(value);
     4117            m_out.branch(isNumber(value, provenType(m_node->child1())), unsure(continuation), unsure(notNumber));
     4118
     4119            // notNumber case.
     4120            LBasicBlock lastNext = m_out.appendTo(notNumber, continuation);
     4121            // We have several attempts to remove ToNumber. But ToNumber still exists.
     4122            // It means that converting non-numbers to numbers by this ToNumber is not rare.
     4123            // Instead of the lazy slow path generator, we call the operation here.
     4124            ValueFromBlock slowResult = m_out.anchor(vmCall(m_out.int64, m_out.operation(operationToNumber), m_callFrame, value));
     4125            m_out.jump(continuation);
     4126
     4127            // continuation case.
     4128            m_out.appendTo(continuation, lastNext);
     4129            setJSValue(m_out.phi(m_out.int64, fastResult, slowResult));
     4130        }
     4131    }
    41024132   
    41034133    void compileToStringOrCallStringConstructor()
     
    48874917            setBoolean(
    48884918                m_out.equal(lowBoolean(m_node->child1()), lowBoolean(m_node->child2())));
     4919            return;
     4920        }
     4921
     4922        if (m_node->isBinaryUseKind(UntypedUse)) {
     4923            nonSpeculativeCompare(
     4924                [&] (LValue left, LValue right) {
     4925                    return m_out.equal(left, right);
     4926                },
     4927                operationCompareStrictEq);
    48894928            return;
    48904929        }
  • trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h

    r200879 r202413  
    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

    r202125 r202413  
    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

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

    r202131 r202413  
    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:
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

    r202244 r202413  
    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

    r202280 r202413  
    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

    r202280 r202413  
    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

    r202363 r202413  
    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
     
    403403
    404404    m_speciesGetterSetter.set(vm, this, GetterSetter::create(vm, this));
    405     m_speciesGetterSetter->setGetter(vm, this, JSFunction::createBuiltinFunction(vm, globalObjectSpeciesGetterCodeGenerator(vm), this, "get [Symbol.species]"));
     405    m_speciesGetterSetter->setGetter(vm, this, JSFunction::createBuiltinFunction(vm, globalOperationsSpeciesGetterCodeGenerator(vm), this, "get [Symbol.species]"));
    406406
    407407    m_typedArrayProto.initLater(
     
    648648    JSFunction* privateFuncAbs = JSFunction::create(vm, this, 0, String(), mathProtoFuncAbs, AbsIntrinsic);
    649649    JSFunction* privateFuncFloor = JSFunction::create(vm, this, 0, String(), mathProtoFuncFloor, FloorIntrinsic);
    650     JSFunction* privateFuncIsFinite = JSFunction::create(vm, this, 0, String(), globalFuncIsFinite);
    651     JSFunction* privateFuncIsNaN = JSFunction::create(vm, this, 0, String(), globalFuncIsNaN);
    652650    JSFunction* privateFuncTrunc = JSFunction::create(vm, this, 0, String(), mathProtoFuncTrunc, TruncIntrinsic);
    653651
     
    716714        GlobalPropertyInfo(vm.propertyNames->builtinNames().floorPrivateName(), privateFuncFloor, DontEnum | DontDelete | ReadOnly),
    717715        GlobalPropertyInfo(vm.propertyNames->builtinNames().truncPrivateName(), privateFuncTrunc, DontEnum | DontDelete | ReadOnly),
    718         GlobalPropertyInfo(vm.propertyNames->builtinNames().isFinitePrivateName(), privateFuncIsFinite, DontEnum | DontDelete | ReadOnly),
    719         GlobalPropertyInfo(vm.propertyNames->builtinNames().isNaNPrivateName(), privateFuncIsNaN, DontEnum | DontDelete | ReadOnly),
    720716        GlobalPropertyInfo(vm.propertyNames->builtinNames().PromisePrivateName(), promiseConstructor, DontEnum | DontDelete | ReadOnly),
    721717        GlobalPropertyInfo(vm.propertyNames->builtinNames().ReflectPrivateName(), reflectObject, DontEnum | DontDelete | ReadOnly),
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

    r201756 r202413  
    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

    r201619 r202413  
    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

    r202092 r202413  
    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

    r197614 r202413  
    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

    r195460 r202413  
    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.