Ignore:
Timestamp:
Dec 24, 2016, 1:26:22 PM (9 years ago)
Author:
[email protected]
Message:

[test262] Fixing mapped arguments object property test case
https://bugs.webkit.org/show_bug.cgi?id=159398

Patch by Caio Lima <Caio Lima> on 2016-12-24
Reviewed by Saam Barati.

JSTests:

  • stress/arguments-bizarre-behaviour-disable-enumerability.js:
  • stress/arguments-define-property.js: Added.

(assert):
(testProperties):

  • stress/arguments-non-configurable.js: Added.

(assert):
(tryChangeNonConfigurableDescriptor):
(set tryChangeNonConfigurableDescriptor):
(tryChangeWritableOfNonConfigurableDescriptor):

  • test262.yaml:

Source/JavaScriptCore:

This patch changes GenericArguments' override mechanism to
implement corret behavior on ECMAScript test262 suite test cases of
mapped arguments object with non-configurable and non-writable
property. Also it is ensuring that arguments[i]
cannot be deleted when argument "i" is {configurable: false}.

The previous implementation is against to the specification for 2 reasons:

  1. Every argument in arguments object are {writable: true} by default (http://www.ecma-international.org/ecma-262/7.0/index.html#sec-createunmappedargumentsobject). It means that we have to stop mapping a defined property index if the new property descriptor contains writable (i.e writable is present) and its value is false (also check https://tc39.github.io/ecma262/#sec-arguments-exotic-objects-defineownproperty-p-desc). Previous implementation considers {writable: false} if writable is not present.
  1. When a property is overriden, "delete" operation is always returning true. However delete operations should follow the specification.

We created an auxilary boolean array named m_modifiedArgumentsDescriptor
to store which arguments[i] descriptor was changed from its default
property descriptor. This modification was necessary because m_overrides
was responsible to keep this information at the same time
of keeping information about arguments mapping. The problem of this apporach was
that we needed to call overridesArgument(i) as soon as the ith argument's property
descriptor was changed and it stops the argument's mapping as sideffect, producing
wrong behavior.
To keep tracking arguments mapping status, we renamed DirectArguments::m_overrides to
DirectArguments::m_mappedArguments and now we it is responsible to manage if an
argument[i] is mapped or not.
With these 2 structures, now it is possible to an argument[i] have its property
descriptor modified and don't stop the mapping as soon as it happens. One example
of that wrong behavior can be found on arguments-bizarre-behaviour-disable-enumerability
test case, that now is fixed by this new mechanism.

  • bytecode/PolymorphicAccess.cpp:

(JSC::AccessCase::generateWithGuard):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileGetByValOnDirectArguments):
(JSC::DFG::SpeculativeJIT::compileGetArrayLength):
(JSC::DFG::SpeculativeJIT::compileCreateDirectArguments):

  • ftl/FTLAbstractHeapRepository.h:
  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileGetArrayLength):
(JSC::FTL::DFG::LowerDFGToB3::compileGetByVal):
(JSC::FTL::DFG::LowerDFGToB3::compileCreateDirectArguments):

  • jit/JITOperations.cpp:

(JSC::canAccessArgumentIndexQuickly):

  • jit/JITPropertyAccess.cpp:

(JSC::JIT::emitDirectArgumentsGetByVal):

  • runtime/DirectArguments.cpp:

(JSC::DirectArguments::estimatedSize):
(JSC::DirectArguments::visitChildren):
(JSC::DirectArguments::overrideThings):
(JSC::DirectArguments::overrideThingsIfNecessary):
(JSC::DirectArguments::unmapArgument):
(JSC::DirectArguments::copyToArguments):
(JSC::DirectArguments::overridesSize):
(JSC::DirectArguments::overrideArgument): Deleted.

  • runtime/DirectArguments.h:

(JSC::DirectArguments::length):
(JSC::DirectArguments::isMappedArgument):
(JSC::DirectArguments::isMappedArgumentInDFG):
(JSC::DirectArguments::getIndexQuickly):
(JSC::DirectArguments::setIndexQuickly):
(JSC::DirectArguments::overrodeThings):
(JSC::DirectArguments::initModifiedArgumentsDescriptorIfNecessary):
(JSC::DirectArguments::setModifiedArgumentDescriptor):
(JSC::DirectArguments::isModifiedArgumentDescriptor):
(JSC::DirectArguments::offsetOfMappedArguments):
(JSC::DirectArguments::offsetOfModifiedArgumentsDescriptor):
(JSC::DirectArguments::canAccessIndexQuickly): Deleted.
(JSC::DirectArguments::canAccessArgumentIndexQuicklyInDFG): Deleted.
(JSC::DirectArguments::offsetOfOverrides): Deleted.

  • runtime/GenericArguments.h:
  • runtime/GenericArgumentsInlines.h:

(JSC::GenericArguments<Type>::visitChildren):
(JSC::GenericArguments<Type>::getOwnPropertySlot):
(JSC::GenericArguments<Type>::getOwnPropertySlotByIndex):
(JSC::GenericArguments<Type>::getOwnPropertyNames):
(JSC::GenericArguments<Type>::put):
(JSC::GenericArguments<Type>::putByIndex):
(JSC::GenericArguments<Type>::deleteProperty):
(JSC::GenericArguments<Type>::deletePropertyByIndex):
(JSC::GenericArguments<Type>::defineOwnProperty):
(JSC::GenericArguments<Type>::initModifiedArgumentsDescriptor):
(JSC::GenericArguments<Type>::initModifiedArgumentsDescriptorIfNecessary):
(JSC::GenericArguments<Type>::setModifiedArgumentDescriptor):
(JSC::GenericArguments<Type>::isModifiedArgumentDescriptor):
(JSC::GenericArguments<Type>::copyToArguments):

  • runtime/ScopedArguments.cpp:

(JSC::ScopedArguments::visitChildren):
(JSC::ScopedArguments::unmapArgument):
(JSC::ScopedArguments::overrideArgument): Deleted.

  • runtime/ScopedArguments.h:

(JSC::ScopedArguments::isMappedArgument):
(JSC::ScopedArguments::isMappedArgumentInDFG):
(JSC::ScopedArguments::getIndexQuickly):
(JSC::ScopedArguments::setIndexQuickly):
(JSC::ScopedArguments::initModifiedArgumentsDescriptorIfNecessary):
(JSC::ScopedArguments::setModifiedArgumentDescriptor):
(JSC::ScopedArguments::isModifiedArgumentDescriptor):
(JSC::ScopedArguments::canAccessIndexQuickly): Deleted.
(JSC::ScopedArguments::canAccessArgumentIndexQuicklyInDFG): Deleted.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/DirectArguments.cpp

    r209897 r210146  
    8787{
    8888    DirectArguments* thisObject = jsCast<DirectArguments*>(cell);
    89     size_t overridesSize = thisObject->m_overrides ? thisObject->overridesSize() : 0;
    90     return Base::estimatedSize(cell) + overridesSize;
     89    size_t mappedArgumentsSize = thisObject->m_mappedArguments ? thisObject->mappedArgumentsSize() * sizeof(bool) : 0;
     90    size_t modifiedArgumentsSize = thisObject->m_modifiedArgumentsDescriptor ? thisObject->m_length * sizeof(bool) : 0;
     91    return Base::estimatedSize(cell) + mappedArgumentsSize + modifiedArgumentsSize;
    9192}
    9293
     
    9697    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    9798    Base::visitChildren(thisObject, visitor);
    98    
     99
    99100    visitor.appendValues(thisObject->storage(), std::max(thisObject->m_length, thisObject->m_minCapacity));
    100101    visitor.append(thisObject->m_callee);
    101102
    102     if (bool* override = thisObject->m_overrides.get())
    103         visitor.markAuxiliary(override);
     103    if (thisObject->m_mappedArguments)
     104        visitor.markAuxiliary(thisObject->m_mappedArguments.get());
     105    GenericArguments<DirectArguments>::visitChildren(thisCell, visitor);
    104106}
    105107
     
    111113void DirectArguments::overrideThings(VM& vm)
    112114{
    113     RELEASE_ASSERT(!m_overrides);
     115    RELEASE_ASSERT(!m_mappedArguments);
    114116   
    115117    putDirect(vm, vm.propertyNames->length, jsNumber(m_length), DontEnum);
     
    117119    putDirect(vm, vm.propertyNames->iteratorSymbol, globalObject()->arrayProtoValuesFunction(), DontEnum);
    118120   
    119     void* backingStore = vm.heap.tryAllocateAuxiliary(this, overridesSize());
     121    void* backingStore = vm.heap.tryAllocateAuxiliary(this, mappedArgumentsSize());
    120122    RELEASE_ASSERT(backingStore);
    121123    bool* overrides = static_cast<bool*>(backingStore);
    122     m_overrides.set(vm, this, overrides);
     124    m_mappedArguments.set(vm, this, overrides);
    123125    for (unsigned i = m_length; i--;)
    124126        overrides[i] = false;
     
    127129void DirectArguments::overrideThingsIfNecessary(VM& vm)
    128130{
    129     if (!m_overrides)
     131    if (!m_mappedArguments)
    130132        overrideThings(vm);
    131133}
    132134
    133 void DirectArguments::overrideArgument(VM& vm, unsigned index)
     135void DirectArguments::unmapArgument(VM& vm, unsigned index)
    134136{
    135137    overrideThingsIfNecessary(vm);
    136     m_overrides.get()[index] = true;
     138    m_mappedArguments.get()[index] = true;
    137139}
    138140
    139141void DirectArguments::copyToArguments(ExecState* exec, VirtualRegister firstElementDest, unsigned offset, unsigned length)
    140142{
    141     if (!m_overrides) {
     143    if (!m_mappedArguments) {
    142144        unsigned limit = std::min(length + offset, m_length);
    143145        unsigned i;
     
    153155}
    154156
    155 unsigned DirectArguments::overridesSize()
     157unsigned DirectArguments::mappedArgumentsSize()
    156158{
    157159    // We always allocate something; in the relatively uncommon case of overriding an empty argument we
    158     // still allocate so that m_overrides is non-null. We use that to indicate that the other properties
     160    // still allocate so that m_mappedArguments is non-null. We use that to indicate that the other properties
    159161    // (length, etc) are overridden.
    160162    return WTF::roundUpToMultipleOf<8>(m_length ? m_length : 1);
Note: See TracChangeset for help on using the changeset viewer.