WebKit Bugzilla
Attachment 358057 Details for
Bug 193031
: [JSC] Optimize Object.prototype.toString
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-193031-20181225165644.patch (text/plain), 33.28 KB, created by
Yusuke Suzuki
on 2018-12-24 23:56:45 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Yusuke Suzuki
Created:
2018-12-24 23:56:45 PST
Size:
33.28 KB
patch
obsolete
>Subversion Revision: 239547 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 0db65496050440b7997f8f561f98171a548c011f..590c0e44dd034060de406159b9966a811a47f935 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,52 @@ >+2018-12-24 Yusuke Suzuki <yusukesuzuki@slowstart.org> >+ >+ [JSC] Optimize Object.prototype.toString >+ https://bugs.webkit.org/show_bug.cgi?id=193031 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * 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): >+ (JSC::DFG::FixupPhase::fixupObjectToString): >+ * dfg/DFGNodeType.h: >+ * dfg/DFGOperations.cpp: >+ * dfg/DFGOperations.h: >+ * dfg/DFGPredictionPropagationPhase.cpp: >+ * dfg/DFGSafeToExecute.h: >+ (JSC::DFG::safeToExecute): >+ * dfg/DFGSpeculativeJIT.cpp: >+ (JSC::DFG::SpeculativeJIT::compileObjectToString): >+ * 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::compileObjectToString): >+ * runtime/Intrinsic.cpp: >+ (JSC::intrinsicName): >+ * runtime/Intrinsic.h: >+ * runtime/ObjectPrototype.cpp: >+ (JSC::ObjectPrototype::finishCreation): >+ (JSC::objectProtoFuncToString): >+ * runtime/ObjectPrototype.h: >+ * runtime/ObjectPrototypeInlines.h: Added. >+ (JSC::structureForPrimitiveValue): >+ (JSC::objectToString): >+ * runtime/StructureRareData.h: >+ > 2018-12-13 Yusuke Suzuki <yusukesuzuki@slowstart.org> > > [BigInt] Support BigInt in JSON.stringify >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >index 5197133ead4b2d28d1fb3ecfc547ff77f01ba905..1cea3387c7e4f13d93d2cb9ea2a1759f6365145d 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >@@ -2620,6 +2620,23 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > break; > } > >+ case ObjectToString: { >+ AbstractValue& source = forNode(node->child1()); >+ bool clobbering = node->child1().useKind() != MiscUse; >+ if (JSValue sourceValue = source.m_value) { >+ if (sourceValue.isUndefinedOrNull()) { >+ if (clobbering) >+ didFoldClobberWorld(); >+ setConstant(node, *m_graph.freeze(sourceValue.isUndefined() ? m_vm.smallStrings.undefinedObjectString() : m_vm.smallStrings.nullObjectString())); >+ break; >+ } >+ } >+ >+ clobberWorld(); >+ setTypeForNode(node, SpecString); >+ break; >+ } >+ > case ToObject: > case CallObjectConstructor: { > AbstractValue& source = forNode(node->child1()); >diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >index d6e3843a8d8349490154e08777274f08655f650b..93529db0f13f5a48333e80bb723d74e6a22e90f7 100644 >--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >@@ -2701,6 +2701,13 @@ bool ByteCodeParser::handleIntrinsicCall(Node* callee, VirtualRegister result, I > return true; > } > >+ case ObjectPrototypeToStringIntrinsic: { >+ insertChecks(); >+ Node* value = get(virtualRegisterForArgument(0, registerOffset)); >+ set(result, addToGraph(ObjectToString, value)); >+ return true; >+ } >+ > case ReflectGetPrototypeOfIntrinsic: { > if (argumentCountIncludingThis != 2) > return false; >diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h >index 48c846bd3897d14de4e25b27d9570d82da871ae9..ad81069568e74cac3046956696d59a13f30ce197 100644 >--- a/Source/JavaScriptCore/dfg/DFGClobberize.h >+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h >@@ -681,6 +681,20 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu > write(Heap); > return; > >+ case ObjectToString: >+ switch (node->child1().useKind()) { >+ case MiscUse: >+ def(PureValue(graph, node)); >+ return; >+ case UntypedUse: >+ read(World); >+ write(Heap); >+ return; >+ default: >+ RELEASE_ASSERT_NOT_REACHED(); >+ return; >+ } >+ > case AtomicsAdd: > case AtomicsAnd: > case AtomicsCompareExchange: >diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >index df74930bdbb3864ad944bc4720712fe0f3947bd5..ddbfa5d83cf5977a07dc37af8d2890222d33f1db 100644 >--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >@@ -372,6 +372,7 @@ bool doesGC(Graph& graph, Node* node) > case StringReplaceRegExp: > case StringSlice: > case StringValueOf: >+ case ObjectToString: > case CreateRest: > case ToLowerCase: > case CallDOMGetter: >diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >index 307632dad59da8e23250db1b4497d0341ba95292..be654cfbd5bd8f0932b8cdfa73065444dee50c60 100644 >--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >@@ -2147,6 +2147,11 @@ class FixupPhase : public Phase { > break; > } > >+ case ObjectToString: { >+ fixupObjectToString(node); >+ break; >+ } >+ > case StringSlice: { > fixEdge<StringUse>(node->child1()); > fixEdge<Int32Use>(node->child2()); >@@ -2931,6 +2936,15 @@ class FixupPhase : public Phase { > } > } > >+ void fixupObjectToString(Node* node) >+ { >+ if (node->child1()->shouldSpeculateMisc()) { >+ fixEdge<MiscUse>(node->child1()); >+ node->clearFlags(NodeMustGenerate); >+ return; >+ } >+ } >+ > bool attemptToMakeFastStringAdd(Node* node) > { > bool goodToGo = true; >diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h >index dc2f3e16b832aac0af7f0ad63c4c8e281dcba34e..03fe46b95184da166aeff5dce1ec157107e693d9 100644 >--- a/Source/JavaScriptCore/dfg/DFGNodeType.h >+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h >@@ -266,6 +266,7 @@ namespace JSC { namespace DFG { > macro(GetPrototypeOf, NodeMustGenerate | NodeResultJS) \ > macro(ObjectCreate, NodeMustGenerate | NodeResultJS) \ > macro(ObjectKeys, NodeMustGenerate | NodeResultJS) \ >+ macro(ObjectToString, NodeMustGenerate | NodeResultJS) \ > \ > /* Atomics object functions. */\ > macro(AtomicsAdd, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \ >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp >index 1da406ba7e92767324201c788b3778b52e698819..dfced10bf264f41040c0d47e3854dcb0dc91c999 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp >+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp >@@ -63,6 +63,7 @@ > #include "JSWeakSet.h" > #include "NumberConstructor.h" > #include "ObjectConstructor.h" >+#include "ObjectPrototypeInlines.h" > #include "Operations.h" > #include "ParseInt.h" > #include "RegExpConstructor.h" >@@ -71,6 +72,7 @@ > #include "Repatch.h" > #include "ScopedArguments.h" > #include "StringConstructor.h" >+#include "StructureRareDataInlines.h" > #include "SuperSampler.h" > #include "Symbol.h" > #include "TypeProfilerLog.h" >@@ -2154,6 +2156,13 @@ JSString* JIT_OPERATION operationStringValueOf(ExecState* exec, EncodedJSValue e > return nullptr; > } > >+JSString* JIT_OPERATION operationObjectToString(ExecState* exec, EncodedJSValue source) >+{ >+ VM& vm = exec->vm(); >+ NativeCallFrameTracer tracer(&vm, exec); >+ return objectToString(exec, JSValue::decode(source)); >+} >+ > JSCell* JIT_OPERATION operationStringSubstr(ExecState* exec, JSCell* cell, int32_t from, int32_t span) > { > VM& vm = exec->vm(); >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h >index 38c116a54f91a615b81c15112148f25f94adb1ef..8b76f4d6bf37401de2c4a97c1c3205527cc63951 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.h >+++ b/Source/JavaScriptCore/dfg/DFGOperations.h >@@ -205,6 +205,7 @@ JSString* JIT_OPERATION operationSingleCharacterString(ExecState*, int32_t); > JSCell* JIT_OPERATION operationStringSubstr(ExecState*, JSCell*, int32_t, int32_t); > JSString* JIT_OPERATION operationStringValueOf(ExecState*, EncodedJSValue); > JSString* JIT_OPERATION operationToLowerCase(ExecState*, JSString*, uint32_t); >+JSString* JIT_OPERATION operationObjectToString(ExecState*, EncodedJSValue); > > char* JIT_OPERATION operationInt32ToString(ExecState*, int32_t, int32_t); > char* JIT_OPERATION operationInt52ToString(ExecState*, int64_t, int32_t); >diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >index b3c69bcf124727bfcc676b2afadab5a88c22f93a..1ba4eff373c8a570ea88cd71ae11210f493ff6d1 100644 >--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >@@ -884,6 +884,7 @@ class PredictionPropagationPhase : public Phase { > case StringValueOf: > case StringSlice: > case ToLowerCase: >+ case ObjectToString: > setPrediction(SpecString); > break; > >diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >index f106982ae39ff3bcc36cfb5aee0d716c07e94316..06da94f441f85d2456100cb18547104c58951b0f 100644 >--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >@@ -452,6 +452,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno > case StringValueOf: > case StringSlice: > case ToLowerCase: >+ case ObjectToString: > case GetMapBucket: > case GetMapBucketHead: > case GetMapBucketNext: >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >index 63e09fb915ea97f04ae1f0f90e0e7f5c192bdd4f..72718782994a2f0590ead77bb139e6da59e7b0a0 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >@@ -12453,6 +12453,63 @@ void SpeculativeJIT::compileObjectKeys(Node* node) > } > } > >+void SpeculativeJIT::compileObjectToString(Node* node) >+{ >+ switch (node->child1().useKind()) { >+ case MiscUse: { >+ JSValueOperand source(this, node->child1(), ManualOperandSpeculation); >+ GPRTemporary result(this); >+ >+ JSValueRegs sourceRegs = source.jsValueRegs(); >+ GPRReg resultGPR = result.gpr(); >+ >+ speculateMisc(node->child1(), sourceRegs); >+ >+ auto isUndefined = m_jit.branchIfUndefined(sourceRegs); >+ m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.vm()->smallStrings.nullObjectString()), resultGPR); >+ auto done = m_jit.jump(); >+ isUndefined.link(&m_jit); >+ m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.vm()->smallStrings.undefinedObjectString()), resultGPR); >+ done.link(&m_jit); >+ >+ cellResult(resultGPR, node); >+ return; >+ } >+ case UntypedUse: { >+ JSValueOperand source(this, node->child1()); >+ >+ JSValueRegs sourceRegs = source.jsValueRegs(); >+ >+ GPRTemporary structure(this); >+ GPRTemporary scratch(this); >+ >+ GPRReg structureGPR = structure.gpr(); >+ GPRReg scratchGPR = scratch.gpr(); >+ >+ CCallHelpers::JumpList slowCases; >+ slowCases.append(m_jit.branchIfNotCell(sourceRegs)); >+ slowCases.append(m_jit.branchIfNotObject(sourceRegs.payloadGPR())); >+ >+ m_jit.emitLoadStructure(*m_jit.vm(), sourceRegs.payloadGPR(), structureGPR, scratchGPR); >+ m_jit.loadPtr(CCallHelpers::Address(structureGPR, Structure::previousOrRareDataOffset()), scratchGPR); >+ >+ slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratchGPR)); >+ slowCases.append(m_jit.branch32(CCallHelpers::Equal, CCallHelpers::Address(scratchGPR, JSCell::structureIDOffset()), TrustedImm32(bitwise_cast<int32_t>(m_jit.vm()->structureStructure->structureID())))); >+ >+ m_jit.loadPtr(CCallHelpers::Address(scratchGPR, StructureRareData::offsetOfObjectToStringValue()), scratchGPR); >+ slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratchGPR)); >+ >+ addSlowPathGenerator(slowPathCall(slowCases, this, operationObjectToString, scratchGPR, sourceRegs)); >+ >+ cellResult(scratchGPR, node); >+ return; >+ } >+ default: >+ DFG_CRASH(m_graph, node, "Bad use kind"); >+ return; >+ } >+} >+ > void SpeculativeJIT::compileObjectCreate(Node* node) > { > switch (node->child1().useKind()) { >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >index dcdf9664fc4de580f87694d7fb78f5f8b6c6757a..28369106eb5fabf0e72d005a56c01fc2d06a5825 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >@@ -1480,6 +1480,7 @@ class SpeculativeJIT { > void compileNewTypedArray(Node*); > void compileToThis(Node*); > void compileObjectKeys(Node*); >+ void compileObjectToString(Node*); > void compileObjectCreate(Node*); > void compileCreateThis(Node*); > void compileNewObject(Node*); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >index fcda6a61f8bc74e7136982422476949f68a085eb..10bddf84252969dcf5dae46238f80595850b64f0 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >@@ -3105,6 +3105,11 @@ void SpeculativeJIT::compile(Node* node) > compileToStringOrCallStringConstructorOrStringValueOf(node); > break; > } >+ >+ case ObjectToString: { >+ compileObjectToString(node); >+ break; >+ } > > case NewStringObject: { > compileNewStringObject(node); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >index 553f86f50675840823a16e5e58386f79bcac4f2e..5d58fda3e76dd6b47f7e6d7ef826c46bad5565d8 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >@@ -3347,6 +3347,11 @@ void SpeculativeJIT::compile(Node* node) > compileToStringOrCallStringConstructorOrStringValueOf(node); > break; > } >+ >+ case ObjectToString: { >+ compileObjectToString(node); >+ break; >+ } > > case NewStringObject: { > compileNewStringObject(node); >diff --git a/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h b/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h >index 9f3aa2fe7dc3ecfeb0c870b81a87cbc11f288051..b7e99844695119b83f39a93e80dc04c85c2b9e45 100644 >--- a/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h >+++ b/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h >@@ -120,6 +120,7 @@ namespace JSC { namespace FTL { > macro(Structure_prototype, Structure::prototypeOffset()) \ > macro(Structure_structureID, Structure::structureIDOffset()) \ > macro(StructureRareData_cachedOwnKeys, StructureRareData::offsetOfCachedOwnKeys()) \ >+ macro(StructureRareData_objectToStringValue, StructureRareData::offsetOfObjectToStringValue()) \ > macro(HashMapImpl_capacity, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfCapacity()) \ > macro(HashMapImpl_buffer, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfBuffer()) \ > macro(HashMapImpl_head, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfHead()) \ >diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >index 23c9396f4d69e04f6f0cb5f491ba04e6ccfad10a..6b7d0fc989fb6a52d3d2fe77211d996b4fd7f5f0 100644 >--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >@@ -333,6 +333,7 @@ inline CapabilityLevel canCompile(Node* node) > case StringValueOf: > case StringSlice: > case ToLowerCase: >+ case ObjectToString: > case NumberToStringWithRadix: > case NumberToStringWithValidRadixConstant: > case CheckSubClass: >diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >index 4130bd1ddb4d46f7fff9e1086309d55e5c9922c2..8fe69e4b965b0a645192ef4e428300e75361a759 100644 >--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >@@ -937,6 +937,9 @@ class LowerDFGToB3 { > case StringFromCharCode: > compileStringFromCharCode(); > break; >+ case ObjectToString: >+ compileObjectToString(); >+ break; > case GetByOffset: > case GetGetterSetterByOffset: > compileGetByOffset(); >@@ -6419,6 +6422,82 @@ class LowerDFGToB3 { > break; > } > } >+ >+ void compileObjectToString() >+ { >+ switch (m_node->child1().useKind()) { >+ case MiscUse: { >+ LBasicBlock undefinedCase = m_out.newBlock(); >+ LBasicBlock nullCase = m_out.newBlock(); >+ LBasicBlock continuation = m_out.newBlock(); >+ >+ speculate(m_node->child1()); >+ LValue source = lowJSValue(m_node->child1(), ManualOperandSpeculation); >+ LValue valueIsUndefined = m_out.equal(source, m_out.constInt64(ValueUndefined)); >+ m_out.branch(valueIsUndefined, unsure(undefinedCase), unsure(nullCase)); >+ >+ LBasicBlock lastNext = m_out.appendTo(undefinedCase, nullCase); >+ ValueFromBlock undefinedString = m_out.anchor(weakPointer(vm().smallStrings.undefinedObjectString())); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(nullCase, continuation); >+ ValueFromBlock nullString = m_out.anchor(weakPointer(vm().smallStrings.nullObjectString())); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(continuation, lastNext); >+ setJSValue(m_out.phi(pointerType(), undefinedString, nullString)); >+ return; >+ } >+ case UntypedUse: { >+ AbstractValue& value = m_state.forNode(m_node->child1()); >+ LBasicBlock cellCase = m_out.newBlock(); >+ LBasicBlock objectCase = m_out.newBlock(); >+ LBasicBlock notNullCase = m_out.newBlock(); >+ LBasicBlock rareDataCase = m_out.newBlock(); >+ LBasicBlock slowCase = m_out.newBlock(); >+ LBasicBlock continuation = m_out.newBlock(); >+ >+ LValue source = lowJSValue(m_node->child1()); >+ m_out.branch(isCell(source, provenType(m_node->child1())), unsure(cellCase), unsure(slowCase)); >+ >+ LBasicBlock lastNext = m_out.appendTo(cellCase, objectCase); >+ m_out.branch(isObject(source, provenType(m_node->child1()) & SpecCell), unsure(objectCase), unsure(slowCase)); >+ >+ m_out.appendTo(objectCase, notNullCase); >+ LValue structure = loadStructure(source); >+ LValue previousOrRareData = m_out.loadPtr(structure, m_heaps.Structure_previousOrRareData); >+ m_out.branch(m_out.notNull(previousOrRareData), unsure(notNullCase), unsure(slowCase)); >+ >+ m_out.appendTo(notNullCase, rareDataCase); >+ m_out.branch( >+ m_out.notEqual(m_out.load32(previousOrRareData, m_heaps.JSCell_structureID), m_out.constInt32(m_graph.m_vm.structureStructure->structureID())), >+ unsure(rareDataCase), unsure(slowCase)); >+ >+ m_out.appendTo(rareDataCase, slowCase); >+ LValue objectToStringValue = m_out.loadPtr(previousOrRareData, m_heaps.StructureRareData_objectToStringValue); >+ ValueFromBlock fastResult = m_out.anchor(objectToStringValue); >+ m_out.branch(m_out.isNull(objectToStringValue), unsure(slowCase), unsure(continuation)); >+ >+ m_out.appendTo(slowCase, continuation); >+ VM& vm = this->vm(); >+ LValue slowResultValue = lazySlowPath( >+ [=, &vm] (const Vector<Location>& locations) -> RefPtr<LazySlowPath::Generator> { >+ return createLazyCallGenerator(vm, >+ operationObjectToString, locations[0].directGPR(), locations[1].directGPR()); >+ }, >+ source); >+ ValueFromBlock slowResult = m_out.anchor(slowResultValue); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(continuation, lastNext); >+ setJSValue(m_out.phi(pointerType(), fastResult, slowResult)); >+ return; >+ } >+ default: >+ DFG_CRASH(m_graph, m_node, "Bad use kind"); >+ return; >+ } >+ } > > void compileToPrimitive() > { >diff --git a/Source/JavaScriptCore/runtime/Intrinsic.cpp b/Source/JavaScriptCore/runtime/Intrinsic.cpp >index fbc4ef3cd8f2ec62da9300da271b1023397434fc..f3db584349abe12237e5db58e9e5074e91d6d6e8 100644 >--- a/Source/JavaScriptCore/runtime/Intrinsic.cpp >+++ b/Source/JavaScriptCore/runtime/Intrinsic.cpp >@@ -121,6 +121,8 @@ const char* intrinsicName(Intrinsic intrinsic) > return "ObjectIsIntrinsic"; > case ObjectKeysIntrinsic: > return "ObjectKeysIntrinsic"; >+ case ObjectPrototypeToStringIntrinsic: >+ return "ObjectPrototypeToStringIntrinsic"; > case ReflectGetPrototypeOfIntrinsic: > return "ReflectGetPrototypeOfIntrinsic"; > case StringPrototypeValueOfIntrinsic: >diff --git a/Source/JavaScriptCore/runtime/Intrinsic.h b/Source/JavaScriptCore/runtime/Intrinsic.h >index b47f46d9e4de0013de8346e82e6816f5fd02f746..15eab26bac6a562c8e2f24e35cd82e2ef4b24d05 100644 >--- a/Source/JavaScriptCore/runtime/Intrinsic.h >+++ b/Source/JavaScriptCore/runtime/Intrinsic.h >@@ -73,6 +73,7 @@ enum Intrinsic { > ObjectGetPrototypeOfIntrinsic, > ObjectIsIntrinsic, > ObjectKeysIntrinsic, >+ ObjectPrototypeToStringIntrinsic, > ReflectGetPrototypeOfIntrinsic, > StringPrototypeValueOfIntrinsic, > StringPrototypeReplaceIntrinsic, >diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp >index 1bd8930834fd680204d3bb86cee2cad0d0c59d46..052eb2120d3df9ba7d313302bd9fea9df127ebbb 100644 >--- a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp >+++ b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp >@@ -27,6 +27,7 @@ > #include "JSFunction.h" > #include "JSString.h" > #include "JSCInlines.h" >+#include "ObjectPrototypeInlines.h" > #include "PropertySlot.h" > #include "StructureInlines.h" > #include "StructureRareDataInlines.h" >@@ -42,6 +43,7 @@ static EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupGetter(ExecState*); > static EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState*); > static EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState*); > static EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState*); >+static EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*); > > STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ObjectPrototype); > >@@ -58,7 +60,7 @@ void ObjectPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) > ASSERT(inherits(vm, info())); > didBecomePrototype(); > >- JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toString, objectProtoFuncToString, static_cast<unsigned>(PropertyAttribute::DontEnum), 0); >+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toString, objectProtoFuncToString, static_cast<unsigned>(PropertyAttribute::DontEnum), 0, ObjectPrototypeToStringIntrinsic); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toLocaleString, objectProtoFuncToLocaleString, static_cast<unsigned>(PropertyAttribute::DontEnum), 0); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->valueOf, objectProtoFuncValueOf, static_cast<unsigned>(PropertyAttribute::DontEnum), 0); > JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->hasOwnProperty, objectProtoFuncHasOwnProperty, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, HasOwnPropertyIntrinsic); >@@ -311,50 +313,8 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState* exec) > > EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState* exec) > { >- VM& vm = exec->vm(); >- auto scope = DECLARE_THROW_SCOPE(vm); >- > JSValue thisValue = exec->thisValue().toThis(exec, StrictMode); >- if (thisValue.isUndefinedOrNull()) >- return JSValue::encode(thisValue.isUndefined() ? vm.smallStrings.undefinedObjectString() : vm.smallStrings.nullObjectString()); >- JSObject* thisObject = thisValue.toObject(exec); >- EXCEPTION_ASSERT(!!scope.exception() == !thisObject); >- if (!thisObject) >- return JSValue::encode(jsUndefined()); >- >- auto result = thisObject->structure(vm)->objectToStringValue(); >- if (result) >- return JSValue::encode(result); >- >- PropertyName toStringTagSymbol = vm.propertyNames->toStringTagSymbol; >- RELEASE_AND_RETURN(scope, JSValue::encode(thisObject->getPropertySlot(exec, toStringTagSymbol, [&] (bool found, PropertySlot& toStringTagSlot) -> JSValue { >- if (found) { >- JSValue stringTag = toStringTagSlot.getValue(exec, toStringTagSymbol); >- RETURN_IF_EXCEPTION(scope, { }); >- if (stringTag.isString()) { >- JSRopeString::RopeBuilder<RecordOverflow> ropeBuilder(vm); >- ropeBuilder.append(vm.smallStrings.objectStringStart()); >- ropeBuilder.append(asString(stringTag)); >- ropeBuilder.append(vm.smallStrings.singleCharacterString(']')); >- if (ropeBuilder.hasOverflowed()) >- return throwOutOfMemoryError(exec, scope); >- >- JSString* result = ropeBuilder.release(); >- thisObject->structure(vm)->setObjectToStringValue(exec, vm, result, toStringTagSlot); >- return result; >- } >- } >- >- String tag = thisObject->methodTable(vm)->toStringName(thisObject, exec); >- RETURN_IF_EXCEPTION(scope, { }); >- String newString = tryMakeString("[object ", WTFMove(tag), "]"); >- if (!newString) >- return throwOutOfMemoryError(exec, scope); >- >- auto result = jsNontrivialString(&vm, newString); >- thisObject->structure(vm)->setObjectToStringValue(exec, vm, result, toStringTagSlot); >- return result; >- }))); >+ return JSValue::encode(objectToString(exec, thisValue)); > } > > } // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.h b/Source/JavaScriptCore/runtime/ObjectPrototype.h >index b70a86580540f0cbc1214d044b0eebe17f8a3b95..602b13dde8a0939f59d274fdd625c9792fe556c1 100644 >--- a/Source/JavaScriptCore/runtime/ObjectPrototype.h >+++ b/Source/JavaScriptCore/runtime/ObjectPrototype.h >@@ -45,6 +45,4 @@ class ObjectPrototype final : public JSNonFinalObject { > ObjectPrototype(VM&, Structure*); > }; > >-JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*); >- > } // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/ObjectPrototypeInlines.h b/Source/JavaScriptCore/runtime/ObjectPrototypeInlines.h >new file mode 100644 >index 0000000000000000000000000000000000000000..578e2ec94be192fe5d667d1a18bf82c4ad66d7c3 >--- /dev/null >+++ b/Source/JavaScriptCore/runtime/ObjectPrototypeInlines.h >@@ -0,0 +1,122 @@ >+/* >+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) >+ * Copyright (C) 2008-2017 Apple Inc. All rights reserved. >+ * >+ * This library is free software; you can redistribute it and/or >+ * modify it under the terms of the GNU Lesser General Public >+ * License as published by the Free Software Foundation; either >+ * version 2 of the License, or (at your option) any later version. >+ * >+ * This library is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >+ * Lesser General Public License for more details. >+ * >+ * You should have received a copy of the GNU Lesser General Public >+ * License along with this library; if not, write to the Free Software >+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA >+ * >+ */ >+ >+#pragma once >+ >+#include "JSCInlines.h" >+#include "JSObject.h" >+#include "JSString.h" >+#include "ObjectPrototype.h" >+#include "PropertySlot.h" >+#include "StructureInlines.h" >+#include "StructureRareDataInlines.h" >+ >+namespace JSC { >+ >+inline Structure* structureForPrimitiveValue(JSGlobalObject* globalObject, JSValue value) >+{ >+ if (value.isCell()) { >+ if (value.isString()) >+ return globalObject->stringObjectStructure(); >+ if (value.isBigInt()) >+ return globalObject->bigIntObjectStructure(); >+ ASSERT(value.isSymbol()); >+ return globalObject->symbolObjectStructure(); >+ } >+ >+ if (value.isNumber()) >+ return globalObject->numberObjectStructure(); >+ if (value.isBoolean()) >+ return globalObject->booleanObjectStructure(); >+ >+ ASSERT(value.isUndefinedOrNull()); >+ return nullptr; >+} >+ >+inline JSString* objectToString(ExecState* exec, JSValue thisValue) >+{ >+ VM& vm = exec->vm(); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ >+ JSObject* thisObject = nullptr; >+ if (thisValue.isObject()) { >+ thisObject = jsCast<JSObject*>(thisValue); >+ if (auto* result = thisObject->structure(vm)->objectToStringValue()) >+ return result; >+ } else { >+ if (thisValue.isUndefinedOrNull()) >+ return thisValue.isUndefined() ? vm.smallStrings.undefinedObjectString() : vm.smallStrings.nullObjectString(); >+ >+ auto* structure = structureForPrimitiveValue(exec->lexicalGlobalObject(), thisValue); >+ ASSERT(structure); >+ if (auto* result = structure->objectToStringValue()) >+ return result; >+ thisObject = thisValue.toObject(exec); >+ EXCEPTION_ASSERT(!!scope.exception() == !thisObject); >+ if (!thisObject) >+ return nullptr; >+ } >+ >+ RELEASE_AND_RETURN(scope, thisObject->getPropertySlot(exec, vm.propertyNames->toStringTagSymbol, [&] (bool found, PropertySlot& toStringTagSlot) -> JSString* { >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ if (found) { >+ JSValue stringTag = toStringTagSlot.getValue(exec, vm.propertyNames->toStringTagSymbol); >+ RETURN_IF_EXCEPTION(scope, { }); >+ if (stringTag.isString()) { >+ JSRopeString::RopeBuilder<RecordOverflow> ropeBuilder(vm); >+ ropeBuilder.append(vm.smallStrings.objectStringStart()); >+ ropeBuilder.append(asString(stringTag)); >+ ropeBuilder.append(vm.smallStrings.singleCharacterString(']')); >+ if (ropeBuilder.hasOverflowed()) { >+ throwOutOfMemoryError(exec, scope); >+ return nullptr; >+ } >+ >+ JSString* result = ropeBuilder.release(); >+ thisObject->structure(vm)->setObjectToStringValue(exec, vm, result, toStringTagSlot); >+ return result; >+ } >+ } >+ >+ String tag = [&] () -> String { >+ auto* methodTable = thisObject->methodTable(vm); >+ auto* toStringNameMethod = methodTable->toStringName; >+ if (toStringNameMethod == &JSObject::toStringName) { >+ auto* classNameMethod = methodTable->className; >+ if (classNameMethod == &JSObject::className) >+ return thisObject->classInfo(vm)->className; >+ return classNameMethod(thisObject, vm); >+ } >+ return toStringNameMethod(thisObject, exec); >+ }(); >+ RETURN_IF_EXCEPTION(scope, { }); >+ String newString = tryMakeString("[object ", WTFMove(tag), "]"); >+ if (!newString) { >+ throwOutOfMemoryError(exec, scope); >+ return nullptr; >+ } >+ >+ auto result = jsNontrivialString(&vm, newString); >+ thisObject->structure(vm)->setObjectToStringValue(exec, vm, result, toStringTagSlot); >+ return result; >+ })); >+} >+ >+} // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/StructureRareData.h b/Source/JavaScriptCore/runtime/StructureRareData.h >index 336732d11d873d42f20f9910871e28c270f6a885..179aa824fb50b7c34c60b73b562e69244d2746e7 100644 >--- a/Source/JavaScriptCore/runtime/StructureRareData.h >+++ b/Source/JavaScriptCore/runtime/StructureRareData.h >@@ -81,6 +81,11 @@ class StructureRareData final : public JSCell { > void setSharedPolyProtoWatchpoint(Box<InlineWatchpointSet>&& sharedPolyProtoWatchpoint) { m_polyProtoWatchpoint = WTFMove(sharedPolyProtoWatchpoint); } > bool hasSharedPolyProtoWatchpoint() const { return static_cast<bool>(m_polyProtoWatchpoint); } > >+ static ptrdiff_t offsetOfObjectToStringValue() >+ { >+ return OBJECT_OFFSETOF(StructureRareData, m_objectToStringValue); >+ } >+ > static JSImmutableButterfly* cachedOwnKeysSentinel() { return bitwise_cast<JSImmutableButterfly*>(static_cast<uintptr_t>(1)); } > > static ptrdiff_t offsetOfCachedOwnKeys()
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 193031
:
358056
|
358057
|
358058
|
358060
|
358062
|
358078
|
358080
|
358110
|
358111
|
358166
|
358211
|
358214