Changeset 269574 in webkit


Ignore:
Timestamp:
Nov 8, 2020 9:02:22 PM (21 months ago)
Author:
ysuzuki@apple.com
Message:

[JSC] Support @@species in ArrayBuffer / SharedArrayBuffer slice
https://bugs.webkit.org/show_bug.cgi?id=218697

Reviewed by Ross Kirsling.

JSTests:

  • test262/expectations.yaml:

Source/JavaScriptCore:

This patch adds support for @@species in ArrayBuffer/SharedArrayBuffer.prototype.slice.
We leverage the mechanism similar to Array's @@species handling: adding fast path with watchpoint.
When we found that some of critical properties (e.g. %Prototype%.constructor, %Constructor%[@@species])
are modified, watchpoint is fired and we go to the slow path. Until that, we use fast path that is
basically the same to the code before this patch.

  • runtime/ArrayBuffer.cpp:

(JSC::ArrayBuffer::slice const):
(JSC::ArrayBuffer::sliceWithClampedIndex const):
(JSC::ArrayBuffer::sliceImpl const): Deleted.

  • runtime/ArrayBuffer.h:
  • runtime/ArrayBufferSharingMode.h:
  • runtime/ArrayPrototype.cpp:

(JSC::speciesWatchpointIsValid):

  • runtime/JSArrayBufferPrototype.cpp:

(JSC::speciesWatchpointIsValid):
(JSC::arrayBufferSlice):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::JSGlobalObject):
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
(JSC::JSGlobalObject::tryInstallSpeciesWatchpoint):
(JSC::JSGlobalObject::tryInstallArraySpeciesWatchpoint):
(JSC::JSGlobalObject::tryInstallArrayBufferSpeciesWatchpoint):

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::arrayBufferSpeciesWatchpointSet):
(JSC::JSGlobalObject::arrayBufferPrototype const):
(JSC::JSGlobalObject::arrayBufferStructure const):
(JSC::JSGlobalObject::arrayBufferConstructor const):

Source/WTF:

Remove ENABLE(SHARED_ARRAY_BUFFER) flag. We use Options::useSharedArrayBuffer() runtime flag instead.

  • wtf/PlatformEnable.h:
Location:
trunk
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r269552 r269574  
     12020-11-08  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Support @@species in ArrayBuffer / SharedArrayBuffer slice
     4        https://bugs.webkit.org/show_bug.cgi?id=218697
     5
     6        Reviewed by Ross Kirsling.
     7
     8        * test262/expectations.yaml:
     9
    1102020-11-06  Dmitry Bezhetskov  <dbezhetskov@igalia.com>
    211
  • trunk/JSTests/test262/expectations.yaml

    r269531 r269574  
    604604test/annexB/language/global-code/switch-dflt-global-skip-early-err.js:
    605605  default: "SyntaxError: Cannot declare a function that shadows a let/const/class/function variable 'f' in strict mode."
    606 test/built-ins/ArrayBuffer/prototype/slice/species-constructor-is-not-object.js:
    607   default: 'Test262Error: `constructor` value is null Expected a TypeError to be thrown but no exception was thrown at all'
    608   strict mode: 'Test262Error: `constructor` value is null Expected a TypeError to be thrown but no exception was thrown at all'
    609 test/built-ins/ArrayBuffer/prototype/slice/species-is-not-constructor.js:
    610   default: 'Test262Error: `constructor[Symbol.species]` value is Object Expected a TypeError to be thrown but no exception was thrown at all'
    611   strict mode: 'Test262Error: `constructor[Symbol.species]` value is Object Expected a TypeError to be thrown but no exception was thrown at all'
    612 test/built-ins/ArrayBuffer/prototype/slice/species-is-not-object.js:
    613   default: 'Test262Error: `constructor[Symbol.species]` value is Boolean Expected a TypeError to be thrown but no exception was thrown at all'
    614   strict mode: 'Test262Error: `constructor[Symbol.species]` value is Boolean Expected a TypeError to be thrown but no exception was thrown at all'
    615 test/built-ins/ArrayBuffer/prototype/slice/species-returns-larger-arraybuffer.js:
    616   default: 'Test262Error: Expected SameValue(«8», «10») to be true'
    617   strict mode: 'Test262Error: Expected SameValue(«8», «10») to be true'
    618 test/built-ins/ArrayBuffer/prototype/slice/species-returns-not-arraybuffer.js:
    619   default: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
    620   strict mode: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
    621 test/built-ins/ArrayBuffer/prototype/slice/species-returns-same-arraybuffer.js:
    622   default: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
    623   strict mode: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
    624 test/built-ins/ArrayBuffer/prototype/slice/species-returns-smaller-arraybuffer.js:
    625   default: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
    626   strict mode: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
    627 test/built-ins/ArrayBuffer/prototype/slice/species.js:
    628   default: 'Test262Error: Expected SameValue(«[object ArrayBuffer]», «undefined») to be true'
    629   strict mode: 'Test262Error: Expected SameValue(«[object ArrayBuffer]», «undefined») to be true'
    630606test/built-ins/Date/UTC/fp-evaluation-order.js:
    631607  default: 'Test262Error: order of operations / precision in MakeTime Expected SameValue(«NaN», «29312») to be true'
     
    848824  default: 'SyntaxError: Invalid regular expression: number too large in {} quantifier'
    849825  strict mode: 'SyntaxError: Invalid regular expression: number too large in {} quantifier'
    850 test/built-ins/SharedArrayBuffer/prototype/slice/species-constructor-is-not-object.js:
    851   default: 'Test262Error: `constructor` value is null Expected a TypeError to be thrown but no exception was thrown at all'
    852   strict mode: 'Test262Error: `constructor` value is null Expected a TypeError to be thrown but no exception was thrown at all'
    853 test/built-ins/SharedArrayBuffer/prototype/slice/species-is-not-constructor.js:
    854   default: 'Test262Error: `constructor[Symbol.species]` value is Object Expected a TypeError to be thrown but no exception was thrown at all'
    855   strict mode: 'Test262Error: `constructor[Symbol.species]` value is Object Expected a TypeError to be thrown but no exception was thrown at all'
    856 test/built-ins/SharedArrayBuffer/prototype/slice/species-is-not-object.js:
    857   default: 'Test262Error: `constructor[Symbol.species]` value is Boolean Expected a TypeError to be thrown but no exception was thrown at all'
    858   strict mode: 'Test262Error: `constructor[Symbol.species]` value is Boolean Expected a TypeError to be thrown but no exception was thrown at all'
    859 test/built-ins/SharedArrayBuffer/prototype/slice/species-returns-larger-arraybuffer.js:
    860   default: 'Test262Error: Expected SameValue(«8», «10») to be true'
    861   strict mode: 'Test262Error: Expected SameValue(«8», «10») to be true'
    862 test/built-ins/SharedArrayBuffer/prototype/slice/species-returns-not-arraybuffer.js:
    863   default: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
    864   strict mode: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
    865 test/built-ins/SharedArrayBuffer/prototype/slice/species-returns-same-arraybuffer.js:
    866   default: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
    867   strict mode: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
    868 test/built-ins/SharedArrayBuffer/prototype/slice/species-returns-smaller-arraybuffer.js:
    869   default: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
    870   strict mode: 'Test262Error: Expected a TypeError to be thrown but no exception was thrown at all'
    871 test/built-ins/SharedArrayBuffer/prototype/slice/species.js:
    872   default: 'Test262Error: Expected SameValue(«[object SharedArrayBuffer]», «undefined») to be true'
    873   strict mode: 'Test262Error: Expected SameValue(«[object SharedArrayBuffer]», «undefined») to be true'
    874826test/built-ins/TypedArray/prototype/every/callbackfn-detachbuffer.js:
    875827  default: 'Test262Error: Expected a TypeError but got a Test262Error (Testing with Float64Array.)'
     
    27462698test/language/statements/class/method/forbidden-ext/b2/cls-decl-meth-forbidden-ext-indirect-access-prop-caller.js:
    27472699  default: 'TypeError: Function.caller used to retrieve strict caller'
    2748 test/language/statements/class/subclass/builtin-objects/ArrayBuffer/regular-subclassing.js:
    2749   default: 'Test262Error: Expected true but got false'
    2750   strict mode: 'Test262Error: Expected true but got false'
    27512700test/language/statements/const/dstr/ary-init-iter-get-err-array-prototype.js:
    27522701  default: 'TypeError: Spread syntax requires ...iterable[Symbol.iterator] to be a function'
  • trunk/Source/JavaScriptCore/ChangeLog

    r269552 r269574  
     12020-11-08  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Support @@species in ArrayBuffer / SharedArrayBuffer slice
     4        https://bugs.webkit.org/show_bug.cgi?id=218697
     5
     6        Reviewed by Ross Kirsling.
     7
     8        This patch adds support for @@species in ArrayBuffer/SharedArrayBuffer.prototype.slice.
     9        We leverage the mechanism similar to Array's @@species handling: adding fast path with watchpoint.
     10        When we found that some of critical properties (e.g. %Prototype%.constructor, %Constructor%[@@species])
     11        are modified, watchpoint is fired and we go to the slow path. Until that, we use fast path that is
     12        basically the same to the code before this patch.
     13
     14        * runtime/ArrayBuffer.cpp:
     15        (JSC::ArrayBuffer::slice const):
     16        (JSC::ArrayBuffer::sliceWithClampedIndex const):
     17        (JSC::ArrayBuffer::sliceImpl const): Deleted.
     18        * runtime/ArrayBuffer.h:
     19        * runtime/ArrayBufferSharingMode.h:
     20        * runtime/ArrayPrototype.cpp:
     21        (JSC::speciesWatchpointIsValid):
     22        * runtime/JSArrayBufferPrototype.cpp:
     23        (JSC::speciesWatchpointIsValid):
     24        (JSC::arrayBufferSlice):
     25        * runtime/JSGlobalObject.cpp:
     26        (JSC::JSGlobalObject::JSGlobalObject):
     27        (JSC::JSGlobalObject::init):
     28        (JSC::JSGlobalObject::visitChildren):
     29        (JSC::JSGlobalObject::tryInstallSpeciesWatchpoint):
     30        (JSC::JSGlobalObject::tryInstallArraySpeciesWatchpoint):
     31        (JSC::JSGlobalObject::tryInstallArrayBufferSpeciesWatchpoint):
     32        * runtime/JSGlobalObject.h:
     33        (JSC::JSGlobalObject::arrayBufferSpeciesWatchpointSet):
     34        (JSC::JSGlobalObject::arrayBufferPrototype const):
     35        (JSC::JSGlobalObject::arrayBufferStructure const):
     36        (JSC::JSGlobalObject::arrayBufferConstructor const):
     37
    1382020-11-06  Dmitry Bezhetskov  <dbezhetskov@igalia.com>
    239
  • trunk/Source/JavaScriptCore/runtime/ArrayBuffer.cpp

    r269343 r269574  
    312312RefPtr<ArrayBuffer> ArrayBuffer::slice(double begin, double end) const
    313313{
    314     return sliceImpl(clampIndex(begin), clampIndex(end));
     314    return sliceWithClampedIndex(clampIndex(begin), clampIndex(end));
    315315}
    316316
    317317RefPtr<ArrayBuffer> ArrayBuffer::slice(double begin) const
    318318{
    319     return sliceImpl(clampIndex(begin), byteLength());
    320 }
    321 
    322 RefPtr<ArrayBuffer> ArrayBuffer::sliceImpl(unsigned begin, unsigned end) const
     319    return sliceWithClampedIndex(clampIndex(begin), byteLength());
     320}
     321
     322RefPtr<ArrayBuffer> ArrayBuffer::sliceWithClampedIndex(unsigned begin, unsigned end) const
    323323{
    324324    unsigned size = begin <= end ? end - begin : 0;
  • trunk/Source/JavaScriptCore/runtime/ArrayBuffer.h

    r269343 r269574  
    138138    JS_EXPORT_PRIVATE RefPtr<ArrayBuffer> slice(double begin, double end) const;
    139139    JS_EXPORT_PRIVATE RefPtr<ArrayBuffer> slice(double begin) const;
     140    JS_EXPORT_PRIVATE RefPtr<ArrayBuffer> sliceWithClampedIndex(unsigned begin, unsigned end) const;
    140141   
    141142    inline void pin();
     
    165166    static RefPtr<ArrayBuffer> tryCreate(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy);
    166167    ArrayBuffer(ArrayBufferContents&&);
    167     RefPtr<ArrayBuffer> sliceImpl(unsigned begin, unsigned end) const;
    168168    inline unsigned clampIndex(double index) const;
    169169    static inline unsigned clampValue(double x, unsigned left, unsigned right);
  • trunk/Source/JavaScriptCore/runtime/ArrayBufferSharingMode.h

    r233122 r269574  
    3131namespace JSC {
    3232
    33 enum class ArrayBufferSharingMode {
    34     Default,
     33enum class ArrayBufferSharingMode : uint8_t {
     34    Default = 0,
    3535    Shared
    3636};
  • trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp

    r268990 r269574  
    187187}
    188188
    189 ALWAYS_INLINE bool speciesWatchpointIsValid(VM& vm, JSObject* thisObject)
     189static ALWAYS_INLINE bool speciesWatchpointIsValid(VM& vm, JSObject* thisObject)
    190190{
    191191    JSGlobalObject* globalObject = thisObject->globalObject(vm);
  • trunk/Source/JavaScriptCore/runtime/JSArrayBufferPrototype.cpp

    r269531 r269574  
    3131
    3232namespace JSC {
     33namespace JSArrayBufferPrototypeInternal {
     34static constexpr bool verbose = false;
     35};
    3336
    3437static JSC_DECLARE_HOST_FUNCTION(arrayBufferProtoFuncSlice);
     
    3740static JSC_DECLARE_HOST_FUNCTION(sharedArrayBufferProtoGetterFuncByteLength);
    3841
    39 static EncodedJSValue arrayBufferSlice(JSGlobalObject* globalObject, JSValue arrayBufferValue, JSValue startValue, JSValue endValue, ArrayBufferSharingMode mode)
    40 {
     42
     43static ALWAYS_INLINE bool speciesWatchpointIsValid(VM& vm, JSObject* thisObject, ArrayBufferSharingMode mode)
     44{
     45    JSGlobalObject* globalObject = thisObject->globalObject(vm);
     46    auto* prototype = globalObject->arrayBufferPrototype(mode);
     47
     48    if (globalObject->arrayBufferSpeciesWatchpointSet(mode).stateOnJSThread() == ClearWatchpoint) {
     49        dataLogLnIf(JSArrayBufferPrototypeInternal::verbose, "Initializing ArrayBuffer species watchpoints for ArrayBuffer.prototype: ", pointerDump(prototype), " with structure: ", pointerDump(prototype->structure(vm)), "\nand ArrayBuffer: ", pointerDump(globalObject->arrayBufferConstructor(mode)), " with structure: ", pointerDump(globalObject->arrayBufferConstructor(mode)->structure(vm)));
     50        globalObject->tryInstallArrayBufferSpeciesWatchpoint(mode);
     51        ASSERT(globalObject->arrayBufferSpeciesWatchpointSet(mode).stateOnJSThread() != ClearWatchpoint);
     52    }
     53
     54    return !thisObject->hasCustomProperties(vm)
     55        && prototype == thisObject->getPrototypeDirect(vm)
     56        && globalObject->arrayBufferSpeciesWatchpointSet(mode).stateOnJSThread() == IsWatched;
     57}
     58
     59enum class SpeciesConstructResult : uint8_t {
     60    FastPath,
     61    Exception,
     62    CreatedObject
     63};
     64
     65static ALWAYS_INLINE std::pair<SpeciesConstructResult, JSArrayBuffer*> speciesConstructArrayBuffer(JSGlobalObject* globalObject, JSArrayBuffer* thisObject, unsigned length, ArrayBufferSharingMode mode)
     66{
     67    // This is optimized way of SpeciesConstruct invoked from {ArrayBuffer,SharedArrayBuffer}.prototype.slice.
     68    // https://tc39.es/ecma262/#sec-arraybuffer.prototype.slice
     69    // https://tc39.es/ecma262/#sec-sharedarraybuffer.prototype.slice
    4170    VM& vm = globalObject->vm();
    4271    auto scope = DECLARE_THROW_SCOPE(vm);
    4372
     73    auto exceptionResult = [] () {
     74        return std::make_pair(SpeciesConstructResult::Exception, nullptr);
     75    };
     76
     77    // Fast path in the normal case where the user has not set an own constructor and the ArrayBuffer.prototype.constructor is normal.
     78    // We need prototype check for subclasses of ArrayBuffer, which are ArrayBuffer objects but have a different prototype by default.
     79    bool isValid = speciesWatchpointIsValid(vm, thisObject, mode);
     80    scope.assertNoException();
     81    if (LIKELY(isValid))
     82        return std::make_pair(SpeciesConstructResult::FastPath, nullptr);
     83
     84    JSValue constructor = thisObject->get(globalObject, vm.propertyNames->constructor);
     85    RETURN_IF_EXCEPTION(scope, exceptionResult());
     86    if (constructor.isConstructor(vm)) {
     87        JSObject* constructorObject = jsCast<JSObject*>(constructor);
     88        JSGlobalObject* globalObjectFromConstructor = constructorObject->globalObject(vm);
     89        bool isArrayBufferConstructorFromAnotherRealm = globalObject != globalObjectFromConstructor
     90            && constructorObject == globalObjectFromConstructor->arrayBufferConstructor(mode);
     91        if (isArrayBufferConstructorFromAnotherRealm)
     92            return std::make_pair(SpeciesConstructResult::FastPath, nullptr);
     93    }
     94    if (constructor.isObject()) {
     95        constructor = constructor.get(globalObject, vm.propertyNames->speciesSymbol);
     96        RETURN_IF_EXCEPTION(scope, exceptionResult());
     97        if (constructor.isNull())
     98            return std::make_pair(SpeciesConstructResult::FastPath, nullptr);
     99    }
     100
     101    if (constructor.isUndefined())
     102        return std::make_pair(SpeciesConstructResult::FastPath, nullptr);
     103
     104    // 16. Let new be ? Construct(ctor, « 𝔽(newLen) »).
     105    MarkedArgumentBuffer args;
     106    args.append(jsNumber(length));
     107    ASSERT(!args.hasOverflowed());
     108    JSObject* newObject = construct(globalObject, constructor, args, "Species construction did not get a valid constructor");
     109    RETURN_IF_EXCEPTION(scope, exceptionResult());
     110
     111    // 17. Perform ? RequireInternalSlot(new, [[ArrayBufferData]]).
     112    JSArrayBuffer* result = jsDynamicCast<JSArrayBuffer*>(vm, newObject);
     113    if (UNLIKELY(!result)) {
     114        throwTypeError(globalObject, scope, "Species construction does not create ArrayBuffer"_s);
     115        return exceptionResult();
     116    }
     117
     118    if (mode == ArrayBufferSharingMode::Default) {
     119        // 18. If IsSharedArrayBuffer(new) is true, throw a TypeError exception.
     120        if (result->isShared()) {
     121            throwTypeError(globalObject, scope, "ArrayBuffer.prototype.slice creates SharedArrayBuffer"_s);
     122            return exceptionResult();
     123        }
     124        // 19. If IsDetachedBuffer(new) is true, throw a TypeError exception.
     125        if (result->impl()->isDetached()) {
     126            throwVMTypeError(globalObject, scope, "Created ArrayBuffer is detached"_s);
     127            return exceptionResult();
     128        }
     129    } else {
     130        // 17. If IsSharedArrayBuffer(new) is false, throw a TypeError exception.
     131        if (!result->isShared()) {
     132            throwTypeError(globalObject, scope, "SharedArrayBuffer.prototype.slice creates non-shared ArrayBuffer"_s);
     133            return exceptionResult();
     134        }
     135    }
     136
     137    // 20. If SameValue(new, O) is true, throw a TypeError exception.
     138    if (result == thisObject) {
     139        throwVMTypeError(globalObject, scope, "Species construction returns same ArrayBuffer to a receiver"_s);
     140        return exceptionResult();
     141    }
     142
     143    // 21. If new.[[ArrayBufferByteLength]] < newLen, throw a TypeError exception.
     144    if (result->impl()->byteLength() < length) {
     145        throwVMTypeError(globalObject, scope, "Species construction returns ArrayBuffer which byteLength is less than requested"_s);
     146        return exceptionResult();
     147    }
     148
     149    return std::make_pair(SpeciesConstructResult::CreatedObject, result);
     150}
     151
     152
     153static EncodedJSValue arrayBufferSlice(JSGlobalObject* globalObject, JSValue arrayBufferValue, JSValue startValue, JSValue endValue, ArrayBufferSharingMode mode)
     154{
     155    // https://tc39.es/ecma262/#sec-arraybuffer.prototype.slice
     156    // https://tc39.es/ecma262/#sec-sharedarraybuffer.prototype.slice
     157
     158    VM& vm = globalObject->vm();
     159    auto scope = DECLARE_THROW_SCOPE(vm);
     160
     161    // 2. Perform ? RequireInternalSlot(O, [[ArrayBufferData]]).
     162    // 3. If IsSharedArrayBuffer(O) is true, throw a TypeError exception.
    44163    JSArrayBuffer* thisObject = jsDynamicCast<JSArrayBuffer*>(vm, arrayBufferValue);
    45164    if (!thisObject || (mode != thisObject->impl()->sharingMode()))
    46165        return throwVMTypeError(globalObject, scope, makeString("Receiver must be "_s, mode == ArrayBufferSharingMode::Default ? "ArrayBuffer"_s : "SharedArrayBuffer"_s));
    47166
     167    // 4. If IsDetachedBuffer(O) is true, throw a TypeError exception.
    48168    if (mode == ArrayBufferSharingMode::Default && thisObject->impl()->isDetached())
    49169        return throwVMTypeError(globalObject, scope, "Receiver is detached"_s);
    50170
    51     double begin = startValue.toIntegerOrInfinity(globalObject);
     171    // 5. Let len be O.[[ArrayBufferByteLength]].
     172    unsigned byteLength = thisObject->impl()->byteLength();
     173    unsigned firstIndex = 0;
     174    double relativeStart = startValue.toIntegerOrInfinity(globalObject);
    52175    RETURN_IF_EXCEPTION(scope, encodedJSValue());
    53 
    54     double end;
     176    if (relativeStart < 0)
     177        firstIndex = static_cast<unsigned>(std::max<double>(byteLength + relativeStart, 0));
     178    else
     179        firstIndex = static_cast<unsigned>(std::min<double>(relativeStart, byteLength));
     180    ASSERT(firstIndex >= 0);
     181    ASSERT(firstIndex <= byteLength);
     182
     183    unsigned finalIndex = 0;
    55184    if (!endValue.isUndefined()) {
    56         end = endValue.toIntegerOrInfinity(globalObject);
     185        double relativeEnd = endValue.toIntegerOrInfinity(globalObject);
    57186        RETURN_IF_EXCEPTION(scope, encodedJSValue());
     187        if (relativeEnd < 0)
     188            finalIndex = static_cast<unsigned>(std::max<double>(byteLength + relativeEnd, 0));
     189        else
     190            finalIndex = static_cast<unsigned>(std::min<double>(relativeEnd, byteLength));
    58191    } else
    59         end = thisObject->impl()->byteLength();
     192        finalIndex = thisObject->impl()->byteLength();
     193    ASSERT(finalIndex >= 0);
     194    ASSERT(finalIndex <= byteLength);
     195
     196    // 14. Let newLen be max(final - first, 0).
     197    unsigned newLength = (finalIndex >= firstIndex) ? finalIndex - firstIndex : 0;
     198
     199    // 15. Let ctor be ? SpeciesConstructor(O, %ArrayBuffer%).
     200    auto speciesResult = speciesConstructArrayBuffer(globalObject, thisObject, newLength, mode);
     201    // We can only get an exception if we call some user function.
     202    EXCEPTION_ASSERT(!!scope.exception() == (speciesResult.first == SpeciesConstructResult::Exception));
     203    if (UNLIKELY(speciesResult.first == SpeciesConstructResult::Exception))
     204        return { };
    60205
    61206    // 23. If IsDetachedBuffer(O) is true, throw a TypeError exception.
    62     // Check detach status again since toIntegerOrInfinity can have side effect.
    63207    if (mode == ArrayBufferSharingMode::Default && thisObject->impl()->isDetached())
    64208        return throwVMTypeError(globalObject, scope, "Receiver is detached"_s);
    65209
    66     auto newBuffer = thisObject->impl()->slice(begin, end);
    67     if (!newBuffer)
    68         return JSValue::encode(throwOutOfMemoryError(globalObject, scope));
    69 
    70     Structure* structure = globalObject->arrayBufferStructure(newBuffer->sharingMode());
    71 
    72     JSArrayBuffer* result = JSArrayBuffer::create(vm, structure, WTFMove(newBuffer));
    73 
    74     return JSValue::encode(result);
     210    if (LIKELY(speciesResult.first == SpeciesConstructResult::FastPath)) {
     211        ASSERT(!thisObject->impl()->isDetached());
     212        auto newBuffer = thisObject->impl()->sliceWithClampedIndex(firstIndex, finalIndex);
     213        if (!newBuffer)
     214            return JSValue::encode(throwOutOfMemoryError(globalObject, scope));
     215        Structure* structure = globalObject->arrayBufferStructure(newBuffer->sharingMode());
     216        JSArrayBuffer* result = JSArrayBuffer::create(vm, structure, WTFMove(newBuffer));
     217        return JSValue::encode(result);
     218    }
     219
     220    // 24. Let fromBuf be O.[[ArrayBufferData]].
     221    // 25. Let toBuf be new.[[ArrayBufferData]].
     222    // 26. Perform CopyDataBlockBytes(toBuf, 0, fromBuf, first, newLen).
     223    JSArrayBuffer* newObject = speciesResult.second;
     224    ASSERT(!thisObject->impl()->isDetached());
     225    ASSERT(!newObject->impl()->isDetached());
     226    ASSERT(newObject->impl()->byteLength() >= newLength);
     227    memcpy(newObject->impl()->data(), static_cast<const char*>(thisObject->impl()->data()) + firstIndex, newLength);
     228    return JSValue::encode(newObject);
    75229}
    76230
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r269531 r269574  
    500500    , m_mapSetWatchpointSet(IsWatched)
    501501    , m_setAddWatchpointSet(IsWatched)
    502     , m_arraySpeciesWatchpointSet(ClearWatchpoint)
    503502    , m_arrayJoinWatchpointSet(IsWatched)
    504503    , m_numberToStringWatchpointSet(IsWatched)
     
    831830        });
    832831
    833 #if ENABLE(SHARED_ARRAY_BUFFER)
    834832    if (Options::useSharedArrayBuffer()) {
    835         m_sharedArrayBufferPrototype.set(vm, this, JSArrayBufferPrototype::create(vm, this, JSArrayBufferPrototype::createStructure(vm, this, m_objectPrototype.get()), ArrayBufferSharingMode::Shared));
    836         m_sharedArrayBufferStructure.set(vm, this, JSArrayBuffer::createStructure(vm, this, m_sharedArrayBufferPrototype.get()));
    837     }
    838 #endif
     833        m_sharedArrayBufferStructure.initLater(
     834            [] (LazyClassStructure::Initializer& init) {
     835                init.setPrototype(JSArrayBufferPrototype::create(init.vm, init.global, JSArrayBufferPrototype::createStructure(init.vm, init.global, init.global->m_objectPrototype.get()), ArrayBufferSharingMode::Shared));
     836                init.setStructure(JSArrayBuffer::createStructure(init.vm, init.global, init.prototype));
     837                init.setConstructor(JSSharedArrayBufferConstructor::create(init.vm, JSSharedArrayBufferConstructor::createStructure(init.vm, init.global, init.global->m_functionPrototype.get()), jsCast<JSArrayBufferPrototype*>(init.prototype), init.global->m_speciesGetterSetter.get()));
     838            });
     839    }
    839840
    840841    m_iteratorPrototype.set(vm, this, IteratorPrototype::create(vm, this, IteratorPrototype::createStructure(vm, this, m_objectPrototype.get())));
     
    901902    m_regExpGlobalData.cachedResult().record(vm, this, nullptr, jsEmptyString(vm), MatchResult(0, 0));
    902903   
    903 #if ENABLE(SHARED_ARRAY_BUFFER)
    904     JSSharedArrayBufferConstructor* sharedArrayBufferConstructor = nullptr;
    905904    AtomicsObject* atomicsObject = nullptr;
    906     if (Options::useSharedArrayBuffer()) {
    907         sharedArrayBufferConstructor = JSSharedArrayBufferConstructor::create(vm, JSSharedArrayBufferConstructor::createStructure(vm, this, m_functionPrototype.get()), m_sharedArrayBufferPrototype.get(), m_speciesGetterSetter.get());
    908         m_sharedArrayBufferPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, sharedArrayBufferConstructor, static_cast<unsigned>(PropertyAttribute::DontEnum));
    909 
     905    if (Options::useSharedArrayBuffer())
    910906        atomicsObject = AtomicsObject::create(vm, this, AtomicsObject::createStructure(vm, this, m_objectPrototype.get()));
    911     }
    912 #endif
    913907
    914908#define CREATE_CONSTRUCTOR_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName, prototypeBase, featureFlag) \
     
    988982    putDirectWithoutTransition(vm, vm.propertyNames->RegExp, regExpConstructor, static_cast<unsigned>(PropertyAttribute::DontEnum));
    989983
    990 #if ENABLE(SHARED_ARRAY_BUFFER)
    991984    if (Options::useSharedArrayBuffer()) {
    992         putDirectWithoutTransition(vm, vm.propertyNames->SharedArrayBuffer, sharedArrayBufferConstructor, static_cast<unsigned>(PropertyAttribute::DontEnum));
     985        putDirectWithoutTransition(vm, vm.propertyNames->SharedArrayBuffer, m_sharedArrayBufferStructure.constructor(this), static_cast<unsigned>(PropertyAttribute::DontEnum));
    993986        putDirectWithoutTransition(vm, vm.propertyNames->Atomics, atomicsObject, static_cast<unsigned>(PropertyAttribute::DontEnum));
    994987    }
    995 #endif
    996988
    997989#define PUT_CONSTRUCTOR_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName, prototypeBase, featureFlag) \
     
    20342026    thisObject->m_callableProxyObjectStructure.visit(visitor);
    20352027    thisObject->m_proxyRevokeStructure.visit(visitor);
     2028    thisObject->m_sharedArrayBufferStructure.visit(visitor);
    20362029
    20372030    for (auto& property : thisObject->m_linkTimeConstants)
    20382031        property.visit(visitor);
    2039    
    2040 #if ENABLE(SHARED_ARRAY_BUFFER)
    2041     visitor.append(thisObject->m_sharedArrayBufferPrototype);
    2042     visitor.append(thisObject->m_sharedArrayBufferStructure);
    2043 #endif
    20442032
    20452033#define VISIT_SIMPLE_TYPE(CapitalName, lowerName, properName, instanceType, jsName, prototypeBase, featureFlag) if (featureFlag) { \
     
    21372125}
    21382126
    2139 void JSGlobalObject::tryInstallArraySpeciesWatchpoint()
    2140 {
    2141     RELEASE_ASSERT(!m_arrayPrototypeConstructorWatchpoint);
    2142     RELEASE_ASSERT(!m_arrayConstructorSpeciesWatchpoint);
     2127void JSGlobalObject::tryInstallSpeciesWatchpoint(JSObject* prototype, JSObject* constructor, std::unique_ptr<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>& constructorWatchpoint, std::unique_ptr<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>& speciesWatchpoint, InlineWatchpointSet& speciesWatchpointSet)
     2128{
     2129    RELEASE_ASSERT(!constructorWatchpoint);
     2130    RELEASE_ASSERT(!speciesWatchpoint);
    21432131
    21442132    VM& vm = this->vm();
    21452133    auto scope = DECLARE_THROW_SCOPE(vm);
    21462134
    2147     // First we need to make sure that the Array.prototype.constructor property points to Array
    2148     // and that Array[Symbol.species] is the primordial GetterSetter.
    2149     ArrayPrototype* arrayPrototype = this->arrayPrototype();
     2135    // First we need to make sure that the %prototype%.constructor property points to a %constructor%
     2136    // and that %constructor%[Symbol.species] is the primordial GetterSetter.
    21502137
    21512138    // We only initialize once so flattening the structures does not have any real cost.
    2152     Structure* prototypeStructure = arrayPrototype->structure(vm);
     2139    Structure* prototypeStructure = prototype->structure(vm);
    21532140    if (prototypeStructure->isDictionary())
    2154         prototypeStructure = prototypeStructure->flattenDictionaryStructure(vm, arrayPrototype);
     2141        prototypeStructure = prototypeStructure->flattenDictionaryStructure(vm, prototype);
    21552142    RELEASE_ASSERT(!prototypeStructure->isDictionary());
    21562143
    2157     ArrayConstructor* arrayConstructor = this->arrayConstructor();
    2158 
    21592144    auto invalidateWatchpoint = [&] {
    2160         m_arraySpeciesWatchpointSet.invalidate(vm, StringFireDetail("Was not able to set up array species watchpoint."));
     2145        speciesWatchpointSet.invalidate(vm, StringFireDetail("Was not able to set up species watchpoint."));
    21612146    };
    21622147
    2163     PropertySlot constructorSlot(arrayPrototype, PropertySlot::InternalMethodType::VMInquiry, &vm);
    2164     arrayPrototype->getOwnPropertySlot(arrayPrototype, this, vm.propertyNames->constructor, constructorSlot);
     2148    PropertySlot constructorSlot(prototype, PropertySlot::InternalMethodType::VMInquiry, &vm);
     2149    prototype->getOwnPropertySlot(prototype, this, vm.propertyNames->constructor, constructorSlot);
    21652150    scope.assertNoException();
    2166     if (constructorSlot.slotBase() != arrayPrototype
     2151    if (constructorSlot.slotBase() != prototype
    21672152        || !constructorSlot.isCacheableValue()
    2168         || constructorSlot.getValue(this, vm.propertyNames->constructor) != arrayConstructor) {
     2153        || constructorSlot.getValue(this, vm.propertyNames->constructor) != constructor) {
    21692154        invalidateWatchpoint();
    21702155        return;
    21712156    }
    21722157
    2173     Structure* constructorStructure = arrayConstructor->structure(vm);
     2158    Structure* constructorStructure = constructor->structure(vm);
    21742159    if (constructorStructure->isDictionary())
    2175         constructorStructure = constructorStructure->flattenDictionaryStructure(vm, arrayConstructor);
    2176 
    2177     PropertySlot speciesSlot(arrayConstructor, PropertySlot::InternalMethodType::VMInquiry, &vm);
    2178     arrayConstructor->getOwnPropertySlot(arrayConstructor, this, vm.propertyNames->speciesSymbol, speciesSlot);
     2160        constructorStructure = constructorStructure->flattenDictionaryStructure(vm, constructor);
     2161
     2162    PropertySlot speciesSlot(constructor, PropertySlot::InternalMethodType::VMInquiry, &vm);
     2163    constructor->getOwnPropertySlot(constructor, this, vm.propertyNames->speciesSymbol, speciesSlot);
    21792164    scope.assertNoException();
    2180     if (speciesSlot.slotBase() != arrayConstructor
     2165    if (speciesSlot.slotBase() != constructor
    21812166        || !speciesSlot.isCacheableGetter()
    21822167        || speciesSlot.getterSetter() != speciesGetterSetter()) {
     
    21892174    constructorStructure->startWatchingPropertyForReplacements(vm, speciesSlot.cachedOffset());
    21902175
    2191     ObjectPropertyCondition constructorCondition = ObjectPropertyCondition::equivalence(vm, arrayPrototype, arrayPrototype, vm.propertyNames->constructor.impl(), arrayConstructor);
    2192     ObjectPropertyCondition speciesCondition = ObjectPropertyCondition::equivalence(vm, arrayPrototype, arrayConstructor, vm.propertyNames->speciesSymbol.impl(), speciesGetterSetter());
     2176    ObjectPropertyCondition constructorCondition = ObjectPropertyCondition::equivalence(vm, prototype, prototype, vm.propertyNames->constructor.impl(), constructor);
     2177    ObjectPropertyCondition speciesCondition = ObjectPropertyCondition::equivalence(vm, prototype, constructor, vm.propertyNames->speciesSymbol.impl(), speciesGetterSetter());
    21932178
    21942179    if (!constructorCondition.isWatchable() || !speciesCondition.isWatchable()) {
     
    21982183
    21992184    // We only watch this from the DFG, and the DFG makes sure to only start watching if the watchpoint is in the IsWatched state.
    2200     RELEASE_ASSERT(!m_arraySpeciesWatchpointSet.isBeingWatched());
    2201     m_arraySpeciesWatchpointSet.touch(vm, "Set up array species watchpoint.");
    2202 
    2203     m_arrayPrototypeConstructorWatchpoint = makeUnique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, constructorCondition, m_arraySpeciesWatchpointSet);
    2204     m_arrayPrototypeConstructorWatchpoint->install(vm);
    2205 
    2206     m_arrayConstructorSpeciesWatchpoint = makeUnique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, speciesCondition, m_arraySpeciesWatchpointSet);
    2207     m_arrayConstructorSpeciesWatchpoint->install(vm);
     2185    RELEASE_ASSERT(!speciesWatchpointSet.isBeingWatched());
     2186    speciesWatchpointSet.touch(vm, "Set up species watchpoint.");
     2187
     2188    constructorWatchpoint = makeUnique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, constructorCondition, speciesWatchpointSet);
     2189    constructorWatchpoint->install(vm);
     2190
     2191    speciesWatchpoint = makeUnique<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>(this, speciesCondition, speciesWatchpointSet);
     2192    speciesWatchpoint->install(vm);
     2193}
     2194
     2195void JSGlobalObject::tryInstallArraySpeciesWatchpoint()
     2196{
     2197    RELEASE_ASSERT(!m_arrayPrototypeConstructorWatchpoint);
     2198    RELEASE_ASSERT(!m_arrayConstructorSpeciesWatchpoint);
     2199
     2200    tryInstallSpeciesWatchpoint(arrayPrototype(), arrayConstructor(), m_arrayPrototypeConstructorWatchpoint, m_arrayConstructorSpeciesWatchpoint, m_arraySpeciesWatchpointSet);
     2201}
     2202
     2203void JSGlobalObject::tryInstallArrayBufferSpeciesWatchpoint(ArrayBufferSharingMode sharingMode)
     2204{
     2205    static_assert(static_cast<unsigned>(ArrayBufferSharingMode::Default) == 0);
     2206    static_assert(static_cast<unsigned>(ArrayBufferSharingMode::Shared) == 1);
     2207    unsigned index = static_cast<unsigned>(sharingMode);
     2208    tryInstallSpeciesWatchpoint(arrayBufferPrototype(sharingMode), arrayBufferConstructor(sharingMode), m_arrayBufferPrototypeConstructorWatchpoints[index], m_arrayBufferConstructorSpeciesWatchpoints[index], arrayBufferSpeciesWatchpointSet(sharingMode));
    22082209}
    22092210
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h

    r268956 r269574  
    421421    LazyProperty<JSGlobalObject, Structure> m_callableProxyObjectStructure;
    422422    LazyProperty<JSGlobalObject, Structure> m_proxyRevokeStructure;
    423 #if ENABLE(SHARED_ARRAY_BUFFER)
    424     WriteBarrier<JSArrayBufferPrototype> m_sharedArrayBufferPrototype;
    425     WriteBarrier<Structure> m_sharedArrayBufferStructure;
    426 #endif
     423    LazyClassStructure m_sharedArrayBufferStructure;
    427424
    428425#define DEFINE_STORAGE_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName, prototypeBase, featureFlag) \
     
    488485    InlineWatchpointSet m_mapSetWatchpointSet;
    489486    InlineWatchpointSet m_setAddWatchpointSet;
    490     InlineWatchpointSet m_arraySpeciesWatchpointSet;
     487    InlineWatchpointSet m_arraySpeciesWatchpointSet { ClearWatchpoint };
    491488    InlineWatchpointSet m_arrayJoinWatchpointSet;
    492489    InlineWatchpointSet m_numberToStringWatchpointSet;
     490    InlineWatchpointSet m_arrayBufferSpeciesWatchpointSet { ClearWatchpoint };
     491    InlineWatchpointSet m_sharedArrayBufferSpeciesWatchpointSet { ClearWatchpoint };
    493492    std::unique_ptr<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>> m_arrayConstructorSpeciesWatchpoint;
    494493    std::unique_ptr<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>> m_arrayPrototypeConstructorWatchpoint;
     
    505504    std::unique_ptr<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>> m_setPrototypeAddWatchpoint;
    506505    std::unique_ptr<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>> m_numberPrototypeToStringWatchpoint;
     506    std::unique_ptr<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>> m_arrayBufferConstructorSpeciesWatchpoints[2];
     507    std::unique_ptr<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>> m_arrayBufferPrototypeConstructorWatchpoints[2];
    507508
    508509public:
     
    521522        RELEASE_ASSERT(Options::useJIT());
    522523        return m_numberToStringWatchpointSet;
     524    }
     525    InlineWatchpointSet& arrayBufferSpeciesWatchpointSet(ArrayBufferSharingMode sharingMode)
     526    {
     527        switch (sharingMode) {
     528        case ArrayBufferSharingMode::Default:
     529            return m_arrayBufferSpeciesWatchpointSet;
     530        case ArrayBufferSharingMode::Shared:
     531            return m_sharedArrayBufferSpeciesWatchpointSet;
     532        }
     533        RELEASE_ASSERT_NOT_REACHED();
     534        return m_arrayBufferSpeciesWatchpointSet;
    523535    }
    524536
     
    872884    static ScriptExecutionStatus scriptExecutionStatus(JSGlobalObject*, JSObject*) { return ScriptExecutionStatus::Running; }
    873885
    874     JSObject* arrayBufferConstructor() const { return m_arrayBufferStructure.constructor(this); }
    875 
    876886    JSObject* arrayBufferPrototype(ArrayBufferSharingMode sharingMode) const
    877887    {
     
    879889        case ArrayBufferSharingMode::Default:
    880890            return m_arrayBufferStructure.prototype(this);
    881 #if ENABLE(SHARED_ARRAY_BUFFER)
    882891        case ArrayBufferSharingMode::Shared:
    883             return m_sharedArrayBufferPrototype.get();
    884 #else
    885         default:
    886             return m_arrayBufferStructure.prototype(this);
    887 #endif
     892            return m_sharedArrayBufferStructure.prototype(this);
    888893        }
     894        RELEASE_ASSERT_NOT_REACHED();
     895        return nullptr;
    889896    }
    890897    Structure* arrayBufferStructure(ArrayBufferSharingMode sharingMode) const
     
    893900        case ArrayBufferSharingMode::Default:
    894901            return m_arrayBufferStructure.get(this);
    895 #if ENABLE(SHARED_ARRAY_BUFFER)
    896902        case ArrayBufferSharingMode::Shared:
    897             return m_sharedArrayBufferStructure.get();
    898 #else
    899         default:
    900             return m_arrayBufferStructure.get(this);
    901 #endif
     903            return m_sharedArrayBufferStructure.get(this);
    902904        }
    903905        RELEASE_ASSERT_NOT_REACHED();
    904906        return nullptr;
    905907    }
     908    JSObject* arrayBufferConstructor(ArrayBufferSharingMode sharingMode) const
     909    {
     910        switch (sharingMode) {
     911        case ArrayBufferSharingMode::Default:
     912            return m_arrayBufferStructure.constructor(this);
     913        case ArrayBufferSharingMode::Shared:
     914            return m_sharedArrayBufferStructure.constructor(this);
     915        }
     916        RELEASE_ASSERT_NOT_REACHED();
     917        return nullptr;
     918    }
     919
    906920
    907921#define DEFINE_ACCESSORS_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName, prototypeBase, featureFlag) \
     
    10791093    void installMapPrototypeWatchpoint(MapPrototype*);
    10801094    void installSetPrototypeWatchpoint(SetPrototype*);
     1095    void tryInstallArrayBufferSpeciesWatchpoint(ArrayBufferSharingMode);
    10811096
    10821097protected:
     1098    void tryInstallSpeciesWatchpoint(JSObject* prototype, JSObject* constructor, std::unique_ptr<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>& constructorWatchpoint, std::unique_ptr<ObjectPropertyChangeAdaptiveWatchpoint<InlineWatchpointSet>>& speciesWatchpoint, InlineWatchpointSet& speciesWatchpointSet);
     1099
    10831100    struct GlobalPropertyInfo {
    10841101        GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a)
  • trunk/Source/WTF/ChangeLog

    r269545 r269574  
     12020-11-08  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Support @@species in ArrayBuffer / SharedArrayBuffer slice
     4        https://bugs.webkit.org/show_bug.cgi?id=218697
     5
     6        Reviewed by Ross Kirsling.
     7
     8        Remove ENABLE(SHARED_ARRAY_BUFFER) flag. We use Options::useSharedArrayBuffer() runtime flag instead.
     9
     10        * wtf/PlatformEnable.h:
     11
    1122020-11-06  Sam Weinig  <weinig@apple.com>
    213
  • trunk/Source/WTF/wtf/PlatformEnable.h

    r269531 r269574  
    830830#endif
    831831
    832 /* Disable SharedArrayBuffers until Spectre security concerns are mitigated. */
    833 #define ENABLE_SHARED_ARRAY_BUFFER 1
    834 
    835 
    836832#if ((PLATFORM(COCOA) || PLATFORM(PLAYSTATION) || PLATFORM(WPE)) && ENABLE(ASYNC_SCROLLING)) || PLATFORM(GTK)
    837833#define ENABLE_KINETIC_SCROLLING 1
Note: See TracChangeset for help on using the changeset viewer.