Changeset 278462 in webkit
- Timestamp:
- Jun 4, 2021 8:58:13 AM (14 months ago)
- Location:
- trunk
- Files:
-
- 1 added
- 33 edited
-
JSTests/ChangeLog (modified) (1 diff)
-
JSTests/microbenchmarks/function-to-string.js (added)
-
Source/JavaScriptCore/CMakeLists.txt (modified) (1 diff)
-
Source/JavaScriptCore/ChangeLog (modified) (1 diff)
-
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (modified) (1 diff)
-
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (modified) (1 diff)
-
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (modified) (1 diff)
-
Source/JavaScriptCore/dfg/DFGClobberize.h (modified) (1 diff)
-
Source/JavaScriptCore/dfg/DFGDoesGC.cpp (modified) (1 diff)
-
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (modified) (1 diff)
-
Source/JavaScriptCore/dfg/DFGNodeType.h (modified) (1 diff)
-
Source/JavaScriptCore/dfg/DFGOperations.cpp (modified) (1 diff)
-
Source/JavaScriptCore/dfg/DFGOperations.h (modified) (1 diff)
-
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (modified) (1 diff)
-
Source/JavaScriptCore/dfg/DFGSafeToExecute.h (modified) (1 diff)
-
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (modified) (3 diffs)
-
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (modified) (1 diff)
-
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (modified) (1 diff)
-
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (modified) (1 diff)
-
Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h (modified) (2 diffs)
-
Source/JavaScriptCore/ftl/FTLCapabilities.cpp (modified) (1 diff)
-
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (modified) (5 diffs)
-
Source/JavaScriptCore/runtime/FunctionExecutable.cpp (modified) (2 diffs)
-
Source/JavaScriptCore/runtime/FunctionExecutable.h (modified) (3 diffs)
-
Source/JavaScriptCore/runtime/FunctionExecutableInlines.h (modified) (1 diff)
-
Source/JavaScriptCore/runtime/FunctionPrototype.cpp (modified) (2 diffs)
-
Source/JavaScriptCore/runtime/Intrinsic.cpp (modified) (1 diff)
-
Source/JavaScriptCore/runtime/Intrinsic.h (modified) (1 diff)
-
Source/JavaScriptCore/runtime/JSFunction.cpp (modified) (1 diff)
-
Source/JavaScriptCore/runtime/JSFunction.h (modified) (1 diff)
-
Source/JavaScriptCore/runtime/JSFunctionInlines.h (modified) (2 diffs)
-
Source/JavaScriptCore/runtime/JSStringInlines.h (modified) (1 diff)
-
Source/JavaScriptCore/runtime/NativeExecutable.cpp (modified) (1 diff)
-
Source/JavaScriptCore/runtime/NativeExecutable.h (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r278445 r278462 1 2021-06-04 Tadeu Zagallo <tzagallo@apple.com> 2 3 Optimize Function.prototype.toString 4 https://bugs.webkit.org/show_bug.cgi?id=226418 5 <rdar://77861846> 6 7 Reviewed by Saam Barati. 8 9 * microbenchmarks/function-to-string.js: Added. 10 (f): 11 (C): 12 (C.prototype.method1): 13 (C.prototype.method2): 14 (test): 15 (test2): 16 1 17 2021-06-03 Ross Kirsling <ross.kirsling@sony.com> 2 18 -
trunk/Source/JavaScriptCore/CMakeLists.txt
r278229 r278462 944 944 runtime/JSArrayIterator.h 945 945 runtime/JSBigInt.h 946 runtime/JSBoundFunction.h 946 947 runtime/JSCConfig.h 947 948 runtime/JSCInlines.h -
trunk/Source/JavaScriptCore/ChangeLog
r278458 r278462 1 2021-06-04 Tadeu Zagallo <tzagallo@apple.com> 2 3 Optimize Function.prototype.toString 4 https://bugs.webkit.org/show_bug.cgi?id=226418 5 <rdar://77861846> 6 7 Reviewed by Saam Barati. 8 9 Add caching to Function.prototype.toString. This is used heavily in Speedometer2, and repeatedly recomputing a 10 string which is a constant is costly. We cache the results of toString in all cases except for bound functions. 11 To make this work for bound functions, we'd need to add a new field they can use for this cache. For other 12 functions, we cache it on the executable (either NativeExecutable or FunctionExecutable). The reason we can't 13 do this on the executable for bound functions is that all bound functions share the same executable, but 14 individual bound functions can have different names. The reason it's valid to cache the results in general is that a 15 function's name field can't be changed from JS code -- it's non-writable. 16 17 This patch also makes Function.prototype.toString an intrinsic in the DFG/FTL. We emit code on the fast path 18 which reads the cached value if it's present. If not, we call into the slow path, which will compute 19 the cached value for non bound functions, or compute the result for bound functions. 20 21 I added a new microbenchmark that speeds up by >35x: 22 23 function-to-string 2197.5952+-30.7118 ^ 59.9861+-2.5550 ^ definitely 36.6350x faster 24 25 * CMakeLists.txt: 26 * JavaScriptCore.xcodeproj/project.pbxproj: 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/DFGDoesGC.cpp: 34 (JSC::DFG::doesGC): 35 * dfg/DFGFixupPhase.cpp: 36 (JSC::DFG::FixupPhase::fixupNode): 37 * dfg/DFGNodeType.h: 38 * dfg/DFGOperations.cpp: 39 (JSC::DFG::JSC_DEFINE_JIT_OPERATION): 40 * dfg/DFGOperations.h: 41 * dfg/DFGPredictionPropagationPhase.cpp: 42 * dfg/DFGSafeToExecute.h: 43 (JSC::DFG::safeToExecute): 44 * dfg/DFGSpeculativeJIT.cpp: 45 (JSC::DFG::getExecutable): 46 (JSC::DFG::SpeculativeJIT::compileFunctionToString): 47 (JSC::DFG::SpeculativeJIT::compileGetExecutable): 48 * dfg/DFGSpeculativeJIT.h: 49 * dfg/DFGSpeculativeJIT32_64.cpp: 50 (JSC::DFG::SpeculativeJIT::compile): 51 * dfg/DFGSpeculativeJIT64.cpp: 52 (JSC::DFG::SpeculativeJIT::compile): 53 * ftl/FTLAbstractHeapRepository.h: 54 * ftl/FTLCapabilities.cpp: 55 (JSC::FTL::canCompile): 56 * ftl/FTLLowerDFGToB3.cpp: 57 (JSC::FTL::DFG::LowerDFGToB3::compileNode): 58 (JSC::FTL::DFG::LowerDFGToB3::getExecutable): 59 (JSC::FTL::DFG::LowerDFGToB3::compileGetExecutable): 60 (JSC::FTL::DFG::LowerDFGToB3::compileFunctionToString): 61 * runtime/FunctionExecutable.cpp: 62 (JSC::FunctionExecutable::visitChildrenImpl): 63 (JSC::FunctionExecutable::toStringSlow): 64 * runtime/FunctionExecutable.h: 65 * runtime/FunctionExecutableInlines.h: 66 (JSC::FunctionExecutable::toString): 67 * runtime/FunctionPrototype.cpp: 68 (JSC::FunctionPrototype::addFunctionProperties): 69 (JSC::JSC_DEFINE_HOST_FUNCTION): 70 * runtime/Intrinsic.cpp: 71 (JSC::intrinsicName): 72 * runtime/Intrinsic.h: 73 * runtime/JSFunction.cpp: 74 (JSC::JSFunction::toString): 75 * runtime/JSFunction.h: 76 * runtime/JSFunctionInlines.h: 77 (JSC::JSFunction::asStringConcurrently const): 78 * runtime/JSStringInlines.h: 79 * runtime/NativeExecutable.cpp: 80 (JSC::NativeExecutable::toStringSlow): 81 (JSC::NativeExecutable::visitChildrenImpl): 82 * runtime/NativeExecutable.h: 83 1 84 2021-06-04 Michael Catanzaro <mcatanzaro@gnome.org> 2 85 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r278445 r278462 1303 1303 86F3EEBD168CDE930077B92A /* ObjCCallbackFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 86F3EEB9168CCF750077B92A /* ObjCCallbackFunction.h */; }; 1304 1304 86F3EEBF168CDE930077B92A /* ObjcRuntimeExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = 86F3EEB616855A5B0077B92A /* ObjcRuntimeExtras.h */; }; 1305 86FA9E92142BBB2E001773B7 /* JSBoundFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 86FA9E90142BBB2E001773B7 /* JSBoundFunction.h */; };1305 86FA9E92142BBB2E001773B7 /* JSBoundFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 86FA9E90142BBB2E001773B7 /* JSBoundFunction.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1306 1306 8B3BF5E41E3D368B0076A87A /* AsyncGeneratorPrototype.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B3BF5E31E3D365A0076A87A /* AsyncGeneratorPrototype.lut.h */; }; 1307 1307 8B6016F61F3E3CC000F9DE6A /* AsyncFromSyncIteratorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B6016F41F3E3CC000F9DE6A /* AsyncFromSyncIteratorPrototype.h */; }; -
trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
r278445 r278462 2856 2856 } 2857 2857 2858 case FunctionToString: { 2859 JSValue value = m_state.forNode(node->child1()).value(); 2860 if (value) { 2861 JSFunction* function = jsDynamicCast<JSFunction*>(m_vm, value); 2862 if (JSString* asString = function->asStringConcurrently(m_vm)) { 2863 setConstant(node, *m_graph.freeze(asString)); 2864 break; 2865 } 2866 } 2867 setForNode(node, m_vm.stringStructure.get()); 2868 break; 2869 } 2870 2858 2871 case NumberToStringWithRadix: { 2859 2872 JSValue radixValue = forNode(node->child2()).m_value; -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r278445 r278462 3741 3741 return false; 3742 3742 #endif 3743 } 3744 3745 case FunctionToStringIntrinsic: { 3746 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3747 return false; 3748 3749 insertChecks(); 3750 Node* function = get(virtualRegisterForArgumentIncludingThis(0, registerOffset)); 3751 Node* resultNode = addToGraph(FunctionToString, function); 3752 setResult(resultNode); 3753 return true; 3743 3754 } 3744 3755 -
trunk/Source/JavaScriptCore/dfg/DFGClobberize.h
r278445 r278462 1819 1819 return; 1820 1820 } 1821 1822 case FunctionToString: 1823 def(PureValue(node)); 1824 return; 1821 1825 1822 1826 case CountExecution: -
trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
r278445 r278462 291 291 case DirectTailCallInlinedCaller: 292 292 case ForceOSRExit: 293 case FunctionToString: 293 294 case GetById: 294 295 case GetByIdDirect: -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r278445 r278462 1974 1974 } 1975 1975 1976 case FunctionToString: { 1977 fixEdge<FunctionUse>(node->child1()); 1978 break; 1979 } 1976 1980 1977 1981 case SetPrivateBrand: { -
trunk/Source/JavaScriptCore/dfg/DFGNodeType.h
r278445 r278462 429 429 macro(NumberToStringWithRadix, NodeResultJS | NodeMustGenerate) \ 430 430 macro(NumberToStringWithValidRadixConstant, NodeResultJS) \ 431 macro(FunctionToString, NodeResultJS) \ 431 432 macro(MakeRope, NodeResultJS) \ 432 433 macro(InByVal, NodeResultBoolean | NodeMustGenerate) \ -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r278338 r278462 2561 2561 } 2562 2562 2563 JSC_DEFINE_JIT_OPERATION(operationFunctionToString, JSString*, (JSGlobalObject* globalObject, JSFunction* function)) 2564 { 2565 VM& vm = globalObject->vm(); 2566 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 2567 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 2568 2569 return function->toString(globalObject); 2570 } 2571 2563 2572 JSC_DEFINE_JIT_OPERATION(operationSingleCharacterString, JSString*, (VM* vmPointer, int32_t character)) 2564 2573 { -
trunk/Source/JavaScriptCore/dfg/DFGOperations.h
r276427 r278462 247 247 JSC_DECLARE_JIT_OPERATION(operationInt52ToStringWithValidRadix, char*, (JSGlobalObject*, int64_t, int32_t)); 248 248 JSC_DECLARE_JIT_OPERATION(operationDoubleToStringWithValidRadix, char*, (JSGlobalObject*, double, int32_t)); 249 JSC_DECLARE_JIT_OPERATION(operationFunctionToString, JSString*, (JSGlobalObject*, JSFunction*)); 249 250 250 251 JSC_DECLARE_JIT_OPERATION(operationNormalizeMapKeyHeapBigInt, EncodedJSValue, (VM*, JSBigInt*)); -
trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r278445 r278462 1159 1159 case CallStringConstructor: 1160 1160 case ToString: 1161 case FunctionToString: 1161 1162 case NumberToStringWithRadix: 1162 1163 case NumberToStringWithValidRadixConstant: -
trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
r278445 r278462 274 274 case LogicalNot: 275 275 case ToString: 276 case FunctionToString: 276 277 case NumberToStringWithValidRadixConstant: 277 278 case StrCat: -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r278445 r278462 53 53 #include "JSAsyncFunction.h" 54 54 #include "JSAsyncGeneratorFunction.h" 55 #include "JSBoundFunction.h" 55 56 #include "JSCInlines.h" 56 57 #include "JSGeneratorFunction.h" … … 10556 10557 } 10557 10558 10559 static void getExecutable(JITCompiler& jit, GPRReg functionGPR, GPRReg resultGPR) 10560 { 10561 jit.loadPtr(JITCompiler::Address(functionGPR, JSFunction::offsetOfExecutableOrRareData()), resultGPR); 10562 auto hasExecutable = jit.branchTestPtr(CCallHelpers::Zero, resultGPR, CCallHelpers::TrustedImm32(JSFunction::rareDataTag)); 10563 jit.loadPtr(CCallHelpers::Address(resultGPR, FunctionRareData::offsetOfExecutable() - JSFunction::rareDataTag), resultGPR); 10564 hasExecutable.link(&jit); 10565 } 10566 10567 void SpeculativeJIT::compileFunctionToString(Node* node) 10568 { 10569 SpeculateCellOperand function(this, node->child1()); 10570 GPRTemporary executable(this); 10571 GPRTemporary result(this); 10572 JITCompiler::JumpList slowCases; 10573 10574 speculateFunction(node->child1(), function.gpr()); 10575 10576 m_jit.emitLoadStructure(vm(), function.gpr(), result.gpr(), executable.gpr()); 10577 m_jit.loadPtr(JITCompiler::Address(result.gpr(), Structure::classInfoOffset()), result.gpr()); 10578 static_assert(std::is_final_v<JSBoundFunction>, "We don't handle subclasses when comparing classInfo below"); 10579 slowCases.append(m_jit.branchPtr(CCallHelpers::Equal, result.gpr(), TrustedImmPtr(JSBoundFunction::info()))); 10580 10581 getExecutable(m_jit, function.gpr(), executable.gpr()); 10582 JITCompiler::Jump isNativeExecutable = m_jit.branch8(JITCompiler::Equal, JITCompiler::Address(executable.gpr(), JSCell::typeInfoTypeOffset()), TrustedImm32(NativeExecutableType)); 10583 10584 m_jit.loadPtr(MacroAssembler::Address(executable.gpr(), FunctionExecutable::offsetOfRareData()), result.gpr()); 10585 slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr())); 10586 m_jit.loadPtr(MacroAssembler::Address(result.gpr(), FunctionExecutable::offsetOfAsStringInRareData()), result.gpr()); 10587 JITCompiler::Jump continuation = m_jit.jump(); 10588 10589 isNativeExecutable.link(&m_jit); 10590 m_jit.loadPtr(MacroAssembler::Address(executable.gpr(), NativeExecutable::offsetOfAsString()), result.gpr()); 10591 10592 continuation.link(&m_jit); 10593 slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr())); 10594 10595 addSlowPathGenerator(slowPathCall(slowCases, this, operationFunctionToString, result.gpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), function.gpr())); 10596 10597 cellResult(result.gpr(), node); 10598 } 10599 10558 10600 void SpeculativeJIT::compileNumberToStringWithValidRadixConstant(Node* node) 10559 10601 { … … 13305 13347 SpeculateCellOperand function(this, node->child1()); 13306 13348 GPRTemporary result(this, Reuse, function); 13307 GPRReg functionGPR = function.gpr(); 13308 GPRReg resultGPR = result.gpr(); 13309 speculateCellType(node->child1(), functionGPR, SpecFunction, JSFunctionType); 13310 m_jit.loadPtr(JITCompiler::Address(functionGPR, JSFunction::offsetOfExecutableOrRareData()), resultGPR); 13311 auto hasExecutable = m_jit.branchTestPtr(CCallHelpers::Zero, resultGPR, CCallHelpers::TrustedImm32(JSFunction::rareDataTag)); 13312 m_jit.loadPtr(CCallHelpers::Address(resultGPR, FunctionRareData::offsetOfExecutable() - JSFunction::rareDataTag), resultGPR); 13313 hasExecutable.link(&m_jit); 13314 cellResult(resultGPR, node); 13349 speculateFunction(node->child1(), function.gpr()); 13350 getExecutable(m_jit, function.gpr(), result.gpr()); 13351 cellResult(result.gpr(), node); 13315 13352 } 13316 13353 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r278253 r278462 1228 1228 1229 1229 void compileToStringOrCallStringConstructorOrStringValueOf(Node*); 1230 void compileFunctionToString(Node*); 1230 1231 void compileNumberToStringWithRadix(Node*); 1231 1232 void compileNumberToStringWithValidRadixConstant(Node*); -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r278445 r278462 3206 3206 break; 3207 3207 } 3208 3209 case FunctionToString: 3210 compileFunctionToString(node); 3211 break; 3208 3212 3209 3213 case NewStringObject: { -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r278445 r278462 3791 3791 break; 3792 3792 } 3793 3794 case FunctionToString: 3795 compileFunctionToString(node); 3796 break; 3793 3797 3794 3798 case NewStringObject: { -
trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h
r265934 r278462 78 78 macro(DirectArguments_mappedArguments, DirectArguments::offsetOfMappedArguments()) \ 79 79 macro(DirectArguments_modifiedArgumentsDescriptor, DirectArguments::offsetOfModifiedArgumentsDescriptor()) \ 80 macro(FunctionExecutable_rareData, FunctionExecutable::offsetOfRareData()) \ 81 macro(FunctionExecutableRareData_asString, FunctionExecutable::offsetOfAsStringInRareData()) \ 80 82 macro(FunctionRareData_allocator, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfileWithPrototype::offsetOfAllocator()) \ 81 83 macro(FunctionRareData_structure, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfileWithPrototype::offsetOfStructure()) \ … … 120 122 macro(JSScope_next, JSScope::offsetOfNext()) \ 121 123 macro(JSSymbolTableObject_symbolTable, JSSymbolTableObject::offsetOfSymbolTable()) \ 124 macro(NativeExecutable_asString, NativeExecutable::offsetOfAsString()) \ 122 125 macro(RegExpObject_regExpAndLastIndexIsNotWritableFlag, RegExpObject::offsetOfRegExpAndLastIndexIsNotWritableFlag()) \ 123 126 macro(RegExpObject_lastIndex, RegExpObject::offsetOfLastIndex()) \ -
trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
r278445 r278462 218 218 case ToNumeric: 219 219 case ToString: 220 case FunctionToString: 220 221 case ToObject: 221 222 case CallObjectConstructor: -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r278445 r278462 78 78 #include "JSAsyncGenerator.h" 79 79 #include "JSAsyncGeneratorFunction.h" 80 #include "JSBoundFunction.h" 80 81 #include "JSCInlines.h" 81 82 #include "JSGenerator.h" … … 1197 1198 compileToStringOrCallStringConstructorOrStringValueOf(); 1198 1199 break; 1200 case FunctionToString: 1201 compileFunctionToString(); 1202 break; 1199 1203 case ToPrimitive: 1200 1204 compileToPrimitive(); … … 3775 3779 } 3776 3780 3777 void compileGetExecutable()3781 LValue getExecutable(LValue function) 3778 3782 { 3779 3783 LBasicBlock continuation = m_out.newBlock(); 3780 3784 LBasicBlock hasRareData = m_out.newBlock(); 3781 LValue cell = lowCell(m_node->child1()); 3782 speculateFunction(m_node->child1(), cell); 3783 3784 LValue rareDataTags = m_out.loadPtr(cell, m_heaps.JSFunction_executableOrRareData); 3785 3786 LValue rareDataTags = m_out.loadPtr(function, m_heaps.JSFunction_executableOrRareData); 3785 3787 ValueFromBlock fastExecutable = m_out.anchor(rareDataTags); 3786 3788 m_out.branch(m_out.testIsZeroPtr(rareDataTags, m_out.constIntPtr(JSFunction::rareDataTag)), unsure(continuation), unsure(hasRareData)); … … 3792 3794 3793 3795 m_out.appendTo(continuation, lastNext); 3794 setJSValue(m_out.phi(pointerType(), fastExecutable, slowExecutable)); 3796 return m_out.phi(pointerType(), fastExecutable, slowExecutable); 3797 } 3798 3799 void compileGetExecutable() 3800 { 3801 LValue cell = lowCell(m_node->child1()); 3802 speculateFunction(m_node->child1(), cell); 3803 LValue executable = getExecutable(cell); 3804 setJSValue(executable); 3795 3805 } 3796 3806 … … 8220 8230 break; 8221 8231 } 8232 } 8233 8234 void compileFunctionToString() 8235 { 8236 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_origin.semantic); 8237 8238 LBasicBlock notBoundFunctionCase = m_out.newBlock(); 8239 LBasicBlock functionExecutableCase = m_out.newBlock(); 8240 LBasicBlock nativeExecutableCase = m_out.newBlock(); 8241 LBasicBlock testPtr = m_out.newBlock(); 8242 LBasicBlock hasRareData = m_out.newBlock(); 8243 LBasicBlock slowCase = m_out.newBlock(); 8244 LBasicBlock continuation = m_out.newBlock(); 8245 8246 LValue function = lowCell(m_node->child1()); 8247 speculateFunction(m_node->child1(), function); 8248 8249 LValue structure = loadStructure(function); 8250 LValue classInfo = m_out.loadPtr(structure, m_heaps.Structure_classInfo); 8251 static_assert(std::is_final_v<JSBoundFunction>, "We don't handle subclasses when comparing classInfo below"); 8252 m_out.branch(m_out.equal(classInfo, m_out.constIntPtr(JSBoundFunction::info())), unsure(slowCase), unsure(notBoundFunctionCase)); 8253 8254 LBasicBlock lastNext = m_out.appendTo(notBoundFunctionCase, nativeExecutableCase); 8255 LValue executable = getExecutable(function); 8256 m_out.branch(isType(executable, NativeExecutableType), unsure(nativeExecutableCase), unsure(functionExecutableCase)); 8257 8258 m_out.appendTo(nativeExecutableCase, functionExecutableCase); 8259 ValueFromBlock nativeResult = m_out.anchor(m_out.loadPtr(executable, m_heaps.NativeExecutable_asString)); 8260 m_out.jump(testPtr); 8261 8262 m_out.appendTo(functionExecutableCase, testPtr); 8263 LValue rareData = m_out.loadPtr(executable, m_heaps.FunctionExecutable_rareData); 8264 m_out.branch(m_out.notNull(rareData), usually(hasRareData), rarely(slowCase)); 8265 8266 m_out.appendTo(hasRareData, slowCase); 8267 ValueFromBlock functionResult = m_out.anchor(m_out.loadPtr(rareData, m_heaps.FunctionExecutableRareData_asString)); 8268 m_out.jump(testPtr); 8269 8270 m_out.appendTo(testPtr, continuation); 8271 LValue asString = m_out.phi(pointerType(), nativeResult, functionResult); 8272 ValueFromBlock fastResult = m_out.anchor(asString); 8273 m_out.branch(m_out.notNull(asString), usually(continuation), rarely(slowCase)); 8274 8275 m_out.appendTo(slowCase, continuation); 8276 ValueFromBlock slowResult = m_out.anchor(vmCall(pointerType(), operationFunctionToString, weakPointer(globalObject), function)); 8277 m_out.jump(continuation); 8278 8279 m_out.appendTo(continuation, lastNext); 8280 setJSValue(m_out.phi(pointerType(), fastResult, slowResult)); 8222 8281 } 8223 8282 -
trunk/Source/JavaScriptCore/runtime/FunctionExecutable.cpp
r278253 r278462 80 80 if (RareData* rareData = thisObject->m_rareData.get()) { 81 81 visitor.append(rareData->m_cachedPolyProtoStructure); 82 visitor.append(rareData->m_asString); 82 83 if (TemplateObjectMap* map = rareData->m_templateObjectMap.get()) { 83 84 Locker locker { thisObject->cellLock() }; … … 117 118 } 118 119 120 JSString* FunctionExecutable::toStringSlow(JSGlobalObject* globalObject) 121 { 122 VM& vm = getVM(globalObject); 123 ASSERT(m_rareData && !m_rareData->m_asString); 124 125 auto throwScope = DECLARE_THROW_SCOPE(vm); 126 127 const auto& cache = [&](JSString* asString) { 128 WTF::storeStoreFence(); 129 m_rareData->m_asString.set(vm, this, asString); 130 return asString; 131 }; 132 133 const auto& cacheIfNoException = [&](JSValue value) -> JSString* { 134 RETURN_IF_EXCEPTION(throwScope, nullptr); 135 return cache(::JSC::asString(value)); 136 }; 137 138 if (isBuiltinFunction()) 139 return cacheIfNoException(jsMakeNontrivialString(globalObject, "function ", name().string(), "() {\n [native code]\n}")); 140 141 if (isClass()) 142 return cache(jsString(vm, classSource().view().toString())); 143 144 String functionHeader; 145 switch (parseMode()) { 146 case SourceParseMode::GeneratorWrapperFunctionMode: 147 case SourceParseMode::GeneratorWrapperMethodMode: 148 functionHeader = "function* "; 149 break; 150 151 case SourceParseMode::NormalFunctionMode: 152 case SourceParseMode::GetterMode: 153 case SourceParseMode::SetterMode: 154 case SourceParseMode::MethodMode: 155 case SourceParseMode::ProgramMode: 156 case SourceParseMode::ModuleAnalyzeMode: 157 case SourceParseMode::ModuleEvaluateMode: 158 case SourceParseMode::GeneratorBodyMode: 159 case SourceParseMode::AsyncGeneratorBodyMode: 160 case SourceParseMode::AsyncFunctionBodyMode: 161 case SourceParseMode::AsyncArrowFunctionBodyMode: 162 functionHeader = "function "; 163 break; 164 165 case SourceParseMode::ArrowFunctionMode: 166 case SourceParseMode::ClassFieldInitializerMode: 167 functionHeader = ""; 168 break; 169 170 case SourceParseMode::AsyncFunctionMode: 171 case SourceParseMode::AsyncMethodMode: 172 functionHeader = "async function "; 173 break; 174 175 case SourceParseMode::AsyncArrowFunctionMode: 176 functionHeader = "async "; 177 break; 178 179 case SourceParseMode::AsyncGeneratorWrapperFunctionMode: 180 case SourceParseMode::AsyncGeneratorWrapperMethodMode: 181 functionHeader = "async function* "; 182 break; 183 } 184 185 StringView src = source().provider()->getRange( 186 parametersStartOffset(), 187 parametersStartOffset() + source().length()); 188 189 String name = this->name().string(); 190 if (name == vm.propertyNames->starDefaultPrivateName.string()) 191 name = emptyString(); 192 return cacheIfNoException(jsMakeNontrivialString(globalObject, functionHeader, name, src)); 193 } 194 119 195 void FunctionExecutable::overrideInfo(const FunctionOverrideInfo& overrideInfo) 120 196 { -
trunk/Source/JavaScriptCore/runtime/FunctionExecutable.h
r278253 r278462 286 286 void finalizeUnconditionally(VM&); 287 287 288 JSString* toString(JSGlobalObject*); 289 JSString* asStringConcurrently() const 290 { 291 if (!m_rareData) 292 return nullptr; 293 return m_rareData->m_asString.get(); 294 } 295 296 static inline ptrdiff_t offsetOfRareData() { return OBJECT_OFFSETOF(FunctionExecutable, m_rareData); } 297 static inline ptrdiff_t offsetOfAsStringInRareData() { return OBJECT_OFFSETOF(RareData, m_asString); } 298 288 299 private: 289 300 friend class ExecutableBase; … … 305 316 std::unique_ptr<TemplateObjectMap> m_templateObjectMap; 306 317 WriteBarrier<Structure> m_cachedPolyProtoStructure; 318 WriteBarrier<JSString> m_asString; 307 319 }; 308 320 … … 314 326 } 315 327 RareData& ensureRareDataSlow(); 328 329 JSString* toStringSlow(JSGlobalObject*); 316 330 317 331 // FIXME: We can merge rareData pointer and top-level executable pointer. First time, setting parent. -
trunk/Source/JavaScriptCore/runtime/FunctionExecutableInlines.h
r246073 r278462 36 36 } 37 37 38 JSString* FunctionExecutable::toString(JSGlobalObject* globalObject) 39 { 40 RareData& rareData = ensureRareData(); 41 if (!rareData.m_asString) 42 return toStringSlow(globalObject); 43 return rareData.m_asString.get(); 44 } 45 38 46 } // namespace JSC 39 47 -
trunk/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
r269922 r278462 55 55 void FunctionPrototype::addFunctionProperties(VM& vm, JSGlobalObject* globalObject, JSFunction** callFunction, JSFunction** applyFunction, JSFunction** hasInstanceSymbolFunction) 56 56 { 57 JSFunction* toStringFunction = JSFunction::create(vm, globalObject, 0, vm.propertyNames->toString.string(), functionProtoFuncToString); 58 putDirectWithoutTransition(vm, vm.propertyNames->toString, toStringFunction, static_cast<unsigned>(PropertyAttribute::DontEnum)); 57 JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().toStringPublicName(), functionProtoFuncToString, static_cast<unsigned>(PropertyAttribute::DontEnum), 0, FunctionToStringIntrinsic); 59 58 60 59 *applyFunction = putDirectBuiltinFunctionWithoutTransition(vm, globalObject, vm.propertyNames->builtinNames().applyPublicName(), functionPrototypeApplyCodeGenerator(vm), static_cast<unsigned>(PropertyAttribute::DontEnum)); … … 82 81 JSFunction* function = jsCast<JSFunction*>(thisValue); 83 82 Integrity::auditStructureID(vm, function->structureID()); 84 if (function->isHostOrBuiltinFunction()) 85 RELEASE_AND_RETURN(scope, JSValue::encode(jsMakeNontrivialString(globalObject, "function ", function->name(vm), "() {\n [native code]\n}"))); 86 87 FunctionExecutable* executable = function->jsExecutable(); 88 if (executable->isClass()) 89 return JSValue::encode(jsString(vm, executable->classSource().view().toString())); 90 91 String functionHeader; 92 switch (executable->parseMode()) { 93 case SourceParseMode::GeneratorWrapperFunctionMode: 94 case SourceParseMode::GeneratorWrapperMethodMode: 95 functionHeader = "function* "; 96 break; 97 98 case SourceParseMode::NormalFunctionMode: 99 case SourceParseMode::GetterMode: 100 case SourceParseMode::SetterMode: 101 case SourceParseMode::MethodMode: 102 case SourceParseMode::ProgramMode: 103 case SourceParseMode::ModuleAnalyzeMode: 104 case SourceParseMode::ModuleEvaluateMode: 105 case SourceParseMode::GeneratorBodyMode: 106 case SourceParseMode::AsyncGeneratorBodyMode: 107 case SourceParseMode::AsyncFunctionBodyMode: 108 case SourceParseMode::AsyncArrowFunctionBodyMode: 109 functionHeader = "function "; 110 break; 111 112 case SourceParseMode::ArrowFunctionMode: 113 case SourceParseMode::ClassFieldInitializerMode: 114 functionHeader = ""; 115 break; 116 117 case SourceParseMode::AsyncFunctionMode: 118 case SourceParseMode::AsyncMethodMode: 119 functionHeader = "async function "; 120 break; 121 122 case SourceParseMode::AsyncArrowFunctionMode: 123 functionHeader = "async "; 124 break; 125 126 case SourceParseMode::AsyncGeneratorWrapperFunctionMode: 127 case SourceParseMode::AsyncGeneratorWrapperMethodMode: 128 functionHeader = "async function* "; 129 break; 130 } 131 132 StringView source = executable->source().provider()->getRange( 133 executable->parametersStartOffset(), 134 executable->parametersStartOffset() + executable->source().length()); 135 RELEASE_AND_RETURN(scope, JSValue::encode(jsMakeNontrivialString(globalObject, functionHeader, function->name(vm), source))); 83 RELEASE_AND_RETURN(scope, JSValue::encode(function->toString(globalObject))); 136 84 } 137 85 -
trunk/Source/JavaScriptCore/runtime/Intrinsic.cpp
r278253 r278462 276 276 case ParseIntIntrinsic: 277 277 return "ParseIntIntrinsic"; 278 case FunctionToStringIntrinsic: 279 return "FunctionToStringIntrinsic"; 278 280 case TypedArrayLengthIntrinsic: 279 281 return "TypedArrayLengthIntrinsic"; -
trunk/Source/JavaScriptCore/runtime/Intrinsic.h
r278340 r278462 153 153 AtomicsXorIntrinsic, 154 154 ParseIntIntrinsic, 155 FunctionToStringIntrinsic, 155 156 156 157 // Getter intrinsics. -
trunk/Source/JavaScriptCore/runtime/JSFunction.cpp
r277665 r278462 248 248 } 249 249 250 JSString* JSFunction::toString(JSGlobalObject* globalObject) 251 { 252 VM& vm = getVM(globalObject); 253 if (inherits<JSBoundFunction>(vm)) { 254 JSBoundFunction* function = jsCast<JSBoundFunction*>(this); 255 auto scope = DECLARE_THROW_SCOPE(vm); 256 JSValue string = jsMakeNontrivialString(globalObject, "function ", function->nameString(), "() {\n [native code]\n}"); 257 RETURN_IF_EXCEPTION(scope, nullptr); 258 return asString(string); 259 } 260 261 if (isHostFunction()) 262 return static_cast<NativeExecutable*>(executable())->toString(globalObject); 263 return jsExecutable()->toString(globalObject); 264 } 265 250 266 const SourceCode* JSFunction::sourceCode() const 251 267 { -
trunk/Source/JavaScriptCore/runtime/JSFunction.h
r277665 r278462 91 91 JS_EXPORT_PRIVATE String displayName(VM&); 92 92 JS_EXPORT_PRIVATE const String calculatedDisplayName(VM&); 93 JS_EXPORT_PRIVATE JSString* toString(JSGlobalObject*); 94 95 JSString* asStringConcurrently(VM&) const; 93 96 94 97 ExecutableBase* executable() const -
trunk/Source/JavaScriptCore/runtime/JSFunctionInlines.h
r257784 r278462 27 27 28 28 #include "FunctionExecutable.h" 29 #include "JSBoundFunction.h" 29 30 #include "JSFunction.h" 30 31 #include "NativeExecutable.h" … … 157 158 } 158 159 160 inline JSString* JSFunction::asStringConcurrently(VM& vm) const 161 { 162 if (inherits<JSBoundFunction>(vm)) 163 return nullptr; 164 if (isHostFunction()) 165 return static_cast<NativeExecutable*>(executable())->asStringConcurrently(); 166 return jsExecutable()->asStringConcurrently(); 167 } 168 159 169 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/JSStringInlines.h
r251425 r278462 26 26 #pragma once 27 27 28 #include "JSGlobalObjectInlines.h" 28 29 #include "JSString.h" 29 30 -
trunk/Source/JavaScriptCore/runtime/NativeExecutable.cpp
r268247 r278462 94 94 } 95 95 96 JSString* NativeExecutable::toStringSlow(JSGlobalObject *globalObject) 97 { 98 VM& vm = getVM(globalObject); 99 100 auto throwScope = DECLARE_THROW_SCOPE(vm); 101 102 JSValue value = jsMakeNontrivialString(globalObject, "function ", name(), "() {\n [native code]\n}"); 103 104 RETURN_IF_EXCEPTION(throwScope, nullptr); 105 106 JSString* asString = ::JSC::asString(value); 107 WTF::storeStoreFence(); 108 m_asString.set(vm, this, asString); 109 return asString; 110 } 111 112 template<typename Visitor> 113 void NativeExecutable::visitChildrenImpl(JSCell* cell, Visitor& visitor) 114 { 115 NativeExecutable* thisObject = jsCast<NativeExecutable*>(cell); 116 ASSERT_GC_OBJECT_INHERITS(thisObject, info()); 117 Base::visitChildren(thisObject, visitor); 118 visitor.append(thisObject->m_asString); 119 } 120 121 DEFINE_VISIT_CHILDREN(NativeExecutable); 122 96 123 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/NativeExecutable.h
r260415 r278462 68 68 } 69 69 70 DECLARE_VISIT_CHILDREN; 70 71 static Structure* createStructure(VM&, JSGlobalObject*, JSValue proto); 71 72 … … 77 78 Intrinsic intrinsic() const; 78 79 80 JSString* toString(JSGlobalObject* globalObject) 81 { 82 if (!m_asString) 83 return toStringSlow(globalObject); 84 return m_asString.get(); 85 } 86 87 JSString* asStringConcurrently() const { return m_asString.get(); } 88 static inline ptrdiff_t offsetOfAsString() { return OBJECT_OFFSETOF(NativeExecutable, m_asString); } 89 79 90 private: 80 91 NativeExecutable(VM&, TaggedNativeFunction, TaggedNativeFunction constructor); 81 92 void finishCreation(VM&, Ref<JITCode>&& callThunk, Ref<JITCode>&& constructThunk, const String& name); 93 94 JSString* toStringSlow(JSGlobalObject*); 82 95 83 96 TaggedNativeFunction m_function; … … 85 98 86 99 String m_name; 100 WriteBarrier<JSString> m_asString; 87 101 }; 88 102
Note: See TracChangeset
for help on using the changeset viewer.