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
3 // found in the LICENSE file.
4
5 #include "src/builtins/builtins-utils-inl.h"
6 #include "src/builtins/builtins.h"
7 #include "src/execution/isolate.h"
8 #include "src/heap/factory.h"
9 #include "src/logging/counters.h"
10 #include "src/numbers/conversions.h"
11 #include "src/objects/js-array-buffer-inl.h"
12 #include "src/objects/objects-inl.h"
13
14 namespace v8 {
15 namespace internal {
16
17 // -----------------------------------------------------------------------------
18 // ES #sec-dataview-objects
19
20 // ES #sec-dataview-constructor
BUILTIN(DataViewConstructor)21 BUILTIN(DataViewConstructor) {
22 const char* const kMethodName = "DataView constructor";
23 HandleScope scope(isolate);
24 // 1. If NewTarget is undefined, throw a TypeError exception.
25 if (args.new_target()->IsUndefined(isolate)) { // [[Call]]
26 THROW_NEW_ERROR_RETURN_FAILURE(
27 isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
28 isolate->factory()->NewStringFromAsciiChecked(
29 "DataView")));
30 }
31 // [[Construct]]
32 Handle<JSFunction> target = args.target();
33 Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
34 Handle<Object> buffer = args.atOrUndefined(isolate, 1);
35 Handle<Object> byte_offset = args.atOrUndefined(isolate, 2);
36 Handle<Object> byte_length = args.atOrUndefined(isolate, 3);
37
38 // 2. Perform ? RequireInternalSlot(buffer, [[ArrayBufferData]]).
39 if (!buffer->IsJSArrayBuffer()) {
40 THROW_NEW_ERROR_RETURN_FAILURE(
41 isolate, NewTypeError(MessageTemplate::kDataViewNotArrayBuffer));
42 }
43 Handle<JSArrayBuffer> array_buffer = Handle<JSArrayBuffer>::cast(buffer);
44
45 // 3. Let offset be ? ToIndex(byteOffset).
46 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
47 isolate, byte_offset,
48 Object::ToIndex(isolate, byte_offset, MessageTemplate::kInvalidOffset));
49 size_t view_byte_offset = byte_offset->Number();
50
51 // 4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
52 if (array_buffer->was_detached()) {
53 THROW_NEW_ERROR_RETURN_FAILURE(
54 isolate, NewTypeError(MessageTemplate::kDetachedOperation,
55 isolate->factory()->NewStringFromAsciiChecked(
56 kMethodName)));
57 }
58
59 // 5. Let bufferByteLength be ArrayBufferByteLength(buffer, SeqCst).
60 size_t buffer_byte_length = array_buffer->GetByteLength();
61
62 // 6. If offset > bufferByteLength, throw a RangeError exception.
63 if (view_byte_offset > buffer_byte_length) {
64 THROW_NEW_ERROR_RETURN_FAILURE(
65 isolate, NewRangeError(MessageTemplate::kInvalidOffset, byte_offset));
66 }
67
68 // 7. Let bufferIsResizable be IsResizableArrayBuffer(buffer).
69 // 8. Let byteLengthChecked be empty.
70 // 9. If bufferIsResizable is true and byteLength is undefined, then
71 // a. Let viewByteLength be auto.
72 // 10. Else if byteLength is undefined, then
73 // a. Let viewByteLength be bufferByteLength - offset.
74 size_t view_byte_length;
75 bool length_tracking = false;
76 if (byte_length->IsUndefined(isolate)) {
77 view_byte_length = buffer_byte_length - view_byte_offset;
78 length_tracking = array_buffer->is_resizable();
79 } else {
80 // 11. Else,
81 // a. Set byteLengthChecked be ? ToIndex(byteLength).
82 // b. Let viewByteLength be byteLengthChecked.
83 // c. If offset + viewByteLength > bufferByteLength, throw a
84 // RangeError exception.
85 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
86 isolate, byte_length,
87 Object::ToIndex(isolate, byte_length,
88 MessageTemplate::kInvalidDataViewLength));
89 if (view_byte_offset + byte_length->Number() > buffer_byte_length) {
90 THROW_NEW_ERROR_RETURN_FAILURE(
91 isolate,
92 NewRangeError(MessageTemplate::kInvalidDataViewLength, byte_length));
93 }
94 view_byte_length = byte_length->Number();
95 }
96
97 // 12. Let O be ? OrdinaryCreateFromConstructor(NewTarget,
98 // "%DataViewPrototype%", «[[DataView]], [[ViewedArrayBuffer]],
99 // [[ByteLength]], [[ByteOffset]]»).
100 Handle<JSObject> result;
101 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
102 isolate, result,
103 JSObject::New(target, new_target, Handle<AllocationSite>::null()));
104 Handle<JSDataView> data_view = Handle<JSDataView>::cast(result);
105 for (int i = 0; i < ArrayBufferView::kEmbedderFieldCount; ++i) {
106 // TODO(v8:10391, saelo): Handle external pointers in EmbedderDataSlot
107 data_view->SetEmbedderField(i, Smi::zero());
108 }
109 data_view->set_bit_field(0);
110 data_view->set_is_backed_by_rab(array_buffer->is_resizable() &&
111 !array_buffer->is_shared());
112 data_view->set_is_length_tracking(length_tracking);
113
114 // We have to set the internal slots before the checks on steps 13 - 17 or
115 // the TorqueGeneratedClassVerifier ended up complaining that the slot is
116 // empty or invalid on heap teardown.
117 // The result object is not observable from JavaScript when steps 13 - 17
118 // early abort so it is fine to set internal slots here.
119
120 // 18. Set O.[[ViewedArrayBuffer]] to buffer.
121 data_view->set_buffer(*array_buffer);
122
123 // 19. Set O.[[ByteLength]] to viewByteLength.
124 data_view->set_byte_length(length_tracking ? 0 : view_byte_length);
125
126 // 20. Set O.[[ByteOffset]] to offset.
127 data_view->set_byte_offset(view_byte_offset);
128 data_view->set_data_pointer(
129 isolate,
130 static_cast<uint8_t*>(array_buffer->backing_store()) + view_byte_offset);
131
132 // 13. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
133 if (array_buffer->was_detached()) {
134 THROW_NEW_ERROR_RETURN_FAILURE(
135 isolate, NewTypeError(MessageTemplate::kDetachedOperation,
136 isolate->factory()->NewStringFromAsciiChecked(
137 kMethodName)));
138 }
139
140 // 14. Let getBufferByteLength be
141 // MakeIdempotentArrayBufferByteLengthGetter(SeqCst).
142 // 15. Set bufferByteLength be getBufferByteLength(buffer).
143 buffer_byte_length = array_buffer->GetByteLength();
144
145 // 16. If offset > bufferByteLength, throw a RangeError exception.
146 if (view_byte_offset > buffer_byte_length) {
147 THROW_NEW_ERROR_RETURN_FAILURE(
148 isolate, NewRangeError(MessageTemplate::kInvalidOffset, byte_offset));
149 }
150
151 // 17. If byteLengthChecked is not empty, then
152 // a. If offset + viewByteLength > bufferByteLength, throw a RangeError
153 // exception.
154 if (!length_tracking &&
155 view_byte_offset + view_byte_length > buffer_byte_length) {
156 THROW_NEW_ERROR_RETURN_FAILURE(
157 isolate, NewRangeError(MessageTemplate::kInvalidDataViewLength));
158 }
159
160 // 21. Return O.
161 return *result;
162 }
163
164 } // namespace internal
165 } // namespace v8
166