Changeset 202680 in webkit
- Timestamp:
- Jun 30, 2016 8:26:47 AM (8 years ago)
- Location:
- trunk
- Files:
-
- 47 added
- 45 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r202679 r202680 1 2016-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 1 50 2016-06-30 Antoine Quint <graouts@apple.com> 2 51 -
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) { 1 for (var i = 0; i < 1e4; ++i) { 2 var sum = 0; 3 [1, 2, 3, 4].forEach(function (value) { 5 4 sum += value; 6 5 }); -
trunk/Source/JavaScriptCore/CMakeLists.txt
r202659 r202680 1219 1219 ${JAVASCRIPTCORE_DIR}/builtins/GeneratorPrototype.js 1220 1220 ${JAVASCRIPTCORE_DIR}/builtins/GlobalObject.js 1221 ${JAVASCRIPTCORE_DIR}/builtins/GlobalOperations.js 1221 1222 ${JAVASCRIPTCORE_DIR}/builtins/InspectorInstrumentationObject.js 1222 1223 ${JAVASCRIPTCORE_DIR}/builtins/InternalPromiseConstructor.js … … 1224 1225 ${JAVASCRIPTCORE_DIR}/builtins/MapPrototype.js 1225 1226 ${JAVASCRIPTCORE_DIR}/builtins/ModuleLoaderObject.js 1227 ${JAVASCRIPTCORE_DIR}/builtins/NumberConstructor.js 1226 1228 ${JAVASCRIPTCORE_DIR}/builtins/NumberPrototype.js 1227 1229 ${JAVASCRIPTCORE_DIR}/builtins/ObjectConstructor.js -
trunk/Source/JavaScriptCore/ChangeLog
r202673 r202680 1 2016-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 1 242 2016-06-29 Benjamin Poulain <benjamin@webkit.org> 2 243 … … 1108 1349 (JSC::DFG::FixupPhase::fixupNode): 1109 1350 (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 1110 1355 * dfg/DFGNode.h: 1111 1356 (JSC::DFG::Node::hasHeapPrediction): -
trunk/Source/JavaScriptCore/DerivedSources.make
r202435 r202680 89 89 $(JavaScriptCore)/builtins/GeneratorPrototype.js \ 90 90 $(JavaScriptCore)/builtins/GlobalObject.js \ 91 $(JavaScriptCore)/builtins/GlobalOperations.js \ 91 92 $(JavaScriptCore)/builtins/InspectorInstrumentationObject.js \ 92 93 $(JavaScriptCore)/builtins/InternalPromiseConstructor.js \ … … 94 95 $(JavaScriptCore)/builtins/MapPrototype.js \ 95 96 $(JavaScriptCore)/builtins/ModuleLoaderObject.js \ 97 $(JavaScriptCore)/builtins/NumberConstructor.js \ 96 98 $(JavaScriptCore)/builtins/NumberPrototype.js \ 97 99 $(JavaScriptCore)/builtins/ObjectConstructor.js \ -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r202659 r202680 3777 3777 A514B2C0185A684400F3C7CB /* InjectedScriptBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedScriptBase.cpp; sourceTree = "<group>"; }; 3778 3778 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>"; }; 3779 3781 A5311C341C77CEAC00E6B1B6 /* HeapSnapshotBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapSnapshotBuilder.cpp; sourceTree = "<group>"; }; 3780 3782 A5311C351C77CEAC00E6B1B6 /* HeapSnapshotBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapSnapshotBuilder.h; sourceTree = "<group>"; }; … … 6896 6898 70B7918F1C0244EC002481E2 /* GeneratorPrototype.js */, 6897 6899 7CF9BC5A1B65D9A3009DB1EF /* GlobalObject.js */, 6900 A52704851D027C8800354C37 /* GlobalOperations.js */, 6898 6901 E35E03611B7AB4850073AD2A /* InspectorInstrumentationObject.js */, 6899 6902 E33F50881B844A1A00413856 /* InternalPromiseConstructor.js */, … … 6901 6904 7035587C1C418419004BD7BF /* MapPrototype.js */, 6902 6905 E30677971B8BC6F5003F87F0 /* ModuleLoaderObject.js */, 6906 A52704861D027C8800354C37 /* NumberConstructor.js */, 6903 6907 A15DE5C51C0FBF8D0089133D /* NumberPrototype.js */, 6904 6908 7CF9BC5C1B65D9B1009DB1EF /* ObjectConstructor.js */, -
trunk/Source/JavaScriptCore/builtins/BuiltinNames.h
r202435 r202680 65 65 macro(floor) \ 66 66 macro(trunc) \ 67 macro(isFinite) \68 macro(isNaN) \69 67 macro(create) \ 70 68 macro(defineProperty) \ -
trunk/Source/JavaScriptCore/builtins/GlobalObject.js
r202435 r202680 1 1 /* 2 * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.2 * Copyright (C) 2015-2016 Yusuke Suzuki <utatane.tea@gmail.com>. 3 3 * Copyright (C) 2016 Apple Inc. All rights reserved. 4 4 * … … 25 25 */ 26 26 27 // @internal28 29 27 @globalPrivate 30 function toInteger(target)28 function isFinite(value) 31 29 { 32 30 "use strict"; 33 31 34 var numberValue = @Number(target); 35 36 // isNaN(numberValue) 32 var numberValue = @toNumber(value); 33 // Return false if numberValue is |NaN|. 37 34 if (numberValue !== numberValue) 38 return 0;39 return @trunc(numberValue);35 return false; 36 return numberValue !== @Infinity && numberValue !== -@Infinity; 40 37 } 41 38 42 39 @globalPrivate 43 function toLength(target)40 function isNaN(value) 44 41 { 45 42 "use strict"; 46 43 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; 51 46 } 52 53 @globalPrivate54 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=15136363 @globalPrivate64 function speciesGetter()65 {66 return this;67 }68 69 @globalPrivate70 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 1 1 /* 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>. 4 3 * 5 4 * Redistribution and use in source and binary forms, with or without … … 45 44 "use strict"; 46 45 47 var maxSafeInteger = 0x1FFFFFFFFFFFFF;48 46 var length = @toInteger(target); 49 47 // 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 51 50 } 52 51 … … 56 55 "use strict"; 57 56 58 return object == = @undefined || object ==null || typeof object === "object";57 return object == null || typeof object === "object"; 59 58 } 60 59 -
trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp
r202435 r202680 55 55 m_arrayIterationKindKeyValue.set(m_vm, jsNumber(ArrayIterateKeyValue)); 56 56 m_MAX_STRING_LENGTH.set(m_vm, jsNumber(JSString::MaxLength)); 57 m_MAX_SAFE_INTEGER.set(m_vm, jsDoubleNumber( 9007199254740991.0)); // 2 ^ 53 - 157 m_MAX_SAFE_INTEGER.set(m_vm, jsDoubleNumber(maxSafeInteger())); 58 58 m_ModuleFetch.set(m_vm, jsNumber(static_cast<unsigned>(ModuleLoaderObject::Status::Fetch))); 59 59 m_ModuleTranslate.set(m_vm, jsNumber(static_cast<unsigned>(ModuleLoaderObject::Status::Translate))); -
trunk/Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h
r202435 r202680 48 48 macro(tryGetById) \ 49 49 macro(putByValDirect) \ 50 macro(toNumber) \ 50 51 macro(toString) 51 52 -
trunk/Source/JavaScriptCore/bytecode/BytecodeList.json
r202633 r202680 32 32 { "name" : "op_inc", "length" : 2 }, 33 33 { "name" : "op_dec", "length" : 2 }, 34 { "name" : "op_to_number", "length" : 3},34 { "name" : "op_to_number", "length" : 4 }, 35 35 { "name" : "op_to_string", "length" : 3 }, 36 36 { "name" : "op_negate", "length" : 3 }, -
trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp
r202659 r202680 993 993 case op_to_number: { 994 994 printUnaryOp(out, exec, location, it, "to_number"); 995 dumpValueProfiling(out, it, hasPrintedProfiling); 995 996 break; 996 997 } … … 2094 2095 case op_get_direct_pname: 2095 2096 case op_get_by_id: 2096 case op_get_from_arguments: { 2097 case op_get_from_arguments: 2098 case op_to_number: { 2097 2099 ValueProfile* profile = &m_valueProfiles[pc[opLength - 1].u.operand]; 2098 2100 ASSERT(profile->m_bytecodeOffset == -1); -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
r202608 r202680 1526 1526 RegisterID* BytecodeGenerator::emitUnaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src) 1527 1527 { 1528 ASSERT_WITH_MESSAGE(op_to_number != opcodeID, "op_to_number is profiled."); 1528 1529 emitOpcode(opcodeID); 1529 1530 instructions().append(dst->index()); 1530 1531 instructions().append(src->index()); 1532 return dst; 1533 } 1534 1535 RegisterID* 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); 1531 1541 return dst; 1532 1542 } -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
r202608 r202680 512 512 513 513 RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src); 514 RegisterID* emitUnaryOpProfiled(OpcodeID, RegisterID* dst, RegisterID* src); 514 515 RegisterID* emitBinaryOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes); 515 516 RegisterID* emitEqualityOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2); … … 538 539 RegisterID* emitMove(RegisterID* dst, RegisterID* src); 539 540 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); } 541 542 RegisterID* emitToString(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_string, dst, src); } 542 543 RegisterID* emitInc(RegisterID* srcDst); -
trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
r202654 r202680 919 919 RefPtr<RegisterID> finalDest = generator.finalDestination(dst); 920 920 return generator.emitTryGetById(finalDest.get(), base.get(), ident); 921 } 922 923 RegisterID* 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())); 921 930 } 922 931 … … 1552 1561 } 1553 1562 1563 // ------------------------------ UnaryPlusNode ----------------------------------- 1564 1565 RegisterID* 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 1554 1573 // ------------------------------ BitwiseNotNode ----------------------------------- 1555 1574 -
trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
r202435 r202680 1828 1828 ASSERT(node->child1().useKind() == UntypedUse); 1829 1829 1830 if (!forNode(node->child1()).m_type) {1831 m_state.setIsValid(false);1832 break;1833 }1834 1835 1830 if (!(forNode(node->child1()).m_type & ~(SpecFullNumber | SpecBoolean | SpecString | SpecSymbol))) { 1836 1831 m_state.setFoundConstants(true); … … 1842 1837 1843 1838 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); 1844 1859 break; 1845 1860 } -
trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
r198770 r202680 361 361 } 362 362 363 case ToPrimitive: { 363 case ToPrimitive: 364 case ToNumber: { 364 365 node->child1()->mergeFlags(flags); 365 366 break; -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r202633 r202680 43 43 #include "GetByIdStatus.h" 44 44 #include "Heap.h" 45 #include "JSCInlines.h" 45 46 #include "JSLexicalEnvironment.h" 46 #include "JSCInlines.h"47 47 #include "JSModuleEnvironment.h" 48 #include "NumberConstructor.h" 48 49 #include "ObjectConstructor.h" 49 50 #include "PreciseJumpTargets.h" … … 216 217 bool handleTypedArrayConstructor(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, TypedArrayType, const ChecksFunctor& insertChecks); 217 218 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); 219 220 Node* handlePutByOffset(Node* base, unsigned identifier, PropertyOffset, const InferredType::Descriptor&, Node* value); 220 221 Node* handleGetByOffset(SpeculatedType, Node* base, unsigned identifierNumber, PropertyOffset, const InferredType::Descriptor&, NodeType = GetByOffset); … … 1652 1653 1653 1654 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)) { 1655 1656 RELEASE_ASSERT(didInsertChecks); 1656 1657 addToGraph(Phantom, callTargetNode); … … 2638 2639 bool ByteCodeParser::handleConstantInternalFunction( 2639 2640 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) 2641 2642 { 2642 2643 if (verbose) … … 2667 2668 set(VirtualRegister(resultOperand), 2668 2669 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 2669 2683 return true; 2670 2684 } … … 5051 5065 5052 5066 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)); 5056 5070 NEXT_OPCODE(op_to_number); 5057 5071 } -
trunk/Source/JavaScriptCore/dfg/DFGClobberize.h
r202435 r202680 1174 1174 write(Heap); 1175 1175 return; 1176 1177 case ToNumber: { 1178 read(World); 1179 write(Heap); 1180 return; 1181 } 1176 1182 1177 1183 case ToString: -
trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
r202435 r202680 567 567 } 568 568 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 569 578 case Check: { 570 579 alreadyHandled = true; -
trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
r202435 r202680 170 170 case LogicalNot: 171 171 case ToPrimitive: 172 case ToNumber: 172 173 case ToString: 173 174 case CallStringConstructor: -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r202435 r202680 988 988 case ToPrimitive: { 989 989 fixupToPrimitive(node); 990 break; 991 } 992 993 case ToNumber: { 994 fixupToNumber(node); 990 995 break; 991 996 } … … 1799 1804 } 1800 1805 } 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 } 1801 1839 1802 1840 void fixupToStringOrCallStringConstructor(Node* node) -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r202435 r202680 1440 1440 case StringReplace: 1441 1441 case StringReplaceRegExp: 1442 case ToNumber: 1442 1443 return true; 1443 1444 default: -
trunk/Source/JavaScriptCore/dfg/DFGNodeType.h
r202435 r202680 323 323 macro(ToPrimitive, NodeResultJS | NodeMustGenerate) \ 324 324 macro(ToString, NodeResultJS | NodeMustGenerate) \ 325 macro(ToNumber, NodeResultJS | NodeMustGenerate) \ 325 326 macro(CallObjectConstructor, NodeResultJS) \ 326 327 macro(CallStringConstructor, NodeResultJS | NodeMustGenerate) \ -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r202588 r202680 732 732 } 733 733 734 EncodedJSValue 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 734 742 EncodedJSValue JIT_OPERATION operationGetByIdWithThis(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedThis, UniquedStringImpl* impl) 735 743 { -
trunk/Source/JavaScriptCore/dfg/DFGOperations.h
r202435 r202680 59 59 EncodedJSValue JIT_OPERATION operationGetByValStringInt(ExecState*, JSString*, int32_t) WTF_INTERNAL; 60 60 EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState*, EncodedJSValue) WTF_INTERNAL; 61 EncodedJSValue JIT_OPERATION operationToNumber(ExecState*, EncodedJSValue) WTF_INTERNAL; 61 62 EncodedJSValue JIT_OPERATION operationGetByIdWithThis(ExecState*, EncodedJSValue, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL; 62 63 EncodedJSValue JIT_OPERATION operationGetByValWithThis(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue) WTF_INTERNAL; -
trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r202435 r202680 713 713 case GetGlobalLexicalVariable: 714 714 case GetClosureVar: 715 case GetFromArguments: { 715 case GetFromArguments: 716 case ToNumber: { 716 717 setPrediction(m_currentNode->getHeapPrediction()); 717 718 break; -
trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
r202435 r202680 273 273 case ToPrimitive: 274 274 case ToString: 275 case ToNumber: 275 276 case SetFunctionName: 276 277 case StrCat: -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r202435 r202680 3568 3568 case ToPrimitive: { 3569 3569 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(); 3576 3576 GPRReg resultTagGPR = resultTag.gpr(); 3577 3577 GPRReg resultPayloadGPR = resultPayload.gpr(); 3578 3578 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); 3583 3583 3584 3584 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); 3587 3587 3588 3588 addSlowPathGenerator( 3589 3589 slowPathCall( 3590 3590 notPrimitive, this, operationToPrimitive, 3591 JSValueRegs(resultTagGPR, resultPayloadGPR), op1TagGPR, op1PayloadGPR));3591 JSValueRegs(resultTagGPR, resultPayloadGPR), argumentTagGPR, argumentPayloadGPR)); 3592 3592 3593 3593 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); 3594 3635 break; 3595 3636 } -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r202435 r202680 3521 3521 case ToPrimitive: { 3522 3522 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(); 3527 3527 GPRReg resultGPR = result.gpr(); 3528 3528 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); 3533 3533 3534 3534 alreadyPrimitive.link(&m_jit); 3535 m_jit.move( op1GPR, resultGPR);3535 m_jit.move(argumentGPR, resultGPR); 3536 3536 3537 3537 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 3540 3574 jsValueResult(resultGPR, node, UseChildrenCalledExplicitly); 3541 3575 break; -
trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
r202435 r202680 162 162 case GetCallee: 163 163 case GetArgumentCountIncludingThis: 164 case ToNumber: 165 case ToString: 164 166 case CallObjectConstructor: 165 case ToString:166 167 case CallStringConstructor: 167 168 case MakeRope: … … 404 405 break; 405 406 if (node->isBinaryUseKind(BooleanUse)) 407 break; 408 if (node->isBinaryUseKind(UntypedUse)) 406 409 break; 407 410 if (node->isBinaryUseKind(SymbolUse)) -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r202519 r202680 723 723 case ReallocatePropertyStorage: 724 724 compileReallocatePropertyStorage(); 725 break; 726 case ToNumber: 727 compileToNumber(); 725 728 break; 726 729 case ToString: … … 4095 4098 object, oldStorage, transition->previous, transition->next)); 4096 4099 } 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 } 4097 4127 4098 4128 void compileToStringOrCallStringConstructor() … … 4882 4912 setBoolean( 4883 4913 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); 4884 4923 return; 4885 4924 } -
trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h
r202435 r202680 756 756 #if USE(JSVALUE64) 757 757 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); 761 759 #else 762 760 UNUSED_PARAM(mode); … … 765 763 #endif 766 764 } 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 767 774 768 775 // Note that the tempGPR is not used in 64-bit mode. … … 771 778 #if USE(JSVALUE64) 772 779 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); 776 781 #else 777 782 UNUSED_PARAM(mode); … … 780 785 #endif 781 786 } 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 782 796 783 797 Jump branchIfNotDoubleKnownNotInt32(JSValueRegs regs, TagRegistersMode mode = HaveTagRegisters) -
trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp
r202435 r202680 517 517 void JIT::emit_op_to_number(Instruction* currentInstruction) 518 518 { 519 int dstVReg = currentInstruction[1].u.operand; 519 520 int srcVReg = currentInstruction[2].u.operand; 520 521 emitGetVirtualRegister(srcVReg, regT0); … … 522 523 addSlowCase(emitJumpIfNotNumber(regT0)); 523 524 524 emitPutVirtualRegister(currentInstruction[1].u.operand); 525 emitValueProfilingSite(); 526 if (srcVReg != dstVReg) 527 emitPutVirtualRegister(dstVReg); 525 528 } 526 529 -
trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
r202435 r202680 829 829 isInt32.link(this); 830 830 831 emitValueProfilingSite(); 831 832 if (src != dst) 832 833 emitStore(dst, regT1, regT0); -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
r202633 r202680 956 956 storei t2, TagOffset[cfr, t1, 8] 957 957 storei t3, PayloadOffset[cfr, t1, 8] 958 dispatch(3) 958 valueProfile(t2, t3, 12, t1) 959 dispatch(4) 959 960 960 961 .opToNumberSlow: 961 962 callOpcodeSlowPath(_slow_path_to_number) 962 dispatch( 3)963 dispatch(4) 963 964 964 965 -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
r202633 r202680 835 835 .opToNumberIsImmediate: 836 836 storeq t2, [cfr, t1, 8] 837 dispatch(3) 837 valueProfile(t2, 3, t0) 838 dispatch(4) 838 839 839 840 .opToNumberSlow: 840 841 callOpcodeSlowPath(_slow_path_to_number) 841 dispatch( 3)842 dispatch(4) 842 843 843 844 -
trunk/Source/JavaScriptCore/parser/Nodes.h
r202435 r202680 968 968 ExpressionNode* expr() { return m_expr; } 969 969 const ExpressionNode* expr() const { return m_expr; } 970 971 private:972 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;973 974 970 OpcodeID opcodeID() const { return m_opcodeID; } 971 972 private: 973 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; 975 974 976 975 ExpressionNode* m_expr; … … 983 982 984 983 private: 984 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; 985 985 986 ExpressionNode* stripUnaryPlus() override { return expr(); } 986 987 }; -
trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
r202435 r202680 347 347 } 348 348 349 SLOW_PATH_DECL(slow_path_to_number)350 {351 BEGIN();352 RETURN(jsNumber(OP_C(2).jsValue().toNumber(exec)));353 }354 355 349 SLOW_PATH_DECL(slow_path_to_string) 356 350 { … … 398 392 static void updateResultProfileForBinaryArithOp(ExecState*, Instruction*, JSValue, JSValue, JSValue) { } 399 393 #endif 394 395 SLOW_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 } 400 402 401 403 SLOW_PATH_DECL(slow_path_add) -
trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
r202631 r202680 212 212 @begin globalObjectTable 213 213 parseFloat globalFuncParseFloat DontEnum|Function 1 214 isNaN globalFuncIsNaNDontEnum|Function 1215 isFinite globalFuncIsFiniteDontEnum|Function 1214 isNaN JSBuiltin DontEnum|Function 1 215 isFinite JSBuiltin DontEnum|Function 1 216 216 escape globalFuncEscape DontEnum|Function 1 217 217 unescape globalFuncUnescape DontEnum|Function 1 … … 407 407 408 408 m_speciesGetterSetter.set(vm, this, GetterSetter::create(vm, this)); 409 m_speciesGetterSetter->setGetter(vm, this, JSFunction::createBuiltinFunction(vm, globalO bjectSpeciesGetterCodeGenerator(vm), this, "get [Symbol.species]"));409 m_speciesGetterSetter->setGetter(vm, this, JSFunction::createBuiltinFunction(vm, globalOperationsSpeciesGetterCodeGenerator(vm), this, "get [Symbol.species]")); 410 410 411 411 m_typedArrayProto.initLater( … … 652 652 JSFunction* privateFuncAbs = JSFunction::create(vm, this, 0, String(), mathProtoFuncAbs, AbsIntrinsic); 653 653 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);656 654 JSFunction* privateFuncTrunc = JSFunction::create(vm, this, 0, String(), mathProtoFuncTrunc, TruncIntrinsic); 657 655 … … 720 718 GlobalPropertyInfo(vm.propertyNames->builtinNames().floorPrivateName(), privateFuncFloor, DontEnum | DontDelete | ReadOnly), 721 719 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),724 720 GlobalPropertyInfo(vm.propertyNames->builtinNames().PromisePrivateName(), promiseConstructor, DontEnum | DontDelete | ReadOnly), 725 721 GlobalPropertyInfo(vm.propertyNames->builtinNames().ReflectPrivateName(), reflectObject, DontEnum | DontDelete | ReadOnly), -
trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
r202435 r202680 707 707 } 708 708 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 720 709 EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec) 721 710 { -
trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h
r202435 r202680 41 41 EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState*); 42 42 EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState*); 43 EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState*);44 EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState*);45 43 EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState*); 46 44 EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState*); -
trunk/Source/JavaScriptCore/runtime/MathCommon.h
r202435 r202680 35 35 double JIT_OPERATION operationMathPow(double x, double y) WTF_INTERNAL; 36 36 int32_t JIT_OPERATION operationToInt32(double) WTF_INTERNAL; 37 38 inline constexpr double maxSafeInteger() 39 { 40 // 2 ^ 53 - 1 41 return 9007199254740991.0; 42 } 43 44 inline constexpr double minSafeInteger() 45 { 46 // -(2 ^ 53 - 1) 47 return -9007199254740991.0; 48 } 37 49 38 50 inline int clz32(uint32_t number) -
trunk/Source/JavaScriptCore/runtime/NumberConstructor.cpp
r202435 r202680 32 32 namespace JSC { 33 33 34 static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsFinite(ExecState*);35 34 static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsInteger(ExecState*); 36 static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsNaN(ExecState*);37 35 static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsSafeInteger(ExecState*); 38 36 39 37 } // namespace JSC 38 39 #include "NumberConstructor.lut.h" 40 40 41 41 namespace JSC { … … 43 43 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(NumberConstructor); 44 44 45 const ClassInfo NumberConstructor::s_info = { "Function", &InternalFunction::s_info, 0, CREATE_METHOD_TABLE(NumberConstructor) }; 45 const 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 */ 46 56 47 57 NumberConstructor::NumberConstructor(VM& vm, Structure* structure) … … 64 74 putDirectWithoutTransition(vm, Identifier::fromString(&vm, "MAX_VALUE"), jsDoubleNumber(1.7976931348623157E+308), DontDelete | DontEnum | ReadOnly); 65 75 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); 68 78 putDirectWithoutTransition(vm, Identifier::fromString(&vm, "NEGATIVE_INFINITY"), jsDoubleNumber(-std::numeric_limits<double>::infinity()), DontDelete | DontEnum | ReadOnly); 69 79 putDirectWithoutTransition(vm, Identifier::fromString(&vm, "POSITIVE_INFINITY"), jsDoubleNumber(std::numeric_limits<double>::infinity()), DontDelete | DontEnum | ReadOnly); 70 80 putDirectWithoutTransition(vm, Identifier::fromString(&vm, "NaN"), jsNaN(), DontDelete | DontEnum | ReadOnly); 71 81 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);77 82 putDirectWithoutTransition(vm, Identifier::fromString(&vm, "parseInt"), numberPrototype->globalObject()->parseIntFunction(), DontEnum); 78 83 } … … 109 114 } 110 115 111 // ECMA-262 20.1.2.2112 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 118 116 // ECMA-262 20.1.2.3 119 117 static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsInteger(ExecState* exec) … … 130 128 } 131 129 return JSValue::encode(jsBoolean(isInteger)); 132 }133 134 // ECMA-262 20.1.2.4135 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())));139 130 } 140 131 -
trunk/Source/JavaScriptCore/runtime/NumberConstructor.h
r202435 r202680 32 32 public: 33 33 typedef InternalFunction Base; 34 static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | ImplementsHasInstance | ImplementsDefaultHasInstance;34 static const unsigned StructureFlags = Base::StructureFlags | ImplementsHasInstance | HasStaticPropertyTable; 35 35 36 36 static NumberConstructor* create(VM& vm, Structure* structure, NumberPrototype* numberPrototype, GetterSetter*)
Note: See TracChangeset
for help on using the changeset viewer.