Diff
Modified: trunk/JSTests/ChangeLog (278461 => 278462)
--- trunk/JSTests/ChangeLog 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/JSTests/ChangeLog 2021-06-04 15:58:13 UTC (rev 278462)
@@ -1,3 +1,19 @@
+2021-06-04 Tadeu Zagallo <[email protected]>
+
+ Optimize Function.prototype.toString
+ https://bugs.webkit.org/show_bug.cgi?id=226418
+ <rdar://77861846>
+
+ Reviewed by Saam Barati.
+
+ * microbenchmarks/function-to-string.js: Added.
+ (f):
+ (C):
+ (C.prototype.method1):
+ (C.prototype.method2):
+ (test):
+ (test2):
+
2021-06-03 Ross Kirsling <[email protected]>
[JSC] Implement JIT ICs for InByVal
Added: trunk/JSTests/microbenchmarks/function-to-string.js (0 => 278462)
--- trunk/JSTests/microbenchmarks/function-to-string.js (rev 0)
+++ trunk/JSTests/microbenchmarks/function-to-string.js 2021-06-04 15:58:13 UTC (rev 278462)
@@ -0,0 +1,40 @@
+function f(x, y, z) {
+ // comment in the body
+ const w = 42;
+ return w + x + y + z;
+
+}
+noInline(f);
+
+class C {
+ // comment in the class
+ constructor() {
+ }
+
+ method1() {
+ return "some string";
+ }
+
+ method2() {
+ return 42;
+ }
+}
+
+function test() {
+ f.toString();
+ C.toString();
+ print.toString();
+}
+noInline(test);
+
+for (let i = 0; i < 1e7; ++i)
+ test();
+
+function test2(x, y, z) {
+ for (let i = 0; i < 1e6; ++i) {
+ f(x.toString(), y.toString(), z.toString(), x.toString(), y.toString());
+ }
+}
+noInline(test2);
+
+test2(f, C, print);
Modified: trunk/Source/_javascript_Core/CMakeLists.txt (278461 => 278462)
--- trunk/Source/_javascript_Core/CMakeLists.txt 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/CMakeLists.txt 2021-06-04 15:58:13 UTC (rev 278462)
@@ -943,6 +943,7 @@
runtime/JSArrayBufferViewInlines.h
runtime/JSArrayIterator.h
runtime/JSBigInt.h
+ runtime/JSBoundFunction.h
runtime/JSCConfig.h
runtime/JSCInlines.h
runtime/JSCJSValue.h
Modified: trunk/Source/_javascript_Core/ChangeLog (278461 => 278462)
--- trunk/Source/_javascript_Core/ChangeLog 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-06-04 15:58:13 UTC (rev 278462)
@@ -1,3 +1,86 @@
+2021-06-04 Tadeu Zagallo <[email protected]>
+
+ Optimize Function.prototype.toString
+ https://bugs.webkit.org/show_bug.cgi?id=226418
+ <rdar://77861846>
+
+ Reviewed by Saam Barati.
+
+ Add caching to Function.prototype.toString. This is used heavily in Speedometer2, and repeatedly recomputing a
+ string which is a constant is costly. We cache the results of toString in all cases except for bound functions.
+ To make this work for bound functions, we'd need to add a new field they can use for this cache. For other
+ functions, we cache it on the executable (either NativeExecutable or FunctionExecutable). The reason we can't
+ do this on the executable for bound functions is that all bound functions share the same executable, but
+ individual bound functions can have different names. The reason it's valid to cache the results in general is that a
+ function's name field can't be changed from JS code -- it's non-writable.
+
+ This patch also makes Function.prototype.toString an intrinsic in the DFG/FTL. We emit code on the fast path
+ which reads the cached value if it's present. If not, we call into the slow path, which will compute
+ the cached value for non bound functions, or compute the result for bound functions.
+
+ I added a new microbenchmark that speeds up by >35x:
+
+ function-to-string 2197.5952+-30.7118 ^ 59.9861+-2.5550 ^ definitely 36.6350x faster
+
+ * CMakeLists.txt:
+ * _javascript_Core.xcodeproj/project.pbxproj:
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGDoesGC.cpp:
+ (JSC::DFG::doesGC):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGNodeType.h:
+ * dfg/DFGOperations.cpp:
+ (JSC::DFG::JSC_DEFINE_JIT_OPERATION):
+ * dfg/DFGOperations.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::safeToExecute):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::getExecutable):
+ (JSC::DFG::SpeculativeJIT::compileFunctionToString):
+ (JSC::DFG::SpeculativeJIT::compileGetExecutable):
+ * dfg/DFGSpeculativeJIT.h:
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * ftl/FTLAbstractHeapRepository.h:
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+ (JSC::FTL::DFG::LowerDFGToB3::getExecutable):
+ (JSC::FTL::DFG::LowerDFGToB3::compileGetExecutable):
+ (JSC::FTL::DFG::LowerDFGToB3::compileFunctionToString):
+ * runtime/FunctionExecutable.cpp:
+ (JSC::FunctionExecutable::visitChildrenImpl):
+ (JSC::FunctionExecutable::toStringSlow):
+ * runtime/FunctionExecutable.h:
+ * runtime/FunctionExecutableInlines.h:
+ (JSC::FunctionExecutable::toString):
+ * runtime/FunctionPrototype.cpp:
+ (JSC::FunctionPrototype::addFunctionProperties):
+ (JSC::JSC_DEFINE_HOST_FUNCTION):
+ * runtime/Intrinsic.cpp:
+ (JSC::intrinsicName):
+ * runtime/Intrinsic.h:
+ * runtime/JSFunction.cpp:
+ (JSC::JSFunction::toString):
+ * runtime/JSFunction.h:
+ * runtime/JSFunctionInlines.h:
+ (JSC::JSFunction::asStringConcurrently const):
+ * runtime/JSStringInlines.h:
+ * runtime/NativeExecutable.cpp:
+ (JSC::NativeExecutable::toStringSlow):
+ (JSC::NativeExecutable::visitChildrenImpl):
+ * runtime/NativeExecutable.h:
+
2021-06-04 Michael Catanzaro <[email protected]>
Fix more GCC warnings
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (278461 => 278462)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2021-06-04 15:58:13 UTC (rev 278462)
@@ -1302,7 +1302,7 @@
86ECA3FA132DF25A002B2AD7 /* DFGScoreBoard.h in Headers */ = {isa = PBXBuildFile; fileRef = 86ECA3F9132DF25A002B2AD7 /* DFGScoreBoard.h */; };
86F3EEBD168CDE930077B92A /* ObjCCallbackFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 86F3EEB9168CCF750077B92A /* ObjCCallbackFunction.h */; };
86F3EEBF168CDE930077B92A /* ObjcRuntimeExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = 86F3EEB616855A5B0077B92A /* ObjcRuntimeExtras.h */; };
- 86FA9E92142BBB2E001773B7 /* JSBoundFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 86FA9E90142BBB2E001773B7 /* JSBoundFunction.h */; };
+ 86FA9E92142BBB2E001773B7 /* JSBoundFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 86FA9E90142BBB2E001773B7 /* JSBoundFunction.h */; settings = {ATTRIBUTES = (Private, ); }; };
8B3BF5E41E3D368B0076A87A /* AsyncGeneratorPrototype.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B3BF5E31E3D365A0076A87A /* AsyncGeneratorPrototype.lut.h */; };
8B6016F61F3E3CC000F9DE6A /* AsyncFromSyncIteratorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B6016F41F3E3CC000F9DE6A /* AsyncFromSyncIteratorPrototype.h */; };
8B9F6D561D5912FA001C739F /* IterationKind.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B9F6D551D5912FA001C739F /* IterationKind.h */; settings = {ATTRIBUTES = (Private, ); }; };
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (278461 => 278462)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2021-06-04 15:58:13 UTC (rev 278462)
@@ -2855,6 +2855,19 @@
break;
}
+ case FunctionToString: {
+ JSValue value = m_state.forNode(node->child1()).value();
+ if (value) {
+ JSFunction* function = jsDynamicCast<JSFunction*>(m_vm, value);
+ if (JSString* asString = function->asStringConcurrently(m_vm)) {
+ setConstant(node, *m_graph.freeze(asString));
+ break;
+ }
+ }
+ setForNode(node, m_vm.stringStructure.get());
+ break;
+ }
+
case NumberToStringWithRadix: {
JSValue radixValue = forNode(node->child2()).m_value;
if (radixValue && radixValue.isInt32()) {
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (278461 => 278462)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2021-06-04 15:58:13 UTC (rev 278462)
@@ -3742,6 +3742,17 @@
#endif
}
+ case FunctionToStringIntrinsic: {
+ if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType))
+ return false;
+
+ insertChecks();
+ Node* function = get(virtualRegisterForArgumentIncludingThis(0, registerOffset));
+ Node* resultNode = addToGraph(FunctionToString, function);
+ setResult(resultNode);
+ return true;
+ }
+
default:
return false;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (278461 => 278462)
--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h 2021-06-04 15:58:13 UTC (rev 278462)
@@ -1818,6 +1818,10 @@
RELEASE_ASSERT_NOT_REACHED();
return;
}
+
+ case FunctionToString:
+ def(PureValue(node));
+ return;
case CountExecution:
case SuperSamplerBegin:
Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (278461 => 278462)
--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2021-06-04 15:58:13 UTC (rev 278462)
@@ -290,6 +290,7 @@
case DirectTailCall:
case DirectTailCallInlinedCaller:
case ForceOSRExit:
+ case FunctionToString:
case GetById:
case GetByIdDirect:
case GetByIdDirectFlush:
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (278461 => 278462)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2021-06-04 15:58:13 UTC (rev 278462)
@@ -1973,6 +1973,10 @@
break;
}
+ case FunctionToString: {
+ fixEdge<FunctionUse>(node->child1());
+ break;
+ }
case SetPrivateBrand: {
fixEdge<CellUse>(node->child1());
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (278461 => 278462)
--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2021-06-04 15:58:13 UTC (rev 278462)
@@ -428,6 +428,7 @@
macro(CallNumberConstructor, NodeResultJS | NodeMustGenerate) \
macro(NumberToStringWithRadix, NodeResultJS | NodeMustGenerate) \
macro(NumberToStringWithValidRadixConstant, NodeResultJS) \
+ macro(FunctionToString, NodeResultJS) \
macro(MakeRope, NodeResultJS) \
macro(InByVal, NodeResultBoolean | NodeMustGenerate) \
macro(InById, NodeResultBoolean | NodeMustGenerate) \
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (278461 => 278462)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp 2021-06-04 15:58:13 UTC (rev 278462)
@@ -2560,6 +2560,15 @@
return reinterpret_cast<char*>(numberToString(vm, value, radix));
}
+JSC_DEFINE_JIT_OPERATION(operationFunctionToString, JSString*, (JSGlobalObject* globalObject, JSFunction* function))
+{
+ VM& vm = globalObject->vm();
+ CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+ JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+ return function->toString(globalObject);
+}
+
JSC_DEFINE_JIT_OPERATION(operationSingleCharacterString, JSString*, (VM* vmPointer, int32_t character))
{
VM& vm = *vmPointer;
Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (278461 => 278462)
--- trunk/Source/_javascript_Core/dfg/DFGOperations.h 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h 2021-06-04 15:58:13 UTC (rev 278462)
@@ -246,6 +246,7 @@
JSC_DECLARE_JIT_OPERATION(operationInt32ToStringWithValidRadix, char*, (JSGlobalObject*, int32_t, int32_t));
JSC_DECLARE_JIT_OPERATION(operationInt52ToStringWithValidRadix, char*, (JSGlobalObject*, int64_t, int32_t));
JSC_DECLARE_JIT_OPERATION(operationDoubleToStringWithValidRadix, char*, (JSGlobalObject*, double, int32_t));
+JSC_DECLARE_JIT_OPERATION(operationFunctionToString, JSString*, (JSGlobalObject*, JSFunction*));
JSC_DECLARE_JIT_OPERATION(operationNormalizeMapKeyHeapBigInt, EncodedJSValue, (VM*, JSBigInt*));
JSC_DECLARE_JIT_OPERATION(operationMapHash, UCPUStrictInt32, (JSGlobalObject*, EncodedJSValue input));
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (278461 => 278462)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2021-06-04 15:58:13 UTC (rev 278462)
@@ -1158,6 +1158,7 @@
case StringCharAt:
case CallStringConstructor:
case ToString:
+ case FunctionToString:
case NumberToStringWithRadix:
case NumberToStringWithValidRadixConstant:
case MakeRope:
Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (278461 => 278462)
--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2021-06-04 15:58:13 UTC (rev 278462)
@@ -273,6 +273,7 @@
case ToBoolean:
case LogicalNot:
case ToString:
+ case FunctionToString:
case NumberToStringWithValidRadixConstant:
case StrCat:
case CallStringConstructor:
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (278461 => 278462)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2021-06-04 15:58:13 UTC (rev 278462)
@@ -52,6 +52,7 @@
#include "JSArrayIterator.h"
#include "JSAsyncFunction.h"
#include "JSAsyncGeneratorFunction.h"
+#include "JSBoundFunction.h"
#include "JSCInlines.h"
#include "JSGeneratorFunction.h"
#include "JSImmutableButterfly.h"
@@ -10555,6 +10556,47 @@
}
}
+static void getExecutable(JITCompiler& jit, GPRReg functionGPR, GPRReg resultGPR)
+{
+ jit.loadPtr(JITCompiler::Address(functionGPR, JSFunction::offsetOfExecutableOrRareData()), resultGPR);
+ auto hasExecutable = jit.branchTestPtr(CCallHelpers::Zero, resultGPR, CCallHelpers::TrustedImm32(JSFunction::rareDataTag));
+ jit.loadPtr(CCallHelpers::Address(resultGPR, FunctionRareData::offsetOfExecutable() - JSFunction::rareDataTag), resultGPR);
+ hasExecutable.link(&jit);
+}
+
+void SpeculativeJIT::compileFunctionToString(Node* node)
+{
+ SpeculateCellOperand function(this, node->child1());
+ GPRTemporary executable(this);
+ GPRTemporary result(this);
+ JITCompiler::JumpList slowCases;
+
+ speculateFunction(node->child1(), function.gpr());
+
+ m_jit.emitLoadStructure(vm(), function.gpr(), result.gpr(), executable.gpr());
+ m_jit.loadPtr(JITCompiler::Address(result.gpr(), Structure::classInfoOffset()), result.gpr());
+ static_assert(std::is_final_v<JSBoundFunction>, "We don't handle subclasses when comparing classInfo below");
+ slowCases.append(m_jit.branchPtr(CCallHelpers::Equal, result.gpr(), TrustedImmPtr(JSBoundFunction::info())));
+
+ getExecutable(m_jit, function.gpr(), executable.gpr());
+ JITCompiler::Jump isNativeExecutable = m_jit.branch8(JITCompiler::Equal, JITCompiler::Address(executable.gpr(), JSCell::typeInfoTypeOffset()), TrustedImm32(NativeExecutableType));
+
+ m_jit.loadPtr(MacroAssembler::Address(executable.gpr(), FunctionExecutable::offsetOfRareData()), result.gpr());
+ slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr()));
+ m_jit.loadPtr(MacroAssembler::Address(result.gpr(), FunctionExecutable::offsetOfAsStringInRareData()), result.gpr());
+ JITCompiler::Jump continuation = m_jit.jump();
+
+ isNativeExecutable.link(&m_jit);
+ m_jit.loadPtr(MacroAssembler::Address(executable.gpr(), NativeExecutable::offsetOfAsString()), result.gpr());
+
+ continuation.link(&m_jit);
+ slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr()));
+
+ addSlowPathGenerator(slowPathCall(slowCases, this, operationFunctionToString, result.gpr(), TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), function.gpr()));
+
+ cellResult(result.gpr(), node);
+}
+
void SpeculativeJIT::compileNumberToStringWithValidRadixConstant(Node* node)
{
compileNumberToStringWithValidRadixConstant(node, node->validRadixConstant());
@@ -13304,14 +13346,9 @@
{
SpeculateCellOperand function(this, node->child1());
GPRTemporary result(this, Reuse, function);
- GPRReg functionGPR = function.gpr();
- GPRReg resultGPR = result.gpr();
- speculateCellType(node->child1(), functionGPR, SpecFunction, JSFunctionType);
- m_jit.loadPtr(JITCompiler::Address(functionGPR, JSFunction::offsetOfExecutableOrRareData()), resultGPR);
- auto hasExecutable = m_jit.branchTestPtr(CCallHelpers::Zero, resultGPR, CCallHelpers::TrustedImm32(JSFunction::rareDataTag));
- m_jit.loadPtr(CCallHelpers::Address(resultGPR, FunctionRareData::offsetOfExecutable() - JSFunction::rareDataTag), resultGPR);
- hasExecutable.link(&m_jit);
- cellResult(resultGPR, node);
+ speculateFunction(node->child1(), function.gpr());
+ getExecutable(m_jit, function.gpr(), result.gpr());
+ cellResult(result.gpr(), node);
}
void SpeculativeJIT::compileGetGetter(Node* node)
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (278461 => 278462)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2021-06-04 15:58:13 UTC (rev 278462)
@@ -1227,6 +1227,7 @@
void emitSwitch(Node*);
void compileToStringOrCallStringConstructorOrStringValueOf(Node*);
+ void compileFunctionToString(Node*);
void compileNumberToStringWithRadix(Node*);
void compileNumberToStringWithValidRadixConstant(Node*);
void compileNumberToStringWithValidRadixConstant(Node*, int32_t radix);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (278461 => 278462)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2021-06-04 15:58:13 UTC (rev 278462)
@@ -3205,6 +3205,10 @@
compileToStringOrCallStringConstructorOrStringValueOf(node);
break;
}
+
+ case FunctionToString:
+ compileFunctionToString(node);
+ break;
case NewStringObject: {
compileNewStringObject(node);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (278461 => 278462)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2021-06-04 15:58:13 UTC (rev 278462)
@@ -3790,6 +3790,10 @@
compileToStringOrCallStringConstructorOrStringValueOf(node);
break;
}
+
+ case FunctionToString:
+ compileFunctionToString(node);
+ break;
case NewStringObject: {
compileNewStringObject(node);
Modified: trunk/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h (278461 => 278462)
--- trunk/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h 2021-06-04 15:58:13 UTC (rev 278462)
@@ -77,6 +77,8 @@
macro(DirectArguments_minCapacity, DirectArguments::offsetOfMinCapacity()) \
macro(DirectArguments_mappedArguments, DirectArguments::offsetOfMappedArguments()) \
macro(DirectArguments_modifiedArgumentsDescriptor, DirectArguments::offsetOfModifiedArgumentsDescriptor()) \
+ macro(FunctionExecutable_rareData, FunctionExecutable::offsetOfRareData()) \
+ macro(FunctionExecutableRareData_asString, FunctionExecutable::offsetOfAsStringInRareData()) \
macro(FunctionRareData_allocator, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfileWithPrototype::offsetOfAllocator()) \
macro(FunctionRareData_structure, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfileWithPrototype::offsetOfStructure()) \
macro(FunctionRareData_prototype, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfileWithPrototype::offsetOfPrototype()) \
@@ -119,6 +121,7 @@
macro(JSRopeString_fiber2, JSRopeString::offsetOfFiber2()) \
macro(JSScope_next, JSScope::offsetOfNext()) \
macro(JSSymbolTableObject_symbolTable, JSSymbolTableObject::offsetOfSymbolTable()) \
+ macro(NativeExecutable_asString, NativeExecutable::offsetOfAsString()) \
macro(RegExpObject_regExpAndLastIndexIsNotWritableFlag, RegExpObject::offsetOfRegExpAndLastIndexIsNotWritableFlag()) \
macro(RegExpObject_lastIndex, RegExpObject::offsetOfLastIndex()) \
macro(ShadowChicken_Packet_callee, OBJECT_OFFSETOF(ShadowChicken::Packet, callee)) \
Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (278461 => 278462)
--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2021-06-04 15:58:13 UTC (rev 278462)
@@ -217,6 +217,7 @@
case ToNumber:
case ToNumeric:
case ToString:
+ case FunctionToString:
case ToObject:
case CallObjectConstructor:
case CallStringConstructor:
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (278461 => 278462)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2021-06-04 15:58:13 UTC (rev 278462)
@@ -77,6 +77,7 @@
#include "JSAsyncFunction.h"
#include "JSAsyncGenerator.h"
#include "JSAsyncGeneratorFunction.h"
+#include "JSBoundFunction.h"
#include "JSCInlines.h"
#include "JSGenerator.h"
#include "JSGeneratorFunction.h"
@@ -1196,6 +1197,9 @@
case StringValueOf:
compileToStringOrCallStringConstructorOrStringValueOf();
break;
+ case FunctionToString:
+ compileFunctionToString();
+ break;
case ToPrimitive:
compileToPrimitive();
break;
@@ -3774,14 +3778,12 @@
speculate(BadIdent, noValue(), nullptr, m_out.notEqual(stringImpl, m_out.constIntPtr(uid)));
}
- void compileGetExecutable()
+ LValue getExecutable(LValue function)
{
LBasicBlock continuation = m_out.newBlock();
LBasicBlock hasRareData = m_out.newBlock();
- LValue cell = lowCell(m_node->child1());
- speculateFunction(m_node->child1(), cell);
- LValue rareDataTags = m_out.loadPtr(cell, m_heaps.JSFunction_executableOrRareData);
+ LValue rareDataTags = m_out.loadPtr(function, m_heaps.JSFunction_executableOrRareData);
ValueFromBlock fastExecutable = m_out.anchor(rareDataTags);
m_out.branch(m_out.testIsZeroPtr(rareDataTags, m_out.constIntPtr(JSFunction::rareDataTag)), unsure(continuation), unsure(hasRareData));
@@ -3791,8 +3793,16 @@
m_out.jump(continuation);
m_out.appendTo(continuation, lastNext);
- setJSValue(m_out.phi(pointerType(), fastExecutable, slowExecutable));
+ return m_out.phi(pointerType(), fastExecutable, slowExecutable);
}
+
+ void compileGetExecutable()
+ {
+ LValue cell = lowCell(m_node->child1());
+ speculateFunction(m_node->child1(), cell);
+ LValue executable = getExecutable(cell);
+ setJSValue(executable);
+ }
void compileArrayify()
{
@@ -8220,6 +8230,55 @@
break;
}
}
+
+ void compileFunctionToString()
+ {
+ JSGlobalObject* globalObject = m_graph.globalObjectFor(m_origin.semantic);
+
+ LBasicBlock notBoundFunctionCase = m_out.newBlock();
+ LBasicBlock functionExecutableCase = m_out.newBlock();
+ LBasicBlock nativeExecutableCase = m_out.newBlock();
+ LBasicBlock testPtr = m_out.newBlock();
+ LBasicBlock hasRareData = m_out.newBlock();
+ LBasicBlock slowCase = m_out.newBlock();
+ LBasicBlock continuation = m_out.newBlock();
+
+ LValue function = lowCell(m_node->child1());
+ speculateFunction(m_node->child1(), function);
+
+ LValue structure = loadStructure(function);
+ LValue classInfo = m_out.loadPtr(structure, m_heaps.Structure_classInfo);
+ static_assert(std::is_final_v<JSBoundFunction>, "We don't handle subclasses when comparing classInfo below");
+ m_out.branch(m_out.equal(classInfo, m_out.constIntPtr(JSBoundFunction::info())), unsure(slowCase), unsure(notBoundFunctionCase));
+
+ LBasicBlock lastNext = m_out.appendTo(notBoundFunctionCase, nativeExecutableCase);
+ LValue executable = getExecutable(function);
+ m_out.branch(isType(executable, NativeExecutableType), unsure(nativeExecutableCase), unsure(functionExecutableCase));
+
+ m_out.appendTo(nativeExecutableCase, functionExecutableCase);
+ ValueFromBlock nativeResult = m_out.anchor(m_out.loadPtr(executable, m_heaps.NativeExecutable_asString));
+ m_out.jump(testPtr);
+
+ m_out.appendTo(functionExecutableCase, testPtr);
+ LValue rareData = m_out.loadPtr(executable, m_heaps.FunctionExecutable_rareData);
+ m_out.branch(m_out.notNull(rareData), usually(hasRareData), rarely(slowCase));
+
+ m_out.appendTo(hasRareData, slowCase);
+ ValueFromBlock functionResult = m_out.anchor(m_out.loadPtr(rareData, m_heaps.FunctionExecutableRareData_asString));
+ m_out.jump(testPtr);
+
+ m_out.appendTo(testPtr, continuation);
+ LValue asString = m_out.phi(pointerType(), nativeResult, functionResult);
+ ValueFromBlock fastResult = m_out.anchor(asString);
+ m_out.branch(m_out.notNull(asString), usually(continuation), rarely(slowCase));
+
+ m_out.appendTo(slowCase, continuation);
+ ValueFromBlock slowResult = m_out.anchor(vmCall(pointerType(), operationFunctionToString, weakPointer(globalObject), function));
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ setJSValue(m_out.phi(pointerType(), fastResult, slowResult));
+ }
void compileToPrimitive()
{
Modified: trunk/Source/_javascript_Core/runtime/FunctionExecutable.cpp (278461 => 278462)
--- trunk/Source/_javascript_Core/runtime/FunctionExecutable.cpp 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/runtime/FunctionExecutable.cpp 2021-06-04 15:58:13 UTC (rev 278462)
@@ -79,6 +79,7 @@
visitor.append(thisObject->m_unlinkedExecutable);
if (RareData* rareData = thisObject->m_rareData.get()) {
visitor.append(rareData->m_cachedPolyProtoStructure);
+ visitor.append(rareData->m_asString);
if (TemplateObjectMap* map = rareData->m_templateObjectMap.get()) {
Locker locker { thisObject->cellLock() };
for (auto& entry : *map)
@@ -116,6 +117,81 @@
return *m_rareData;
}
+JSString* FunctionExecutable::toStringSlow(JSGlobalObject* globalObject)
+{
+ VM& vm = getVM(globalObject);
+ ASSERT(m_rareData && !m_rareData->m_asString);
+
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+ const auto& cache = [&](JSString* asString) {
+ WTF::storeStoreFence();
+ m_rareData->m_asString.set(vm, this, asString);
+ return asString;
+ };
+
+ const auto& cacheIfNoException = [&](JSValue value) -> JSString* {
+ RETURN_IF_EXCEPTION(throwScope, nullptr);
+ return cache(::JSC::asString(value));
+ };
+
+ if (isBuiltinFunction())
+ return cacheIfNoException(jsMakeNontrivialString(globalObject, "function ", name().string(), "() {\n [native code]\n}"));
+
+ if (isClass())
+ return cache(jsString(vm, classSource().view().toString()));
+
+ String functionHeader;
+ switch (parseMode()) {
+ case SourceParseMode::GeneratorWrapperFunctionMode:
+ case SourceParseMode::GeneratorWrapperMethodMode:
+ functionHeader = "function* ";
+ break;
+
+ case SourceParseMode::NormalFunctionMode:
+ case SourceParseMode::GetterMode:
+ case SourceParseMode::SetterMode:
+ case SourceParseMode::MethodMode:
+ case SourceParseMode::ProgramMode:
+ case SourceParseMode::ModuleAnalyzeMode:
+ case SourceParseMode::ModuleEvaluateMode:
+ case SourceParseMode::GeneratorBodyMode:
+ case SourceParseMode::AsyncGeneratorBodyMode:
+ case SourceParseMode::AsyncFunctionBodyMode:
+ case SourceParseMode::AsyncArrowFunctionBodyMode:
+ functionHeader = "function ";
+ break;
+
+ case SourceParseMode::ArrowFunctionMode:
+ case SourceParseMode::ClassFieldInitializerMode:
+ functionHeader = "";
+ break;
+
+ case SourceParseMode::AsyncFunctionMode:
+ case SourceParseMode::AsyncMethodMode:
+ functionHeader = "async function ";
+ break;
+
+ case SourceParseMode::AsyncArrowFunctionMode:
+ functionHeader = "async ";
+ break;
+
+ case SourceParseMode::AsyncGeneratorWrapperFunctionMode:
+ case SourceParseMode::AsyncGeneratorWrapperMethodMode:
+ functionHeader = "async function* ";
+ break;
+ }
+
+ StringView src = ""
+ parametersStartOffset(),
+ parametersStartOffset() + source().length());
+
+ String name = this->name().string();
+ if (name == vm.propertyNames->starDefaultPrivateName.string())
+ name = emptyString();
+ return cacheIfNoException(jsMakeNontrivialString(globalObject, functionHeader, name, src));
+}
+
void FunctionExecutable::overrideInfo(const FunctionOverrideInfo& overrideInfo)
{
auto& rareData = ensureRareData();
Modified: trunk/Source/_javascript_Core/runtime/FunctionExecutable.h (278461 => 278462)
--- trunk/Source/_javascript_Core/runtime/FunctionExecutable.h 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/runtime/FunctionExecutable.h 2021-06-04 15:58:13 UTC (rev 278462)
@@ -285,6 +285,17 @@
void finalizeUnconditionally(VM&);
+ JSString* toString(JSGlobalObject*);
+ JSString* asStringConcurrently() const
+ {
+ if (!m_rareData)
+ return nullptr;
+ return m_rareData->m_asString.get();
+ }
+
+ static inline ptrdiff_t offsetOfRareData() { return OBJECT_OFFSETOF(FunctionExecutable, m_rareData); }
+ static inline ptrdiff_t offsetOfAsStringInRareData() { return OBJECT_OFFSETOF(RareData, m_asString); }
+
private:
friend class ExecutableBase;
FunctionExecutable(VM&, const SourceCode&, UnlinkedFunctionExecutable*, Intrinsic, bool isInsideOrdinaryFunction);
@@ -304,6 +315,7 @@
unsigned m_typeProfilingEndOffset { UINT_MAX };
std::unique_ptr<TemplateObjectMap> m_templateObjectMap;
WriteBarrier<Structure> m_cachedPolyProtoStructure;
+ WriteBarrier<JSString> m_asString;
};
RareData& ensureRareData()
@@ -314,6 +326,8 @@
}
RareData& ensureRareDataSlow();
+ JSString* toStringSlow(JSGlobalObject*);
+
// FIXME: We can merge rareData pointer and top-level executable pointer. First time, setting parent.
// If RareData is required, materialize RareData, swap it, and store top-level executable pointer inside RareData.
// https://bugs.webkit.org/show_bug.cgi?id=197625
Modified: trunk/Source/_javascript_Core/runtime/FunctionExecutableInlines.h (278461 => 278462)
--- trunk/Source/_javascript_Core/runtime/FunctionExecutableInlines.h 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/runtime/FunctionExecutableInlines.h 2021-06-04 15:58:13 UTC (rev 278462)
@@ -35,5 +35,13 @@
m_singleton.finalizeUnconditionally(vm);
}
+JSString* FunctionExecutable::toString(JSGlobalObject* globalObject)
+{
+ RareData& rareData = ensureRareData();
+ if (!rareData.m_asString)
+ return toStringSlow(globalObject);
+ return rareData.m_asString.get();
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp (278461 => 278462)
--- trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp 2021-06-04 15:58:13 UTC (rev 278462)
@@ -54,8 +54,7 @@
void FunctionPrototype::addFunctionProperties(VM& vm, JSGlobalObject* globalObject, JSFunction** callFunction, JSFunction** applyFunction, JSFunction** hasInstanceSymbolFunction)
{
- JSFunction* toStringFunction = JSFunction::create(vm, globalObject, 0, vm.propertyNames->toString.string(), functionProtoFuncToString);
- putDirectWithoutTransition(vm, vm.propertyNames->toString, toStringFunction, static_cast<unsigned>(PropertyAttribute::DontEnum));
+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().toStringPublicName(), functionProtoFuncToString, static_cast<unsigned>(PropertyAttribute::DontEnum), 0, FunctionToStringIntrinsic);
*applyFunction = putDirectBuiltinFunctionWithoutTransition(vm, globalObject, vm.propertyNames->builtinNames().applyPublicName(), functionPrototypeApplyCodeGenerator(vm), static_cast<unsigned>(PropertyAttribute::DontEnum));
*callFunction = putDirectBuiltinFunctionWithoutTransition(vm, globalObject, vm.propertyNames->builtinNames().callPublicName(), functionPrototypeCallCodeGenerator(vm), static_cast<unsigned>(PropertyAttribute::DontEnum));
@@ -81,58 +80,7 @@
if (thisValue.inherits<JSFunction>(vm)) {
JSFunction* function = jsCast<JSFunction*>(thisValue);
Integrity::auditStructureID(vm, function->structureID());
- if (function->isHostOrBuiltinFunction())
- RELEASE_AND_RETURN(scope, JSValue::encode(jsMakeNontrivialString(globalObject, "function ", function->name(vm), "() {\n [native code]\n}")));
-
- FunctionExecutable* executable = function->jsExecutable();
- if (executable->isClass())
- return JSValue::encode(jsString(vm, executable->classSource().view().toString()));
-
- String functionHeader;
- switch (executable->parseMode()) {
- case SourceParseMode::GeneratorWrapperFunctionMode:
- case SourceParseMode::GeneratorWrapperMethodMode:
- functionHeader = "function* ";
- break;
-
- case SourceParseMode::NormalFunctionMode:
- case SourceParseMode::GetterMode:
- case SourceParseMode::SetterMode:
- case SourceParseMode::MethodMode:
- case SourceParseMode::ProgramMode:
- case SourceParseMode::ModuleAnalyzeMode:
- case SourceParseMode::ModuleEvaluateMode:
- case SourceParseMode::GeneratorBodyMode:
- case SourceParseMode::AsyncGeneratorBodyMode:
- case SourceParseMode::AsyncFunctionBodyMode:
- case SourceParseMode::AsyncArrowFunctionBodyMode:
- functionHeader = "function ";
- break;
-
- case SourceParseMode::ArrowFunctionMode:
- case SourceParseMode::ClassFieldInitializerMode:
- functionHeader = "";
- break;
-
- case SourceParseMode::AsyncFunctionMode:
- case SourceParseMode::AsyncMethodMode:
- functionHeader = "async function ";
- break;
-
- case SourceParseMode::AsyncArrowFunctionMode:
- functionHeader = "async ";
- break;
-
- case SourceParseMode::AsyncGeneratorWrapperFunctionMode:
- case SourceParseMode::AsyncGeneratorWrapperMethodMode:
- functionHeader = "async function* ";
- break;
- }
-
- StringView source = executable->source().provider()->getRange(
- executable->parametersStartOffset(),
- executable->parametersStartOffset() + executable->source().length());
- RELEASE_AND_RETURN(scope, JSValue::encode(jsMakeNontrivialString(globalObject, functionHeader, function->name(vm), source)));
+ RELEASE_AND_RETURN(scope, JSValue::encode(function->toString(globalObject)));
}
if (thisValue.inherits<InternalFunction>(vm)) {
Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.cpp (278461 => 278462)
--- trunk/Source/_javascript_Core/runtime/Intrinsic.cpp 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.cpp 2021-06-04 15:58:13 UTC (rev 278462)
@@ -275,6 +275,8 @@
return "AtomicsXorIntrinsic";
case ParseIntIntrinsic:
return "ParseIntIntrinsic";
+ case FunctionToStringIntrinsic:
+ return "FunctionToStringIntrinsic";
case TypedArrayLengthIntrinsic:
return "TypedArrayLengthIntrinsic";
case TypedArrayByteLengthIntrinsic:
Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.h (278461 => 278462)
--- trunk/Source/_javascript_Core/runtime/Intrinsic.h 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.h 2021-06-04 15:58:13 UTC (rev 278462)
@@ -152,6 +152,7 @@
AtomicsWaitIntrinsic,
AtomicsXorIntrinsic,
ParseIntIntrinsic,
+ FunctionToStringIntrinsic,
// Getter intrinsics.
TypedArrayLengthIntrinsic,
Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (278461 => 278462)
--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp 2021-06-04 15:58:13 UTC (rev 278462)
@@ -247,6 +247,22 @@
return jsExecutable()->ecmaName().string();
}
+JSString* JSFunction::toString(JSGlobalObject* globalObject)
+{
+ VM& vm = getVM(globalObject);
+ if (inherits<JSBoundFunction>(vm)) {
+ JSBoundFunction* function = jsCast<JSBoundFunction*>(this);
+ auto scope = DECLARE_THROW_SCOPE(vm);
+ JSValue string = jsMakeNontrivialString(globalObject, "function ", function->nameString(), "() {\n [native code]\n}");
+ RETURN_IF_EXCEPTION(scope, nullptr);
+ return asString(string);
+ }
+
+ if (isHostFunction())
+ return static_cast<NativeExecutable*>(executable())->toString(globalObject);
+ return jsExecutable()->toString(globalObject);
+}
+
const SourceCode* JSFunction::sourceCode() const
{
if (isHostOrBuiltinFunction())
Modified: trunk/Source/_javascript_Core/runtime/JSFunction.h (278461 => 278462)
--- trunk/Source/_javascript_Core/runtime/JSFunction.h 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.h 2021-06-04 15:58:13 UTC (rev 278462)
@@ -90,7 +90,10 @@
JS_EXPORT_PRIVATE String name(VM&);
JS_EXPORT_PRIVATE String displayName(VM&);
JS_EXPORT_PRIVATE const String calculatedDisplayName(VM&);
+ JS_EXPORT_PRIVATE JSString* toString(JSGlobalObject*);
+ JSString* asStringConcurrently(VM&) const;
+
ExecutableBase* executable() const
{
uintptr_t executableOrRareData = m_executableOrRareData;
Modified: trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h (278461 => 278462)
--- trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h 2021-06-04 15:58:13 UTC (rev 278462)
@@ -26,6 +26,7 @@
#pragma once
#include "FunctionExecutable.h"
+#include "JSBoundFunction.h"
#include "JSFunction.h"
#include "NativeExecutable.h"
@@ -156,4 +157,13 @@
return rareData;
}
+inline JSString* JSFunction::asStringConcurrently(VM& vm) const
+{
+ if (inherits<JSBoundFunction>(vm))
+ return nullptr;
+ if (isHostFunction())
+ return static_cast<NativeExecutable*>(executable())->asStringConcurrently();
+ return jsExecutable()->asStringConcurrently();
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/JSStringInlines.h (278461 => 278462)
--- trunk/Source/_javascript_Core/runtime/JSStringInlines.h 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/runtime/JSStringInlines.h 2021-06-04 15:58:13 UTC (rev 278462)
@@ -25,6 +25,7 @@
#pragma once
+#include "JSGlobalObjectInlines.h"
#include "JSString.h"
namespace JSC {
Modified: trunk/Source/_javascript_Core/runtime/NativeExecutable.cpp (278461 => 278462)
--- trunk/Source/_javascript_Core/runtime/NativeExecutable.cpp 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/runtime/NativeExecutable.cpp 2021-06-04 15:58:13 UTC (rev 278462)
@@ -93,4 +93,31 @@
return CodeBlockHash(bitwise_cast<uintptr_t>(m_constructor));
}
+JSString* NativeExecutable::toStringSlow(JSGlobalObject *globalObject)
+{
+ VM& vm = getVM(globalObject);
+
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+ JSValue value = jsMakeNontrivialString(globalObject, "function ", name(), "() {\n [native code]\n}");
+
+ RETURN_IF_EXCEPTION(throwScope, nullptr);
+
+ JSString* asString = ::JSC::asString(value);
+ WTF::storeStoreFence();
+ m_asString.set(vm, this, asString);
+ return asString;
+}
+
+template<typename Visitor>
+void NativeExecutable::visitChildrenImpl(JSCell* cell, Visitor& visitor)
+{
+ NativeExecutable* thisObject = jsCast<NativeExecutable*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+ visitor.append(thisObject->m_asString);
+}
+
+DEFINE_VISIT_CHILDREN(NativeExecutable);
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/NativeExecutable.h (278461 => 278462)
--- trunk/Source/_javascript_Core/runtime/NativeExecutable.h 2021-06-04 15:48:55 UTC (rev 278461)
+++ trunk/Source/_javascript_Core/runtime/NativeExecutable.h 2021-06-04 15:58:13 UTC (rev 278462)
@@ -67,6 +67,7 @@
return OBJECT_OFFSETOF(NativeExecutable, m_constructor);
}
+ DECLARE_VISIT_CHILDREN;
static Structure* createStructure(VM&, JSGlobalObject*, JSValue proto);
DECLARE_INFO;
@@ -76,14 +77,27 @@
const DOMJIT::Signature* signatureFor(CodeSpecializationKind) const;
Intrinsic intrinsic() const;
+ JSString* toString(JSGlobalObject* globalObject)
+ {
+ if (!m_asString)
+ return toStringSlow(globalObject);
+ return m_asString.get();
+ }
+
+ JSString* asStringConcurrently() const { return m_asString.get(); }
+ static inline ptrdiff_t offsetOfAsString() { return OBJECT_OFFSETOF(NativeExecutable, m_asString); }
+
private:
NativeExecutable(VM&, TaggedNativeFunction, TaggedNativeFunction constructor);
void finishCreation(VM&, Ref<JITCode>&& callThunk, Ref<JITCode>&& constructThunk, const String& name);
+ JSString* toStringSlow(JSGlobalObject*);
+
TaggedNativeFunction m_function;
TaggedNativeFunction m_constructor;
String m_name;
+ WriteBarrier<JSString> m_asString;
};
} // namespace JSC