[WTF] Import std::optional reference implementation as WTF::Optional
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSGenericTypedArrayView.h
1 /*
2  * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #pragma once
27
28 #include "JSArrayBufferView.h"
29 #include "ThrowScope.h"
30 #include "ToNativeFromValue.h"
31
32 namespace JSC {
33
34 JS_EXPORT_PRIVATE const ClassInfo* getInt8ArrayClassInfo();
35 JS_EXPORT_PRIVATE const ClassInfo* getInt16ArrayClassInfo();
36 JS_EXPORT_PRIVATE const ClassInfo* getInt32ArrayClassInfo();
37 JS_EXPORT_PRIVATE const ClassInfo* getUint8ArrayClassInfo();
38 JS_EXPORT_PRIVATE const ClassInfo* getUint8ClampedArrayClassInfo();
39 JS_EXPORT_PRIVATE const ClassInfo* getUint16ArrayClassInfo();
40 JS_EXPORT_PRIVATE const ClassInfo* getUint32ArrayClassInfo();
41 JS_EXPORT_PRIVATE const ClassInfo* getFloat32ArrayClassInfo();
42 JS_EXPORT_PRIVATE const ClassInfo* getFloat64ArrayClassInfo();
43
44 // A typed array view is our representation of a typed array object as seen
45 // from JavaScript. For example:
46 //
47 // var o = new Int8Array(100);
48 //
49 // Here, 'o' points to a JSGenericTypedArrayView<int8_t>.
50 //
51 // Views contain five fields:
52 //
53 //     Structure* S     // from JSCell
54 //     Butterfly* B     // from JSObject
55 //     ElementType* V
56 //     uint32_t L
57 //     TypedArrayMode M
58 //
59 // These fields take up a total of four pointer-width words. FIXME: Make
60 // it take less words!
61 //
62 // B is usually unused but may stored some additional "overflow" data for
63 // one of the modes. V always points to the base of the typed array's data,
64 // and may point to either GC-managed copied space, or data in the C heap;
65 // which of those things it points to is governed by the mode although for
66 // simple accesses to the view you can just read from the pointer either
67 // way. M specifies the mode of the view. L is the length, in units that
68 // depend on the view's type.
69
70 // The JSGenericTypedArrayView is templatized by an Adaptor that controls
71 // the element type and how it's converted; it should obey the following
72 // interface; I use int8_t as an example:
73 //
74 // struct Adaptor {
75 //     typedef int8_t Type;
76 //     typedef Int8Array ViewType;
77 //     typedef JSInt8Array JSViewType;
78 //     static int8_t toNativeFromInt32(int32_t);
79 //     static int8_t toNativeFromUint32(uint32_t);
80 //     static int8_t toNativeFromDouble(double);
81 //     static JSValue toJSValue(int8_t);
82 //     static double toDouble(int8_t);
83 //     template<T> static T::Type convertTo(uint8_t);
84 // };
85
86 enum class CopyType {
87     LeftToRight,
88     Unobservable,
89 };
90
91 static const char* const typedArrayBufferHasBeenDetachedErrorMessage = "Underlying ArrayBuffer has been detached from the view";
92
93 template<typename Adaptor>
94 class JSGenericTypedArrayView : public JSArrayBufferView {
95 public:
96     typedef JSArrayBufferView Base;
97     typedef typename Adaptor::Type ElementType;
98
99     static const unsigned StructureFlags = Base::StructureFlags | OverridesGetPropertyNames | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
100
101     static const unsigned elementSize = sizeof(typename Adaptor::Type);
102     
103 protected:
104     JSGenericTypedArrayView(VM&, ConstructionContext&);
105     
106 public:
107     static JSGenericTypedArrayView* create(ExecState*, Structure*, unsigned length);
108     static JSGenericTypedArrayView* createWithFastVector(ExecState*, Structure*, unsigned length, void* vector);
109     static JSGenericTypedArrayView* createUninitialized(ExecState*, Structure*, unsigned length);
110     static JSGenericTypedArrayView* create(ExecState*, Structure*, PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned length);
111     static JSGenericTypedArrayView* create(VM&, Structure*, PassRefPtr<typename Adaptor::ViewType> impl);
112     static JSGenericTypedArrayView* create(Structure*, JSGlobalObject*, PassRefPtr<typename Adaptor::ViewType> impl);
113     
114     unsigned byteLength() const { return m_length * sizeof(typename Adaptor::Type); }
115     size_t byteSize() const { return sizeOf(m_length, sizeof(typename Adaptor::Type)); }
116     
117     const typename Adaptor::Type* typedVector() const
118     {
119         return bitwise_cast<const typename Adaptor::Type*>(vector());
120     }
121     typename Adaptor::Type* typedVector()
122     {
123         return bitwise_cast<typename Adaptor::Type*>(vector());
124     }
125
126     // These methods are meant to match indexed access methods that JSObject
127     // supports - hence the slight redundancy.
128     bool canGetIndexQuickly(unsigned i)
129     {
130         return i < m_length;
131     }
132     bool canSetIndexQuickly(unsigned i)
133     {
134         return i < m_length;
135     }
136     
137     typename Adaptor::Type getIndexQuicklyAsNativeValue(unsigned i)
138     {
139         ASSERT(i < m_length);
140         return typedVector()[i];
141     }
142     
143     double getIndexQuicklyAsDouble(unsigned i)
144     {
145         return Adaptor::toDouble(getIndexQuicklyAsNativeValue(i));
146     }
147     
148     JSValue getIndexQuickly(unsigned i)
149     {
150         return Adaptor::toJSValue(getIndexQuicklyAsNativeValue(i));
151     }
152     
153     void setIndexQuicklyToNativeValue(unsigned i, typename Adaptor::Type value)
154     {
155         ASSERT(i < m_length);
156         typedVector()[i] = value;
157     }
158     
159     void setIndexQuicklyToDouble(unsigned i, double value)
160     {
161         setIndexQuicklyToNativeValue(i, toNativeFromValue<Adaptor>(jsNumber(value)));
162     }
163     
164     void setIndexQuickly(unsigned i, JSValue value)
165     {
166         ASSERT(!value.isObject());
167         setIndexQuicklyToNativeValue(i, toNativeFromValue<Adaptor>(value));
168     }
169     
170     bool setIndex(ExecState* exec, unsigned i, JSValue jsValue)
171     {
172         VM& vm = exec->vm();
173         auto scope = DECLARE_THROW_SCOPE(vm);
174
175         typename Adaptor::Type value = toNativeFromValue<Adaptor>(exec, jsValue);
176         RETURN_IF_EXCEPTION(scope, false);
177
178         if (isNeutered()) {
179             throwTypeError(exec, scope, ASCIILiteral(typedArrayBufferHasBeenDetachedErrorMessage));
180             return false;
181         }
182
183         if (i >= m_length)
184             return false;
185
186         setIndexQuicklyToNativeValue(i, value);
187         return true;
188     }
189
190     static ElementType toAdaptorNativeFromValue(ExecState* exec, JSValue jsValue) { return toNativeFromValue<Adaptor>(exec, jsValue); }
191
192     static std::optional<ElementType> toAdaptorNativeFromValueWithoutCoercion(JSValue jsValue) { return toNativeFromValueWithoutCoercion<Adaptor>(jsValue); }
193
194     void sort()
195     {
196         RELEASE_ASSERT(!isNeutered());
197         switch (Adaptor::typeValue) {
198         case TypeFloat32:
199             sortFloat<int32_t>();
200             break;
201         case TypeFloat64:
202             sortFloat<int64_t>();
203             break;
204         default: {
205             ElementType* array = typedVector();
206             std::sort(array, array + m_length);
207             break;
208         }
209         }
210     }
211
212     bool canAccessRangeQuickly(unsigned offset, unsigned length)
213     {
214         return offset <= m_length
215             && offset + length <= m_length
216             // check overflow
217             && offset + length >= offset;
218     }
219     
220     // Like canSetQuickly, except: if it returns false, it will throw the
221     // appropriate exception.
222     bool validateRange(ExecState*, unsigned offset, unsigned length);
223
224     // Returns true if successful, and false on error; if it returns false
225     // then it will have thrown an exception.
226     bool set(ExecState*, unsigned offset, JSObject*, unsigned objectOffset, unsigned length, CopyType type = CopyType::Unobservable);
227     
228     PassRefPtr<typename Adaptor::ViewType> possiblySharedTypedImpl();
229     PassRefPtr<typename Adaptor::ViewType> unsharedTypedImpl();
230
231     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
232     {
233         return Structure::create(vm, globalObject, prototype, TypeInfo(typeForTypedArrayType(Adaptor::typeValue), StructureFlags), info(), NonArray);
234     }
235     
236     static const ClassInfo s_info; // This is never accessed directly, since that would break linkage on some compilers.
237     
238     static const ClassInfo* info()
239     {
240         switch (Adaptor::typeValue) {
241         case TypeInt8:
242             return getInt8ArrayClassInfo();
243         case TypeInt16:
244             return getInt16ArrayClassInfo();
245         case TypeInt32:
246             return getInt32ArrayClassInfo();
247         case TypeUint8:
248             return getUint8ArrayClassInfo();
249         case TypeUint8Clamped:
250             return getUint8ClampedArrayClassInfo();
251         case TypeUint16:
252             return getUint16ArrayClassInfo();
253         case TypeUint32:
254             return getUint32ArrayClassInfo();
255         case TypeFloat32:
256             return getFloat32ArrayClassInfo();
257         case TypeFloat64:
258             return getFloat64ArrayClassInfo();
259         default:
260             RELEASE_ASSERT_NOT_REACHED();
261             return 0;
262         }
263     }
264     
265     ArrayBuffer* existingBuffer();
266
267     static const TypedArrayType TypedArrayStorageType = Adaptor::typeValue;
268
269     // This is the default DOM unwrapping. It calls toUnsharedNativeTypedView().
270     static RefPtr<typename Adaptor::ViewType> toWrapped(JSValue);
271     
272 protected:
273     friend struct TypedArrayClassInfos;
274
275     static EncodedJSValue throwNeuteredTypedArrayTypeError(ExecState*, EncodedJSValue, PropertyName);
276
277     static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
278     static bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
279     static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
280     static bool deleteProperty(JSCell*, ExecState*, PropertyName);
281
282     static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
283     static bool putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
284     static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
285     
286     static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
287
288     static size_t estimatedSize(JSCell*);
289     static void visitChildren(JSCell*, SlotVisitor&);
290
291     // Allocates the full-on native buffer and moves data into the C heap if
292     // necessary. Note that this never allocates in the GC heap.
293     static ArrayBuffer* slowDownAndWasteMemory(JSArrayBufferView*);
294     static PassRefPtr<ArrayBufferView> getTypedArrayImpl(JSArrayBufferView*);
295
296 private:
297     // Returns true if successful, and false on error; it will throw on error.
298     template<typename OtherAdaptor>
299     bool setWithSpecificType(
300         ExecState*, unsigned offset, JSGenericTypedArrayView<OtherAdaptor>*,
301         unsigned objectOffset, unsigned length, CopyType);
302
303     // The ECMA 6 spec states that floating point Typed Arrays should have the following ordering:
304     //
305     // -Inifinity < negative finite numbers < -0.0 < 0.0 < positive finite numbers < Infinity < NaN
306     // Note: regardless of the sign or exact representation of a NaN it is greater than all other values.
307     //
308     // An interesting fact about IEEE 754 floating point numbers is that have an adjacent representation
309     // i.e. for any finite floating point x there does not exist a finite floating point y such that
310     // ((float) ((int) x + 1)) > y > x (where int represents a signed bit integer with the same number
311     // of bits as float). Thus, if we have an array of floating points if we view it as an
312     // array of signed bit integers it will sort in the format we desire. Note, denormal
313     // numbers fit this property as they are floating point numbers with a exponent field of all
314     // zeros so they will be closer to the signed zeros than any normalized number.
315     //
316     // All the processors we support, however, use twos complement. Fortunately, if you compare a signed
317     // bit number as if it were twos complement the result will be correct assuming both numbers are not
318     // negative. e.g.
319     //
320     //    - <=> - = reversed (-30 > -20 = true)
321     //    + <=> + = ordered (30 > 20 = true)
322     //    - <=> + = ordered (-30 > 20 = false)
323     //    + <=> - = ordered (30 > -20 = true)
324     //
325     // For NaN, we normalize the NaN to a peticular representation; the sign bit is 0, all exponential bits
326     // are 1 and only the MSB of the mantissa is 1. So, NaN is recognized as the largest integral numbers.
327
328     void purifyArray()
329     {
330         ElementType* array = typedVector();
331         for (unsigned i = 0; i < m_length; i++)
332             array[i] = purifyNaN(array[i]);
333     }
334
335     template<typename IntegralType>
336     static bool ALWAYS_INLINE sortComparison(IntegralType a, IntegralType b)
337     {
338         if (a >= 0 || b >= 0)
339             return a < b;
340         return a > b;
341     }
342
343     template<typename IntegralType>
344     void sortFloat()
345     {
346         ASSERT(sizeof(IntegralType) == sizeof(ElementType));
347
348         // Since there might be another view that sets the bits of
349         // our floats to NaNs with negative sign bits we need to
350         // purify the array.
351         // We use a separate function here to avoid the strict aliasing rule.
352         // We could use a union but ASAN seems to frown upon that.
353         purifyArray();
354
355         IntegralType* array = reinterpret_cast_ptr<IntegralType*>(typedVector());
356         std::sort(array, array + m_length, sortComparison<IntegralType>);
357
358     }
359
360 };
361
362 template<typename Adaptor>
363 inline RefPtr<typename Adaptor::ViewType> toPossiblySharedNativeTypedView(JSValue value)
364 {
365     typename Adaptor::JSViewType* wrapper = jsDynamicCast<typename Adaptor::JSViewType*>(value);
366     if (!wrapper)
367         return nullptr;
368     return wrapper->possiblySharedTypedImpl();
369 }
370
371 template<typename Adaptor>
372 inline RefPtr<typename Adaptor::ViewType> toUnsharedNativeTypedView(JSValue value)
373 {
374     RefPtr<typename Adaptor::ViewType> result = toPossiblySharedNativeTypedView<Adaptor>(value);
375     if (!result || result->isShared())
376         return nullptr;
377     return result;
378 }
379
380 template<typename Adaptor>
381 RefPtr<typename Adaptor::ViewType> JSGenericTypedArrayView<Adaptor>::toWrapped(JSValue value)
382 {
383     return JSC::toUnsharedNativeTypedView<Adaptor>(value);
384 }
385
386 } // namespace JSC