| Index: src/builtins/builtins-dataview.cc
|
| diff --git a/src/builtins/builtins-dataview.cc b/src/builtins/builtins-dataview.cc
|
| index 32c5a83d2f9cd6f0a2e939881e51fc3e871b4e47..3d14e31d3a3ba377f47eb2dc2b46e66461169849 100644
|
| --- a/src/builtins/builtins-dataview.cc
|
| +++ b/src/builtins/builtins-dataview.cc
|
| @@ -129,5 +129,209 @@ BUILTIN(DataViewPrototypeGetByteOffset) {
|
| return data_view->byte_offset();
|
| }
|
|
|
| +namespace {
|
| +
|
| +bool NeedToFlipBytes(bool is_little_endian) {
|
| +#ifdef V8_TARGET_LITTLE_ENDIAN
|
| + return !is_little_endian;
|
| +#else
|
| + return is_little_endian;
|
| +#endif
|
| +}
|
| +
|
| +template <size_t n>
|
| +void CopyBytes(uint8_t* target, uint8_t const* source) {
|
| + for (size_t i = 0; i < n; i++) {
|
| + *(target++) = *(source++);
|
| + }
|
| +}
|
| +
|
| +template <size_t n>
|
| +void FlipBytes(uint8_t* target, uint8_t const* source) {
|
| + source = source + (n - 1);
|
| + for (size_t i = 0; i < n; i++) {
|
| + *(target++) = *(source--);
|
| + }
|
| +}
|
| +
|
| +// ES6 section 24.2.1.1 GetViewValue (view, requestIndex, isLittleEndian, type)
|
| +template <typename T>
|
| +MaybeHandle<Object> GetViewValue(Isolate* isolate, Handle<JSDataView> data_view,
|
| + Handle<Object> request_index,
|
| + bool is_little_endian) {
|
| + ASSIGN_RETURN_ON_EXCEPTION(
|
| + isolate, request_index,
|
| + Object::ToIndex(isolate, request_index,
|
| + MessageTemplate::kInvalidDataViewAccessorOffset),
|
| + Object);
|
| + size_t get_index = 0;
|
| + if (!TryNumberToSize(*request_index, &get_index)) {
|
| + THROW_NEW_ERROR(
|
| + isolate, NewRangeError(MessageTemplate::kInvalidDataViewAccessorOffset),
|
| + Object);
|
| + }
|
| + Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()),
|
| + isolate);
|
| + size_t const data_view_byte_offset = NumberToSize(data_view->byte_offset());
|
| + size_t const data_view_byte_length = NumberToSize(data_view->byte_length());
|
| + if (get_index + sizeof(T) > data_view_byte_length ||
|
| + get_index + sizeof(T) < get_index) { // overflow
|
| + THROW_NEW_ERROR(
|
| + isolate, NewRangeError(MessageTemplate::kInvalidDataViewAccessorOffset),
|
| + Object);
|
| + }
|
| + union {
|
| + T data;
|
| + uint8_t bytes[sizeof(T)];
|
| + } v;
|
| + size_t const buffer_offset = data_view_byte_offset + get_index;
|
| + DCHECK_GE(NumberToSize(buffer->byte_length()), buffer_offset + sizeof(T));
|
| + uint8_t const* const source =
|
| + static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
|
| + if (NeedToFlipBytes(is_little_endian)) {
|
| + FlipBytes<sizeof(T)>(v.bytes, source);
|
| + } else {
|
| + CopyBytes<sizeof(T)>(v.bytes, source);
|
| + }
|
| + return isolate->factory()->NewNumber(v.data);
|
| +}
|
| +
|
| +template <typename T>
|
| +T DataViewConvertValue(double value);
|
| +
|
| +template <>
|
| +int8_t DataViewConvertValue<int8_t>(double value) {
|
| + return static_cast<int8_t>(DoubleToInt32(value));
|
| +}
|
| +
|
| +template <>
|
| +int16_t DataViewConvertValue<int16_t>(double value) {
|
| + return static_cast<int16_t>(DoubleToInt32(value));
|
| +}
|
| +
|
| +template <>
|
| +int32_t DataViewConvertValue<int32_t>(double value) {
|
| + return DoubleToInt32(value);
|
| +}
|
| +
|
| +template <>
|
| +uint8_t DataViewConvertValue<uint8_t>(double value) {
|
| + return static_cast<uint8_t>(DoubleToUint32(value));
|
| +}
|
| +
|
| +template <>
|
| +uint16_t DataViewConvertValue<uint16_t>(double value) {
|
| + return static_cast<uint16_t>(DoubleToUint32(value));
|
| +}
|
| +
|
| +template <>
|
| +uint32_t DataViewConvertValue<uint32_t>(double value) {
|
| + return DoubleToUint32(value);
|
| +}
|
| +
|
| +template <>
|
| +float DataViewConvertValue<float>(double value) {
|
| + return static_cast<float>(value);
|
| +}
|
| +
|
| +template <>
|
| +double DataViewConvertValue<double>(double value) {
|
| + return value;
|
| +}
|
| +
|
| +// ES6 section 24.2.1.2 SetViewValue (view, requestIndex, isLittleEndian, type,
|
| +// value)
|
| +template <typename T>
|
| +MaybeHandle<Object> SetViewValue(Isolate* isolate, Handle<JSDataView> data_view,
|
| + Handle<Object> request_index,
|
| + bool is_little_endian, Handle<Object> value) {
|
| + ASSIGN_RETURN_ON_EXCEPTION(
|
| + isolate, request_index,
|
| + Object::ToIndex(isolate, request_index,
|
| + MessageTemplate::kInvalidDataViewAccessorOffset),
|
| + Object);
|
| + ASSIGN_RETURN_ON_EXCEPTION(isolate, value, Object::ToNumber(value), Object);
|
| + size_t get_index = 0;
|
| + if (!TryNumberToSize(*request_index, &get_index)) {
|
| + THROW_NEW_ERROR(
|
| + isolate, NewRangeError(MessageTemplate::kInvalidDataViewAccessorOffset),
|
| + Object);
|
| + }
|
| + Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()),
|
| + isolate);
|
| + size_t const data_view_byte_offset = NumberToSize(data_view->byte_offset());
|
| + size_t const data_view_byte_length = NumberToSize(data_view->byte_length());
|
| + if (get_index + sizeof(T) > data_view_byte_length ||
|
| + get_index + sizeof(T) < get_index) { // overflow
|
| + THROW_NEW_ERROR(
|
| + isolate, NewRangeError(MessageTemplate::kInvalidDataViewAccessorOffset),
|
| + Object);
|
| + }
|
| + union {
|
| + T data;
|
| + uint8_t bytes[sizeof(T)];
|
| + } v;
|
| + v.data = DataViewConvertValue<T>(value->Number());
|
| + size_t const buffer_offset = data_view_byte_offset + get_index;
|
| + DCHECK(NumberToSize(buffer->byte_length()) >= buffer_offset + sizeof(T));
|
| + uint8_t* const target =
|
| + static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
|
| + if (NeedToFlipBytes(is_little_endian)) {
|
| + FlipBytes<sizeof(T)>(target, v.bytes);
|
| + } else {
|
| + CopyBytes<sizeof(T)>(target, v.bytes);
|
| + }
|
| + return isolate->factory()->undefined_value();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +#define DATA_VIEW_PROTOTYPE_GET(Type, type) \
|
| + BUILTIN(DataViewPrototypeGet##Type) { \
|
| + HandleScope scope(isolate); \
|
| + CHECK_RECEIVER(JSDataView, data_view, "DataView.prototype.get" #Type); \
|
| + Handle<Object> byte_offset = args.atOrUndefined(isolate, 1); \
|
| + Handle<Object> is_little_endian = args.atOrUndefined(isolate, 2); \
|
| + Handle<Object> result; \
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( \
|
| + isolate, result, \
|
| + GetViewValue<type>(isolate, data_view, byte_offset, \
|
| + is_little_endian->BooleanValue())); \
|
| + return *result; \
|
| + }
|
| +DATA_VIEW_PROTOTYPE_GET(Int8, int8_t)
|
| +DATA_VIEW_PROTOTYPE_GET(Uint8, uint8_t)
|
| +DATA_VIEW_PROTOTYPE_GET(Int16, int16_t)
|
| +DATA_VIEW_PROTOTYPE_GET(Uint16, uint16_t)
|
| +DATA_VIEW_PROTOTYPE_GET(Int32, int32_t)
|
| +DATA_VIEW_PROTOTYPE_GET(Uint32, uint32_t)
|
| +DATA_VIEW_PROTOTYPE_GET(Float32, float)
|
| +DATA_VIEW_PROTOTYPE_GET(Float64, double)
|
| +#undef DATA_VIEW_PROTOTYPE_GET
|
| +
|
| +#define DATA_VIEW_PROTOTYPE_SET(Type, type) \
|
| + BUILTIN(DataViewPrototypeSet##Type) { \
|
| + HandleScope scope(isolate); \
|
| + CHECK_RECEIVER(JSDataView, data_view, "DataView.prototype.set" #Type); \
|
| + Handle<Object> byte_offset = args.atOrUndefined(isolate, 1); \
|
| + Handle<Object> value = args.atOrUndefined(isolate, 2); \
|
| + Handle<Object> is_little_endian = args.atOrUndefined(isolate, 3); \
|
| + Handle<Object> result; \
|
| + ASSIGN_RETURN_FAILURE_ON_EXCEPTION( \
|
| + isolate, result, \
|
| + SetViewValue<type>(isolate, data_view, byte_offset, \
|
| + is_little_endian->BooleanValue(), value)); \
|
| + return *result; \
|
| + }
|
| +DATA_VIEW_PROTOTYPE_SET(Int8, int8_t)
|
| +DATA_VIEW_PROTOTYPE_SET(Uint8, uint8_t)
|
| +DATA_VIEW_PROTOTYPE_SET(Int16, int16_t)
|
| +DATA_VIEW_PROTOTYPE_SET(Uint16, uint16_t)
|
| +DATA_VIEW_PROTOTYPE_SET(Int32, int32_t)
|
| +DATA_VIEW_PROTOTYPE_SET(Uint32, uint32_t)
|
| +DATA_VIEW_PROTOTYPE_SET(Float32, float)
|
| +DATA_VIEW_PROTOTYPE_SET(Float64, double)
|
| +#undef DATA_VIEW_PROTOTYPE_SET
|
| +
|
| } // namespace internal
|
| } // namespace v8
|
|
|