Changeset 273135 in webkit
- Timestamp:
- Feb 19, 2021 1:42:20 AM (3 years ago)
- Location:
- trunk
- Files:
-
- 3 added
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r273107 r273135 1 2021-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 1 16 2021-02-18 Caio Lima <ticaiolima@gmail.com> 2 17 -
trunk/Source/JavaScriptCore/ChangeLog
r273128 r273135 1 2021-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 1 48 2021-02-18 Chris Dumez <cdumez@apple.com> 2 49 -
trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp
r272766 r273135 423 423 createRareDataIfNecessary(); 424 424 425 setConstantIdentifierSetRegisters(vm, unlinkedCodeBlock->constantIdentifierSets());426 RETURN_IF_EXCEPTION(throwScope, false);427 428 425 if (size_t count = unlinkedCodeBlock->numberOfExceptionHandlers()) { 429 426 m_rareData->m_exceptionHandlers.resizeToFit(count); … … 889 886 } 890 887 #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 }913 888 } 914 889 -
trunk/Source/JavaScriptCore/bytecode/CodeBlock.h
r266359 r273135 954 954 void updateAllValueProfilePredictionsAndCountLiveness(unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles); 955 955 956 void setConstantIdentifierSetRegisters(VM&, const RefCountedArray<ConstantIdentifierSetEntry>& constants);957 958 956 void setConstantRegisters(const RefCountedArray<WriteBarrier<Unknown>>& constants, const RefCountedArray<SourceCodeRepresentation>& constantsSourceCodeRepresentation, ScriptExecutable* topLevelExecutable); 959 957 -
trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
r272580 r273135 75 75 typedef unsigned UnlinkedObjectAllocationProfile; 76 76 typedef unsigned UnlinkedLLIntCallLinkInfo; 77 using ConstantIdentifierSetEntry = std::pair<IdentifierSet, unsigned>;78 77 79 78 struct UnlinkedStringJumpTable { … … 163 162 164 163 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; } 166 165 167 166 // Jumps … … 412 411 RefCountedArray<InstructionStream::Offset> m_opProfileControlFlowBytecodeOffsets; 413 412 RefCountedArray<BitVector> m_bitVectors; 414 RefCountedArray< ConstantIdentifierSetEntry> m_constantIdentifierSets;413 RefCountedArray<IdentifierSet> m_constantIdentifierSets; 415 414 416 415 unsigned m_needsClassFieldInitializer : 1; -
trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlockGenerator.h
r272580 r273135 112 112 113 113 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; 122 121 } 123 122 … … 211 210 Vector<InstructionStream::Offset> m_opProfileControlFlowBytecodeOffsets; 212 211 Vector<BitVector> m_bitVectors; 213 Vector< ConstantIdentifierSetEntry> m_constantIdentifierSets;212 Vector<IdentifierSet> m_constantIdentifierSets; 214 213 }; 215 214 -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
r273107 r273135 1841 1841 } 1842 1842 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; 1843 RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, IdentifierSet&& set) 1844 { 1845 unsigned setIndex = m_codeBlock->addSetConstant(WTFMove(set)); 1846 return emitLoad(dst, jsNumber(setIndex)); 1862 1847 } 1863 1848 -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
r273107 r273135 706 706 RegisterID* emitLoad(RegisterID* dst, const Identifier&); 707 707 RegisterID* emitLoad(RegisterID* dst, JSValue, SourceCodeRepresentation = SourceCodeRepresentation::Other); 708 RegisterID* emitLoad(RegisterID* dst, IdentifierSet& excludedList);708 RegisterID* emitLoad(RegisterID* dst, IdentifierSet&& excludedList); 709 709 710 710 template<typename UnaryOp, typename = std::enable_if_t<UnaryOp::opcodeID != op_negate>> -
trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
r273107 r273135 5509 5509 generator.emitRequireObjectCoercible(rhs, "Right side of assignment cannot be destructured"_s); 5510 5510 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 5523 5511 BytecodeGenerator::PreservedTDZStack preservedTDZStack; 5524 5512 generator.preserveTDZStack(preservedTDZStack); 5525 5513 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 } 5570 5527 } 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()); 5571 5599 } 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()); 5574 5614 } 5575 5576 if (m_containsRestElement) {5577 if (m_containsComputedProperty) {5578 if (target.propertyExpression)5579 propertyName = generator.emitToPropertyKey(generator.tempDestination(propertyName.get()), propertyName.get());5580 else5581 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 } else5588 excludedSet.add(target.propertyName.impl());5589 }5590 5591 if (target.defaultValue)5592 assignDefaultValueIfUndefined(generator, temp.get(), target.defaultValue);5593 if (directBinding)5594 finishDirectBindingAssignment();5595 else5596 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 @copyDataProperties5603 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());5618 5615 } 5619 5616 } … … 5826 5823 RefPtr<RegisterID> copyDataProperties = generator.moveLinkTimeConstant(nullptr, LinkTimeConstant::copyDataProperties); 5827 5824 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()); 5832 5828 5829 // This must be non-tail-call because @copyDataProperties accesses caller-frame. 5833 5830 generator.emitCall(generator.newTemporary(), copyDataProperties.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd(), DebuggableCall::No); 5834 5831 -
trunk/Source/JavaScriptCore/runtime/CachedTypes.cpp
r272580 r273135 963 963 }; 964 964 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) const974 {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 984 965 class CachedCodeBlockRareData : public CachedObject<UnlinkedCodeBlock::RareData> { 985 966 public: … … 1022 1003 CachedVector<InstructionStream::Offset> m_opProfileControlFlowBytecodeOffsets; 1023 1004 CachedVector<CachedBitVector> m_bitVectors; 1024 CachedVector<Cached ConstantIdentifierSetEntry> m_constantIdentifierSets;1005 CachedVector<CachedHashSet<CachedRefPtr<CachedUniquedStringImpl>, IdentifierRepHash>> m_constantIdentifierSets; 1025 1006 unsigned m_needsClassFieldInitializer : 1; 1026 1007 unsigned m_privateBrandRequirement : 1; -
trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
r272428 r273135 28 28 #include "CallFrame.h" 29 29 #include "IndirectEvalExecutable.h" 30 #include "InlineCallFrame.h" 30 31 #include "Interpreter.h" 31 32 #include "IntlDateTimeFormat.h" … … 835 836 }; 836 837 838 static 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 837 847 // https://tc39.es/ecma262/#sec-copydataproperties 838 848 JSC_DEFINE_HOST_FUNCTION(globalFuncCopyDataProperties, (JSGlobalObject* globalObject, CallFrame* callFrame)) … … 841 851 auto scope = DECLARE_THROW_SCOPE(vm); 842 852 843 JSFinalObject* target = jsCast<JSFinalObject*>(callFrame-> uncheckedArgument(0));853 JSFinalObject* target = jsCast<JSFinalObject*>(callFrame->thisValue()); 844 854 ASSERT(target->isStructureExtensible(vm)); 845 855 846 JSValue sourceValue = callFrame->uncheckedArgument( 1);856 JSValue sourceValue = callFrame->uncheckedArgument(0); 847 857 if (sourceValue.isUndefinedOrNull()) 848 return JSValue::encode( jsUndefined());858 return JSValue::encode(target); 849 859 850 860 JSObject* source = sourceValue.toObject(globalObject); 851 861 scope.assertNoException(); 852 862 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 { 858 885 ASSERT(!propertyName.isPrivateName()); 859 886 if (!excludedSet) 860 887 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()); 865 889 }; 866 890 … … 889 913 return true; 890 914 915 if (isPropertyNameExcluded(propertyName)) 916 return true; 917 891 918 properties.append(entry.key); 892 919 values.appendWithCrashOnOverflow(source->getDirect(entry.offset)); … … 899 926 // FIXME: We could put properties in a batching manner to accelerate CopyDataProperties more. 900 927 // 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;905 928 target->putDirect(vm, properties[i].get(), values.at(i)); 906 929 } … … 911 934 912 935 for (const auto& propertyName : propertyNames) { 913 bool excluded = isPropertyNameExcluded(globalObject, propertyName); 914 RETURN_IF_EXCEPTION(scope, { }); 915 if (excluded) 936 if (isPropertyNameExcluded(propertyName)) 916 937 continue; 917 938 … … 936 957 } 937 958 938 return JSValue::encode(jsUndefined()); 959 ensureStillAliveHere(unlinkedCodeBlock); 960 return JSValue::encode(target); 939 961 } 940 962
Note: See TracChangeset
for help on using the changeset viewer.