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