Changeset 212939 in webkit
- Timestamp:
- Feb 23, 2017 8:07:30 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 28 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r212922 r212939 1 2017-02-23 Saam Barati <sbarati@apple.com> 2 3 Intrinsicify parseInt 4 https://bugs.webkit.org/show_bug.cgi?id=168627 5 6 Reviewed by Filip Pizlo. 7 8 * stress/parse-int-intrinsic.js: Added. 9 (assert): 10 (testIntrinsic.let.s): 11 (testIntrinsic): 12 (testIntrinsic2.baz): 13 (testIntrinsic2): 14 (testIntrinsic3.foo): 15 (testIntrinsic3): 16 (testIntrinsic4.foo): 17 (testIntrinsic4): 18 (testIntrinsic5.foo): 19 (testIntrinsic5): 20 (testIntrinsic6.foo): 21 (testIntrinsic6): 22 (testIntrinsic7.foo): 23 (testIntrinsic7): 24 1 25 2017-02-23 JF Bastien <jfbastien@apple.com> 2 26 -
trunk/Source/JavaScriptCore/ChangeLog
r212922 r212939 1 2017-02-23 Saam Barati <sbarati@apple.com> 2 3 Intrinsicify parseInt 4 https://bugs.webkit.org/show_bug.cgi?id=168627 5 6 Reviewed by Filip Pizlo. 7 8 This patch makes parseInt an intrinsic in the DFG and FTL. 9 We do our best to eliminate this node. If we speculate that 10 the first operand to the operation is an int32, and that there 11 isn't a second operand, we convert to the identity of the first 12 operand. That's because parseInt(someInt) === someInt. 13 14 If the first operand is proven to be an integer, and the second 15 operand is the integer 0 or the integer 10, we can eliminate the 16 node by making it an identity over its first operand. That's 17 because parseInt(someInt, 0) === someInt and parseInt(someInt, 10) === someInt. 18 19 If we are not able to constant fold the node away, we try to remove 20 checks. The most common use case of parseInt is that its first operand 21 is a proven string. The DFG might be able to remove type checks in this 22 case. We also set up CSE rules for parseInt(someString, someIntRadix) 23 because it's a "pure" operation (modulo resolving a rope). 24 25 This looks to be a 4% Octane/Box2D progression. 26 27 * dfg/DFGAbstractInterpreterInlines.h: 28 (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): 29 * dfg/DFGByteCodeParser.cpp: 30 (JSC::DFG::ByteCodeParser::handleIntrinsicCall): 31 * dfg/DFGClobberize.h: 32 (JSC::DFG::clobberize): 33 * dfg/DFGConstantFoldingPhase.cpp: 34 (JSC::DFG::ConstantFoldingPhase::foldConstants): 35 * dfg/DFGDoesGC.cpp: 36 (JSC::DFG::doesGC): 37 * dfg/DFGFixupPhase.cpp: 38 (JSC::DFG::FixupPhase::fixupNode): 39 * dfg/DFGNode.h: 40 (JSC::DFG::Node::hasHeapPrediction): 41 * dfg/DFGNodeType.h: 42 * dfg/DFGOperations.cpp: 43 (JSC::DFG::parseIntResult): 44 * dfg/DFGOperations.h: 45 * dfg/DFGPredictionPropagationPhase.cpp: 46 * dfg/DFGSafeToExecute.h: 47 (JSC::DFG::safeToExecute): 48 * dfg/DFGSpeculativeJIT.cpp: 49 (JSC::DFG::SpeculativeJIT::compileParseInt): 50 * dfg/DFGSpeculativeJIT.h: 51 (JSC::DFG::SpeculativeJIT::callOperation): 52 (JSC::DFG::SpeculativeJIT::appendCallSetResult): 53 * dfg/DFGSpeculativeJIT32_64.cpp: 54 (JSC::DFG::SpeculativeJIT::compile): 55 * dfg/DFGSpeculativeJIT64.cpp: 56 (JSC::DFG::SpeculativeJIT::compile): 57 * ftl/FTLCapabilities.cpp: 58 (JSC::FTL::canCompile): 59 * ftl/FTLLowerDFGToB3.cpp: 60 (JSC::FTL::DFG::LowerDFGToB3::compileNode): 61 (JSC::FTL::DFG::LowerDFGToB3::compileParseInt): 62 * jit/JITOperations.h: 63 * parser/Lexer.cpp: 64 * runtime/ErrorInstance.cpp: 65 * runtime/Intrinsic.h: 66 * runtime/JSGlobalObject.cpp: 67 (JSC::JSGlobalObject::init): 68 * runtime/JSGlobalObjectFunctions.cpp: 69 (JSC::toStringView): Deleted. 70 (JSC::isStrWhiteSpace): Deleted. 71 (JSC::parseDigit): Deleted. 72 (JSC::parseIntOverflow): Deleted. 73 (JSC::parseInt): Deleted. 74 * runtime/JSGlobalObjectFunctions.h: 75 * runtime/ParseInt.h: Added. 76 (JSC::parseDigit): 77 (JSC::parseIntOverflow): 78 (JSC::isStrWhiteSpace): 79 (JSC::parseInt): 80 (JSC::toStringView): 81 * runtime/StringPrototype.cpp: 82 1 83 2017-02-23 JF Bastien <jfbastien@apple.com> 2 84 -
trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
r211463 r212939 2929 2929 break; 2930 2930 2931 case ParseInt: { 2932 AbstractValue value = forNode(node->child1()); 2933 if (value.m_type && !(value.m_type & ~SpecInt32Only)) { 2934 JSValue radix; 2935 if (!node->child2()) 2936 radix = jsNumber(0); 2937 else 2938 radix = forNode(node->child2()).m_value; 2939 2940 if (radix.isNumber() 2941 && (radix.asNumber() == 0 || radix.asNumber() == 10)) { 2942 m_state.setFoundConstants(true); 2943 forNode(node).setType(SpecInt32Only); 2944 break; 2945 } 2946 } 2947 2948 if (node->child1().useKind() == UntypedUse) 2949 clobberWorld(node->origin.semantic, clobberLimit); 2950 forNode(node).setType(m_graph, SpecBytecodeNumber); 2951 break; 2952 } 2953 2931 2954 case CreateRest: 2932 2955 if (!m_graph.isWatchingHavingABadTimeWatchpoint(node)) { -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r212818 r212939 2359 2359 return false; 2360 2360 } 2361 } 2362 2363 case ParseIntIntrinsic: { 2364 if (argumentCountIncludingThis < 2) 2365 return false; 2366 2367 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell) || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 2368 return false; 2369 2370 insertChecks(); 2371 VirtualRegister valueOperand = virtualRegisterForArgument(1, registerOffset); 2372 Node* parseInt; 2373 if (argumentCountIncludingThis == 2) 2374 parseInt = addToGraph(ParseInt, OpInfo(), OpInfo(prediction), get(valueOperand)); 2375 else { 2376 ASSERT(argumentCountIncludingThis > 2); 2377 VirtualRegister radixOperand = virtualRegisterForArgument(2, registerOffset); 2378 parseInt = addToGraph(ParseInt, OpInfo(), OpInfo(prediction), get(valueOperand), get(radixOperand)); 2379 } 2380 set(VirtualRegister(resultOperand), parseInt); 2381 return true; 2361 2382 } 2362 2383 -
trunk/Source/JavaScriptCore/dfg/DFGClobberize.h
r210695 r212939 889 889 return; 890 890 891 case ParseInt: 892 // Note: We would have eliminated a ParseInt that has just a single child as an Int32Use inside fixup. 893 if (node->child1().useKind() == StringUse && (!node->child2() || node->child2().useKind() == Int32Use)) { 894 def(PureValue(node)); 895 return; 896 } 897 898 read(World); 899 write(Heap); 900 return; 901 891 902 case OverridesHasInstance: 892 903 read(JSCell_typeInfoFlags); -
trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
r211247 r212939 603 603 } 604 604 605 case ParseInt: { 606 AbstractValue& value = m_state.forNode(node->child1()); 607 if (!value.m_type || (value.m_type & ~SpecInt32Only)) 608 break; 609 610 JSValue radix; 611 if (!node->child2()) 612 radix = jsNumber(0); 613 else 614 radix = m_state.forNode(node->child2()).m_value; 615 616 if (!radix.isNumber()) 617 break; 618 619 if (radix.asNumber() == 0 || radix.asNumber() == 10) { 620 node->child2() = Edge(); 621 node->convertToIdentity(); 622 changed = true; 623 } 624 625 break; 626 } 627 605 628 case Check: { 606 629 alreadyHandled = true; -
trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
r210695 r212939 311 311 case CallDOM: 312 312 case ArraySlice: 313 case ParseInt: // We might resolve a rope even though we don't clobber anything. 313 314 return true; 314 315 -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r211908 r212939 1791 1791 case Call: { 1792 1792 attemptToMakeCallDOM(node); 1793 break; 1794 } 1795 1796 case ParseInt: { 1797 if (node->child1()->shouldSpeculateInt32() && !node->child2()) { 1798 fixEdge<Int32Use>(node->child1()); 1799 node->convertToIdentity(); 1800 break; 1801 } 1802 1803 if (node->child1()->shouldSpeculateString()) { 1804 fixEdge<StringUse>(node->child1()); 1805 node->clearFlags(NodeMustGenerate); 1806 } 1807 1808 if (node->child2()) 1809 fixEdge<Int32Use>(node->child2()); 1810 1793 1811 break; 1794 1812 } -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r211908 r212939 1485 1485 case CallDOMGetter: 1486 1486 case CallDOM: 1487 case ParseInt: 1487 1488 return true; 1488 1489 default: -
trunk/Source/JavaScriptCore/dfg/DFGNodeType.h
r210695 r212939 245 245 macro(CheckStringIdent, NodeMustGenerate) \ 246 246 macro(CheckTypeInfoFlags, NodeMustGenerate) /* Takes an OpInfo with the flags you want to test are set */\ 247 macro(ParseInt, NodeMustGenerate | NodeResultJS) \ 247 248 \ 248 249 /* Optimizations for array mutation. */\ -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r211658 r212939 57 57 #include "ObjectConstructor.h" 58 58 #include "Operations.h" 59 #include "ParseInt.h" 59 60 #include "RegExpObject.h" 60 61 #include "Repatch.h" … … 173 174 PutPropertySlot slot(thisVal, strict); 174 175 baseValue.putInline(exec, ident, putValue, slot); 176 } 177 178 static ALWAYS_INLINE EncodedJSValue parseIntResult(double input) 179 { 180 int asInt = static_cast<int>(input); 181 if (static_cast<double>(asInt) == input) 182 return JSValue::encode(jsNumber(asInt)); 183 return JSValue::encode(jsNumber(input)); 175 184 } 176 185 … … 849 858 return JSValue::encode(asRegExpObject(base)->exec(exec, globalObject, input)); 850 859 } 860 861 EncodedJSValue JIT_OPERATION operationParseIntNoRadixGeneric(ExecState* exec, EncodedJSValue value) 862 { 863 VM& vm = exec->vm(); 864 NativeCallFrameTracer tracer(&vm, exec); 865 866 return toStringView(exec, JSValue::decode(value), [&] (StringView view) { 867 // This version is as if radix was undefined. Hence, undefined.toNumber() === 0. 868 return parseIntResult(parseInt(view, 0)); 869 }); 870 } 871 872 EncodedJSValue JIT_OPERATION operationParseIntStringNoRadix(ExecState* exec, JSString* string) 873 { 874 VM& vm = exec->vm(); 875 NativeCallFrameTracer tracer(&vm, exec); 876 auto scope = DECLARE_THROW_SCOPE(vm); 877 878 auto viewWithString = string->viewWithUnderlyingString(*exec); 879 RETURN_IF_EXCEPTION(scope, { }); 880 881 // This version is as if radix was undefined. Hence, undefined.toNumber() === 0. 882 return parseIntResult(parseInt(viewWithString.view, 0)); 883 } 884 885 EncodedJSValue JIT_OPERATION operationParseIntString(ExecState* exec, JSString* string, int32_t radix) 886 { 887 VM& vm = exec->vm(); 888 NativeCallFrameTracer tracer(&vm, exec); 889 auto scope = DECLARE_THROW_SCOPE(vm); 890 891 auto viewWithString = string->viewWithUnderlyingString(*exec); 892 RETURN_IF_EXCEPTION(scope, { }); 893 894 // This version is as if radix was undefined. Hence, undefined.toNumber() === 0. 895 return parseIntResult(parseInt(viewWithString.view, radix)); 896 } 897 898 EncodedJSValue JIT_OPERATION operationParseIntGeneric(ExecState* exec, EncodedJSValue value, int32_t radix) 899 { 900 VM& vm = exec->vm(); 901 NativeCallFrameTracer tracer(&vm, exec); 902 903 return toStringView(exec, JSValue::decode(value), [&] (StringView view) { 904 return parseIntResult(parseInt(view, radix)); 905 }); 906 } 851 907 852 908 size_t JIT_OPERATION operationRegExpTestString(ExecState* exec, JSGlobalObject* globalObject, RegExpObject* regExpObject, JSString* input) -
trunk/Source/JavaScriptCore/dfg/DFGOperations.h
r211245 r212939 164 164 JSCell* JIT_OPERATION operationJSSetFindBucket(ExecState*, JSCell*, EncodedJSValue, int32_t); 165 165 166 EncodedJSValue JIT_OPERATION operationParseIntNoRadixGeneric(ExecState*, EncodedJSValue); 167 EncodedJSValue JIT_OPERATION operationParseIntStringNoRadix(ExecState*, JSString*); 168 EncodedJSValue JIT_OPERATION operationParseIntString(ExecState*, JSString*, int32_t); 169 EncodedJSValue JIT_OPERATION operationParseIntGeneric(ExecState*, EncodedJSValue, int32_t); 170 166 171 JSCell* JIT_OPERATION operationNewStringObject(ExecState*, JSString*, Structure*); 167 172 JSCell* JIT_OPERATION operationToStringOnCell(ExecState*, JSCell*); -
trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r210695 r212939 965 965 case ToIndexString: { 966 966 setPrediction(SpecString); 967 break; 968 } 969 case ParseInt: { 970 // We expect this node to almost always produce an int32. However, 971 // it's possible it produces NaN or integers out of int32 range. We 972 // rely on the heap prediction since the parseInt() call profiled 973 // its result. 974 setPrediction(m_currentNode->getHeapPrediction()); 967 975 break; 968 976 } -
trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
r211247 r212939 270 270 case ProfileControlFlow: 271 271 case CheckTypeInfoFlags: 272 case ParseInt: 272 273 case OverridesHasInstance: 273 274 case InstanceOf: -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r212909 r212939 3119 3119 3120 3120 noResult(node); 3121 } 3122 3123 void SpeculativeJIT::compileParseInt(Node* node) 3124 { 3125 RELEASE_ASSERT(node->child1().useKind() == UntypedUse || node->child1().useKind() == StringUse); 3126 3127 GPRFlushedCallResult resultPayload(this); 3128 GPRReg resultPayloadGPR = resultPayload.gpr(); 3129 #if USE(JSVALUE64) 3130 JSValueRegs resultRegs(resultPayloadGPR); 3131 #else 3132 GPRFlushedCallResult2 resultTag(this); 3133 GPRReg resultTagGPR = resultTag.gpr(); 3134 JSValueRegs resultRegs(resultTagGPR, resultPayloadGPR); 3135 #endif 3136 3137 if (node->child2()) { 3138 SpeculateInt32Operand radix(this, node->child2()); 3139 GPRReg radixGPR = radix.gpr(); 3140 if (node->child1().useKind() == UntypedUse) { 3141 JSValueOperand value(this, node->child1()); 3142 3143 flushRegisters(); 3144 #if USE(JSVALUE64) 3145 callOperation(operationParseIntGeneric, resultRegs.gpr(), value.gpr(), radixGPR); 3146 #else 3147 callOperation(operationParseIntGeneric, resultRegs, value.jsValueRegs(), radixGPR); 3148 #endif 3149 m_jit.exceptionCheck(); 3150 } else { 3151 SpeculateCellOperand value(this, node->child1()); 3152 GPRReg valueGPR = value.gpr(); 3153 speculateString(node->child1(), valueGPR); 3154 3155 flushRegisters(); 3156 #if USE(JSVALUE64) 3157 callOperation(operationParseIntString, resultRegs.gpr(), valueGPR, radixGPR); 3158 #else 3159 callOperation(operationParseIntString, resultRegs, valueGPR, radixGPR); 3160 #endif 3161 m_jit.exceptionCheck(); 3162 } 3163 } else { 3164 if (node->child1().useKind() == UntypedUse) { 3165 JSValueOperand value(this, node->child1()); 3166 3167 flushRegisters(); 3168 #if USE(JSVALUE64) 3169 callOperation(operationParseIntNoRadixGeneric, resultRegs.gpr(), value.jsValueRegs()); 3170 #else 3171 callOperation(operationParseIntNoRadixGeneric, resultRegs, value.jsValueRegs()); 3172 #endif 3173 m_jit.exceptionCheck(); 3174 } else { 3175 SpeculateCellOperand value(this, node->child1()); 3176 GPRReg valueGPR = value.gpr(); 3177 speculateString(node->child1(), valueGPR); 3178 3179 flushRegisters(); 3180 callOperation(operationParseIntStringNoRadix, resultRegs, valueGPR); 3181 m_jit.exceptionCheck(); 3182 } 3183 } 3184 3185 jsValueResult(resultRegs, node); 3121 3186 } 3122 3187 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r211908 r212939 1308 1308 return appendCallSetResult(operation, result); 1309 1309 } 1310 1311 JITCompiler::Call callOperation(J_JITOperation_EJss operation, JSValueRegs result, GPRReg arg1) 1312 { 1313 m_jit.setupArgumentsWithExecState(arg1); 1314 return appendCallSetResult(operation, result); 1315 } 1316 1310 1317 JITCompiler::Call callOperation(T_JITOperation_EJss operation, GPRReg result, GPRReg arg1) 1311 1318 { … … 1889 1896 m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg.payloadGPR(), arg.tagGPR(), mathIC); 1890 1897 return appendCallSetResult(operation, result.payloadGPR(), result.tagGPR()); 1898 } 1899 JITCompiler::Call callOperation(J_JITOperation_EJZ operation, JSValueRegs result, JSValueRegs arg1, GPRReg arg2) 1900 { 1901 m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1.payloadGPR(), arg1.tagGPR(), arg2); 1902 return appendCallSetResult(operation, result); 1891 1903 } 1892 1904 JITCompiler::Call callOperation(J_JITOperation_EJJMic operation, JSValueRegs result, JSValueRegs arg1, JSValueRegs arg2, TrustedImmPtr mathIC) … … 2435 2447 m_jit.setupResults(result1, result2); 2436 2448 return call; 2449 } 2450 JITCompiler::Call appendCallSetResult(const FunctionPtr& function, JSValueRegs resultRegs) 2451 { 2452 #if USE(JSVALUE64) 2453 return appendCallSetResult(function, resultRegs.gpr()); 2454 #else 2455 return appendCallSetResult(function, resultRegs.payloadGPR(), resultRegs.tagGPR()); 2456 #endif 2437 2457 } 2438 2458 #if CPU(X86) … … 2685 2705 void compileCheckTypeInfoFlags(Node*); 2686 2706 void compileCheckStringIdent(Node*); 2707 2708 void compileParseInt(Node*); 2687 2709 2688 2710 void compileValueRep(Node*); -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r211908 r212939 4667 4667 } 4668 4668 4669 case ParseInt: { 4670 compileParseInt(node); 4671 break; 4672 } 4673 4669 4674 case CheckTypeInfoFlags: { 4670 4675 compileCheckTypeInfoFlags(node); -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r211908 r212939 4635 4635 } 4636 4636 4637 case ParseInt: { 4638 compileParseInt(node); 4639 break; 4640 } 4641 4637 4642 case OverridesHasInstance: { 4638 4643 -
trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
r210695 r212939 284 284 case CallDOMGetter: 285 285 case ArraySlice: 286 case ParseInt: 286 287 // These are OK. 287 288 break; -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r212453 r212939 960 960 case IsTypedArrayView: 961 961 compileIsTypedArrayView(); 962 break; 963 case ParseInt: 964 compileParseInt(); 962 965 break; 963 966 case TypeOf: … … 8220 8223 m_out.appendTo(continuation, lastNext); 8221 8224 setBoolean(m_out.phi(Int32, fastResult, slowResult)); 8225 } 8226 8227 void compileParseInt() 8228 { 8229 RELEASE_ASSERT(m_node->child1().useKind() == UntypedUse || m_node->child1().useKind() == StringUse); 8230 LValue result; 8231 if (m_node->child2()) { 8232 LValue radix = lowInt32(m_node->child2()); 8233 if (m_node->child1().useKind() == UntypedUse) 8234 result = vmCall(Int64, m_out.operation(operationParseIntGeneric), m_callFrame, lowJSValue(m_node->child1()), radix); 8235 else 8236 result = vmCall(Int64, m_out.operation(operationParseIntString), m_callFrame, lowString(m_node->child1()), radix); 8237 } else { 8238 if (m_node->child1().useKind() == UntypedUse) 8239 result = vmCall(Int64, m_out.operation(operationParseIntNoRadixGeneric), m_callFrame, lowJSValue(m_node->child1())); 8240 else 8241 result = vmCall(Int64, m_out.operation(operationParseIntStringNoRadix), m_callFrame, lowString(m_node->child1())); 8242 } 8243 setJSValue(result); 8222 8244 } 8223 8245 -
trunk/Source/JavaScriptCore/jit/JITOperations.h
r211908 r212939 154 154 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJMic)(ExecState*, EncodedJSValue, void*); 155 155 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJssZ)(ExecState*, JSString*, int32_t); 156 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJss)(ExecState*, JSString*); 156 157 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJssReo)(ExecState*, JSString*, RegExpObject*); 157 158 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJssReoJss)(ExecState*, JSString*, RegExpObject*, JSString*); -
trunk/Source/JavaScriptCore/parser/Lexer.cpp
r211319 r212939 30 30 #include "JSCInlines.h" 31 31 #include "JSFunctionInlines.h" 32 #include "JSGlobalObjectFunctions.h"33 32 #include "KeywordLookup.h" 34 33 #include "Lexer.lut.h" 35 34 #include "Nodes.h" 35 #include "ParseInt.h" 36 36 #include "Parser.h" 37 37 #include <ctype.h> -
trunk/Source/JavaScriptCore/runtime/ErrorInstance.cpp
r211247 r212939 26 26 #include "JSScope.h" 27 27 #include "JSCInlines.h" 28 #include " JSGlobalObjectFunctions.h"28 #include "ParseInt.h" 29 29 #include <wtf/text/StringBuilder.h> 30 30 -
trunk/Source/JavaScriptCore/runtime/Intrinsic.h
r210695 r212939 80 80 AtomicsXorIntrinsic, 81 81 ToLowerCaseIntrinsic, 82 ParseIntIntrinsic, 82 83 83 84 // Getter intrinsics. -
trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
r212378 r212939 577 577 m_proxyRevokeStructure.set(vm, this, ProxyRevoke::createStructure(vm, this, m_functionPrototype.get())); 578 578 579 m_parseIntFunction.set(vm, this, JSFunction::create(vm, this, 2, vm.propertyNames->parseInt.string(), globalFuncParseInt, NoIntrinsic));579 m_parseIntFunction.set(vm, this, JSFunction::create(vm, this, 2, vm.propertyNames->parseInt.string(), globalFuncParseInt, ParseIntIntrinsic)); 580 580 putDirectWithoutTransition(vm, vm.propertyNames->parseInt, m_parseIntFunction.get(), DontEnum); 581 581 -
trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
r212438 r212939 42 42 #include "Nodes.h" 43 43 #include "JSCInlines.h" 44 #include "ParseInt.h" 44 45 #include "Parser.h" 45 46 #include "StackVisitor.h" … … 61 62 62 63 static const char* const ObjectProtoCalledOnNullOrUndefinedError = "Object.prototype.__proto__ called on null or undefined"; 63 64 template<typename CallbackWhenNoException>65 static ALWAYS_INLINE typename std::result_of<CallbackWhenNoException(StringView)>::type toStringView(ExecState* exec, JSValue value, CallbackWhenNoException callback)66 {67 VM& vm = exec->vm();68 auto scope = DECLARE_THROW_SCOPE(vm);69 JSString* string = value.toStringOrNull(exec);70 if (UNLIKELY(!string))71 return { };72 auto viewWithString = string->viewWithUnderlyingString(*exec);73 RETURN_IF_EXCEPTION(scope, { });74 return callback(viewWithString.view);75 }76 64 77 65 template<unsigned charactersCount> … … 252 240 } 253 241 254 bool isStrWhiteSpace(UChar c)255 {256 switch (c) {257 // ECMA-262-5th 7.2 & 7.3258 case 0x0009:259 case 0x000A:260 case 0x000B:261 case 0x000C:262 case 0x000D:263 case 0x0020:264 case 0x00A0:265 case 0x180E: // This character used to be in Zs category before Unicode 6.3, and EcmaScript says that we should keep treating it as such.266 case 0x2028:267 case 0x2029:268 case 0xFEFF:269 return true;270 default:271 return c > 0xFF && u_charType(c) == U_SPACE_SEPARATOR;272 }273 }274 275 static int parseDigit(unsigned short c, int radix)276 {277 int digit = -1;278 279 if (isASCIIDigit(c))280 digit = c - '0';281 else if (isASCIIUpper(c))282 digit = c - 'A' + 10;283 else if (isASCIILower(c))284 digit = c - 'a' + 10;285 286 if (digit >= radix)287 return -1;288 return digit;289 }290 291 double parseIntOverflow(const LChar* s, unsigned length, int radix)292 {293 double number = 0.0;294 double radixMultiplier = 1.0;295 296 for (const LChar* p = s + length - 1; p >= s; p--) {297 if (radixMultiplier == std::numeric_limits<double>::infinity()) {298 if (*p != '0') {299 number = std::numeric_limits<double>::infinity();300 break;301 }302 } else {303 int digit = parseDigit(*p, radix);304 number += digit * radixMultiplier;305 }306 307 radixMultiplier *= radix;308 }309 310 return number;311 }312 313 static double parseIntOverflow(const UChar* s, unsigned length, int radix)314 {315 double number = 0.0;316 double radixMultiplier = 1.0;317 318 for (const UChar* p = s + length - 1; p >= s; p--) {319 if (radixMultiplier == std::numeric_limits<double>::infinity()) {320 if (*p != '0') {321 number = std::numeric_limits<double>::infinity();322 break;323 }324 } else {325 int digit = parseDigit(*p, radix);326 number += digit * radixMultiplier;327 }328 329 radixMultiplier *= radix;330 }331 332 return number;333 }334 335 static double parseIntOverflow(StringView string, int radix)336 {337 if (string.is8Bit())338 return parseIntOverflow(string.characters8(), string.length(), radix);339 return parseIntOverflow(string.characters16(), string.length(), radix);340 }341 342 // ES5.1 15.1.2.2343 template <typename CharType>344 ALWAYS_INLINE345 static double parseInt(StringView s, const CharType* data, int radix)346 {347 // 1. Let inputString be ToString(string).348 // 2. Let S be a newly created substring of inputString consisting of the first character that is not a349 // StrWhiteSpaceChar and all characters following that character. (In other words, remove leading white350 // space.) If inputString does not contain any such characters, let S be the empty string.351 int length = s.length();352 int p = 0;353 while (p < length && isStrWhiteSpace(data[p]))354 ++p;355 356 // 3. Let sign be 1.357 // 4. If S is not empty and the first character of S is a minus sign -, let sign be -1.358 // 5. If S is not empty and the first character of S is a plus sign + or a minus sign -, then remove the first character from S.359 double sign = 1;360 if (p < length) {361 if (data[p] == '+')362 ++p;363 else if (data[p] == '-') {364 sign = -1;365 ++p;366 }367 }368 369 // 6. Let R = ToInt32(radix).370 // 7. Let stripPrefix be true.371 // 8. If R != 0,then372 // b. If R != 16, let stripPrefix be false.373 // 9. Else, R == 0374 // a. LetR = 10.375 // 10. If stripPrefix is true, then376 // a. If the length of S is at least 2 and the first two characters of S are either ―0x or ―0X,377 // then remove the first two characters from S and let R = 16.378 // 11. If S contains any character that is not a radix-R digit, then let Z be the substring of S379 // consisting of all characters before the first such character; otherwise, let Z be S.380 if ((radix == 0 || radix == 16) && length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X')) {381 radix = 16;382 p += 2;383 } else if (radix == 0)384 radix = 10;385 386 // 8.a If R < 2 or R > 36, then return NaN.387 if (radix < 2 || radix > 36)388 return PNaN;389 390 // 13. Let mathInt be the mathematical integer value that is represented by Z in radix-R notation, using the letters391 // A-Z and a-z for digits with values 10 through 35. (However, if R is 10 and Z contains more than 20 significant392 // digits, every significant digit after the 20th may be replaced by a 0 digit, at the option of the implementation;393 // and if R is not 2, 4, 8, 10, 16, or 32, then mathInt may be an implementation-dependent approximation to the394 // mathematical integer value that is represented by Z in radix-R notation.)395 // 14. Let number be the Number value for mathInt.396 int firstDigitPosition = p;397 bool sawDigit = false;398 double number = 0;399 while (p < length) {400 int digit = parseDigit(data[p], radix);401 if (digit == -1)402 break;403 sawDigit = true;404 number *= radix;405 number += digit;406 ++p;407 }408 409 // 12. If Z is empty, return NaN.410 if (!sawDigit)411 return PNaN;412 413 // Alternate code path for certain large numbers.414 if (number >= mantissaOverflowLowerBound) {415 if (radix == 10) {416 size_t parsedLength;417 number = parseDouble(s.substring(firstDigitPosition, p - firstDigitPosition), parsedLength);418 } else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)419 number = parseIntOverflow(s.substring(firstDigitPosition, p - firstDigitPosition), radix);420 }421 422 // 15. Return sign x number.423 return sign * number;424 }425 426 static double parseInt(StringView s, int radix)427 {428 if (s.is8Bit())429 return parseInt(s, s.characters8(), radix);430 return parseInt(s, s.characters16(), radix);431 }432 433 242 static const int SizeOfInfinity = 8; 434 243 -
trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h
r210522 r212939 53 53 EncodedJSValue JSC_HOST_CALL globalFuncImportModule(ExecState*); 54 54 55 static const double mantissaOverflowLowerBound = 9007199254740992.0;56 double parseIntOverflow(const LChar*, unsigned length, int radix);57 bool isStrWhiteSpace(UChar);58 55 double jsToNumber(StringView); 59 56 -
trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp
r212791 r212939 38 38 #include "Lookup.h" 39 39 #include "ObjectPrototype.h" 40 #include "ParseInt.h" 40 41 #include "PropertyNameArray.h" 41 42 #include "RegExpCache.h"
Note: See TracChangeset
for help on using the changeset viewer.