Changeset 228968 in webkit
- Timestamp:
- Feb 23, 2018 4:48:32 PM (6 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 20 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r228966 r228968 1 2018-02-23 Saam Barati <sbarati@apple.com> 2 3 Make Number.isInteger an intrinsic 4 https://bugs.webkit.org/show_bug.cgi?id=183088 5 6 Reviewed by JF Bastien. 7 8 * stress/number-is-integer-intrinsic.js: Added. 9 1 10 2018-02-23 Oleksandr Skachkov <gskachkov@gmail.com> 2 11 -
trunk/Source/JavaScriptCore/ChangeLog
r228966 r228968 1 2018-02-23 Saam Barati <sbarati@apple.com> 2 3 Make Number.isInteger an intrinsic 4 https://bugs.webkit.org/show_bug.cgi?id=183088 5 6 Reviewed by JF Bastien. 7 8 When profiling the ML subtest in ARES, I noticed it was spending some 9 time in Number.isInteger. This patch makes that operation an intrinsic 10 in the DFG/FTL. It might be a speedup by 1% or so on that subtest, but 11 it's likely not an aggregate speedup on ARES. However, it is definitely 12 faster than calling into a builtin function, so we might as well have 13 it as an intrinsic. 14 15 * dfg/DFGAbstractInterpreterInlines.h: 16 (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): 17 * dfg/DFGByteCodeParser.cpp: 18 (JSC::DFG::ByteCodeParser::handleIntrinsicCall): 19 * dfg/DFGClobberize.h: 20 (JSC::DFG::clobberize): 21 * dfg/DFGDoesGC.cpp: 22 (JSC::DFG::doesGC): 23 * dfg/DFGFixupPhase.cpp: 24 (JSC::DFG::FixupPhase::fixupNode): 25 * dfg/DFGNodeType.h: 26 * dfg/DFGOperations.cpp: 27 * dfg/DFGOperations.h: 28 * dfg/DFGPredictionPropagationPhase.cpp: 29 * dfg/DFGSafeToExecute.h: 30 (JSC::DFG::safeToExecute): 31 * dfg/DFGSpeculativeJIT32_64.cpp: 32 (JSC::DFG::SpeculativeJIT::compile): 33 * dfg/DFGSpeculativeJIT64.cpp: 34 (JSC::DFG::SpeculativeJIT::compile): 35 * ftl/FTLCapabilities.cpp: 36 (JSC::FTL::canCompile): 37 * ftl/FTLLowerDFGToB3.cpp: 38 (JSC::FTL::DFG::LowerDFGToB3::compileNode): 39 (JSC::FTL::DFG::LowerDFGToB3::compileNumberIsInteger): 40 (JSC::FTL::DFG::LowerDFGToB3::unboxDouble): 41 * runtime/Intrinsic.cpp: 42 (JSC::intrinsicName): 43 * runtime/Intrinsic.h: 44 * runtime/NumberConstructor.cpp: 45 (JSC::NumberConstructor::finishCreation): 46 (JSC::numberConstructorFuncIsInteger): 47 * runtime/NumberConstructor.h: 48 (JSC::NumberConstructor::isIntegerImpl): 49 1 50 2018-02-23 Oleksandr Skachkov <gskachkov@gmail.com> 2 51 -
trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
r228693 r228968 37 37 #include "JITOperations.h" 38 38 #include "MathCommon.h" 39 #include "NumberConstructor.h" 39 40 #include "Operations.h" 40 41 #include "PutByIdStatus.h" … … 1177 1178 case IsBoolean: 1178 1179 case IsNumber: 1180 case NumberIsInteger: 1179 1181 case IsObject: 1180 1182 case IsObjectOrNull: … … 1200 1202 case IsNumber: 1201 1203 setConstant(node, jsBoolean(child.value().isNumber())); 1204 break; 1205 case NumberIsInteger: 1206 setConstant(node, jsBoolean(NumberConstructor::isIntegerImpl(child.value()))); 1202 1207 break; 1203 1208 case IsObject: … … 1308 1313 1309 1314 break; 1315 1316 case NumberIsInteger: 1317 if (!(child.m_type & ~SpecInt32Only)) { 1318 setConstant(node, jsBoolean(true)); 1319 constantWasSet = true; 1320 break; 1321 } 1322 1323 if (!(child.m_type & SpecFullNumber)) { 1324 setConstant(node, jsBoolean(false)); 1325 constantWasSet = true; 1326 break; 1327 } 1328 1329 break; 1330 1310 1331 case IsObject: 1311 1332 if (!(child.m_type & ~SpecObject)) { -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r228950 r228968 3124 3124 set(VirtualRegister(resultOperand), result); 3125 3125 } 3126 return true; 3127 } 3128 3129 case NumberIsIntegerIntrinsic: { 3130 if (argumentCountIncludingThis < 2) 3131 return false; 3132 3133 insertChecks(); 3134 Node* input = get(virtualRegisterForArgument(1, registerOffset)); 3135 Node* result = addToGraph(NumberIsInteger, input); 3136 set(VirtualRegister(resultOperand), result); 3126 3137 return true; 3127 3138 } -
trunk/Source/JavaScriptCore/dfg/DFGClobberize.h
r228860 r228968 170 170 case IsBoolean: 171 171 case IsNumber: 172 case NumberIsInteger: 172 173 case IsObject: 173 174 case IsTypedArrayView: -
trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
r228411 r228968 175 175 case IsBoolean: 176 176 case IsNumber: 177 case NumberIsInteger: 177 178 case IsObject: 178 179 case IsObjectOrNull: -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r228720 r228968 2107 2107 case ThrowStaticError: 2108 2108 fixEdge<StringUse>(node->child1()); 2109 break; 2110 2111 case NumberIsInteger: 2112 if (node->child1()->shouldSpeculateInt32()) { 2113 m_insertionSet.insertNode( 2114 m_indexInBlock, SpecNone, Check, node->origin, 2115 Edge(node->child1().node(), Int32Use)); 2116 m_graph.convertToConstant(node, jsBoolean(true)); 2117 break; 2118 } 2109 2119 break; 2110 2120 -
trunk/Source/JavaScriptCore/dfg/DFGNodeType.h
r228411 r228968 349 349 macro(IsBoolean, NodeResultBoolean) \ 350 350 macro(IsNumber, NodeResultBoolean) \ 351 macro(NumberIsInteger, NodeResultBoolean) \ 351 352 macro(IsObject, NodeResultBoolean) \ 352 353 macro(IsObjectOrNull, NodeResultBoolean) \ -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r228725 r228968 60 60 #include "JSWeakMap.h" 61 61 #include "JSWeakSet.h" 62 #include "NumberConstructor.h" 62 63 #include "ObjectConstructor.h" 63 64 #include "Operations.h" … … 2255 2256 } 2256 2257 2258 int32_t JIT_OPERATION operationNumberIsInteger(ExecState* exec, EncodedJSValue value) 2259 { 2260 VM& vm = exec->vm(); 2261 NativeCallFrameTracer tracer(&vm, exec); 2262 return NumberConstructor::isIntegerImpl(JSValue::decode(value)); 2263 } 2264 2257 2265 int32_t JIT_OPERATION operationArrayIndexOfString(ExecState* exec, Butterfly* butterfly, JSString* searchElement, int32_t index) 2258 2266 { -
trunk/Source/JavaScriptCore/dfg/DFGOperations.h
r227723 r228968 255 255 int64_t JIT_OPERATION operationConvertDoubleToInt52(double); 256 256 257 int32_t JIT_OPERATION operationNumberIsInteger(ExecState*, EncodedJSValue); 258 257 259 size_t JIT_OPERATION operationDefaultHasInstance(ExecState*, JSCell* value, JSCell* proto); 258 260 -
trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r228411 r228968 850 850 case IsBoolean: 851 851 case IsNumber: 852 case NumberIsInteger: 852 853 case IsObject: 853 854 case IsObjectOrNull: -
trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
r228411 r228968 307 307 case IsBoolean: 308 308 case IsNumber: 309 case NumberIsInteger: 309 310 case IsObject: 310 311 case IsObjectOrNull: -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r228438 r228968 4403 4403 m_jit.compare32(JITCompiler::Below, result.gpr(), JITCompiler::TrustedImm32(JSValue::LowestTag + 1), result.gpr()); 4404 4404 booleanResult(result.gpr(), node); 4405 break; 4406 } 4407 4408 case NumberIsInteger: { 4409 JSValueOperand input(this, node->child1()); 4410 JSValueRegs inputRegs = input.jsValueRegs(); 4411 flushRegisters(); 4412 GPRFlushedCallResult result(this); 4413 GPRReg resultGPR = result.gpr(); 4414 callOperation(operationNumberIsInteger, resultGPR, inputRegs); 4415 booleanResult(resultGPR, node); 4405 4416 break; 4406 4417 } -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r228420 r228968 4645 4645 break; 4646 4646 } 4647 4647 4648 case NumberIsInteger: { 4649 JSValueOperand value(this, node->child1()); 4650 GPRTemporary result(this, Reuse, value); 4651 4652 FPRTemporary temp1(this); 4653 FPRTemporary temp2(this); 4654 4655 JSValueRegs valueRegs = JSValueRegs(value.gpr()); 4656 GPRReg resultGPR = value.gpr(); 4657 4658 FPRReg tempFPR1 = temp1.fpr(); 4659 FPRReg tempFPR2 = temp2.fpr(); 4660 4661 MacroAssembler::JumpList done; 4662 4663 auto isInt32 = m_jit.branchIfInt32(valueRegs); 4664 auto notNumber = m_jit.branchIfNotDoubleKnownNotInt32(valueRegs); 4665 4666 // We're a double here. 4667 m_jit.unboxDouble(valueRegs.gpr(), resultGPR, tempFPR1); 4668 m_jit.urshift64(TrustedImm32(52), resultGPR); 4669 m_jit.and32(TrustedImm32(0x7ff), resultGPR); 4670 auto notNanNorInfinity = m_jit.branch32(JITCompiler::NotEqual, TrustedImm32(0x7ff), resultGPR); 4671 m_jit.move(TrustedImm32(ValueFalse), resultGPR); 4672 done.append(m_jit.jump()); 4673 4674 notNanNorInfinity.link(&m_jit); 4675 m_jit.roundTowardZeroDouble(tempFPR1, tempFPR2); 4676 m_jit.compareDouble(JITCompiler::DoubleEqual, tempFPR1, tempFPR2, resultGPR); 4677 m_jit.or32(TrustedImm32(ValueFalse), resultGPR); 4678 done.append(m_jit.jump()); 4679 4680 isInt32.link(&m_jit); 4681 m_jit.move(TrustedImm32(ValueTrue), resultGPR); 4682 done.append(m_jit.jump()); 4683 4684 notNumber.link(&m_jit); 4685 m_jit.move(TrustedImm32(ValueFalse), resultGPR); 4686 4687 done.link(&m_jit); 4688 jsValueResult(resultGPR, node, DataFormatJSBoolean); 4689 break; 4690 } 4691 4648 4692 case MapHash: { 4649 4693 switch (node->child1().useKind()) { -
trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
r228943 r228968 222 222 case IsBoolean: 223 223 case IsNumber: 224 case NumberIsInteger: 224 225 case IsObject: 225 226 case IsObjectOrNull: -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r228943 r228968 1062 1062 case IsNumber: 1063 1063 compileIsNumber(); 1064 break; 1065 case NumberIsInteger: 1066 compileNumberIsInteger(); 1064 1067 break; 1065 1068 case IsCellWithType: … … 8778 8781 { 8779 8782 setBoolean(isNumber(lowJSValue(m_node->child1()), provenType(m_node->child1()))); 8783 } 8784 8785 void compileNumberIsInteger() 8786 { 8787 LBasicBlock notInt32 = m_out.newBlock(); 8788 LBasicBlock doubleCase = m_out.newBlock(); 8789 LBasicBlock doubleNotNanOrInf = m_out.newBlock(); 8790 LBasicBlock continuation = m_out.newBlock(); 8791 8792 LValue input = lowJSValue(m_node->child1()); 8793 8794 ValueFromBlock trueResult = m_out.anchor(m_out.booleanTrue); 8795 m_out.branch( 8796 isInt32(input, provenType(m_node->child1())), unsure(continuation), unsure(notInt32)); 8797 8798 LBasicBlock lastNext = m_out.appendTo(notInt32, doubleCase); 8799 ValueFromBlock falseResult = m_out.anchor(m_out.booleanFalse); 8800 m_out.branch( 8801 isNotNumber(input, provenType(m_node->child1())), unsure(continuation), unsure(doubleCase)); 8802 8803 m_out.appendTo(doubleCase, doubleNotNanOrInf); 8804 LValue doubleAsInt; 8805 LValue asDouble = unboxDouble(input, &doubleAsInt); 8806 LValue expBits = m_out.bitAnd(m_out.lShr(doubleAsInt, m_out.constInt32(52)), m_out.constInt64(0x7ff)); 8807 m_out.branch( 8808 m_out.equal(expBits, m_out.constInt64(0x7ff)), 8809 unsure(continuation), unsure(doubleNotNanOrInf)); 8810 8811 m_out.appendTo(doubleNotNanOrInf, continuation); 8812 B3::PatchpointValue* patchpoint = m_out.patchpoint(Int32); 8813 patchpoint->appendSomeRegister(asDouble); 8814 patchpoint->numFPScratchRegisters = 1; 8815 patchpoint->effects = Effects::none(); 8816 patchpoint->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) { 8817 GPRReg result = params[0].gpr(); 8818 FPRReg input = params[1].fpr(); 8819 FPRReg temp = params.fpScratch(0); 8820 jit.roundTowardZeroDouble(input, temp); 8821 jit.compareDouble(MacroAssembler::DoubleEqual, input, temp, result); 8822 }); 8823 ValueFromBlock patchpointResult = m_out.anchor(patchpoint); 8824 m_out.jump(continuation); 8825 8826 m_out.appendTo(continuation, lastNext); 8827 setBoolean(m_out.phi(Int32, trueResult, falseResult, patchpointResult)); 8780 8828 } 8781 8829 … … 14319 14367 } 14320 14368 14321 LValue unboxDouble(LValue jsValue) 14322 { 14323 return m_out.bitCast(m_out.add(jsValue, m_tagTypeNumber), Double); 14369 LValue unboxDouble(LValue jsValue, LValue* unboxedAsInt = nullptr) 14370 { 14371 LValue asInt = m_out.add(jsValue, m_tagTypeNumber); 14372 if (unboxedAsInt) 14373 *unboxedAsInt = asInt; 14374 return m_out.bitCast(asInt, Double); 14324 14375 } 14325 14376 LValue boxDouble(LValue doubleValue) -
trunk/Source/JavaScriptCore/runtime/Intrinsic.cpp
r228950 r228968 130 130 case NumberPrototypeToStringIntrinsic: 131 131 return "NumberPrototypeToStringIntrinsic"; 132 case NumberIsIntegerIntrinsic: 133 return "NumberIsIntegerIntrinsic"; 132 134 case IMulIntrinsic: 133 135 return "IMulIntrinsic"; -
trunk/Source/JavaScriptCore/runtime/Intrinsic.h
r228950 r228968 78 78 StringPrototypeToLowerCaseIntrinsic, 79 79 NumberPrototypeToStringIntrinsic, 80 NumberIsIntegerIntrinsic, 80 81 IMulIntrinsic, 81 82 RandomIntrinsic, -
trunk/Source/JavaScriptCore/runtime/NumberConstructor.cpp
r224487 r228968 48 48 @begin numberConstructorTable 49 49 isFinite JSBuiltin DontEnum|Function 1 50 isInteger numberConstructorFuncIsInteger DontEnum|Function 151 50 isNaN JSBuiltin DontEnum|Function 1 52 51 isSafeInteger numberConstructorFuncIsSafeInteger DontEnum|Function 1 … … 67 66 ASSERT(inherits(vm, info())); 68 67 68 JSGlobalObject* globalObject = numberPrototype->globalObject(); 69 69 70 putDirectWithoutTransition(vm, vm.propertyNames->prototype, numberPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); 70 71 putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum); … … 81 82 putDirectWithoutTransition(vm, vm.propertyNames->parseInt, numberPrototype->globalObject()->parseIntFunction(), static_cast<unsigned>(PropertyAttribute::DontEnum)); 82 83 putDirectWithoutTransition(vm, vm.propertyNames->parseFloat, numberPrototype->globalObject()->parseFloatFunction(), static_cast<unsigned>(PropertyAttribute::DontEnum)); 84 85 JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(Identifier::fromString(&vm, "isInteger"), numberConstructorFuncIsInteger, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, NumberIsIntegerIntrinsic); 83 86 } 84 87 … … 107 110 static EncodedJSValue JSC_HOST_CALL numberConstructorFuncIsInteger(ExecState* exec) 108 111 { 109 JSValue argument = exec->argument(0); 110 bool isInteger; 111 if (argument.isInt32()) 112 isInteger = true; 113 else if (!argument.isDouble()) 114 isInteger = false; 115 else { 116 double number = argument.asDouble(); 117 isInteger = std::isfinite(number) && trunc(number) == number; 118 } 119 return JSValue::encode(jsBoolean(isInteger)); 112 return JSValue::encode(jsBoolean(NumberConstructor::isIntegerImpl(exec->argument(0)))); 120 113 } 121 114 -
trunk/Source/JavaScriptCore/runtime/NumberConstructor.h
r224487 r228968 47 47 } 48 48 49 static bool isIntegerImpl(JSValue value) 50 { 51 if (value.isInt32()) 52 return true; 53 if (!value.isDouble()) 54 return false; 55 56 double number = value.asDouble(); 57 return std::isfinite(number) && trunc(number) == number; 58 } 59 49 60 protected: 50 61 void finishCreation(VM&, NumberPrototype*);
Note: See TracChangeset
for help on using the changeset viewer.