WebKit Bugzilla
Attachment 349041 Details for
Bug 189151
: [DFG] DFG should handle String#toString
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-189151-20180907023556.patch (text/plain), 24.39 KB, created by
Yusuke Suzuki
on 2018-09-06 10:35:57 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Yusuke Suzuki
Created:
2018-09-06 10:35:57 PDT
Size:
24.39 KB
patch
obsolete
>Subversion Revision: 235739 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 164950e090b54f7769c6b47352761032f026dcc9..314c0175317c0b80bfc1f13c76859d7c3ca2366d 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,59 @@ >+2018-09-06 Yusuke Suzuki <yusukesuzuki@slowstart.org> >+ >+ [DFG] DFG should handle String#toString >+ https://bugs.webkit.org/show_bug.cgi?id=189151 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ We handle String#toString and String#valueOf in DFG by introducing StringValueOf node. >+ In the fixup phase, we attempt to lower StringValueOf to the existing ToString or Identity >+ nodes. If we fail to lower it, we have StringValueOf(UntypedUse), which may raise an error >+ if an argument is neither String nor StringObject. The error message in String#toString and >+ String#valueOf is poor, which will be handled in a separate bug[1]. >+ >+ It improves simple microbenchmarks by 53.4 - 67.6%. >+ >+ baseline patched >+ >+ string-object-to-string 21.7308+-3.3147 ^ 12.9655+-0.0527 ^ definitely 1.6760x faster >+ string-object-value-of 20.1122+-0.0691 ^ 13.1134+-0.2482 ^ definitely 1.5337x faster >+ >+ [1]: https://bugs.webkit.org/show_bug.cgi?id=189357 >+ >+ * 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::fixupStringValueOf): >+ * dfg/DFGNode.h: >+ (JSC::DFG::Node::convertToToString): >+ * dfg/DFGNodeType.h: >+ * dfg/DFGOperations.cpp: >+ * dfg/DFGOperations.h: >+ * dfg/DFGPredictionPropagationPhase.cpp: >+ * dfg/DFGSafeToExecute.h: >+ (JSC::DFG::safeToExecute): >+ * dfg/DFGSpeculativeJIT.cpp: >+ (JSC::DFG::SpeculativeJIT::compileToStringOrCallStringConstructorOrStringValueOf): >+ (JSC::DFG::SpeculativeJIT::compileToStringOrCallStringConstructor): Deleted. >+ * dfg/DFGSpeculativeJIT.h: >+ * dfg/DFGSpeculativeJIT32_64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGSpeculativeJIT64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * ftl/FTLCapabilities.cpp: >+ (JSC::FTL::canCompile): >+ * ftl/FTLLowerDFGToB3.cpp: >+ (JSC::FTL::DFG::LowerDFGToB3::compileNode): >+ (JSC::FTL::DFG::LowerDFGToB3::compileToStringOrCallStringConstructorOrStringValueOf): >+ (JSC::FTL::DFG::LowerDFGToB3::compileToStringOrCallStringConstructor): Deleted. >+ > 2018-09-05 Mark Lam <mark.lam@apple.com> > > JSPropertyNameEnumerator::visitChildren() needs to visit its m_cachedStructureID. >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >index 497d772a3c7d5792183c69bb32b1507f2c9bd0f4..e53dd96a9f47612bbc208a85bcb444285b21bf68 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >@@ -1175,6 +1175,12 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > break; > } > >+ case StringValueOf: { >+ clobberWorld(); >+ setTypeForNode(node, SpecString); >+ break; >+ } >+ > case StringSlice: { > setTypeForNode(node, SpecString); > break; >diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >index a8f932c63a800bd261330e6a0904432a41505c53..6e9b6fc91aafb5d205a873fa3aff4a53c682b25e 100644 >--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >@@ -2691,6 +2691,13 @@ bool ByteCodeParser::handleIntrinsicCall(Node* callee, int resultOperand, Intrin > return true; > } > >+ case StringPrototypeValueOfIntrinsic: { >+ insertChecks(); >+ Node* value = get(virtualRegisterForArgument(0, registerOffset)); >+ set(VirtualRegister(resultOperand), addToGraph(StringValueOf, value)); >+ return true; >+ } >+ > case StringPrototypeReplaceIntrinsic: { > if (argumentCountIncludingThis != 3) > return false; >diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h >index b02f2c05c2c3e5c494b3ccf447e52185792c128f..4fd9db61a8a812e17b271134f930ee21466b3c4e 100644 >--- a/Source/JavaScriptCore/dfg/DFGClobberize.h >+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h >@@ -652,6 +652,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu > case NumberToStringWithRadix: > case CreateThis: > case InstanceOf: >+ case StringValueOf: > read(World); > write(Heap); > return; >diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >index 2b0d4df94fcd6dac639cf9a017b694686d3f23f3..cb167f029ce3023ed3a0e3237f31afa557a66c61 100644 >--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >@@ -363,6 +363,7 @@ bool doesGC(Graph& graph, Node* node) > case StringReplace: > case StringReplaceRegExp: > case StringSlice: >+ case StringValueOf: > case CreateRest: > case ToLowerCase: > case CallDOMGetter: >diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >index c44db1a49d26d3079431080a03f49fc09e4d89c9..49881dcf112a7af18f6b2b563e81be879a8143de 100644 >--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >@@ -1994,6 +1994,11 @@ class FixupPhase : public Phase { > break; > } > >+ case StringValueOf: { >+ fixupStringValueOf(node); >+ break; >+ } >+ > case StringSlice: { > fixEdge<StringUse>(node->child1()); > fixEdge<Int32Use>(node->child2()); >@@ -2753,6 +2758,31 @@ class FixupPhase : public Phase { > } > } > >+ void fixupStringValueOf(Node* node) >+ { >+ if (node->child1()->shouldSpeculateString()) { >+ fixEdge<StringUse>(node->child1()); >+ node->convertToIdentity(); >+ return; >+ } >+ >+ if (node->child1()->shouldSpeculateStringObject()) { >+ fixEdge<StringObjectUse>(node->child1()); >+ node->convertToToString(); >+ // It does not need to look up a toString property for the StringObject case. So we can clear NodeMustGenerate. >+ node->clearFlags(NodeMustGenerate); >+ return; >+ } >+ >+ if (node->child1()->shouldSpeculateStringOrStringObject()) { >+ fixEdge<StringOrStringObjectUse>(node->child1()); >+ node->convertToToString(); >+ // It does not need to look up a toString property for the StringObject case. So we can clear NodeMustGenerate. >+ node->clearFlags(NodeMustGenerate); >+ return; >+ } >+ } >+ > bool attemptToMakeFastStringAdd(Node* node) > { > bool goodToGo = true; >diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h >index f7aa9f71d5dfa2fb58b11dfe12a5e81a27cf35d1..7889f3f57f66789fef1005ded7fb3cf1996c59ea 100644 >--- a/Source/JavaScriptCore/dfg/DFGNode.h >+++ b/Source/JavaScriptCore/dfg/DFGNode.h >@@ -694,7 +694,7 @@ struct Node { > > void convertToToString() > { >- ASSERT(m_op == ToPrimitive); >+ ASSERT(m_op == ToPrimitive || m_op == StringValueOf); > m_op = ToString; > } > >diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h >index af3db342c7ae2c9fda079554fadf9dda05ff98fb..d30c925d98f445ba080a9a2cc80917db448a7470 100644 >--- a/Source/JavaScriptCore/dfg/DFGNodeType.h >+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h >@@ -465,6 +465,7 @@ namespace JSC { namespace DFG { > macro(WeakMapSet, NodeMustGenerate | NodeHasVarArgs) \ > macro(ExtractValueFromWeakMapGet, NodeResultJS) \ > \ >+ macro(StringValueOf, NodeMustGenerate | NodeResultJS) \ > macro(StringSlice, NodeResultJS) \ > macro(ToLowerCase, NodeResultJS) \ > /* Nodes for DOM JIT */\ >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp >index 6a4c0c523a18bdbec5d8c630418cecbdcfb8a54b..2da8050066830600122bc0f0f29c1a2a0747dbb5 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp >+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp >@@ -2013,6 +2013,25 @@ StringImpl* JIT_OPERATION operationResolveRope(ExecState* exec, JSString* string > return string->value(exec).impl(); > } > >+JSCell* JIT_OPERATION operationStringValueOf(ExecState* exec, EncodedJSValue encodedArgument) >+{ >+ VM& vm = exec->vm(); >+ NativeCallFrameTracer tracer(&vm, exec); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ >+ JSValue argument = JSValue::decode(encodedArgument); >+ >+ if (argument.isString()) >+ return asString(argument); >+ >+ auto* stringObject = jsDynamicCast<StringObject*>(vm, argument); >+ if (stringObject) >+ return stringObject->internalValue(); >+ >+ throwVMTypeError(exec, scope); >+ return nullptr; >+} >+ > 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 35bf6bceadb644d004c76c985f631d5233d007cd..91a7e5c6b5c011916ae70f65da5e0445de1955a1 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.h >+++ b/Source/JavaScriptCore/dfg/DFGOperations.h >@@ -193,6 +193,7 @@ StringImpl* JIT_OPERATION operationResolveRope(ExecState*, JSString*); > JSString* JIT_OPERATION operationSingleCharacterString(ExecState*, int32_t); > > JSCell* JIT_OPERATION operationStringSubstr(ExecState*, JSCell*, int32_t, int32_t); >+JSCell* JIT_OPERATION operationStringValueOf(ExecState*, EncodedJSValue); > JSString* JIT_OPERATION operationToLowerCase(ExecState*, JSString*, uint32_t); > > char* JIT_OPERATION operationInt32ToString(ExecState*, int32_t, int32_t); >diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >index a8b92cb83aa7a2a8bb138f4e410eca03f9b96b1a..f37fd06395144c41f495281804f3b4303e827c22 100644 >--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >@@ -826,6 +826,7 @@ class PredictionPropagationPhase : public Phase { > break; > } > >+ case StringValueOf: > case StringSlice: > case ToLowerCase: > setPrediction(SpecString); >diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >index 4bfb61594b810a9c1ddd56af71ef3f68015bd2f9..60801d064960809e72ecdc875303ff751e07a012 100644 >--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >@@ -440,6 +440,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno > case ResolveScope: > case MapHash: > case NormalizeMapKey: >+ case StringValueOf: > case StringSlice: > case ToLowerCase: > case GetMapBucket: >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >index 15c92916893fae51a6dc22797c634ab748082d3f..bdb4db724c32cf0ecb8ad4cd8b88f0301add10f4 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >@@ -9233,8 +9233,9 @@ GPRReg SpeculativeJIT::temporaryRegisterForPutByVal(GPRTemporary& temporary, Arr > return temporary.gpr(); > } > >-void SpeculativeJIT::compileToStringOrCallStringConstructor(Node* node) >+void SpeculativeJIT::compileToStringOrCallStringConstructorOrStringValueOf(Node* node) > { >+ ASSERT(node->op() != StringValueOf || node->child1().useKind() == UntypedUse); > switch (node->child1().useKind()) { > case NotCellUse: { > JSValueOperand op1(this, node->child1(), ManualOperandSpeculation); >@@ -9279,6 +9280,8 @@ void SpeculativeJIT::compileToStringOrCallStringConstructor(Node* node) > } > if (node->op() == ToString) > callOperation(operationToString, resultGPR, op1Regs); >+ else if (node->op() == StringValueOf) >+ callOperation(operationStringValueOf, resultGPR, op1Regs); > else { > ASSERT(node->op() == CallStringConstructor); > callOperation(operationCallStringConstructor, resultGPR, op1Regs); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >index 7fefd12afade6d2bcdc1f42fd41694c5dc911257..e5c30af35210b3ba0444a184d24a322dcced5cc7 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >@@ -1248,7 +1248,7 @@ class SpeculativeJIT { > void emitSwitchString(Node*, SwitchData*); > void emitSwitch(Node*); > >- void compileToStringOrCallStringConstructor(Node*); >+ void compileToStringOrCallStringConstructorOrStringValueOf(Node*); > void compileNumberToStringWithRadix(Node*); > void compileNumberToStringWithValidRadixConstant(Node*); > void compileNumberToStringWithValidRadixConstant(Node*, int32_t radix); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >index 59ce3a1fad8a0f2342b487054b682fd1904b6b35..166e4a4c8844f2f89376106e3789cd36fd119b22 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >@@ -3077,8 +3077,9 @@ void SpeculativeJIT::compile(Node* node) > } > > case ToString: >- case CallStringConstructor: { >- compileToStringOrCallStringConstructor(node); >+ case CallStringConstructor: >+ case StringValueOf: { >+ compileToStringOrCallStringConstructorOrStringValueOf(node); > break; > } > >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >index 025b41bfb4d9811047256864d343360263d965c1..121fd63f877c8ada608e1df0d8a09c52d5719bdf 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >@@ -3326,8 +3326,9 @@ void SpeculativeJIT::compile(Node* node) > } > > case ToString: >- case CallStringConstructor: { >- compileToStringOrCallStringConstructor(node); >+ case CallStringConstructor: >+ case StringValueOf: { >+ compileToStringOrCallStringConstructorOrStringValueOf(node); > break; > } > >diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >index f1822a47426c46fd04281524095d14be731f8e33..3e4afad0c46cab8d78973808cf8548dd18cc6bda 100644 >--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >@@ -321,6 +321,7 @@ inline CapabilityLevel canCompile(Node* node) > case SameValue: > case DefineDataProperty: > case DefineAccessorProperty: >+ case StringValueOf: > case StringSlice: > case ToLowerCase: > case NumberToStringWithRadix: >diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >index 6516636418eaca337b5bf8b0e3327323a8e955d5..707bd773d717fbb44be8f87d2636d6b084175696 100644 >--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >@@ -891,7 +891,8 @@ class LowerDFGToB3 { > break; > case ToString: > case CallStringConstructor: >- compileToStringOrCallStringConstructor(); >+ case StringValueOf: >+ compileToStringOrCallStringConstructorOrStringValueOf(); > break; > case ToPrimitive: > compileToPrimitive(); >@@ -6119,8 +6120,9 @@ class LowerDFGToB3 { > } > } > >- void compileToStringOrCallStringConstructor() >+ void compileToStringOrCallStringConstructorOrStringValueOf() > { >+ ASSERT(m_node->op() != StringValueOf || m_node->child1().useKind() == UntypedUse); > switch (m_node->child1().useKind()) { > case StringObjectUse: { > LValue cell = lowCell(m_node->child1()); >@@ -6191,10 +6193,14 @@ class LowerDFGToB3 { > > m_out.appendTo(notString, continuation); > LValue operation; >- if (m_node->child1().useKind() == CellUse) >+ if (m_node->child1().useKind() == CellUse) { >+ ASSERT(m_node->op() != StringValueOf); > operation = m_out.operation(m_node->op() == ToString ? operationToStringOnCell : operationCallStringConstructorOnCell); >- else >- operation = m_out.operation(m_node->op() == ToString ? operationToString : operationCallStringConstructor); >+ } else { >+ operation = m_out.operation(m_node->op() == ToString >+ ? operationToString : m_node->op() == StringValueOf >+ ? operationStringValueOf : operationCallStringConstructor); >+ } > ValueFromBlock convertedResult = m_out.anchor(vmCall(Int64, operation, m_callFrame, value)); > m_out.jump(continuation); > >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index d26760d673704c5f2a77d0c811f655bcc55aa623..532a192319e670c8301490c9306d253ca3f58538 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,36 @@ >+2018-09-06 Yusuke Suzuki <yusukesuzuki@slowstart.org> >+ >+ [DFG] DFG should handle String#toString >+ https://bugs.webkit.org/show_bug.cgi?id=189151 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ The error message in String#toString and String#valueOf is poor, which will be >+ handled in a separate bug[1]. >+ >+ [1]: https://bugs.webkit.org/show_bug.cgi?id=189357 >+ >+ * microbenchmarks/string-object-to-string.js: Added. >+ (test): >+ * microbenchmarks/string-object-value-of.js: Added. >+ (test): >+ * stress/string-to-string-error.js: Added. >+ (shouldThrow): >+ (test): >+ * stress/string-to-string.js: Added. >+ (shouldBe): >+ (test1): >+ (test2): >+ (test3): >+ * stress/string-value-of-error.js: Added. >+ (shouldThrow): >+ (test): >+ * stress/string-value-of.js: Added. >+ (shouldBe): >+ (test1): >+ (test2): >+ (test3): >+ > 2018-09-05 Mark Lam <mark.lam@apple.com> > > JSPropertyNameEnumerator::visitChildren() needs to visit its m_cachedStructureID. >diff --git a/JSTests/microbenchmarks/string-object-to-string.js b/JSTests/microbenchmarks/string-object-to-string.js >new file mode 100644 >index 0000000000000000000000000000000000000000..8d866550df94cd23a38ed2aa4b6d636491da70cd >--- /dev/null >+++ b/JSTests/microbenchmarks/string-object-to-string.js >@@ -0,0 +1,15 @@ >+const chars = 'abcdefghijklmnopqrstuvwxyz'; >+var prim = ''; >+for (var i = 0; i < 32768; i++) { >+ prim += chars.charAt(~~(Math.random() * 26)); >+} >+const obj = new String(prim); >+ >+function test(obj) >+{ >+ return obj.toString(); >+} >+noInline(test); >+ >+for (var i = 0; i < 1e6; ++i) >+ test(obj); >diff --git a/JSTests/microbenchmarks/string-object-value-of.js b/JSTests/microbenchmarks/string-object-value-of.js >new file mode 100644 >index 0000000000000000000000000000000000000000..b71eb9c579836a800445f805c8cf4df1d3ac4f40 >--- /dev/null >+++ b/JSTests/microbenchmarks/string-object-value-of.js >@@ -0,0 +1,15 @@ >+const chars = 'abcdefghijklmnopqrstuvwxyz'; >+var prim = ''; >+for (var i = 0; i < 32768; i++) { >+ prim += chars.charAt(~~(Math.random() * 26)); >+} >+const obj = new String(prim); >+ >+function test(obj) >+{ >+ return obj.valueOf(); >+} >+noInline(test); >+ >+for (var i = 0; i < 1e6; ++i) >+ test(obj); >diff --git a/JSTests/stress/string-to-string-error.js b/JSTests/stress/string-to-string-error.js >new file mode 100644 >index 0000000000000000000000000000000000000000..e2d906221b662d0e545fbf205805462121a260ab >--- /dev/null >+++ b/JSTests/stress/string-to-string-error.js >@@ -0,0 +1,33 @@ >+function shouldThrow(func, errorMessage) { >+ var errorThrown = false; >+ var error = null; >+ try { >+ func(); >+ } catch (e) { >+ errorThrown = true; >+ error = e; >+ } >+ if (!errorThrown) >+ throw new Error('not thrown'); >+ if (String(error) !== errorMessage) >+ throw new Error(`bad error: ${String(error)}`); >+} >+ >+var toString = String.prototype.toString; >+function test(string) >+{ >+ return toString.call(string); >+} >+noInline(test); >+ >+var object = {}; >+var symbol = Symbol("Cocoa"); >+for (var i = 0; i < 3e3; ++i) { >+ shouldThrow(() => test(object), `TypeError: Type error`); >+ shouldThrow(() => test(false), `TypeError: Type error`); >+ shouldThrow(() => test(true), `TypeError: Type error`); >+ shouldThrow(() => test(42), `TypeError: Type error`); >+ shouldThrow(() => test(null), `TypeError: Type error`); >+ shouldThrow(() => test(undefined), `TypeError: Type error`); >+ shouldThrow(() => test(symbol), `TypeError: Type error`); >+} >diff --git a/JSTests/stress/string-to-string.js b/JSTests/stress/string-to-string.js >new file mode 100644 >index 0000000000000000000000000000000000000000..ba0e7e3d60ad6575dcaa370cc958f9daa6e476cc >--- /dev/null >+++ b/JSTests/stress/string-to-string.js >@@ -0,0 +1,38 @@ >+function shouldBe(actual, expected) { >+ if (actual !== expected) >+ throw new Error('bad value: ' + actual); >+} >+ >+function test1(string) >+{ >+ return string.toString(); >+} >+noInline(test1); >+ >+function test2(string) >+{ >+ return string.toString(); >+} >+noInline(test2); >+ >+function test3(string) >+{ >+ return string.toString(); >+} >+noInline(test3); >+ >+var string = "Hello"; >+var stringObject = new String(string); >+ >+for (var i = 0; i < 1e6; ++i) { >+ shouldBe(test1(string), string); >+ shouldBe(test2(stringObject), string); >+ if (i & 1) >+ shouldBe(test3(string), string); >+ else >+ shouldBe(test3(stringObject), string); >+} >+ >+shouldBe(test1({}), `[object Object]`); >+shouldBe(test2({}), `[object Object]`); >+shouldBe(test3({}), `[object Object]`); >diff --git a/JSTests/stress/string-value-of-error.js b/JSTests/stress/string-value-of-error.js >new file mode 100644 >index 0000000000000000000000000000000000000000..2068ec3250942b5e7b5e7a84f79f58a78706cd62 >--- /dev/null >+++ b/JSTests/stress/string-value-of-error.js >@@ -0,0 +1,33 @@ >+function shouldThrow(func, errorMessage) { >+ var errorThrown = false; >+ var error = null; >+ try { >+ func(); >+ } catch (e) { >+ errorThrown = true; >+ error = e; >+ } >+ if (!errorThrown) >+ throw new Error('not thrown'); >+ if (String(error) !== errorMessage) >+ throw new Error(`bad error: ${String(error)}`); >+} >+ >+var valueOf = String.prototype.valueOf; >+function test(string) >+{ >+ return valueOf.call(string); >+} >+noInline(test); >+ >+var object = {}; >+var symbol = Symbol("Cocoa"); >+for (var i = 0; i < 3e3; ++i) { >+ shouldThrow(() => test(object), `TypeError: Type error`); >+ shouldThrow(() => test(false), `TypeError: Type error`); >+ shouldThrow(() => test(true), `TypeError: Type error`); >+ shouldThrow(() => test(42), `TypeError: Type error`); >+ shouldThrow(() => test(null), `TypeError: Type error`); >+ shouldThrow(() => test(undefined), `TypeError: Type error`); >+ shouldThrow(() => test(symbol), `TypeError: Type error`); >+} >diff --git a/JSTests/stress/string-value-of.js b/JSTests/stress/string-value-of.js >new file mode 100644 >index 0000000000000000000000000000000000000000..4f6d2fd5ec6970b5eefee5e09db66a4a83d18c28 >--- /dev/null >+++ b/JSTests/stress/string-value-of.js >@@ -0,0 +1,39 @@ >+function shouldBe(actual, expected) { >+ if (actual !== expected) >+ throw new Error('bad value: ' + actual); >+} >+ >+function test1(string) >+{ >+ return string.valueOf(); >+} >+noInline(test1); >+ >+function test2(string) >+{ >+ return string.valueOf(); >+} >+noInline(test2); >+ >+function test3(string) >+{ >+ return string.valueOf(); >+} >+noInline(test3); >+ >+var string = "Hello"; >+var stringObject = new String(string); >+ >+for (var i = 0; i < 1e6; ++i) { >+ shouldBe(test1(string), string); >+ shouldBe(test2(stringObject), string); >+ if (i & 1) >+ shouldBe(test3(string), string); >+ else >+ shouldBe(test3(stringObject), string); >+} >+ >+var object = {}; >+shouldBe(test1(object), object); >+shouldBe(test2(object), object); >+shouldBe(test3(object), object);
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
Flags:
saam
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 189151
:
348495
|
348629
|
348706
| 349041