55f346e3a4351e6e43ec0c670e2e5d31c1d68a50
[WebKit-https.git] / Source / JavaScriptCore / runtime / ArrayBufferView.h
1 /*
2  * Copyright (C) 2009, 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 "ArrayBuffer.h"
29 #include "TypedArrayType.h"
30 #include <algorithm>
31 #include <limits.h>
32 #include <wtf/PassRefPtr.h>
33 #include <wtf/RefCounted.h>
34 #include <wtf/RefPtr.h>
35
36 namespace JSC {
37
38 class JSArrayBufferView;
39 class JSGlobalObject;
40 class ExecState;
41
42 class ArrayBufferView : public RefCounted<ArrayBufferView> {
43 public:
44     virtual TypedArrayType getType() const = 0;
45
46     bool isNeutered() const
47     {
48         return !m_buffer || m_buffer->isNeutered();
49     }
50     
51     PassRefPtr<ArrayBuffer> possiblySharedBuffer() const
52     {
53         if (isNeutered())
54             return 0;
55         return m_buffer;
56     }
57     
58     PassRefPtr<ArrayBuffer> unsharedBuffer() const
59     {
60         PassRefPtr<ArrayBuffer> result = possiblySharedBuffer();
61         RELEASE_ASSERT(!result->isShared());
62         return result;
63     }
64     
65     bool isShared() const
66     {
67         if (isNeutered())
68             return false;
69         return m_buffer->isShared();
70     }
71
72     void* baseAddress() const
73     {
74         if (isNeutered())
75             return 0;
76         return m_baseAddress;
77     }
78
79     void* data() const { return baseAddress(); }
80
81     unsigned byteOffset() const
82     {
83         if (isNeutered())
84             return 0;
85         return m_byteOffset;
86     }
87
88     virtual unsigned byteLength() const = 0;
89
90     JS_EXPORT_PRIVATE void setNeuterable(bool flag);
91     bool isNeuterable() const { return m_isNeuterable; }
92
93     JS_EXPORT_PRIVATE virtual ~ArrayBufferView();
94
95     // Helper to verify byte offset is size aligned.
96     static bool verifyByteOffsetAlignment(unsigned byteOffset, size_t size)
97     {
98         return !(byteOffset & (size - 1));
99     }
100
101     // Helper to verify that a given sub-range of an ArrayBuffer is
102     // within range.
103     static bool verifySubRangeLength(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned numElements, size_t size)
104     {
105         unsigned byteLength = buffer->byteLength();
106         if (byteOffset > byteLength)
107             return false;
108         unsigned remainingElements = (byteLength - byteOffset) / size;
109         if (numElements > remainingElements)
110             return false;
111         return true;
112     }
113     
114     virtual JSArrayBufferView* wrap(ExecState*, JSGlobalObject*) = 0;
115     
116 protected:
117     JS_EXPORT_PRIVATE ArrayBufferView(PassRefPtr<ArrayBuffer>, unsigned byteOffset);
118
119     inline bool setImpl(ArrayBufferView*, unsigned byteOffset);
120
121     inline bool setRangeImpl(const char* data, size_t dataByteLength, unsigned byteOffset);
122
123     inline bool zeroRangeImpl(unsigned byteOffset, size_t rangeByteLength);
124
125     static inline void calculateOffsetAndLength(
126         int start, int end, unsigned arraySize,
127         unsigned* offset, unsigned* length);
128
129     // Input offset is in number of elements from this array's view;
130     // output offset is in number of bytes from the underlying buffer's view.
131     template <typename T>
132     static void clampOffsetAndNumElements(
133         PassRefPtr<ArrayBuffer> buffer,
134         unsigned arrayByteOffset,
135         unsigned *offset,
136         unsigned *numElements)
137     {
138         unsigned maxOffset = (UINT_MAX - arrayByteOffset) / sizeof(T);
139         if (*offset > maxOffset) {
140             *offset = buffer->byteLength();
141             *numElements = 0;
142             return;
143         }
144         *offset = arrayByteOffset + *offset * sizeof(T);
145         *offset = std::min(buffer->byteLength(), *offset);
146         unsigned remainingElements = (buffer->byteLength() - *offset) / sizeof(T);
147         *numElements = std::min(remainingElements, *numElements);
148     }
149
150     // This is the address of the ArrayBuffer's storage, plus the byte offset.
151     void* m_baseAddress;
152
153     unsigned m_byteOffset : 31;
154     bool m_isNeuterable : 1;
155
156 private:
157     friend class ArrayBuffer;
158     RefPtr<ArrayBuffer> m_buffer;
159 };
160
161 bool ArrayBufferView::setImpl(ArrayBufferView* array, unsigned byteOffset)
162 {
163     if (byteOffset > byteLength()
164         || byteOffset + array->byteLength() > byteLength()
165         || byteOffset + array->byteLength() < byteOffset) {
166         // Out of range offset or overflow
167         return false;
168     }
169     
170     char* base = static_cast<char*>(baseAddress());
171     memmove(base + byteOffset, array->baseAddress(), array->byteLength());
172     return true;
173 }
174
175 bool ArrayBufferView::setRangeImpl(const char* data, size_t dataByteLength, unsigned byteOffset)
176 {
177     if (byteOffset > byteLength()
178         || byteOffset + dataByteLength > byteLength()
179         || byteOffset + dataByteLength < byteOffset) {
180         // Out of range offset or overflow
181         return false;
182     }
183     
184     char* base = static_cast<char*>(baseAddress());
185     memmove(base + byteOffset, data, dataByteLength);
186     return true;
187 }
188
189 bool ArrayBufferView::zeroRangeImpl(unsigned byteOffset, size_t rangeByteLength)
190 {
191     if (byteOffset > byteLength()
192         || byteOffset + rangeByteLength > byteLength()
193         || byteOffset + rangeByteLength < byteOffset) {
194         // Out of range offset or overflow
195         return false;
196     }
197     
198     char* base = static_cast<char*>(baseAddress());
199     memset(base + byteOffset, 0, rangeByteLength);
200     return true;
201 }
202
203 void ArrayBufferView::calculateOffsetAndLength(
204     int start, int end, unsigned arraySize, unsigned* offset, unsigned* length)
205 {
206     if (start < 0)
207         start += arraySize;
208     if (start < 0)
209         start = 0;
210     if (end < 0)
211         end += arraySize;
212     if (end < 0)
213         end = 0;
214     if (static_cast<unsigned>(end) > arraySize)
215         end = arraySize;
216     if (end < start)
217         end = start;
218     *offset = static_cast<unsigned>(start);
219     *length = static_cast<unsigned>(end - start);
220 }
221
222 } // namespace JSC
223
224 using JSC::ArrayBufferView;