Changeset 273135 in webkit


Ignore:
Timestamp:
Feb 19, 2021 1:42:20 AM (3 years ago)
Author:
ysuzuki@apple.com
Message:

[JSC] Simplify excludedSet handling in object rest expression
https://bugs.webkit.org/show_bug.cgi?id=221668

Reviewed by Alexey Shvayka.

JSTests:

  • microbenchmarks/object-rest-computed-destructuring.js: Added.
  • stress/object-rest-computed-inlined-numbers.js: Added.

(inner):
(outer):

  • stress/object-rest-computed-inlined.js: Added.

(inner):
(outer):

Source/JavaScriptCore:

This patch simplifies Object rest/spread by avoiding use of JSSet.
Instead, we store IdentifierSet into UnlinkedCodeBlock's vector and
access this directly through JS constant number.
And for additional properties, we collect it during destructuring,
and pass it to @copyDataProperties as an argument so that we do not
need to call Set#add in JS side.

We also check (isNumber()
isString) conditions for properties to

avoid calling ToPropertyKey for constant case. This is OK since we
will call ToPropertyKey inside @copyDataProperties, and this is
side-effect free if the input is number or string.

This patch shows 2x improvement in microbenchmarking.

ToT Patched

object-rest-computed-destructuring 62.9960+-6.5072 30.2157+-1.1420 definitely 2.0849x faster

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::finishCreation):
(JSC::CodeBlock::setConstantIdentifierSetRegisters): Deleted.

  • bytecode/CodeBlock.h:
  • bytecode/UnlinkedCodeBlock.h:

(JSC::UnlinkedCodeBlock::constantIdentifierSets):

  • bytecode/UnlinkedCodeBlockGenerator.h:

(JSC::UnlinkedCodeBlockGenerator::constantIdentifierSets):
(JSC::UnlinkedCodeBlockGenerator::addSetConstant):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitLoad):

  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/NodesCodegen.cpp:

(JSC::ObjectPatternNode::bindValue const):
(JSC::ObjectSpreadExpressionNode::emitBytecode):

  • runtime/CachedTypes.cpp:

(JSC::CachedConstantIdentifierSetEntry::encode): Deleted.
(JSC::CachedConstantIdentifierSetEntry::decode const): Deleted.

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::getCallerCodeBlock):
(JSC::JSC_DEFINE_HOST_FUNCTION):

Location:
trunk
Files:
3 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r273107 r273135  
     12021-02-19  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Simplify excludedSet handling in object rest expression
     4        https://bugs.webkit.org/show_bug.cgi?id=221668
     5
     6        Reviewed by Alexey Shvayka.
     7
     8        * microbenchmarks/object-rest-computed-destructuring.js: Added.
     9        * stress/object-rest-computed-inlined-numbers.js: Added.
     10        (inner):
     11        (outer):
     12        * stress/object-rest-computed-inlined.js: Added.
     13        (inner):
     14        (outer):
     15
    1162021-02-18  Caio Lima  <ticaiolima@gmail.com>
    217
  • trunk/Source/JavaScriptCore/ChangeLog

    r273128 r273135  
     12021-02-19  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Simplify excludedSet handling in object rest expression
     4        https://bugs.webkit.org/show_bug.cgi?id=221668
     5
     6        Reviewed by Alexey Shvayka.
     7
     8        This patch simplifies Object rest/spread by avoiding use of JSSet.
     9        Instead, we store IdentifierSet into UnlinkedCodeBlock's vector and
     10        access this directly through JS constant number.
     11        And for additional properties, we collect it during destructuring,
     12        and pass it to @copyDataProperties as an argument so that we do not
     13        need to call Set#add in JS side.
     14
     15        We also check (isNumber() || isString) conditions for properties to
     16        avoid calling ToPropertyKey for constant case. This is OK since we
     17        will call ToPropertyKey inside @copyDataProperties, and this is
     18        side-effect free if the input is number or string.
     19
     20        This patch shows 2x improvement in microbenchmarking.
     21
     22                                                       ToT                     Patched
     23
     24        object-rest-computed-destructuring       62.9960+-6.5072     ^     30.2157+-1.1420        ^ definitely 2.0849x faster
     25
     26        * bytecode/CodeBlock.cpp:
     27        (JSC::CodeBlock::finishCreation):
     28        (JSC::CodeBlock::setConstantIdentifierSetRegisters): Deleted.
     29        * bytecode/CodeBlock.h:
     30        * bytecode/UnlinkedCodeBlock.h:
     31        (JSC::UnlinkedCodeBlock::constantIdentifierSets):
     32        * bytecode/UnlinkedCodeBlockGenerator.h:
     33        (JSC::UnlinkedCodeBlockGenerator::constantIdentifierSets):
     34        (JSC::UnlinkedCodeBlockGenerator::addSetConstant):
     35        * bytecompiler/BytecodeGenerator.cpp:
     36        (JSC::BytecodeGenerator::emitLoad):
     37        * bytecompiler/BytecodeGenerator.h:
     38        * bytecompiler/NodesCodegen.cpp:
     39        (JSC::ObjectPatternNode::bindValue const):
     40        (JSC::ObjectSpreadExpressionNode::emitBytecode):
     41        * runtime/CachedTypes.cpp:
     42        (JSC::CachedConstantIdentifierSetEntry::encode): Deleted.
     43        (JSC::CachedConstantIdentifierSetEntry::decode const): Deleted.
     44        * runtime/JSGlobalObjectFunctions.cpp:
     45        (JSC::getCallerCodeBlock):
     46        (JSC::JSC_DEFINE_HOST_FUNCTION):
     47
    1482021-02-18  Chris Dumez  <cdumez@apple.com>
    249
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r272766 r273135  
    423423        createRareDataIfNecessary();
    424424
    425         setConstantIdentifierSetRegisters(vm, unlinkedCodeBlock->constantIdentifierSets());
    426         RETURN_IF_EXCEPTION(throwScope, false);
    427 
    428425        if (size_t count = unlinkedCodeBlock->numberOfExceptionHandlers()) {
    429426            m_rareData->m_exceptionHandlers.resizeToFit(count);
     
    889886    }
    890887#endif // ENABLE(JIT)
    891 }
    892 
    893 void CodeBlock::setConstantIdentifierSetRegisters(VM& vm, const RefCountedArray<ConstantIdentifierSetEntry>& constants)
    894 {
    895     auto scope = DECLARE_THROW_SCOPE(vm);
    896     JSGlobalObject* globalObject = m_globalObject.get();
    897 
    898     for (const auto& entry : constants) {
    899         const IdentifierSet& set = entry.first;
    900 
    901         Structure* setStructure = globalObject->setStructure();
    902         RETURN_IF_EXCEPTION(scope, void());
    903         JSSet* jsSet = JSSet::create(globalObject, vm, setStructure, set.size());
    904         RETURN_IF_EXCEPTION(scope, void());
    905 
    906         for (const auto& setEntry : set) {
    907             JSString* jsString = jsOwnedString(vm, setEntry.get());
    908             jsSet->add(globalObject, jsString);
    909             RETURN_IF_EXCEPTION(scope, void());
    910         }
    911         m_constantRegisters[entry.second].set(vm, this, jsSet);
    912     }
    913888}
    914889
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.h

    r266359 r273135  
    954954    void updateAllValueProfilePredictionsAndCountLiveness(unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles);
    955955
    956     void setConstantIdentifierSetRegisters(VM&, const RefCountedArray<ConstantIdentifierSetEntry>& constants);
    957 
    958956    void setConstantRegisters(const RefCountedArray<WriteBarrier<Unknown>>& constants, const RefCountedArray<SourceCodeRepresentation>& constantsSourceCodeRepresentation, ScriptExecutable* topLevelExecutable);
    959957
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h

    r272580 r273135  
    7575typedef unsigned UnlinkedObjectAllocationProfile;
    7676typedef unsigned UnlinkedLLIntCallLinkInfo;
    77 using ConstantIdentifierSetEntry = std::pair<IdentifierSet, unsigned>;
    7877
    7978struct UnlinkedStringJumpTable {
     
    163162
    164163    unsigned numberOfConstantIdentifierSets() const { return m_rareData ? m_rareData->m_constantIdentifierSets.size() : 0; }
    165     const RefCountedArray<ConstantIdentifierSetEntry>& constantIdentifierSets() { ASSERT(m_rareData); return m_rareData->m_constantIdentifierSets; }
     164    const RefCountedArray<IdentifierSet>& constantIdentifierSets() { ASSERT(m_rareData); return m_rareData->m_constantIdentifierSets; }
    166165
    167166    // Jumps
     
    412411        RefCountedArray<InstructionStream::Offset> m_opProfileControlFlowBytecodeOffsets;
    413412        RefCountedArray<BitVector> m_bitVectors;
    414         RefCountedArray<ConstantIdentifierSetEntry> m_constantIdentifierSets;
     413        RefCountedArray<IdentifierSet> m_constantIdentifierSets;
    415414
    416415        unsigned m_needsClassFieldInitializer : 1;
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlockGenerator.h

    r272580 r273135  
    112112
    113113    unsigned numberOfConstantIdentifierSets() const { return m_constantIdentifierSets.size(); }
    114     const Vector<ConstantIdentifierSetEntry>& constantIdentifierSets() { return m_constantIdentifierSets; }
    115     void addSetConstant(IdentifierSet& set)
    116     {
    117         ASSERT(m_vm.heap.isDeferred());
    118         unsigned result = m_constantRegisters.size();
    119         m_constantRegisters.append(WriteBarrier<Unknown>());
    120         m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other);
    121         m_constantIdentifierSets.append(ConstantIdentifierSetEntry(set, result));
     114    const Vector<IdentifierSet>& constantIdentifierSets() { return m_constantIdentifierSets; }
     115    unsigned addSetConstant(IdentifierSet&& set)
     116    {
     117        ASSERT(m_vm.heap.isDeferred());
     118        unsigned result = m_constantIdentifierSets.size();
     119        m_constantIdentifierSets.append(WTFMove(set));
     120        return result;
    122121    }
    123122
     
    211210    Vector<InstructionStream::Offset> m_opProfileControlFlowBytecodeOffsets;
    212211    Vector<BitVector> m_bitVectors;
    213     Vector<ConstantIdentifierSetEntry> m_constantIdentifierSets;
     212    Vector<IdentifierSet> m_constantIdentifierSets;
    214213};
    215214
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r273107 r273135  
    18411841}
    18421842
    1843 RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, IdentifierSet& set)
    1844 {
    1845     if (m_codeBlock->numberOfConstantIdentifierSets()) {
    1846         for (const auto& entry : m_codeBlock->constantIdentifierSets()) {
    1847             if (entry.first != set)
    1848                 continue;
    1849            
    1850             return &m_constantPoolRegisters[entry.second];
    1851         }
    1852     }
    1853    
    1854     unsigned index = addConstantIndex();
    1855     m_codeBlock->addSetConstant(set);
    1856     RegisterID* m_setRegister = &m_constantPoolRegisters[index];
    1857    
    1858     if (dst)
    1859         return move(dst, m_setRegister);
    1860    
    1861     return m_setRegister;
     1843RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, IdentifierSet&& set)
     1844{
     1845    unsigned setIndex = m_codeBlock->addSetConstant(WTFMove(set));
     1846    return emitLoad(dst, jsNumber(setIndex));
    18621847}
    18631848
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r273107 r273135  
    706706        RegisterID* emitLoad(RegisterID* dst, const Identifier&);
    707707        RegisterID* emitLoad(RegisterID* dst, JSValue, SourceCodeRepresentation = SourceCodeRepresentation::Other);
    708         RegisterID* emitLoad(RegisterID* dst, IdentifierSet& excludedList);
     708        RegisterID* emitLoad(RegisterID* dst, IdentifierSet&& excludedList);
    709709
    710710        template<typename UnaryOp, typename = std::enable_if_t<UnaryOp::opcodeID != op_negate>>
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r273107 r273135  
    55095509    generator.emitRequireObjectCoercible(rhs, "Right side of assignment cannot be destructured"_s);
    55105510
    5511     RefPtr<RegisterID> excludedList;
    5512     IdentifierSet excludedSet;
    5513     RefPtr<RegisterID> addMethod;
    5514     if (m_containsRestElement && m_containsComputedProperty) {
    5515         RefPtr<RegisterID> setConstructor = generator.moveLinkTimeConstant(nullptr, LinkTimeConstant::Set);
    5516 
    5517         CallArguments args(generator, nullptr, 0);
    5518         excludedList = generator.emitConstruct(generator.newTemporary(), setConstructor.get(), setConstructor.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd());
    5519 
    5520         addMethod = generator.emitGetById(generator.newTemporary(), excludedList.get(), generator.propertyNames().builtinNames().addPrivateName());
    5521     }
    5522 
    55235511    BytecodeGenerator::PreservedTDZStack preservedTDZStack;
    55245512    generator.preserveTDZStack(preservedTDZStack);
    55255513
    5526     for (size_t i = 0; i < m_targetPatterns.size(); i++) {
    5527         const auto& target = m_targetPatterns[i];
    5528         if (target.bindingType == BindingType::Element) {
    5529             // If the destructuring becomes get_by_id and mov, then we should store results directly to the local's binding.
    5530             // From
    5531             //     get_by_id          dst:loc10, base:loc9, property:0
    5532             //     mov                dst:loc6, src:loc10
    5533             // To
    5534             //     get_by_id          dst:loc6, base:loc9, property:0
    5535             auto writableDirectBindingIfPossible = [&]() -> RegisterID* {
    5536                 // The following pattern is possible. In that case, after setting |data| local variable, we need to store property name into the set.
    5537                 // So, old property name |data| result must be kept before setting it into |data|.
    5538                 //     ({ [data]: data, ...obj } = object);
    5539                 if (m_containsRestElement && m_containsComputedProperty && target.propertyExpression)
    5540                     return nullptr;
    5541                 // default value can include a reference to local variable. So filling value to a local variable can differ result.
    5542                 // We give up fast path if default value includes non constant.
    5543                 // For example,
    5544                 //     ({ data = data } = object);
    5545                 if (target.defaultValue && !target.defaultValue->isConstant())
    5546                     return nullptr;
    5547                 return target.pattern->writableDirectBindingIfPossible(generator);
    5548             };
    5549 
    5550             auto finishDirectBindingAssignment = [&]() {
    5551                 ASSERT(writableDirectBindingIfPossible());
    5552                 target.pattern->finishDirectBindingAssignment(generator);
    5553             };
    5554 
    5555             RefPtr<RegisterID> temp;
    5556             RegisterID* directBinding = writableDirectBindingIfPossible();
    5557             if (directBinding)
    5558                 temp = directBinding;
    5559             else
    5560                 temp = generator.newTemporary();
    5561 
    5562             RefPtr<RegisterID> propertyName;
    5563             if (!target.propertyExpression) {
    5564                 Optional<uint32_t> optionalIndex = parseIndex(target.propertyName);
    5565                 if (!optionalIndex)
    5566                     generator.emitGetById(temp.get(), rhs, target.propertyName);
    5567                 else {
    5568                     RefPtr<RegisterID> propertyIndex = generator.emitLoad(nullptr, jsNumber(optionalIndex.value()));
    5569                     generator.emitGetByVal(temp.get(), rhs, propertyIndex.get());
     5514    {
     5515        RefPtr<RegisterID> newObject;
     5516        IdentifierSet excludedSet;
     5517        Optional<CallArguments> args;
     5518        unsigned numberOfComputedProperties = 0;
     5519        unsigned indexInArguments = 2;
     5520        if (m_containsRestElement) {
     5521            if (m_containsComputedProperty) {
     5522                for (const auto& target : m_targetPatterns) {
     5523                    if (target.bindingType == BindingType::Element) {
     5524                        if (target.propertyExpression)
     5525                            ++numberOfComputedProperties;
     5526                    }
    55705527                }
     5528            }
     5529            newObject = generator.newTemporary();
     5530            args.emplace(generator, nullptr, indexInArguments + numberOfComputedProperties);
     5531        }
     5532
     5533        for (size_t i = 0; i < m_targetPatterns.size(); i++) {
     5534            const auto& target = m_targetPatterns[i];
     5535            if (target.bindingType == BindingType::Element) {
     5536                // If the destructuring becomes get_by_id and mov, then we should store results directly to the local's binding.
     5537                // From
     5538                //     get_by_id          dst:loc10, base:loc9, property:0
     5539                //     mov                dst:loc6, src:loc10
     5540                // To
     5541                //     get_by_id          dst:loc6, base:loc9, property:0
     5542                auto writableDirectBindingIfPossible = [&]() -> RegisterID* {
     5543                    // The following pattern is possible. In that case, after setting |data| local variable, we need to store property name into the set.
     5544                    // So, old property name |data| result must be kept before setting it into |data|.
     5545                    //     ({ [data]: data, ...obj } = object);
     5546                    if (m_containsRestElement && m_containsComputedProperty && target.propertyExpression)
     5547                        return nullptr;
     5548                    // default value can include a reference to local variable. So filling value to a local variable can differ result.
     5549                    // We give up fast path if default value includes non constant.
     5550                    // For example,
     5551                    //     ({ data = data } = object);
     5552                    if (target.defaultValue && !target.defaultValue->isConstant())
     5553                        return nullptr;
     5554                    return target.pattern->writableDirectBindingIfPossible(generator);
     5555                };
     5556
     5557                auto finishDirectBindingAssignment = [&]() {
     5558                    ASSERT(writableDirectBindingIfPossible());
     5559                    target.pattern->finishDirectBindingAssignment(generator);
     5560                };
     5561
     5562                RefPtr<RegisterID> temp;
     5563                RegisterID* directBinding = writableDirectBindingIfPossible();
     5564                if (directBinding)
     5565                    temp = directBinding;
     5566                else
     5567                    temp = generator.newTemporary();
     5568
     5569                if (!target.propertyExpression) {
     5570                    Optional<uint32_t> optionalIndex = parseIndex(target.propertyName);
     5571                    if (!optionalIndex)
     5572                        generator.emitGetById(temp.get(), rhs, target.propertyName);
     5573                    else {
     5574                        RefPtr<RegisterID> propertyIndex = generator.emitLoad(nullptr, jsNumber(optionalIndex.value()));
     5575                        generator.emitGetByVal(temp.get(), rhs, propertyIndex.get());
     5576                    }
     5577                    if (m_containsRestElement)
     5578                        excludedSet.add(target.propertyName.impl());
     5579                } else {
     5580                    RefPtr<RegisterID> propertyName;
     5581                    if (m_containsRestElement) {
     5582                        propertyName = generator.emitNodeForProperty(args->argumentRegister(indexInArguments++), target.propertyExpression);
     5583                        // ToPropertyKey(Number | String) does not have side-effect.
     5584                        // And @copyDataProperties performs ToPropertyKey internally.
     5585                        // And for Number case, passing it to GetByVal is better for performance.
     5586                        if (!target.propertyExpression->isNumber() || !target.propertyExpression->isString())
     5587                            propertyName = generator.emitToPropertyKey(propertyName.get(), propertyName.get());
     5588                    } else
     5589                        propertyName = generator.emitNodeForProperty(target.propertyExpression);
     5590                    generator.emitGetByVal(temp.get(), rhs, propertyName.get());
     5591                }
     5592
     5593                if (target.defaultValue)
     5594                    assignDefaultValueIfUndefined(generator, temp.get(), target.defaultValue);
     5595                if (directBinding)
     5596                    finishDirectBindingAssignment();
     5597                else
     5598                    target.pattern->bindValue(generator, temp.get());
    55715599            } else {
    5572                 propertyName = generator.emitNodeForProperty(target.propertyExpression);
    5573                 generator.emitGetByVal(temp.get(), rhs, propertyName.get());
     5600                ASSERT(target.bindingType == BindingType::RestElement);
     5601                ASSERT(i == m_targetPatterns.size() - 1);
     5602
     5603                generator.emitNewObject(newObject.get());
     5604
     5605                // load and call @copyDataProperties
     5606                RefPtr<RegisterID> copyDataProperties = generator.moveLinkTimeConstant(nullptr, LinkTimeConstant::copyDataProperties);
     5607
     5608                // This must be non-tail-call because @copyDataProperties accesses caller-frame.
     5609                generator.move(args->thisRegister(), newObject.get());
     5610                generator.move(args->argumentRegister(0), rhs);
     5611                generator.emitLoad(args->argumentRegister(1), WTFMove(excludedSet));
     5612                generator.emitCall(generator.newTemporary(), copyDataProperties.get(), NoExpectedFunction, args.value(), divot(), divotStart(), divotEnd(), DebuggableCall::No);
     5613                target.pattern->bindValue(generator, newObject.get());
    55745614            }
    5575 
    5576             if (m_containsRestElement) {
    5577                 if (m_containsComputedProperty) {
    5578                     if (target.propertyExpression)
    5579                         propertyName = generator.emitToPropertyKey(generator.tempDestination(propertyName.get()), propertyName.get());
    5580                     else
    5581                         propertyName = generator.emitLoad(nullptr, target.propertyName);
    5582 
    5583                     CallArguments args(generator, nullptr, 1);
    5584                     generator.move(args.thisRegister(), excludedList.get());
    5585                     generator.move(args.argumentRegister(0), propertyName.get());
    5586                     generator.emitCall(generator.newTemporary(), addMethod.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd(), DebuggableCall::No);
    5587                 } else
    5588                     excludedSet.add(target.propertyName.impl());
    5589             }
    5590 
    5591             if (target.defaultValue)
    5592                 assignDefaultValueIfUndefined(generator, temp.get(), target.defaultValue);
    5593             if (directBinding)
    5594                 finishDirectBindingAssignment();
    5595             else
    5596                 target.pattern->bindValue(generator, temp.get());
    5597         } else {
    5598             ASSERT(target.bindingType == BindingType::RestElement);
    5599             ASSERT(i == m_targetPatterns.size() - 1);
    5600             RefPtr<RegisterID> newObject = generator.emitNewObject(generator.newTemporary());
    5601            
    5602             // load and call @copyDataProperties
    5603             RefPtr<RegisterID> copyDataProperties = generator.moveLinkTimeConstant(nullptr, LinkTimeConstant::copyDataProperties);
    5604            
    5605             CallArguments args(generator, nullptr, 3);
    5606             generator.emitLoad(args.thisRegister(), jsUndefined());
    5607             generator.move(args.argumentRegister(0), newObject.get());
    5608             generator.move(args.argumentRegister(1), rhs);
    5609             if (m_containsComputedProperty)
    5610                 generator.move(args.argumentRegister(2), excludedList.get());
    5611             else {
    5612                 RefPtr<RegisterID> excludedSetReg = generator.emitLoad(generator.newTemporary(), excludedSet);
    5613                 generator.move(args.argumentRegister(2), excludedSetReg.get());
    5614             }
    5615 
    5616             generator.emitCall(generator.newTemporary(), copyDataProperties.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd(), DebuggableCall::No);
    5617             target.pattern->bindValue(generator, newObject.get());
    56185615        }
    56195616    }
     
    58265823    RefPtr<RegisterID> copyDataProperties = generator.moveLinkTimeConstant(nullptr, LinkTimeConstant::copyDataProperties);
    58275824   
    5828     CallArguments args(generator, nullptr, 2);
    5829     generator.emitLoad(args.thisRegister(), jsUndefined());
    5830     generator.move(args.argumentRegister(0), dst);
    5831     generator.move(args.argumentRegister(1), src.get());
     5825    CallArguments args(generator, nullptr, 1);
     5826    generator.move(args.thisRegister(), dst);
     5827    generator.move(args.argumentRegister(0), src.get());
    58325828   
     5829    // This must be non-tail-call because @copyDataProperties accesses caller-frame.
    58335830    generator.emitCall(generator.newTemporary(), copyDataProperties.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd(), DebuggableCall::No);
    58345831   
  • trunk/Source/JavaScriptCore/runtime/CachedTypes.cpp

    r272580 r273135  
    963963};
    964964
    965 class CachedConstantIdentifierSetEntry : public VariableLengthObject<ConstantIdentifierSetEntry> {
    966 public:
    967     void encode(Encoder& encoder, const ConstantIdentifierSetEntry& entry)
    968     {
    969         m_constant = entry.second;
    970         m_set.encode(encoder, entry.first);
    971     }
    972 
    973     void decode(Decoder& decoder, ConstantIdentifierSetEntry& entry) const
    974     {
    975         entry.second = m_constant;
    976         m_set.decode(decoder, entry.first);
    977     }
    978 
    979 private:
    980     unsigned m_constant;
    981     CachedHashSet<CachedRefPtr<CachedUniquedStringImpl>, IdentifierRepHash> m_set;
    982 };
    983 
    984965class CachedCodeBlockRareData : public CachedObject<UnlinkedCodeBlock::RareData> {
    985966public:
     
    10221003    CachedVector<InstructionStream::Offset> m_opProfileControlFlowBytecodeOffsets;
    10231004    CachedVector<CachedBitVector> m_bitVectors;
    1024     CachedVector<CachedConstantIdentifierSetEntry> m_constantIdentifierSets;
     1005    CachedVector<CachedHashSet<CachedRefPtr<CachedUniquedStringImpl>, IdentifierRepHash>> m_constantIdentifierSets;
    10251006    unsigned m_needsClassFieldInitializer : 1;
    10261007    unsigned m_privateBrandRequirement : 1;
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

    r272428 r273135  
    2828#include "CallFrame.h"
    2929#include "IndirectEvalExecutable.h"
     30#include "InlineCallFrame.h"
    3031#include "Interpreter.h"
    3132#include "IntlDateTimeFormat.h"
     
    835836};
    836837
     838static CodeBlock* getCallerCodeBlock(CallFrame* callFrame)
     839{
     840    CallFrame* callerFrame = callFrame->callerFrame();
     841    CodeOrigin codeOrigin = callerFrame->codeOrigin();
     842    if (codeOrigin && codeOrigin.inlineCallFrame())
     843        return baselineCodeBlockForInlineCallFrame(codeOrigin.inlineCallFrame());
     844    return callerFrame->codeBlock();
     845}
     846
    837847// https://tc39.es/ecma262/#sec-copydataproperties
    838848JSC_DEFINE_HOST_FUNCTION(globalFuncCopyDataProperties, (JSGlobalObject* globalObject, CallFrame* callFrame))
     
    841851    auto scope = DECLARE_THROW_SCOPE(vm);
    842852
    843     JSFinalObject* target = jsCast<JSFinalObject*>(callFrame->uncheckedArgument(0));
     853    JSFinalObject* target = jsCast<JSFinalObject*>(callFrame->thisValue());
    844854    ASSERT(target->isStructureExtensible(vm));
    845855
    846     JSValue sourceValue = callFrame->uncheckedArgument(1);
     856    JSValue sourceValue = callFrame->uncheckedArgument(0);
    847857    if (sourceValue.isUndefinedOrNull())
    848         return JSValue::encode(jsUndefined());
     858        return JSValue::encode(target);
    849859
    850860    JSObject* source = sourceValue.toObject(globalObject);
    851861    scope.assertNoException();
    852862
    853     JSSet* excludedSet = nullptr;
    854     if (callFrame->argumentCount() > 2)
    855         excludedSet = jsCast<JSSet*>(callFrame->uncheckedArgument(2));
    856 
    857     auto isPropertyNameExcluded = [&] (JSGlobalObject* globalObject, PropertyName propertyName) -> bool {
     863    UnlinkedCodeBlock* unlinkedCodeBlock = nullptr;
     864    const IdentifierSet* excludedSet = nullptr;
     865    Optional<IdentifierSet> newlyCreatedSet;
     866    if (callFrame->argumentCount() > 1) {
     867        int32_t setIndex = callFrame->uncheckedArgument(1).asUInt32AsAnyInt();
     868        CodeBlock* codeBlock = getCallerCodeBlock(callFrame);
     869        ASSERT(codeBlock);
     870        unlinkedCodeBlock = codeBlock->unlinkedCodeBlock();
     871        excludedSet = &unlinkedCodeBlock->constantIdentifierSets()[setIndex];
     872        if (callFrame->argumentCount() > 2) {
     873            newlyCreatedSet.emplace(*excludedSet);
     874            for (unsigned index = 2; index < callFrame->argumentCount(); ++index) {
     875                // This isn't observable since ObjectPatternNode::bindValue() also performs ToPropertyKey.
     876                auto propertyName = callFrame->uncheckedArgument(index).toPropertyKey(globalObject);
     877                RETURN_IF_EXCEPTION(scope, { });
     878                newlyCreatedSet->add(propertyName.impl());
     879            }
     880            excludedSet = &newlyCreatedSet.value();
     881        }
     882    }
     883
     884    auto isPropertyNameExcluded = [&] (PropertyName propertyName) -> bool {
    858885        ASSERT(!propertyName.isPrivateName());
    859886        if (!excludedSet)
    860887            return false;
    861 
    862         JSValue propertyNameValue = identifierToJSValue(vm, Identifier::fromUid(vm, propertyName.uid()));
    863         RETURN_IF_EXCEPTION(scope, false);
    864         return excludedSet->has(globalObject, propertyNameValue);
     888        return excludedSet->contains(propertyName.uid());
    865889    };
    866890
     
    889913                return true;
    890914
     915            if (isPropertyNameExcluded(propertyName))
     916                return true;
     917
    891918            properties.append(entry.key);
    892919            values.appendWithCrashOnOverflow(source->getDirect(entry.offset));
     
    899926            // FIXME: We could put properties in a batching manner to accelerate CopyDataProperties more.
    900927            // https://bugs.webkit.org/show_bug.cgi?id=185358
    901             bool excluded = isPropertyNameExcluded(globalObject, properties[i].get());
    902             RETURN_IF_EXCEPTION(scope, { });
    903             if (excluded)
    904                 continue;
    905928            target->putDirect(vm, properties[i].get(), values.at(i));
    906929        }
     
    911934
    912935        for (const auto& propertyName : propertyNames) {
    913             bool excluded = isPropertyNameExcluded(globalObject, propertyName);
    914             RETURN_IF_EXCEPTION(scope, { });
    915             if (excluded)
     936            if (isPropertyNameExcluded(propertyName))
    916937                continue;
    917938
     
    936957    }
    937958
    938     return JSValue::encode(jsUndefined());
     959    ensureStillAliveHere(unlinkedCodeBlock);
     960    return JSValue::encode(target);
    939961}
    940962
Note: See TracChangeset for help on using the changeset viewer.