Changeset 251456 in webkit


Ignore:
Timestamp:
Oct 22, 2019 2:18:29 PM (5 years ago)
Author:
mark.lam@apple.com
Message:

Clients of JSArray::tryCreateUninitializedRestricted() should invoke the mutatorFence().
https://bugs.webkit.org/show_bug.cgi?id=203231
<rdar://problem/56486552>

Reviewed by Saam Barati.

Clients of JSArray::tryCreateUninitializedRestricted() creates a partially
initialized JSArray butterfly, with the contract that it (the client) will take
care of filling in all the missing indexed properties before setting the newly
created array loose in the world. We intentionally do not unconditionally write
barrier the newly created array but, instead, rely on an owner object (or GC root)
that it gets put into to scan it.

That said, we do need to ensure that all the stores are completed before this
array is put in an owner object (or GC root) which makes it scannable by the GC.
This ensures that the GC will not be scanning a partially initialized array
butterfly. To achieve this, we should invoke the mutatorFence after the clients
of JSArray::tryCreateUninitializedRestricted() finish initializing the array.

By design, all clients of tryCreateUninitializedRestricted() must instantiate an
ObjectInitializationScope RAII object. This patch makes use of the
ObjectInitializationScope destructor to invoke the mutatorFence.

Note: we technically only need to invoke the fence if we succeeded in allocating
the array. However, we just invoke the fence unconditionally because we expect
that in the common path, we will succeed in allocating the array. The release
build version of ObjectInitializationScope does not keep record of whether we
succeed in allocating the array anyway. To keep the behavior consistent, the
debug build version of ObjectInitializationScope will also unconditionally
invoke the fence even if we failed to allocate the array.

This patch also does the following:

  1. Replaced the setting of the public length in arrayProtoPrivateFuncConcatMemcpy() with an assertion. The public length was already set by tryCreateUninitializedRestricted() earlier.

Ditto for JSArray::fastSlice().

  1. Removed a redundant instance of ObjectInitializationScope in createEmptyRegExpMatchesArray().
  • runtime/ArrayPrototype.cpp:

(JSC::arrayProtoPrivateFuncConcatMemcpy):

  • runtime/JSArray.cpp:

(JSC::JSArray::fastSlice):

  • runtime/ObjectInitializationScope.cpp:

(JSC::ObjectInitializationScope::~ObjectInitializationScope):

  • runtime/ObjectInitializationScope.h:

(JSC::ObjectInitializationScope::~ObjectInitializationScope):

  • runtime/RegExpMatchesArray.cpp:

(JSC::createEmptyRegExpMatchesArray):

Location:
trunk/Source/JavaScriptCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r251447 r251456  
     12019-10-22  Mark Lam  <mark.lam@apple.com>
     2
     3        Clients of JSArray::tryCreateUninitializedRestricted() should invoke the mutatorFence().
     4        https://bugs.webkit.org/show_bug.cgi?id=203231
     5        <rdar://problem/56486552>
     6
     7        Reviewed by Saam Barati.
     8
     9        Clients of JSArray::tryCreateUninitializedRestricted() creates a partially
     10        initialized JSArray butterfly, with the contract that it (the client) will take
     11        care of filling in all the missing indexed properties before setting the newly
     12        created array loose in the world.  We intentionally do not unconditionally write
     13        barrier the newly created array but, instead, rely on an owner object (or GC root)
     14        that it gets put into to scan it.
     15
     16        That said, we do need to ensure that all the stores are completed before this
     17        array is put in an owner object (or GC root) which makes it scannable by the GC.
     18        This ensures that the GC will not be scanning a partially initialized array
     19        butterfly.  To achieve this, we should invoke the mutatorFence after the clients
     20        of JSArray::tryCreateUninitializedRestricted() finish initializing the array.
     21
     22        By design, all clients of tryCreateUninitializedRestricted() must instantiate an
     23        ObjectInitializationScope RAII object.  This patch makes use of the
     24        ObjectInitializationScope destructor to invoke the mutatorFence.
     25
     26        Note: we technically only need to invoke the fence if we succeeded in allocating
     27        the array.  However, we just invoke the fence unconditionally because we expect
     28        that in the common path, we will succeed in allocating the array.  The release
     29        build version of ObjectInitializationScope does not keep record of whether we
     30        succeed in allocating the array anyway.  To keep the behavior consistent, the
     31        debug build version of ObjectInitializationScope will also unconditionally
     32        invoke the fence even if we failed to allocate the array.
     33
     34        This patch also does the following:
     35
     36        1. Replaced the setting of the public length in arrayProtoPrivateFuncConcatMemcpy()
     37           with an assertion.  The public length was already set by
     38           tryCreateUninitializedRestricted() earlier.
     39
     40           Ditto for JSArray::fastSlice().
     41
     42        2. Removed a redundant instance of ObjectInitializationScope in
     43           createEmptyRegExpMatchesArray().
     44
     45        * runtime/ArrayPrototype.cpp:
     46        (JSC::arrayProtoPrivateFuncConcatMemcpy):
     47        * runtime/JSArray.cpp:
     48        (JSC::JSArray::fastSlice):
     49        * runtime/ObjectInitializationScope.cpp:
     50        (JSC::ObjectInitializationScope::~ObjectInitializationScope):
     51        * runtime/ObjectInitializationScope.h:
     52        (JSC::ObjectInitializationScope::~ObjectInitializationScope):
     53        * runtime/RegExpMatchesArray.cpp:
     54        (JSC::createEmptyRegExpMatchesArray):
     55
    1562019-10-22  Mark Lam  <mark.lam@apple.com>
    257
  • trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp

    r251425 r251456  
    15821582    }
    15831583
    1584     result->butterfly()->setPublicLength(resultSize);
     1584    ASSERT(result->butterfly()->publicLength() == resultSize);
    15851585    return JSValue::encode(result);
    15861586}
  • trunk/Source/JavaScriptCore/runtime/JSArray.cpp

    r251425 r251456  
    793793        else
    794794            memcpy(resultButterfly.contiguous().data(), butterfly()->contiguous().data() + startIndex, sizeof(JSValue) * count);
    795         resultButterfly.setPublicLength(count);
    796 
     795
     796        ASSERT(resultButterfly.publicLength() == count);
    797797        return resultArray;
    798798    }
  • trunk/Source/JavaScriptCore/runtime/ObjectInitializationScope.cpp

    r233722 r251456  
    11/*
    2  * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
     2 * Copyright (C) 2017-2019 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    4343ObjectInitializationScope::~ObjectInitializationScope()
    4444{
     45    m_vm.heap.mutatorFence();
    4546    if (!m_object)
    4647        return;
  • trunk/Source/JavaScriptCore/runtime/ObjectInitializationScope.h

    r233722 r251456  
    11/*
    2  * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
     2 * Copyright (C) 2017-2019 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    4141        : m_vm(vm)
    4242    { }
     43    ALWAYS_INLINE ~ObjectInitializationScope()
     44    {
     45        m_vm.heap.mutatorFence();
     46    }
    4347
    4448    ALWAYS_INLINE VM& vm() const { return m_vm; }
  • trunk/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp

    r249175 r251456  
    5555        }
    5656    } else {
    57         ObjectInitializationScope scope(vm);
    5857        array = tryCreateUninitializedRegExpMatchesArray(scope, &deferralContext, globalObject->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
    5958        RELEASE_ASSERT(array);
Note: See TracChangeset for help on using the changeset viewer.