OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/builtins/builtins.h" | 5 #include "src/builtins/builtins.h" |
6 #include "src/builtins/builtins-utils.h" | 6 #include "src/builtins/builtins-utils.h" |
7 | 7 |
8 namespace v8 { | 8 namespace v8 { |
9 namespace internal { | 9 namespace internal { |
10 | 10 |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 | 122 |
123 // ES6 section 24.2.4.3 get DataView.prototype.byteOffset | 123 // ES6 section 24.2.4.3 get DataView.prototype.byteOffset |
124 BUILTIN(DataViewPrototypeGetByteOffset) { | 124 BUILTIN(DataViewPrototypeGetByteOffset) { |
125 HandleScope scope(isolate); | 125 HandleScope scope(isolate); |
126 CHECK_RECEIVER(JSDataView, data_view, "get DataView.prototype.byteOffset"); | 126 CHECK_RECEIVER(JSDataView, data_view, "get DataView.prototype.byteOffset"); |
127 // TODO(bmeurer): According to the ES6 spec, we should throw a TypeError | 127 // TODO(bmeurer): According to the ES6 spec, we should throw a TypeError |
128 // here if the JSArrayBuffer of the {data_view} was neutered. | 128 // here if the JSArrayBuffer of the {data_view} was neutered. |
129 return data_view->byte_offset(); | 129 return data_view->byte_offset(); |
130 } | 130 } |
131 | 131 |
| 132 namespace { |
| 133 |
| 134 bool NeedToFlipBytes(bool is_little_endian) { |
| 135 #ifdef V8_TARGET_LITTLE_ENDIAN |
| 136 return !is_little_endian; |
| 137 #else |
| 138 return is_little_endian; |
| 139 #endif |
| 140 } |
| 141 |
| 142 template <size_t n> |
| 143 void CopyBytes(uint8_t* target, uint8_t const* source) { |
| 144 for (size_t i = 0; i < n; i++) { |
| 145 *(target++) = *(source++); |
| 146 } |
| 147 } |
| 148 |
| 149 template <size_t n> |
| 150 void FlipBytes(uint8_t* target, uint8_t const* source) { |
| 151 source = source + (n - 1); |
| 152 for (size_t i = 0; i < n; i++) { |
| 153 *(target++) = *(source--); |
| 154 } |
| 155 } |
| 156 |
| 157 // ES6 section 24.2.1.1 GetViewValue (view, requestIndex, isLittleEndian, type) |
| 158 template <typename T> |
| 159 MaybeHandle<Object> GetViewValue(Isolate* isolate, Handle<JSDataView> data_view, |
| 160 Handle<Object> request_index, |
| 161 bool is_little_endian) { |
| 162 ASSIGN_RETURN_ON_EXCEPTION( |
| 163 isolate, request_index, |
| 164 Object::ToIndex(isolate, request_index, |
| 165 MessageTemplate::kInvalidDataViewAccessorOffset), |
| 166 Object); |
| 167 size_t get_index = 0; |
| 168 if (!TryNumberToSize(*request_index, &get_index)) { |
| 169 THROW_NEW_ERROR( |
| 170 isolate, NewRangeError(MessageTemplate::kInvalidDataViewAccessorOffset), |
| 171 Object); |
| 172 } |
| 173 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()), |
| 174 isolate); |
| 175 size_t const data_view_byte_offset = NumberToSize(data_view->byte_offset()); |
| 176 size_t const data_view_byte_length = NumberToSize(data_view->byte_length()); |
| 177 if (get_index + sizeof(T) > data_view_byte_length || |
| 178 get_index + sizeof(T) < get_index) { // overflow |
| 179 THROW_NEW_ERROR( |
| 180 isolate, NewRangeError(MessageTemplate::kInvalidDataViewAccessorOffset), |
| 181 Object); |
| 182 } |
| 183 union { |
| 184 T data; |
| 185 uint8_t bytes[sizeof(T)]; |
| 186 } v; |
| 187 size_t const buffer_offset = data_view_byte_offset + get_index; |
| 188 DCHECK_GE(NumberToSize(buffer->byte_length()), buffer_offset + sizeof(T)); |
| 189 uint8_t const* const source = |
| 190 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset; |
| 191 if (NeedToFlipBytes(is_little_endian)) { |
| 192 FlipBytes<sizeof(T)>(v.bytes, source); |
| 193 } else { |
| 194 CopyBytes<sizeof(T)>(v.bytes, source); |
| 195 } |
| 196 return isolate->factory()->NewNumber(v.data); |
| 197 } |
| 198 |
| 199 template <typename T> |
| 200 T DataViewConvertValue(double value); |
| 201 |
| 202 template <> |
| 203 int8_t DataViewConvertValue<int8_t>(double value) { |
| 204 return static_cast<int8_t>(DoubleToInt32(value)); |
| 205 } |
| 206 |
| 207 template <> |
| 208 int16_t DataViewConvertValue<int16_t>(double value) { |
| 209 return static_cast<int16_t>(DoubleToInt32(value)); |
| 210 } |
| 211 |
| 212 template <> |
| 213 int32_t DataViewConvertValue<int32_t>(double value) { |
| 214 return DoubleToInt32(value); |
| 215 } |
| 216 |
| 217 template <> |
| 218 uint8_t DataViewConvertValue<uint8_t>(double value) { |
| 219 return static_cast<uint8_t>(DoubleToUint32(value)); |
| 220 } |
| 221 |
| 222 template <> |
| 223 uint16_t DataViewConvertValue<uint16_t>(double value) { |
| 224 return static_cast<uint16_t>(DoubleToUint32(value)); |
| 225 } |
| 226 |
| 227 template <> |
| 228 uint32_t DataViewConvertValue<uint32_t>(double value) { |
| 229 return DoubleToUint32(value); |
| 230 } |
| 231 |
| 232 template <> |
| 233 float DataViewConvertValue<float>(double value) { |
| 234 return static_cast<float>(value); |
| 235 } |
| 236 |
| 237 template <> |
| 238 double DataViewConvertValue<double>(double value) { |
| 239 return value; |
| 240 } |
| 241 |
| 242 // ES6 section 24.2.1.2 SetViewValue (view, requestIndex, isLittleEndian, type, |
| 243 // value) |
| 244 template <typename T> |
| 245 MaybeHandle<Object> SetViewValue(Isolate* isolate, Handle<JSDataView> data_view, |
| 246 Handle<Object> request_index, |
| 247 bool is_little_endian, Handle<Object> value) { |
| 248 ASSIGN_RETURN_ON_EXCEPTION( |
| 249 isolate, request_index, |
| 250 Object::ToIndex(isolate, request_index, |
| 251 MessageTemplate::kInvalidDataViewAccessorOffset), |
| 252 Object); |
| 253 ASSIGN_RETURN_ON_EXCEPTION(isolate, value, Object::ToNumber(value), Object); |
| 254 size_t get_index = 0; |
| 255 if (!TryNumberToSize(*request_index, &get_index)) { |
| 256 THROW_NEW_ERROR( |
| 257 isolate, NewRangeError(MessageTemplate::kInvalidDataViewAccessorOffset), |
| 258 Object); |
| 259 } |
| 260 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()), |
| 261 isolate); |
| 262 size_t const data_view_byte_offset = NumberToSize(data_view->byte_offset()); |
| 263 size_t const data_view_byte_length = NumberToSize(data_view->byte_length()); |
| 264 if (get_index + sizeof(T) > data_view_byte_length || |
| 265 get_index + sizeof(T) < get_index) { // overflow |
| 266 THROW_NEW_ERROR( |
| 267 isolate, NewRangeError(MessageTemplate::kInvalidDataViewAccessorOffset), |
| 268 Object); |
| 269 } |
| 270 union { |
| 271 T data; |
| 272 uint8_t bytes[sizeof(T)]; |
| 273 } v; |
| 274 v.data = DataViewConvertValue<T>(value->Number()); |
| 275 size_t const buffer_offset = data_view_byte_offset + get_index; |
| 276 DCHECK(NumberToSize(buffer->byte_length()) >= buffer_offset + sizeof(T)); |
| 277 uint8_t* const target = |
| 278 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset; |
| 279 if (NeedToFlipBytes(is_little_endian)) { |
| 280 FlipBytes<sizeof(T)>(target, v.bytes); |
| 281 } else { |
| 282 CopyBytes<sizeof(T)>(target, v.bytes); |
| 283 } |
| 284 return isolate->factory()->undefined_value(); |
| 285 } |
| 286 |
| 287 } // namespace |
| 288 |
| 289 #define DATA_VIEW_PROTOTYPE_GET(Type, type) \ |
| 290 BUILTIN(DataViewPrototypeGet##Type) { \ |
| 291 HandleScope scope(isolate); \ |
| 292 CHECK_RECEIVER(JSDataView, data_view, "DataView.prototype.get" #Type); \ |
| 293 Handle<Object> byte_offset = args.atOrUndefined(isolate, 1); \ |
| 294 Handle<Object> is_little_endian = args.atOrUndefined(isolate, 2); \ |
| 295 Handle<Object> result; \ |
| 296 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( \ |
| 297 isolate, result, \ |
| 298 GetViewValue<type>(isolate, data_view, byte_offset, \ |
| 299 is_little_endian->BooleanValue())); \ |
| 300 return *result; \ |
| 301 } |
| 302 DATA_VIEW_PROTOTYPE_GET(Int8, int8_t) |
| 303 DATA_VIEW_PROTOTYPE_GET(Uint8, uint8_t) |
| 304 DATA_VIEW_PROTOTYPE_GET(Int16, int16_t) |
| 305 DATA_VIEW_PROTOTYPE_GET(Uint16, uint16_t) |
| 306 DATA_VIEW_PROTOTYPE_GET(Int32, int32_t) |
| 307 DATA_VIEW_PROTOTYPE_GET(Uint32, uint32_t) |
| 308 DATA_VIEW_PROTOTYPE_GET(Float32, float) |
| 309 DATA_VIEW_PROTOTYPE_GET(Float64, double) |
| 310 #undef DATA_VIEW_PROTOTYPE_GET |
| 311 |
| 312 #define DATA_VIEW_PROTOTYPE_SET(Type, type) \ |
| 313 BUILTIN(DataViewPrototypeSet##Type) { \ |
| 314 HandleScope scope(isolate); \ |
| 315 CHECK_RECEIVER(JSDataView, data_view, "DataView.prototype.set" #Type); \ |
| 316 Handle<Object> byte_offset = args.atOrUndefined(isolate, 1); \ |
| 317 Handle<Object> value = args.atOrUndefined(isolate, 2); \ |
| 318 Handle<Object> is_little_endian = args.atOrUndefined(isolate, 3); \ |
| 319 Handle<Object> result; \ |
| 320 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( \ |
| 321 isolate, result, \ |
| 322 SetViewValue<type>(isolate, data_view, byte_offset, \ |
| 323 is_little_endian->BooleanValue(), value)); \ |
| 324 return *result; \ |
| 325 } |
| 326 DATA_VIEW_PROTOTYPE_SET(Int8, int8_t) |
| 327 DATA_VIEW_PROTOTYPE_SET(Uint8, uint8_t) |
| 328 DATA_VIEW_PROTOTYPE_SET(Int16, int16_t) |
| 329 DATA_VIEW_PROTOTYPE_SET(Uint16, uint16_t) |
| 330 DATA_VIEW_PROTOTYPE_SET(Int32, int32_t) |
| 331 DATA_VIEW_PROTOTYPE_SET(Uint32, uint32_t) |
| 332 DATA_VIEW_PROTOTYPE_SET(Float32, float) |
| 333 DATA_VIEW_PROTOTYPE_SET(Float64, double) |
| 334 #undef DATA_VIEW_PROTOTYPE_SET |
| 335 |
132 } // namespace internal | 336 } // namespace internal |
133 } // namespace v8 | 337 } // namespace v8 |
OLD | NEW |