Title: [239612] trunk
Revision
239612
Author
[email protected]
Date
2019-01-04 09:04:09 -0800 (Fri, 04 Jan 2019)

Log Message

[JSC] Optimize Object.prototype.toString
https://bugs.webkit.org/show_bug.cgi?id=193031

Reviewed by Saam Barati.

JSTests:

* stress/object-tostring-changed-proto.js: Added.
(shouldBe):
(test):
* stress/object-tostring-changed.js: Added.
(shouldBe):
(test):
* stress/object-tostring-misc.js: Added.
(shouldBe):
(test):
(i.switch):
* stress/object-tostring-other.js: Added.
(shouldBe):
(test):
* stress/object-tostring-untyped.js: Added.
(shouldBe):
(test):
(i.switch):

Source/_javascript_Core:

Object.prototype.toString is frequently used for type checking.
It is called many times in wtb-lebab.js. This patch optimizes
Object.prototype.toString by the following two optimizations.

1. We should emit code looking up cached to string in DFG and FTL.

toString's result is cached in the Structure. We emit a fast path code
in DFG and FTL to lookup this cache.

2. We should not create objects for primitive values in major cases.

When Object.prototype.toString(primitive) is called, this primitive is converted
to an object by calling ToObject. But if the result is appropriately cached in
the Structure, we should get it in the fast path without creating this object.
When converting primitives to objects, Structures used in these newly created objects
are known (Structure for StringObject etc.). So we can first query the cached string
before actually converting primitives to objects.

This patch improves wtb-lebab.js by roughly 2%.

    before:    lebab:  8.90 runs/s
    after :    lebab:  9.09 runs/s

* _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):
(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:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (239611 => 239612)


--- trunk/JSTests/ChangeLog	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/JSTests/ChangeLog	2019-01-04 17:04:09 UTC (rev 239612)
@@ -1,3 +1,28 @@
+2019-01-02  Yusuke Suzuki  <[email protected]>
+
+        [JSC] Optimize Object.prototype.toString
+        https://bugs.webkit.org/show_bug.cgi?id=193031
+
+        Reviewed by Saam Barati.
+
+        * stress/object-tostring-changed-proto.js: Added.
+        (shouldBe):
+        (test):
+        * stress/object-tostring-changed.js: Added.
+        (shouldBe):
+        (test):
+        * stress/object-tostring-misc.js: Added.
+        (shouldBe):
+        (test):
+        (i.switch):
+        * stress/object-tostring-other.js: Added.
+        (shouldBe):
+        (test):
+        * stress/object-tostring-untyped.js: Added.
+        (shouldBe):
+        (test):
+        (i.switch):
+
 2019-01-03  Ross Kirsling  <[email protected]>
 
         test262-runner misbehaves when test file YAML has a trailing space

Added: trunk/JSTests/stress/object-tostring-changed-proto.js (0 => 239612)


--- trunk/JSTests/stress/object-tostring-changed-proto.js	                        (rev 0)
+++ trunk/JSTests/stress/object-tostring-changed-proto.js	2019-01-04 17:04:09 UTC (rev 239612)
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+noInline(shouldBe);
+
+function test(value)
+{
+    return Object.prototype.toString.call(value);
+}
+noInline(test);
+
+var object = {};
+for (var i = 0; i < 1e5; ++i)
+    shouldBe(test(object), `[object Object]`);
+Object.prototype[Symbol.toStringTag] = "Hello";
+shouldBe(test(object), `[object Hello]`);

Added: trunk/JSTests/stress/object-tostring-changed.js (0 => 239612)


--- trunk/JSTests/stress/object-tostring-changed.js	                        (rev 0)
+++ trunk/JSTests/stress/object-tostring-changed.js	2019-01-04 17:04:09 UTC (rev 239612)
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+noInline(shouldBe);
+
+function test(value)
+{
+    return Object.prototype.toString.call(value);
+}
+noInline(test);
+
+var object = {};
+for (var i = 0; i < 1e5; ++i)
+    shouldBe(test(object), `[object Object]`);
+object[Symbol.toStringTag] = "Hello";
+shouldBe(test(object), `[object Hello]`);

Added: trunk/JSTests/stress/object-tostring-misc.js (0 => 239612)


--- trunk/JSTests/stress/object-tostring-misc.js	                        (rev 0)
+++ trunk/JSTests/stress/object-tostring-misc.js	2019-01-04 17:04:09 UTC (rev 239612)
@@ -0,0 +1,26 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+noInline(shouldBe);
+
+function test(value)
+{
+    return Object.prototype.toString.call(value);
+}
+noInline(test);
+
+for (var i = 0; i < 1e6; ++i) {
+    switch (i % 3) {
+    case 0:
+        shouldBe(test(null), `[object Null]`);
+        break;
+    case 1:
+        shouldBe(test(undefined), `[object Undefined]`);
+        break;
+    case 2:
+        shouldBe(test(true), `[object Boolean]`);
+        break;
+    }
+}

Added: trunk/JSTests/stress/object-tostring-other.js (0 => 239612)


--- trunk/JSTests/stress/object-tostring-other.js	                        (rev 0)
+++ trunk/JSTests/stress/object-tostring-other.js	2019-01-04 17:04:09 UTC (rev 239612)
@@ -0,0 +1,19 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+noInline(shouldBe);
+
+function test(value)
+{
+    return Object.prototype.toString.call(value);
+}
+noInline(test);
+
+for (var i = 0; i < 1e6; ++i) {
+    if (i & 0x1)
+        shouldBe(test(null), `[object Null]`);
+    else
+        shouldBe(test(undefined), `[object Undefined]`);
+}

Added: trunk/JSTests/stress/object-tostring-untyped.js (0 => 239612)


--- trunk/JSTests/stress/object-tostring-untyped.js	                        (rev 0)
+++ trunk/JSTests/stress/object-tostring-untyped.js	2019-01-04 17:04:09 UTC (rev 239612)
@@ -0,0 +1,50 @@
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+noInline(shouldBe);
+
+function test(value)
+{
+    return Object.prototype.toString.call(value);
+}
+noInline(test);
+
+var value0 = {};
+var value1 = { [Symbol.toStringTag]: "Hello" };
+var value2 = new Date();
+var value3 = "Hello";
+var value4 = 42;
+var value5 = Symbol("Cocoa");
+var value6 = 42.195;
+var value7 = false;
+
+for (var i = 0; i < 1e6; ++i) {
+    switch (i % 8) {
+    case 0:
+        shouldBe(test(value0), `[object Object]`);
+        break;
+    case 1:
+        shouldBe(test(value1), `[object Hello]`);
+        break;
+    case 2:
+        shouldBe(test(value2), `[object Date]`);
+        break;
+    case 3:
+        shouldBe(test(value3), `[object String]`);
+        break;
+    case 4:
+        shouldBe(test(value4), `[object Number]`);
+        break;
+    case 5:
+        shouldBe(test(value5), `[object Symbol]`);
+        break;
+    case 6:
+        shouldBe(test(value6), `[object Number]`);
+        break;
+    case 7:
+        shouldBe(test(value7), `[object Boolean]`);
+        break;
+    }
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (239611 => 239612)


--- trunk/Source/_javascript_Core/ChangeLog	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/ChangeLog	2019-01-04 17:04:09 UTC (rev 239612)
@@ -1,3 +1,76 @@
+2019-01-02  Yusuke Suzuki  <[email protected]>
+
+        [JSC] Optimize Object.prototype.toString
+        https://bugs.webkit.org/show_bug.cgi?id=193031
+
+        Reviewed by Saam Barati.
+
+        Object.prototype.toString is frequently used for type checking.
+        It is called many times in wtb-lebab.js. This patch optimizes
+        Object.prototype.toString by the following two optimizations.
+
+        1. We should emit code looking up cached to string in DFG and FTL.
+
+        toString's result is cached in the Structure. We emit a fast path code
+        in DFG and FTL to lookup this cache.
+
+        2. We should not create objects for primitive values in major cases.
+
+        When Object.prototype.toString(primitive) is called, this primitive is converted
+        to an object by calling ToObject. But if the result is appropriately cached in
+        the Structure, we should get it in the fast path without creating this object.
+        When converting primitives to objects, Structures used in these newly created objects
+        are known (Structure for StringObject etc.). So we can first query the cached string
+        before actually converting primitives to objects.
+
+        This patch improves wtb-lebab.js by roughly 2%.
+
+            before:    lebab:  8.90 runs/s
+            after :    lebab:  9.09 runs/s
+
+        * _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):
+        (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:
+
 2019-01-03  Michael Saboff  <[email protected]>
 
         DFG IntegerRangeOptimization phase exceeding loop limit shouldn't ASSERT

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (239611 => 239612)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2019-01-04 17:04:09 UTC (rev 239612)
@@ -1624,6 +1624,7 @@
 		BC18C4440E16F5CD00B34460 /* NumberPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C50E16D4E900A06E92 /* NumberPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		BC18C4450E16F5CD00B34460 /* ObjectConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C70E16D4E900A06E92 /* ObjectConstructor.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		BC18C4460E16F5CD00B34460 /* ObjectPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C90E16D4E900A06E92 /* ObjectPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		5E158AC350BC4EC7877DC0F4 /* ObjectPrototypeInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D0CC9E1CBC149AB8F403434 /* ObjectPrototypeInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		BC18C4480E16F5CD00B34460 /* Operations.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A8780255597D01FF60F7 /* Operations.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		BC18C44B0E16F5CD00B34460 /* Parser.h in Headers */ = {isa = PBXBuildFile; fileRef = 93F0B3AA09BB4DC00068FCE3 /* Parser.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		BC18C4540E16F5CD00B34460 /* PropertyNameArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 65400C100A69BAF200509887 /* PropertyNameArray.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -4486,6 +4487,7 @@
 		BC2680C70E16D4E900A06E92 /* ObjectConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectConstructor.h; sourceTree = "<group>"; };
 		BC2680C80E16D4E900A06E92 /* ObjectPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectPrototype.cpp; sourceTree = "<group>"; };
 		BC2680C90E16D4E900A06E92 /* ObjectPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectPrototype.h; sourceTree = "<group>"; };
+		6D0CC9E1CBC149AB8F403434 /* ObjectPrototypeInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectPrototypeInlines.h; sourceTree = "<group>"; };
 		BC2680E60E16D52300A06E92 /* NumberConstructor.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NumberConstructor.lut.h; sourceTree = "<group>"; };
 		BC3046060E1F497F003232CF /* Error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Error.h; sourceTree = "<group>"; };
 		BC337BDE0E1AF0B80076918A /* GetterSetter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = GetterSetter.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
@@ -7000,6 +7002,7 @@
 				E3C295DC1ED2CBAA00D3016F /* ObjectPropertyChangeAdaptiveWatchpoint.h */,
 				BC2680C80E16D4E900A06E92 /* ObjectPrototype.cpp */,
 				BC2680C90E16D4E900A06E92 /* ObjectPrototype.h */,
+				6D0CC9E1CBC149AB8F403434 /* ObjectPrototypeInlines.h */,
 				F692A8770255597D01FF60F7 /* Operations.cpp */,
 				F692A8780255597D01FF60F7 /* Operations.h */,
 				0FE228EA1436AB2300196C48 /* Options.cpp */,
@@ -9447,6 +9450,7 @@
 				0FD3E40A1B618B6600C80E1E /* ObjectPropertyCondition.h in Headers */,
 				0FD3E40C1B618B6600C80E1E /* ObjectPropertyConditionSet.h in Headers */,
 				BC18C4460E16F5CD00B34460 /* ObjectPrototype.h in Headers */,
+				5E158AC350BC4EC7877DC0F4 /* ObjectPrototypeInlines.h in Headers */,
 				E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */,
 				14F79F70216EAFD200046D39 /* Opcode.h in Headers */,
 				FE64872E2141D04800AB0D3E /* OpcodeInlines.h in Headers */,

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (239611 => 239612)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2019-01-04 17:04:09 UTC (rev 239612)
@@ -2620,6 +2620,24 @@
         break;
     }
 
+    case ObjectToString: {
+        AbstractValue& source = forNode(node->child1());
+        bool clobbering = node->child1().useKind() != OtherUse;
+        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;
+            }
+        }
+
+        if (clobbering)
+            clobberWorld();
+        setTypeForNode(node, SpecString);
+        break;
+    }
+
     case ToObject:
     case CallObjectConstructor: {
         AbstractValue& source = forNode(node->child1());

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (239611 => 239612)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2019-01-04 17:04:09 UTC (rev 239612)
@@ -2701,6 +2701,13 @@
         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;

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (239611 => 239612)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2019-01-04 17:04:09 UTC (rev 239612)
@@ -681,6 +681,20 @@
         write(Heap);
         return;
 
+    case ObjectToString:
+        switch (node->child1().useKind()) {
+        case OtherUse:
+            def(PureValue(node));
+            return;
+        case UntypedUse:
+            read(World);
+            write(Heap);
+            return;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            return;
+        }
+
     case AtomicsAdd:
     case AtomicsAnd:
     case AtomicsCompareExchange:

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (239611 => 239612)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2019-01-04 17:04:09 UTC (rev 239612)
@@ -372,6 +372,7 @@
     case StringReplaceRegExp:
     case StringSlice:
     case StringValueOf:
+    case ObjectToString:
     case CreateRest:
     case ToLowerCase:
     case CallDOMGetter:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (239611 => 239612)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2019-01-04 17:04:09 UTC (rev 239612)
@@ -2147,6 +2147,11 @@
             break;
         }
 
+        case ObjectToString: {
+            fixupObjectToString(node);
+            break;
+        }
+
         case StringSlice: {
             fixEdge<StringUse>(node->child1());
             fixEdge<Int32Use>(node->child2());
@@ -2931,6 +2936,15 @@
         }
     }
 
+    void fixupObjectToString(Node* node)
+    {
+        if (node->child1()->shouldSpeculateOther()) {
+            fixEdge<OtherUse>(node->child1());
+            node->clearFlags(NodeMustGenerate);
+            return;
+        }
+    }
+
     bool attemptToMakeFastStringAdd(Node* node)
     {
         bool goodToGo = true;

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (239611 => 239612)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2019-01-04 17:04:09 UTC (rev 239612)
@@ -266,6 +266,7 @@
     macro(GetPrototypeOf, NodeMustGenerate | NodeResultJS) \
     macro(ObjectCreate, NodeMustGenerate | NodeResultJS) \
     macro(ObjectKeys, NodeMustGenerate | NodeResultJS) \
+    macro(ObjectToString, NodeMustGenerate | NodeResultJS) \
     \
     /* Atomics object functions. */\
     macro(AtomicsAdd, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (239611 => 239612)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2019-01-04 17:04:09 UTC (rev 239612)
@@ -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 @@
     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();

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (239611 => 239612)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.h	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h	2019-01-04 17:04:09 UTC (rev 239612)
@@ -205,6 +205,7 @@
 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);

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (239611 => 239612)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2019-01-04 17:04:09 UTC (rev 239612)
@@ -884,6 +884,7 @@
         case StringValueOf:
         case StringSlice:
         case ToLowerCase:
+        case ObjectToString:
             setPrediction(SpecString);
             break;
 

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (239611 => 239612)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2019-01-04 17:04:09 UTC (rev 239612)
@@ -452,6 +452,7 @@
     case StringValueOf:
     case StringSlice:
     case ToLowerCase:
+    case ObjectToString:
     case GetMapBucket:
     case GetMapBucketHead:
     case GetMapBucketNext:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (239611 => 239612)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2019-01-04 17:04:09 UTC (rev 239612)
@@ -12453,6 +12453,63 @@
     }
 }
 
+void SpeculativeJIT::compileObjectToString(Node* node)
+{
+    switch (node->child1().useKind()) {
+    case OtherUse: {
+        JSValueOperand source(this, node->child1(), ManualOperandSpeculation);
+        GPRTemporary result(this);
+
+        JSValueRegs sourceRegs = source.jsValueRegs();
+        GPRReg resultGPR = result.gpr();
+
+        speculateOther(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()) {

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (239611 => 239612)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2019-01-04 17:04:09 UTC (rev 239612)
@@ -1480,6 +1480,7 @@
     void compileNewTypedArray(Node*);
     void compileToThis(Node*);
     void compileObjectKeys(Node*);
+    void compileObjectToString(Node*);
     void compileObjectCreate(Node*);
     void compileCreateThis(Node*);
     void compileNewObject(Node*);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (239611 => 239612)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2019-01-04 17:04:09 UTC (rev 239612)
@@ -3105,6 +3105,11 @@
         compileToStringOrCallStringConstructorOrStringValueOf(node);
         break;
     }
+
+    case ObjectToString: {
+        compileObjectToString(node);
+        break;
+    }
         
     case NewStringObject: {
         compileNewStringObject(node);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (239611 => 239612)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2019-01-04 17:04:09 UTC (rev 239612)
@@ -3347,6 +3347,11 @@
         compileToStringOrCallStringConstructorOrStringValueOf(node);
         break;
     }
+
+    case ObjectToString: {
+        compileObjectToString(node);
+        break;
+    }
         
     case NewStringObject: {
         compileNewStringObject(node);

Modified: trunk/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h (239611 => 239612)


--- trunk/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/ftl/FTLAbstractHeapRepository.h	2019-01-04 17:04:09 UTC (rev 239612)
@@ -120,6 +120,7 @@
     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()) \

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (239611 => 239612)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2019-01-04 17:04:09 UTC (rev 239612)
@@ -333,6 +333,7 @@
     case StringValueOf:
     case StringSlice:
     case ToLowerCase:
+    case ObjectToString:
     case NumberToStringWithRadix:
     case NumberToStringWithValidRadixConstant:
     case CheckSubClass:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (239611 => 239612)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2019-01-04 17:04:09 UTC (rev 239612)
@@ -937,6 +937,9 @@
         case StringFromCharCode:
             compileStringFromCharCode();
             break;
+        case ObjectToString:
+            compileObjectToString();
+            break;
         case GetByOffset:
         case GetGetterSetterByOffset:
             compileGetByOffset();
@@ -6419,6 +6422,61 @@
             break;
         }
     }
+
+    void compileObjectToString()
+    {
+        switch (m_node->child1().useKind()) {
+        case OtherUse: {
+            speculate(m_node->child1());
+            LValue source = lowJSValue(m_node->child1(), ManualOperandSpeculation);
+            LValue result = m_out.select(m_out.equal(source, m_out.constInt64(ValueUndefined)),
+                weakPointer(vm().smallStrings.undefinedObjectString()), weakPointer(vm().smallStrings.nullObjectString()));
+            setJSValue(result);
+            return;
+        }
+        case UntypedUse: {
+            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);
+            LValue slowResultValue = vmCall(pointerType(), m_out.operation(operationObjectToString), m_callFrame, 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()
     {

Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.cpp (239611 => 239612)


--- trunk/Source/_javascript_Core/runtime/Intrinsic.cpp	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.cpp	2019-01-04 17:04:09 UTC (rev 239612)
@@ -121,6 +121,8 @@
         return "ObjectIsIntrinsic";
     case ObjectKeysIntrinsic:
         return "ObjectKeysIntrinsic";
+    case ObjectPrototypeToStringIntrinsic:
+        return "ObjectPrototypeToStringIntrinsic";
     case ReflectGetPrototypeOfIntrinsic:
         return "ReflectGetPrototypeOfIntrinsic";
     case StringPrototypeValueOfIntrinsic:

Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.h (239611 => 239612)


--- trunk/Source/_javascript_Core/runtime/Intrinsic.h	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.h	2019-01-04 17:04:09 UTC (rev 239612)
@@ -73,6 +73,7 @@
     ObjectGetPrototypeOfIntrinsic,
     ObjectIsIntrinsic,
     ObjectKeysIntrinsic,
+    ObjectPrototypeToStringIntrinsic,
     ReflectGetPrototypeOfIntrinsic,
     StringPrototypeValueOfIntrinsic,
     StringPrototypeReplaceIntrinsic,

Modified: trunk/Source/_javascript_Core/runtime/ObjectPrototype.cpp (239611 => 239612)


--- trunk/Source/_javascript_Core/runtime/ObjectPrototype.cpp	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/runtime/ObjectPrototype.cpp	2019-01-04 17:04:09 UTC (rev 239612)
@@ -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 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 @@
     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 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

Modified: trunk/Source/_javascript_Core/runtime/ObjectPrototype.h (239611 => 239612)


--- trunk/Source/_javascript_Core/runtime/ObjectPrototype.h	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/runtime/ObjectPrototype.h	2019-01-04 17:04:09 UTC (rev 239612)
@@ -45,6 +45,4 @@
     ObjectPrototype(VM&, Structure*);
 };
 
-JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*);
-
 } // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/ObjectPrototypeInlines.h (0 => 239612)


--- trunk/Source/_javascript_Core/runtime/ObjectPrototypeInlines.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/ObjectPrototypeInlines.h	2019-01-04 17:04:09 UTC (rev 239612)
@@ -0,0 +1,112 @@
+/*
+ *  Copyright (C) 1999-2000 Harri Porten ([email protected])
+ *  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;
+}
+
+ALWAYS_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 = thisObject->methodTable(vm)->toStringName(thisObject, exec);
+        RETURN_IF_EXCEPTION(scope, { });
+        String newString = tryMakeString("[object ", WTFMove(tag), "]");
+        if (!newString) {
+            throwOutOfMemoryError(exec, scope);
+            return nullptr;
+        }
+
+        auto result = jsNontrivialString(&vm, WTFMove(newString));
+        thisObject->structure(vm)->setObjectToStringValue(exec, vm, result, toStringTagSlot);
+        return result;
+    }));
+}
+
+} // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/StructureRareData.h (239611 => 239612)


--- trunk/Source/_javascript_Core/runtime/StructureRareData.h	2019-01-04 16:44:43 UTC (rev 239611)
+++ trunk/Source/_javascript_Core/runtime/StructureRareData.h	2019-01-04 17:04:09 UTC (rev 239612)
@@ -81,6 +81,11 @@
     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()
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to