Changeset 239612 in webkit


Ignore:
Timestamp:
Jan 4, 2019 9:04:09 AM (5 years ago)
Author:
yusukesuzuki@slowstart.org
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/JavaScriptCore:

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.

  1. 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

  • JavaScriptCore.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:
Location:
trunk
Files:
6 added
25 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r239605 r239612  
     12019-01-02  Yusuke Suzuki  <yusukesuzuki@slowstart.org>
     2
     3        [JSC] Optimize Object.prototype.toString
     4        https://bugs.webkit.org/show_bug.cgi?id=193031
     5
     6        Reviewed by Saam Barati.
     7
     8        * stress/object-tostring-changed-proto.js: Added.
     9        (shouldBe):
     10        (test):
     11        * stress/object-tostring-changed.js: Added.
     12        (shouldBe):
     13        (test):
     14        * stress/object-tostring-misc.js: Added.
     15        (shouldBe):
     16        (test):
     17        (i.switch):
     18        * stress/object-tostring-other.js: Added.
     19        (shouldBe):
     20        (test):
     21        * stress/object-tostring-untyped.js: Added.
     22        (shouldBe):
     23        (test):
     24        (i.switch):
     25
    1262019-01-03  Ross Kirsling  <ross.kirsling@sony.com>
    227
  • trunk/Source/JavaScriptCore/ChangeLog

    r239595 r239612  
     12019-01-02  Yusuke Suzuki  <yusukesuzuki@slowstart.org>
     2
     3        [JSC] Optimize Object.prototype.toString
     4        https://bugs.webkit.org/show_bug.cgi?id=193031
     5
     6        Reviewed by Saam Barati.
     7
     8        Object.prototype.toString is frequently used for type checking.
     9        It is called many times in wtb-lebab.js. This patch optimizes
     10        Object.prototype.toString by the following two optimizations.
     11
     12        1. We should emit code looking up cached to string in DFG and FTL.
     13
     14        toString's result is cached in the Structure. We emit a fast path code
     15        in DFG and FTL to lookup this cache.
     16
     17        2. We should not create objects for primitive values in major cases.
     18
     19        When Object.prototype.toString(primitive) is called, this primitive is converted
     20        to an object by calling ToObject. But if the result is appropriately cached in
     21        the Structure, we should get it in the fast path without creating this object.
     22        When converting primitives to objects, Structures used in these newly created objects
     23        are known (Structure for StringObject etc.). So we can first query the cached string
     24        before actually converting primitives to objects.
     25
     26        This patch improves wtb-lebab.js by roughly 2%.
     27
     28            before:    lebab:  8.90 runs/s
     29            after :    lebab:  9.09 runs/s
     30
     31        * JavaScriptCore.xcodeproj/project.pbxproj:
     32        * dfg/DFGAbstractInterpreterInlines.h:
     33        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     34        * dfg/DFGByteCodeParser.cpp:
     35        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
     36        * dfg/DFGClobberize.h:
     37        (JSC::DFG::clobberize):
     38        * dfg/DFGDoesGC.cpp:
     39        (JSC::DFG::doesGC):
     40        * dfg/DFGFixupPhase.cpp:
     41        (JSC::DFG::FixupPhase::fixupNode):
     42        (JSC::DFG::FixupPhase::fixupObjectToString):
     43        * dfg/DFGNodeType.h:
     44        * dfg/DFGOperations.cpp:
     45        * dfg/DFGOperations.h:
     46        * dfg/DFGPredictionPropagationPhase.cpp:
     47        * dfg/DFGSafeToExecute.h:
     48        (JSC::DFG::safeToExecute):
     49        * dfg/DFGSpeculativeJIT.cpp:
     50        (JSC::DFG::SpeculativeJIT::compileObjectToString):
     51        * dfg/DFGSpeculativeJIT.h:
     52        * dfg/DFGSpeculativeJIT32_64.cpp:
     53        (JSC::DFG::SpeculativeJIT::compile):
     54        * dfg/DFGSpeculativeJIT64.cpp:
     55        (JSC::DFG::SpeculativeJIT::compile):
     56        * ftl/FTLAbstractHeapRepository.h:
     57        * ftl/FTLCapabilities.cpp:
     58        (JSC::FTL::canCompile):
     59        * ftl/FTLLowerDFGToB3.cpp:
     60        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     61        (JSC::FTL::DFG::LowerDFGToB3::compileObjectToString):
     62        * runtime/Intrinsic.cpp:
     63        (JSC::intrinsicName):
     64        * runtime/Intrinsic.h:
     65        * runtime/ObjectPrototype.cpp:
     66        (JSC::ObjectPrototype::finishCreation):
     67        (JSC::objectProtoFuncToString):
     68        * runtime/ObjectPrototype.h:
     69        * runtime/ObjectPrototypeInlines.h: Added.
     70        (JSC::structureForPrimitiveValue):
     71        (JSC::objectToString):
     72        * runtime/StructureRareData.h:
     73
    1742019-01-03  Michael Saboff  <msaboff@apple.com>
    275
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r238756 r239612  
    16251625                BC18C4450E16F5CD00B34460 /* ObjectConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C70E16D4E900A06E92 /* ObjectConstructor.h */; settings = {ATTRIBUTES = (Private, ); }; };
    16261626                BC18C4460E16F5CD00B34460 /* ObjectPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C90E16D4E900A06E92 /* ObjectPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1627                5E158AC350BC4EC7877DC0F4 /* ObjectPrototypeInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 6D0CC9E1CBC149AB8F403434 /* ObjectPrototypeInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
    16271628                BC18C4480E16F5CD00B34460 /* Operations.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A8780255597D01FF60F7 /* Operations.h */; settings = {ATTRIBUTES = (Private, ); }; };
    16281629                BC18C44B0E16F5CD00B34460 /* Parser.h in Headers */ = {isa = PBXBuildFile; fileRef = 93F0B3AA09BB4DC00068FCE3 /* Parser.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    44874488                BC2680C80E16D4E900A06E92 /* ObjectPrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectPrototype.cpp; sourceTree = "<group>"; };
    44884489                BC2680C90E16D4E900A06E92 /* ObjectPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectPrototype.h; sourceTree = "<group>"; };
     4490                6D0CC9E1CBC149AB8F403434 /* ObjectPrototypeInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectPrototypeInlines.h; sourceTree = "<group>"; };
    44894491                BC2680E60E16D52300A06E92 /* NumberConstructor.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NumberConstructor.lut.h; sourceTree = "<group>"; };
    44904492                BC3046060E1F497F003232CF /* Error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Error.h; sourceTree = "<group>"; };
     
    70017003                                BC2680C80E16D4E900A06E92 /* ObjectPrototype.cpp */,
    70027004                                BC2680C90E16D4E900A06E92 /* ObjectPrototype.h */,
     7005                                6D0CC9E1CBC149AB8F403434 /* ObjectPrototypeInlines.h */,
    70037006                                F692A8770255597D01FF60F7 /* Operations.cpp */,
    70047007                                F692A8780255597D01FF60F7 /* Operations.h */,
     
    94489451                                0FD3E40C1B618B6600C80E1E /* ObjectPropertyConditionSet.h in Headers */,
    94499452                                BC18C4460E16F5CD00B34460 /* ObjectPrototype.h in Headers */,
     9453                                5E158AC350BC4EC7877DC0F4 /* ObjectPrototypeInlines.h in Headers */,
    94509454                                E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */,
    94519455                                14F79F70216EAFD200046D39 /* Opcode.h in Headers */,
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r239438 r239612  
    26182618        clobberWorld();
    26192619        setTypeForNode(node, SpecArray);
     2620        break;
     2621    }
     2622
     2623    case ObjectToString: {
     2624        AbstractValue& source = forNode(node->child1());
     2625        bool clobbering = node->child1().useKind() != OtherUse;
     2626        if (JSValue sourceValue = source.m_value) {
     2627            if (sourceValue.isUndefinedOrNull()) {
     2628                if (clobbering)
     2629                    didFoldClobberWorld();
     2630                setConstant(node, *m_graph.freeze(sourceValue.isUndefined() ? m_vm.smallStrings.undefinedObjectString() : m_vm.smallStrings.nullObjectString()));
     2631                break;
     2632            }
     2633        }
     2634
     2635        if (clobbering)
     2636            clobberWorld();
     2637        setTypeForNode(node, SpecString);
    26202638        break;
    26212639    }
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r239324 r239612  
    26992699        insertChecks();
    27002700        set(result, addToGraph(ObjectKeys, get(virtualRegisterForArgument(1, registerOffset))));
     2701        return true;
     2702    }
     2703
     2704    case ObjectPrototypeToStringIntrinsic: {
     2705        insertChecks();
     2706        Node* value = get(virtualRegisterForArgument(0, registerOffset));
     2707        set(result, addToGraph(ObjectToString, value));
    27012708        return true;
    27022709    }
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r239438 r239612  
    682682        return;
    683683
     684    case ObjectToString:
     685        switch (node->child1().useKind()) {
     686        case OtherUse:
     687            def(PureValue(node));
     688            return;
     689        case UntypedUse:
     690            read(World);
     691            write(Heap);
     692            return;
     693        default:
     694            RELEASE_ASSERT_NOT_REACHED();
     695            return;
     696        }
     697
    684698    case AtomicsAdd:
    685699    case AtomicsAnd:
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r239324 r239612  
    373373    case StringSlice:
    374374    case StringValueOf:
     375    case ObjectToString:
    375376    case CreateRest:
    376377    case ToLowerCase:
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r239324 r239612  
    21452145        case StringValueOf: {
    21462146            fixupStringValueOf(node);
     2147            break;
     2148        }
     2149
     2150        case ObjectToString: {
     2151            fixupObjectToString(node);
    21472152            break;
    21482153        }
     
    29322937    }
    29332938
     2939    void fixupObjectToString(Node* node)
     2940    {
     2941        if (node->child1()->shouldSpeculateOther()) {
     2942            fixEdge<OtherUse>(node->child1());
     2943            node->clearFlags(NodeMustGenerate);
     2944            return;
     2945        }
     2946    }
     2947
    29342948    bool attemptToMakeFastStringAdd(Node* node)
    29352949    {
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r239324 r239612  
    267267    macro(ObjectCreate, NodeMustGenerate | NodeResultJS) \
    268268    macro(ObjectKeys, NodeMustGenerate | NodeResultJS) \
     269    macro(ObjectToString, NodeMustGenerate | NodeResultJS) \
    269270    \
    270271    /* Atomics object functions. */\
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r239427 r239612  
    6464#include "NumberConstructor.h"
    6565#include "ObjectConstructor.h"
     66#include "ObjectPrototypeInlines.h"
    6667#include "Operations.h"
    6768#include "ParseInt.h"
     
    7273#include "ScopedArguments.h"
    7374#include "StringConstructor.h"
     75#include "StructureRareDataInlines.h"
    7476#include "SuperSampler.h"
    7577#include "Symbol.h"
     
    21532155    throwVMTypeError(exec, scope);
    21542156    return nullptr;
     2157}
     2158
     2159JSString* JIT_OPERATION operationObjectToString(ExecState* exec, EncodedJSValue source)
     2160{
     2161    VM& vm = exec->vm();
     2162    NativeCallFrameTracer tracer(&vm, exec);
     2163    return objectToString(exec, JSValue::decode(source));
    21552164}
    21562165
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r239324 r239612  
    206206JSString* JIT_OPERATION operationStringValueOf(ExecState*, EncodedJSValue);
    207207JSString* JIT_OPERATION operationToLowerCase(ExecState*, JSString*, uint32_t);
     208JSString* JIT_OPERATION operationObjectToString(ExecState*, EncodedJSValue);
    208209
    209210char* JIT_OPERATION operationInt32ToString(ExecState*, int32_t, int32_t);
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r239324 r239612  
    885885        case StringSlice:
    886886        case ToLowerCase:
     887        case ObjectToString:
    887888            setPrediction(SpecString);
    888889            break;
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r239324 r239612  
    453453    case StringSlice:
    454454    case ToLowerCase:
     455    case ObjectToString:
    455456    case GetMapBucket:
    456457    case GetMapBucketHead:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r239427 r239612  
    1245412454}
    1245512455
     12456void SpeculativeJIT::compileObjectToString(Node* node)
     12457{
     12458    switch (node->child1().useKind()) {
     12459    case OtherUse: {
     12460        JSValueOperand source(this, node->child1(), ManualOperandSpeculation);
     12461        GPRTemporary result(this);
     12462
     12463        JSValueRegs sourceRegs = source.jsValueRegs();
     12464        GPRReg resultGPR = result.gpr();
     12465
     12466        speculateOther(node->child1(), sourceRegs);
     12467
     12468        auto isUndefined = m_jit.branchIfUndefined(sourceRegs);
     12469        m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.vm()->smallStrings.nullObjectString()), resultGPR);
     12470        auto done = m_jit.jump();
     12471        isUndefined.link(&m_jit);
     12472        m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.vm()->smallStrings.undefinedObjectString()), resultGPR);
     12473        done.link(&m_jit);
     12474
     12475        cellResult(resultGPR, node);
     12476        return;
     12477    }
     12478    case UntypedUse: {
     12479        JSValueOperand source(this, node->child1());
     12480
     12481        JSValueRegs sourceRegs = source.jsValueRegs();
     12482
     12483        GPRTemporary structure(this);
     12484        GPRTemporary scratch(this);
     12485
     12486        GPRReg structureGPR = structure.gpr();
     12487        GPRReg scratchGPR = scratch.gpr();
     12488
     12489        CCallHelpers::JumpList slowCases;
     12490        slowCases.append(m_jit.branchIfNotCell(sourceRegs));
     12491        slowCases.append(m_jit.branchIfNotObject(sourceRegs.payloadGPR()));
     12492
     12493        m_jit.emitLoadStructure(*m_jit.vm(), sourceRegs.payloadGPR(), structureGPR, scratchGPR);
     12494        m_jit.loadPtr(CCallHelpers::Address(structureGPR, Structure::previousOrRareDataOffset()), scratchGPR);
     12495
     12496        slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratchGPR));
     12497        slowCases.append(m_jit.branch32(CCallHelpers::Equal, CCallHelpers::Address(scratchGPR, JSCell::structureIDOffset()), TrustedImm32(bitwise_cast<int32_t>(m_jit.vm()->structureStructure->structureID()))));
     12498
     12499        m_jit.loadPtr(CCallHelpers::Address(scratchGPR, StructureRareData::offsetOfObjectToStringValue()), scratchGPR);
     12500        slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratchGPR));
     12501
     12502        addSlowPathGenerator(slowPathCall(slowCases, this, operationObjectToString, scratchGPR, sourceRegs));
     12503
     12504        cellResult(scratchGPR, node);
     12505        return;
     12506    }
     12507    default:
     12508        DFG_CRASH(m_graph, node, "Bad use kind");
     12509        return;
     12510    }
     12511}
     12512
    1245612513void SpeculativeJIT::compileObjectCreate(Node* node)
    1245712514{
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r239427 r239612  
    14811481    void compileToThis(Node*);
    14821482    void compileObjectKeys(Node*);
     1483    void compileObjectToString(Node*);
    14831484    void compileObjectCreate(Node*);
    14841485    void compileCreateThis(Node*);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r239427 r239612  
    31043104    case StringValueOf: {
    31053105        compileToStringOrCallStringConstructorOrStringValueOf(node);
     3106        break;
     3107    }
     3108
     3109    case ObjectToString: {
     3110        compileObjectToString(node);
    31063111        break;
    31073112    }
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r239427 r239612  
    33463346    case StringValueOf: {
    33473347        compileToStringOrCallStringConstructorOrStringValueOf(node);
     3348        break;
     3349    }
     3350
     3351    case ObjectToString: {
     3352        compileObjectToString(node);
    33483353        break;
    33493354    }
  • trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h

    r239324 r239612  
    121121    macro(Structure_structureID, Structure::structureIDOffset()) \
    122122    macro(StructureRareData_cachedOwnKeys, StructureRareData::offsetOfCachedOwnKeys()) \
     123    macro(StructureRareData_objectToStringValue, StructureRareData::offsetOfObjectToStringValue()) \
    123124    macro(HashMapImpl_capacity, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfCapacity()) \
    124125    macro(HashMapImpl_buffer,  HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfBuffer()) \
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r239324 r239612  
    334334    case StringSlice:
    335335    case ToLowerCase:
     336    case ObjectToString:
    336337    case NumberToStringWithRadix:
    337338    case NumberToStringWithValidRadixConstant:
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r239427 r239612  
    938938            compileStringFromCharCode();
    939939            break;
     940        case ObjectToString:
     941            compileObjectToString();
     942            break;
    940943        case GetByOffset:
    941944        case GetGetterSetterByOffset:
     
    64186421            DFG_CRASH(m_graph, m_node, "Bad use kind");
    64196422            break;
     6423        }
     6424    }
     6425
     6426    void compileObjectToString()
     6427    {
     6428        switch (m_node->child1().useKind()) {
     6429        case OtherUse: {
     6430            speculate(m_node->child1());
     6431            LValue source = lowJSValue(m_node->child1(), ManualOperandSpeculation);
     6432            LValue result = m_out.select(m_out.equal(source, m_out.constInt64(ValueUndefined)),
     6433                weakPointer(vm().smallStrings.undefinedObjectString()), weakPointer(vm().smallStrings.nullObjectString()));
     6434            setJSValue(result);
     6435            return;
     6436        }
     6437        case UntypedUse: {
     6438            LBasicBlock cellCase = m_out.newBlock();
     6439            LBasicBlock objectCase = m_out.newBlock();
     6440            LBasicBlock notNullCase = m_out.newBlock();
     6441            LBasicBlock rareDataCase = m_out.newBlock();
     6442            LBasicBlock slowCase = m_out.newBlock();
     6443            LBasicBlock continuation = m_out.newBlock();
     6444
     6445            LValue source = lowJSValue(m_node->child1());
     6446            m_out.branch(isCell(source, provenType(m_node->child1())), unsure(cellCase), unsure(slowCase));
     6447
     6448            LBasicBlock lastNext = m_out.appendTo(cellCase, objectCase);
     6449            m_out.branch(isObject(source, provenType(m_node->child1()) & SpecCell), unsure(objectCase), unsure(slowCase));
     6450
     6451            m_out.appendTo(objectCase, notNullCase);
     6452            LValue structure = loadStructure(source);
     6453            LValue previousOrRareData = m_out.loadPtr(structure, m_heaps.Structure_previousOrRareData);
     6454            m_out.branch(m_out.notNull(previousOrRareData), unsure(notNullCase), unsure(slowCase));
     6455
     6456            m_out.appendTo(notNullCase, rareDataCase);
     6457            m_out.branch(
     6458                m_out.notEqual(m_out.load32(previousOrRareData, m_heaps.JSCell_structureID), m_out.constInt32(m_graph.m_vm.structureStructure->structureID())),
     6459                unsure(rareDataCase), unsure(slowCase));
     6460
     6461            m_out.appendTo(rareDataCase, slowCase);
     6462            LValue objectToStringValue = m_out.loadPtr(previousOrRareData, m_heaps.StructureRareData_objectToStringValue);
     6463            ValueFromBlock fastResult = m_out.anchor(objectToStringValue);
     6464            m_out.branch(m_out.isNull(objectToStringValue), unsure(slowCase), unsure(continuation));
     6465
     6466            m_out.appendTo(slowCase, continuation);
     6467            LValue slowResultValue = vmCall(pointerType(), m_out.operation(operationObjectToString), m_callFrame, source);
     6468            ValueFromBlock slowResult = m_out.anchor(slowResultValue);
     6469            m_out.jump(continuation);
     6470
     6471            m_out.appendTo(continuation, lastNext);
     6472            setJSValue(m_out.phi(pointerType(), fastResult, slowResult));
     6473            return;
     6474        }
     6475        default:
     6476            DFG_CRASH(m_graph, m_node, "Bad use kind");
     6477            return;
    64206478        }
    64216479    }
  • trunk/Source/JavaScriptCore/runtime/Intrinsic.cpp

    r239324 r239612  
    122122    case ObjectKeysIntrinsic:
    123123        return "ObjectKeysIntrinsic";
     124    case ObjectPrototypeToStringIntrinsic:
     125        return "ObjectPrototypeToStringIntrinsic";
    124126    case ReflectGetPrototypeOfIntrinsic:
    125127        return "ReflectGetPrototypeOfIntrinsic";
  • trunk/Source/JavaScriptCore/runtime/Intrinsic.h

    r239324 r239612  
    7474    ObjectIsIntrinsic,
    7575    ObjectKeysIntrinsic,
     76    ObjectPrototypeToStringIntrinsic,
    7677    ReflectGetPrototypeOfIntrinsic,
    7778    StringPrototypeValueOfIntrinsic,
  • trunk/Source/JavaScriptCore/runtime/ObjectPrototype.cpp

    r239427 r239612  
    2828#include "JSString.h"
    2929#include "JSCInlines.h"
     30#include "ObjectPrototypeInlines.h"
    3031#include "PropertySlot.h"
    3132#include "StructureInlines.h"
     
    4344static EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState*);
    4445static EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState*);
     46static EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*);
    4547
    4648STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ObjectPrototype);
     
    5961    didBecomePrototype();
    6062   
    61     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toString, objectProtoFuncToString, static_cast<unsigned>(PropertyAttribute::DontEnum), 0);
     63    JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toString, objectProtoFuncToString, static_cast<unsigned>(PropertyAttribute::DontEnum), 0, ObjectPrototypeToStringIntrinsic);
    6264    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->toLocaleString, objectProtoFuncToLocaleString, static_cast<unsigned>(PropertyAttribute::DontEnum), 0);
    6365    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->valueOf, objectProtoFuncValueOf, static_cast<unsigned>(PropertyAttribute::DontEnum), 0);
     
    312314EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState* exec)
    313315{
    314     VM& vm = exec->vm();
    315     auto scope = DECLARE_THROW_SCOPE(vm);
    316 
    317316    JSValue thisValue = exec->thisValue().toThis(exec, StrictMode);
    318     if (thisValue.isUndefinedOrNull())
    319         return JSValue::encode(thisValue.isUndefined() ? vm.smallStrings.undefinedObjectString() : vm.smallStrings.nullObjectString());
    320     JSObject* thisObject = thisValue.toObject(exec);
    321     EXCEPTION_ASSERT(!!scope.exception() == !thisObject);
    322     if (!thisObject)
    323         return JSValue::encode(jsUndefined());
    324 
    325     auto result = thisObject->structure(vm)->objectToStringValue();
    326     if (result)
    327         return JSValue::encode(result);
    328 
    329     PropertyName toStringTagSymbol = vm.propertyNames->toStringTagSymbol;
    330     RELEASE_AND_RETURN(scope, JSValue::encode(thisObject->getPropertySlot(exec, toStringTagSymbol, [&] (bool found, PropertySlot& toStringTagSlot) -> JSValue {
    331         if (found) {
    332             JSValue stringTag = toStringTagSlot.getValue(exec, toStringTagSymbol);
    333             RETURN_IF_EXCEPTION(scope, { });
    334             if (stringTag.isString()) {
    335                 JSRopeString::RopeBuilder<RecordOverflow> ropeBuilder(vm);
    336                 ropeBuilder.append(vm.smallStrings.objectStringStart());
    337                 ropeBuilder.append(asString(stringTag));
    338                 ropeBuilder.append(vm.smallStrings.singleCharacterString(']'));
    339                 if (ropeBuilder.hasOverflowed())
    340                     return throwOutOfMemoryError(exec, scope);
    341 
    342                 JSString* result = ropeBuilder.release();
    343                 thisObject->structure(vm)->setObjectToStringValue(exec, vm, result, toStringTagSlot);
    344                 return result;
    345             }
    346         }
    347 
    348         String tag = thisObject->methodTable(vm)->toStringName(thisObject, exec);
    349         RETURN_IF_EXCEPTION(scope, { });
    350         String newString = tryMakeString("[object ", WTFMove(tag), "]");
    351         if (!newString)
    352             return throwOutOfMemoryError(exec, scope);
    353 
    354         auto result = jsNontrivialString(&vm, newString);
    355         thisObject->structure(vm)->setObjectToStringValue(exec, vm, result, toStringTagSlot);
    356         return result;
    357     })));
     317    return JSValue::encode(objectToString(exec, thisValue));
    358318}
    359319
  • trunk/Source/JavaScriptCore/runtime/ObjectPrototype.h

    r229413 r239612  
    4646};
    4747
    48 JS_EXPORT_PRIVATE EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*);
    49 
    5048} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/StructureRareData.h

    r239324 r239612  
    8282    bool hasSharedPolyProtoWatchpoint() const { return static_cast<bool>(m_polyProtoWatchpoint); }
    8383
     84    static ptrdiff_t offsetOfObjectToStringValue()
     85    {
     86        return OBJECT_OFFSETOF(StructureRareData, m_objectToStringValue);
     87    }
     88
    8489    static JSImmutableButterfly* cachedOwnKeysSentinel() { return bitwise_cast<JSImmutableButterfly*>(static_cast<uintptr_t>(1)); }
    8590
Note: See TracChangeset for help on using the changeset viewer.