Index: src/runtime.cc |
diff --git a/src/runtime.cc b/src/runtime.cc |
index 0046ff667ead130fd9bb19c70caf972d90e17cd4..966e6cce1c9f37dfa2c43fc15af19ab4f760cc69 100644 |
--- a/src/runtime.cc |
+++ b/src/runtime.cc |
@@ -1003,6 +1003,256 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) { |
} |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewInitialize) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 4); |
+ CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); |
+ CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset, 2); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, byte_length, 3); |
+ |
+ holder->set_buffer(*buffer); |
+ ASSERT(byte_offset->IsNumber()); |
+ ASSERT( |
+ NumberToSize(isolate, buffer->byte_length()) >= |
+ NumberToSize(isolate, *byte_offset) |
+ + NumberToSize(isolate, *byte_length)); |
+ holder->set_byte_offset(*byte_offset); |
+ ASSERT(byte_length->IsNumber()); |
+ holder->set_byte_length(*byte_length); |
+ |
+ holder->set_weak_next(buffer->weak_first_array()); |
+ buffer->set_weak_first_array(*holder); |
+ |
+ return isolate->heap()->undefined_value(); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetBuffer) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 1); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, holder, 0); |
+ if (!holder->IsJSDataView()) { |
rossberg
2013/06/21 08:44:01
Why not move this check to the JavaScript side? (h
Dmitry Lomov (no reviews)
2013/06/21 11:32:10
Done.
|
+ return isolate->Throw(*isolate->factory()->NewTypeError( |
+ "not_data_view", HandleVector<Object>(NULL, 0))); |
+ } |
+ Handle<JSDataView> data_view(JSDataView::cast(*holder)); |
+ return data_view->buffer(); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteOffset) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 1); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, holder, 0); |
+ if (!holder->IsJSDataView()) { |
+ return isolate->Throw(*isolate->factory()->NewTypeError( |
+ "not_data_view", HandleVector<Object>(NULL, 0))); |
+ } |
+ Handle<JSDataView> data_view(JSDataView::cast(*holder)); |
+ return data_view->byte_offset(); |
+} |
+ |
+ |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGetByteLength) { |
+ HandleScope scope(isolate); |
+ ASSERT(args.length() == 1); |
+ CONVERT_ARG_HANDLE_CHECKED(Object, holder, 0); |
+ if (!holder->IsJSDataView()) { |
+ return isolate->Throw(*isolate->factory()->NewTypeError( |
+ "not_data_view", HandleVector<Object>(NULL, 0))); |
+ } |
+ Handle<JSDataView> data_view(JSDataView::cast(*holder)); |
+ return data_view->byte_length(); |
+} |
+ |
+ |
+inline static bool NeedToFlipBytes(bool is_little_endian) { |
+#ifdef V8_TARGET_LITTLE_ENDIAN |
+ return !is_little_endian; |
+#else |
+ return is_little_endian; |
+#endif |
+} |
+ |
+ |
+inline void SwapBytes(uint8_t* p, uint8_t* q) { |
+ uint8_t temp = *p; |
rossberg
2013/06/21 08:44:01
Nit: indentation
Dmitry Lomov (no reviews)
2013/06/21 11:32:10
Done.
|
+ *p = *q; |
+ *q = temp; |
+} |
+ |
+ |
+template<int n> |
+void FlipBytes(uint8_t* p, bool is_little_endian); |
+ |
+ |
+template<> |
+void FlipBytes<1>(uint8_t*, bool) {} |
+ |
+ |
+template<> |
+void FlipBytes<2>(uint8_t* p, bool is_little_endian) { |
+ if (!NeedToFlipBytes(is_little_endian)) return; |
+ SwapBytes(p, p+1); |
+} |
+ |
+ |
+template<> |
+void FlipBytes<4>(uint8_t* p, bool is_little_endian) { |
+ if (!NeedToFlipBytes(is_little_endian)) return; |
+ SwapBytes(p+1, p+2); |
+ SwapBytes(p, p+3); |
+} |
+ |
+ |
+template<> |
+void FlipBytes<8>(uint8_t* p, bool is_little_endian) { |
+ if (!NeedToFlipBytes(is_little_endian)) return; |
+ SwapBytes(p+3, p+4); |
+ SwapBytes(p+2, p+5); |
+ SwapBytes(p+1, p+6); |
+ SwapBytes(p, p+7); |
+} |
+ |
+ |
+template<typename T> |
+inline static bool DataViewGetValue( |
+ Isolate* isolate, |
+ Handle<JSDataView> data_view, |
+ Handle<Object> byte_offset_obj, |
+ bool is_little_endian, |
+ T* result) { |
+ size_t byte_offset = NumberToSize(isolate, *byte_offset_obj); |
+ Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer())); |
+ |
+ size_t data_view_byte_offset = |
+ NumberToSize(isolate, data_view->byte_offset()); |
+ size_t data_view_byte_length = |
+ NumberToSize(isolate, data_view->byte_length()); |
+ if (byte_offset + sizeof(T) > data_view_byte_length || |
+ byte_offset + sizeof(T) < byte_offset) { // overflow |
+ return false; |
+ } |
+ |
+ union Value { |
+ T data; |
rossberg
2013/06/21 08:44:01
Nit: indentation
Dmitry Lomov (no reviews)
2013/06/21 11:32:10
Done. Didn't move this to v8utils.h, because it lo
|
+ uint8_t bytes[sizeof(T)]; |
+ }; |
+ |
+ Value value; |
+ size_t buffer_offset = data_view_byte_offset + byte_offset; |
+ ASSERT( |
+ NumberToSize(isolate, buffer->byte_length()) |
+ >= buffer_offset + sizeof(T)); |
+ OS::MemCopy(value.bytes, |
rossberg
2013/06/21 08:44:01
OS::MemCopy seems overkill here. Use at least the
Dmitry Lomov (no reviews)
2013/06/21 11:32:10
Done.
|
+ static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset, |
+ sizeof(T)); |
+ FlipBytes<sizeof(T)>(value.bytes, is_little_endian); |
+ *result = value.data; |
+ return true; |
+} |
+ |
+ |
+template<typename T> |
+static bool DataViewSetValue( |
+ Isolate* isolate, |
+ Handle<JSDataView> data_view, |
+ Handle<Object> byte_offset_obj, |
+ bool is_little_endian, |
+ T data) { |
+ size_t byte_offset = NumberToSize(isolate, *byte_offset_obj); |
+ Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer())); |
+ |
+ size_t data_view_byte_offset = |
+ NumberToSize(isolate, data_view->byte_offset()); |
+ size_t data_view_byte_length = |
+ NumberToSize(isolate, data_view->byte_length()); |
+ if (byte_offset + sizeof(T) > data_view_byte_length || |
+ byte_offset + sizeof(T) < byte_offset) { // overflow |
+ return false; |
+ } |
+ |
+ union Value { |
+ T data; |
rossberg
2013/06/21 08:44:01
Nit: indentation
Dmitry Lomov (no reviews)
2013/06/21 11:32:10
Done.
|
+ uint8_t bytes[sizeof(T)]; |
+ }; |
+ |
+ Value value; |
+ value.data = data; |
+ size_t buffer_offset = data_view_byte_offset + byte_offset; |
+ ASSERT( |
+ NumberToSize(isolate, buffer->byte_length()) |
+ >= buffer_offset + sizeof(T)); |
+ FlipBytes<sizeof(T)>(value.bytes, is_little_endian); |
+ OS::MemCopy( |
+ static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset, |
+ value.bytes, |
+ sizeof(T)); |
+ return true; |
+} |
+ |
+ |
+#define DATA_VIEW_GETTER(TypeName, Type, Convertor) \ |
rossberg
2013/06/21 08:44:01
Nit: I think the spelling is Converter
Dmitry Lomov (no reviews)
2013/06/21 11:32:10
Done.
Dmitry Lomov (no reviews)
2013/06/21 11:32:10
Done.
|
+ RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewGet##TypeName) { \ |
+ HandleScope scope(isolate); \ |
+ ASSERT(args.length() == 3); \ |
+ CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \ |
+ CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \ |
+ CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \ |
+ Type result; \ |
+ if (DataViewGetValue( \ |
+ isolate, holder, offset, is_little_endian, &result)) { \ |
+ return isolate->heap()->Convertor(result); \ |
+ } else { \ |
+ return isolate->Throw(*isolate->factory()->NewRangeError( \ |
+ "invalid_data_view_accessor_offset", \ |
+ HandleVector<Object>(NULL, 0))); \ |
+ } \ |
+ } |
+ |
+DATA_VIEW_GETTER(Uint8, uint8_t, NumberFromUint32) |
+DATA_VIEW_GETTER(Int8, int8_t, NumberFromInt32) |
+DATA_VIEW_GETTER(Uint16, uint16_t, NumberFromUint32) |
+DATA_VIEW_GETTER(Int16, int16_t, NumberFromInt32) |
+DATA_VIEW_GETTER(Uint32, uint32_t, NumberFromUint32) |
+DATA_VIEW_GETTER(Int32, int32_t, NumberFromInt32) |
+DATA_VIEW_GETTER(Float32, float, NumberFromDouble) |
+DATA_VIEW_GETTER(Float64, double, NumberFromDouble) |
+ |
+#undef DATA_VIEW_GETTER |
+ |
+#define DATA_VIEW_SETTER(TypeName, Type) \ |
+ RUNTIME_FUNCTION(MaybeObject*, Runtime_DataViewSet##TypeName) { \ |
+ HandleScope scope(isolate); \ |
+ ASSERT(args.length() == 4); \ |
+ CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \ |
+ CONVERT_ARG_HANDLE_CHECKED(Object, offset, 1); \ |
+ CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); \ |
+ CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \ |
+ Type v = static_cast<Type>(value->Number()); \ |
+ if (DataViewSetValue( \ |
+ isolate, holder, offset, is_little_endian, v)) { \ |
+ return isolate->heap()->undefined_value(); \ |
+ } else { \ |
+ return isolate->Throw(*isolate->factory()->NewRangeError( \ |
+ "invalid_data_view_accessor_offset", \ |
+ HandleVector<Object>(NULL, 0))); \ |
+ } \ |
+ } |
+ |
+DATA_VIEW_SETTER(Uint8, uint8_t) |
+DATA_VIEW_SETTER(Int8, int8_t) |
+DATA_VIEW_SETTER(Uint16, uint16_t) |
+DATA_VIEW_SETTER(Int16, int16_t) |
+DATA_VIEW_SETTER(Uint32, uint32_t) |
+DATA_VIEW_SETTER(Int32, int32_t) |
+DATA_VIEW_SETTER(Float32, float) |
+DATA_VIEW_SETTER(Float64, double) |
+ |
+#undef DATA_VIEW_SETTER |
+ |
+ |
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) { |
HandleScope scope(isolate); |
ASSERT(args.length() == 1); |