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