• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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