/ runtime / JSDataViewPrototype.cpp
JSDataViewPrototype.cpp
  1  /*
  2   * Copyright (C) 2013-2019 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  #include "config.h"
 27  #include "JSDataViewPrototype.h"
 28  
 29  #include "JSArrayBuffer.h"
 30  #include "JSCInlines.h"
 31  #include "JSDataView.h"
 32  #include "ToNativeFromValue.h"
 33  #include "TypedArrayAdaptors.h"
 34  #include <wtf/FlipBytes.h>
 35  
 36  namespace JSC {
 37  
 38  /* Source for JSDataViewPrototype.lut.h
 39  @begin dataViewTable
 40    getInt8               dataViewProtoFuncGetInt8             DontEnum|Function       1  DataViewGetInt8
 41    getUint8              dataViewProtoFuncGetUint8            DontEnum|Function       1  DataViewGetUint8
 42    getInt16              dataViewProtoFuncGetInt16            DontEnum|Function       1  DataViewGetInt16
 43    getUint16             dataViewProtoFuncGetUint16           DontEnum|Function       1  DataViewGetUint16
 44    getInt32              dataViewProtoFuncGetInt32            DontEnum|Function       1  DataViewGetInt32
 45    getUint32             dataViewProtoFuncGetUint32           DontEnum|Function       1  DataViewGetUint32
 46    getFloat32            dataViewProtoFuncGetFloat32          DontEnum|Function       1  DataViewGetFloat32
 47    getFloat64            dataViewProtoFuncGetFloat64          DontEnum|Function       1  DataViewGetFloat64
 48    setInt8               dataViewProtoFuncSetInt8             DontEnum|Function       2  DataViewSetInt8
 49    setUint8              dataViewProtoFuncSetUint8            DontEnum|Function       2  DataViewSetUint8
 50    setInt16              dataViewProtoFuncSetInt16            DontEnum|Function       2  DataViewSetInt16
 51    setUint16             dataViewProtoFuncSetUint16           DontEnum|Function       2  DataViewSetUint16
 52    setInt32              dataViewProtoFuncSetInt32            DontEnum|Function       2  DataViewSetInt32
 53    setUint32             dataViewProtoFuncSetUint32           DontEnum|Function       2  DataViewSetUint32
 54    setFloat32            dataViewProtoFuncSetFloat32          DontEnum|Function       2  DataViewSetFloat32
 55    setFloat64            dataViewProtoFuncSetFloat64          DontEnum|Function       2  DataViewSetFloat64
 56    buffer                dataViewProtoGetterBuffer            DontEnum|Accessor       0
 57    byteLength            dataViewProtoGetterByteLength        DontEnum|Accessor       0
 58    byteOffset            dataViewProtoGetterByteOffset        DontEnum|Accessor       0
 59  @end
 60  */
 61  
 62  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoFuncGetInt8);
 63  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoFuncGetInt16);
 64  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoFuncGetInt32);
 65  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoFuncGetUint8);
 66  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoFuncGetUint16);
 67  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoFuncGetUint32);
 68  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoFuncGetFloat32);
 69  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoFuncGetFloat64);
 70  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoFuncSetInt8);
 71  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoFuncSetInt16);
 72  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoFuncSetInt32);
 73  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoFuncSetUint8);
 74  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoFuncSetUint16);
 75  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoFuncSetUint32);
 76  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoFuncSetFloat32);
 77  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoFuncSetFloat64);
 78  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoGetterBuffer);
 79  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoGetterByteLength);
 80  static JSC_DECLARE_HOST_FUNCTION(dataViewProtoGetterByteOffset);
 81  
 82  }
 83  
 84  #include "JSDataViewPrototype.lut.h"
 85  
 86  namespace JSC {
 87  
 88  const ClassInfo JSDataViewPrototype::s_info = {
 89      "DataView", &Base::s_info, &dataViewTable, nullptr,
 90      CREATE_METHOD_TABLE(JSDataViewPrototype)
 91  };
 92  
 93  JSDataViewPrototype::JSDataViewPrototype(VM& vm, Structure* structure)
 94      : Base(vm, structure)
 95  {
 96  }
 97  
 98  JSDataViewPrototype* JSDataViewPrototype::create(VM& vm, Structure* structure)
 99  {
100      JSDataViewPrototype* prototype =
101          new (NotNull, allocateCell<JSDataViewPrototype>(vm.heap))
102          JSDataViewPrototype(vm, structure);
103      prototype->finishCreation(vm);
104      return prototype;
105  }
106  
107  void JSDataViewPrototype::finishCreation(JSC::VM& vm)
108  {
109      Base::finishCreation(vm);
110      ASSERT(inherits(vm, info()));
111      JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
112  }
113  
114  Structure* JSDataViewPrototype::createStructure(
115      VM& vm, JSGlobalObject* globalObject, JSValue prototype)
116  {
117      return Structure::create(
118          vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
119  }
120  
121  template<typename Adaptor>
122  EncodedJSValue getData(JSGlobalObject* globalObject, CallFrame* callFrame)
123  {
124      VM& vm = globalObject->vm();
125      auto scope = DECLARE_THROW_SCOPE(vm);
126  
127      JSDataView* dataView = jsDynamicCast<JSDataView*>(vm, callFrame->thisValue());
128      if (!dataView)
129          return throwVMTypeError(globalObject, scope, "Receiver of DataView method must be a DataView"_s);
130      
131      unsigned byteOffset = callFrame->argument(0).toIndex(globalObject, "byteOffset");
132      RETURN_IF_EXCEPTION(scope, encodedJSValue());
133      
134      bool littleEndian = false;
135      unsigned elementSize = sizeof(typename Adaptor::Type);
136      if (elementSize > 1 && callFrame->argumentCount() >= 2) {
137          littleEndian = callFrame->uncheckedArgument(1).toBoolean(globalObject);
138          RETURN_IF_EXCEPTION(scope, encodedJSValue());
139      }
140  
141      if (dataView->isDetached())
142          return throwVMTypeError(globalObject, scope, "Underlying ArrayBuffer has been detached from the view"_s);
143  
144      unsigned byteLength = dataView->length();
145      if (elementSize > byteLength || byteOffset > byteLength - elementSize)
146          return throwVMRangeError(globalObject, scope, "Out of bounds access"_s);
147  
148      const unsigned dataSize = sizeof(typename Adaptor::Type);
149      union {
150          typename Adaptor::Type value;
151          uint8_t rawBytes[dataSize];
152      } u = { };
153  
154      uint8_t* dataPtr = static_cast<uint8_t*>(dataView->vector()) + byteOffset;
155  
156      if (needToFlipBytesIfLittleEndian(littleEndian)) {
157          for (unsigned i = dataSize; i--;)
158              u.rawBytes[i] = *dataPtr++;
159      } else {
160          for (unsigned i = 0; i < dataSize; i++)
161              u.rawBytes[i] = *dataPtr++;
162      }
163  
164      return JSValue::encode(Adaptor::toJSValue(u.value));
165  }
166  
167  template<typename Adaptor>
168  EncodedJSValue setData(JSGlobalObject* globalObject, CallFrame* callFrame)
169  {
170      VM& vm = globalObject->vm();
171      auto scope = DECLARE_THROW_SCOPE(vm);
172  
173      JSDataView* dataView = jsDynamicCast<JSDataView*>(vm, callFrame->thisValue());
174      if (!dataView)
175          return throwVMTypeError(globalObject, scope, "Receiver of DataView method must be a DataView"_s);
176      
177      unsigned byteOffset = callFrame->argument(0).toIndex(globalObject, "byteOffset");
178      RETURN_IF_EXCEPTION(scope, encodedJSValue());
179  
180      const unsigned dataSize = sizeof(typename Adaptor::Type);
181      union {
182          typename Adaptor::Type value;
183          uint8_t rawBytes[dataSize];
184      } u;
185  
186      u.value = toNativeFromValue<Adaptor>(globalObject, callFrame->argument(1));
187      RETURN_IF_EXCEPTION(scope, encodedJSValue());
188      
189      bool littleEndian = false;
190      unsigned elementSize = sizeof(typename Adaptor::Type);
191      if (elementSize > 1 && callFrame->argumentCount() >= 3) {
192          littleEndian = callFrame->uncheckedArgument(2).toBoolean(globalObject);
193          RETURN_IF_EXCEPTION(scope, encodedJSValue());
194      }
195  
196      if (dataView->isDetached())
197          return throwVMTypeError(globalObject, scope, "Underlying ArrayBuffer has been detached from the view"_s);
198  
199      unsigned byteLength = dataView->length();
200      if (elementSize > byteLength || byteOffset > byteLength - elementSize)
201          return throwVMRangeError(globalObject, scope, "Out of bounds access"_s);
202  
203      uint8_t* dataPtr = static_cast<uint8_t*>(dataView->vector()) + byteOffset;
204  
205      if (needToFlipBytesIfLittleEndian(littleEndian)) {
206          for (unsigned i = dataSize; i--;)
207              *dataPtr++ = u.rawBytes[i];
208      } else {
209          for (unsigned i = 0; i < dataSize; i++)
210              *dataPtr++ = u.rawBytes[i];
211      }
212  
213      return JSValue::encode(jsUndefined());
214  }
215  
216  IGNORE_CLANG_WARNINGS_BEGIN("missing-prototypes")
217  
218  JSC_DEFINE_HOST_FUNCTION(dataViewProtoGetterBuffer, (JSGlobalObject* globalObject, CallFrame* callFrame))
219  {
220      VM& vm = globalObject->vm();
221      auto scope = DECLARE_THROW_SCOPE(vm);
222  
223      JSDataView* view = jsDynamicCast<JSDataView*>(vm, callFrame->thisValue());
224      if (!view)
225          return throwVMTypeError(globalObject, scope, "DataView.prototype.buffer expects |this| to be a DataView object");
226  
227      RELEASE_AND_RETURN(scope, JSValue::encode(view->possiblySharedJSBuffer(globalObject)));
228  }
229  
230  JSC_DEFINE_HOST_FUNCTION(dataViewProtoGetterByteLength, (JSGlobalObject* globalObject, CallFrame* callFrame))
231  {
232      VM& vm = globalObject->vm();
233      auto scope = DECLARE_THROW_SCOPE(vm);
234  
235      JSDataView* view = jsDynamicCast<JSDataView*>(vm, callFrame->thisValue());
236      if (!view)
237          return throwVMTypeError(globalObject, scope, "DataView.prototype.byteLength expects |this| to be a DataView object");
238      if (view->isDetached())
239          return throwVMTypeError(globalObject, scope, "Underlying ArrayBuffer has been detached from the view"_s);
240  
241      return JSValue::encode(jsNumber(view->length()));
242  }
243  
244  JSC_DEFINE_HOST_FUNCTION(dataViewProtoGetterByteOffset, (JSGlobalObject* globalObject, CallFrame* callFrame))
245  {
246      VM& vm = globalObject->vm();
247      auto scope = DECLARE_THROW_SCOPE(vm);
248  
249      JSDataView* view = jsDynamicCast<JSDataView*>(vm, callFrame->thisValue());
250      if (!view)
251          return throwVMTypeError(globalObject, scope, "DataView.prototype.byteOffset expects |this| to be a DataView object");
252      if (view->isDetached())
253          return throwVMTypeError(globalObject, scope, "Underlying ArrayBuffer has been detached from the view"_s);
254  
255      return JSValue::encode(jsNumber(view->byteOffset()));
256  }
257  
258  JSC_DEFINE_HOST_FUNCTION(dataViewProtoFuncGetInt8, (JSGlobalObject* globalObject, CallFrame* callFrame))
259  {
260      return getData<Int8Adaptor>(globalObject, callFrame);
261  }
262  
263  JSC_DEFINE_HOST_FUNCTION(dataViewProtoFuncGetInt16, (JSGlobalObject* globalObject, CallFrame* callFrame))
264  {
265      return getData<Int16Adaptor>(globalObject, callFrame);
266  }
267  
268  JSC_DEFINE_HOST_FUNCTION(dataViewProtoFuncGetInt32, (JSGlobalObject* globalObject, CallFrame* callFrame))
269  {
270      return getData<Int32Adaptor>(globalObject, callFrame);
271  }
272  
273  JSC_DEFINE_HOST_FUNCTION(dataViewProtoFuncGetUint8, (JSGlobalObject* globalObject, CallFrame* callFrame))
274  {
275      return getData<Uint8Adaptor>(globalObject, callFrame);
276  }
277  
278  JSC_DEFINE_HOST_FUNCTION(dataViewProtoFuncGetUint16, (JSGlobalObject* globalObject, CallFrame* callFrame))
279  {
280      return getData<Uint16Adaptor>(globalObject, callFrame);
281  }
282  
283  JSC_DEFINE_HOST_FUNCTION(dataViewProtoFuncGetUint32, (JSGlobalObject* globalObject, CallFrame* callFrame))
284  {
285      return getData<Uint32Adaptor>(globalObject, callFrame);
286  }
287  
288  JSC_DEFINE_HOST_FUNCTION(dataViewProtoFuncGetFloat32, (JSGlobalObject* globalObject, CallFrame* callFrame))
289  {
290      return getData<Float32Adaptor>(globalObject, callFrame);
291  }
292  
293  JSC_DEFINE_HOST_FUNCTION(dataViewProtoFuncGetFloat64, (JSGlobalObject* globalObject, CallFrame* callFrame))
294  {
295      return getData<Float64Adaptor>(globalObject, callFrame);
296  }
297  
298  JSC_DEFINE_HOST_FUNCTION(dataViewProtoFuncSetInt8, (JSGlobalObject* globalObject, CallFrame* callFrame))
299  {
300      return setData<Int8Adaptor>(globalObject, callFrame);
301  }
302  
303  JSC_DEFINE_HOST_FUNCTION(dataViewProtoFuncSetInt16, (JSGlobalObject* globalObject, CallFrame* callFrame))
304  {
305      return setData<Int16Adaptor>(globalObject, callFrame);
306  }
307  
308  JSC_DEFINE_HOST_FUNCTION(dataViewProtoFuncSetInt32, (JSGlobalObject* globalObject, CallFrame* callFrame))
309  {
310      return setData<Int32Adaptor>(globalObject, callFrame);
311  }
312  
313  JSC_DEFINE_HOST_FUNCTION(dataViewProtoFuncSetUint8, (JSGlobalObject* globalObject, CallFrame* callFrame))
314  {
315      return setData<Uint8Adaptor>(globalObject, callFrame);
316  }
317  
318  JSC_DEFINE_HOST_FUNCTION(dataViewProtoFuncSetUint16, (JSGlobalObject* globalObject, CallFrame* callFrame))
319  {
320      return setData<Uint16Adaptor>(globalObject, callFrame);
321  }
322  
323  JSC_DEFINE_HOST_FUNCTION(dataViewProtoFuncSetUint32, (JSGlobalObject* globalObject, CallFrame* callFrame))
324  {
325      return setData<Uint32Adaptor>(globalObject, callFrame);
326  }
327  
328  JSC_DEFINE_HOST_FUNCTION(dataViewProtoFuncSetFloat32, (JSGlobalObject* globalObject, CallFrame* callFrame))
329  {
330      return setData<Float32Adaptor>(globalObject, callFrame);
331  }
332  
333  JSC_DEFINE_HOST_FUNCTION(dataViewProtoFuncSetFloat64, (JSGlobalObject* globalObject, CallFrame* callFrame))
334  {
335      return setData<Float64Adaptor>(globalObject, callFrame);
336  }
337  IGNORE_CLANG_WARNINGS_END
338  
339  } // namespace JSC