Line data Source code
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.h"
6 : #include "src/builtins/builtins.h"
7 : #include "src/conversions.h"
8 : #include "src/counters.h"
9 : #include "src/objects-inl.h"
10 :
11 : namespace v8 {
12 : namespace internal {
13 :
14 : #define CHECK_SHARED(expected, name, method) \
15 : if (name->is_shared() != expected) { \
16 : THROW_NEW_ERROR_RETURN_FAILURE( \
17 : isolate, \
18 : NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, \
19 : isolate->factory()->NewStringFromAsciiChecked(method), \
20 : name)); \
21 : }
22 :
23 : // -----------------------------------------------------------------------------
24 : // ES6 section 21.1 ArrayBuffer Objects
25 :
26 : // ES6 section 24.1.2.1 ArrayBuffer ( length ) for the [[Call]] case.
27 261 : BUILTIN(ArrayBufferConstructor) {
28 : HandleScope scope(isolate);
29 : Handle<JSFunction> target = args.target();
30 : DCHECK(*target == target->native_context()->array_buffer_fun() ||
31 : *target == target->native_context()->shared_array_buffer_fun());
32 261 : THROW_NEW_ERROR_RETURN_FAILURE(
33 : isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
34 : handle(target->shared()->name(), isolate)));
35 : }
36 :
37 : namespace {
38 :
39 120905 : Object* ConstructBuffer(Isolate* isolate, Handle<JSFunction> target,
40 : Handle<JSReceiver> new_target, Handle<Object> length,
41 : bool initialize) {
42 : Handle<JSObject> result;
43 241810 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
44 : JSObject::New(target, new_target));
45 : size_t byte_length;
46 120905 : if (!TryNumberToSize(*length, &byte_length)) {
47 0 : THROW_NEW_ERROR_RETURN_FAILURE(
48 : isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength));
49 : }
50 : SharedFlag shared_flag =
51 : (*target == target->native_context()->array_buffer_fun())
52 : ? SharedFlag::kNotShared
53 120905 : : SharedFlag::kShared;
54 120905 : if (!JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer>::cast(result),
55 : isolate, byte_length, initialize,
56 120905 : shared_flag)) {
57 0 : THROW_NEW_ERROR_RETURN_FAILURE(
58 : isolate, NewRangeError(MessageTemplate::kArrayBufferAllocationFailed));
59 : }
60 120905 : return *result;
61 : }
62 :
63 : } // namespace
64 :
65 : // ES6 section 24.1.2.1 ArrayBuffer ( length ) for the [[Construct]] case.
66 358635 : BUILTIN(ArrayBufferConstructor_ConstructStub) {
67 : HandleScope scope(isolate);
68 119545 : Handle<JSFunction> target = args.target();
69 119545 : Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
70 : Handle<Object> length = args.atOrUndefined(isolate, 1);
71 : DCHECK(*target == target->native_context()->array_buffer_fun() ||
72 : *target == target->native_context()->shared_array_buffer_fun());
73 :
74 : Handle<Object> number_length;
75 119545 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_length,
76 : Object::ToInteger(isolate, length));
77 119545 : if (number_length->Number() < 0.0) {
78 198 : THROW_NEW_ERROR_RETURN_FAILURE(
79 : isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength));
80 : }
81 :
82 119446 : return ConstructBuffer(isolate, target, new_target, number_length, true);
83 : }
84 :
85 : // This is a helper to construct an ArrayBuffer with uinitialized memory.
86 : // This means the caller must ensure the buffer is totally initialized in
87 : // all cases, or we will expose uinitialized memory to user code.
88 4377 : BUILTIN(ArrayBufferConstructor_DoNotInitialize) {
89 : HandleScope scope(isolate);
90 2918 : Handle<JSFunction> target(isolate->native_context()->array_buffer_fun());
91 1459 : Handle<Object> length = args.atOrUndefined(isolate, 1);
92 2918 : return ConstructBuffer(isolate, target, target, length, false);
93 : }
94 :
95 : // ES6 section 24.1.4.1 get ArrayBuffer.prototype.byteLength
96 59586 : BUILTIN(ArrayBufferPrototypeGetByteLength) {
97 : const char* const kMethodName = "get ArrayBuffer.prototype.byteLength";
98 : HandleScope scope(isolate);
99 19946 : CHECK_RECEIVER(JSArrayBuffer, array_buffer, kMethodName);
100 19876 : CHECK_SHARED(false, array_buffer, kMethodName);
101 : // TODO(franzih): According to the ES6 spec, we should throw a TypeError
102 : // here if the JSArrayBuffer is detached.
103 19820 : return array_buffer->byte_length();
104 : }
105 :
106 : // ES7 sharedmem 6.3.4.1 get SharedArrayBuffer.prototype.byteLength
107 310212 : BUILTIN(SharedArrayBufferPrototypeGetByteLength) {
108 : const char* const kMethodName = "get SharedArrayBuffer.prototype.byteLength";
109 : HandleScope scope(isolate);
110 103404 : CHECK_RECEIVER(JSArrayBuffer, array_buffer,
111 : "get SharedArrayBuffer.prototype.byteLength");
112 103446 : CHECK_SHARED(true, array_buffer, kMethodName);
113 103390 : return array_buffer->byte_length();
114 : }
115 :
116 : // ES6 section 24.1.3.1 ArrayBuffer.isView ( arg )
117 1218 : BUILTIN(ArrayBufferIsView) {
118 : SealHandleScope shs(isolate);
119 : DCHECK_EQ(2, args.length());
120 406 : Object* arg = args[1];
121 406 : return isolate->heap()->ToBoolean(arg->IsJSArrayBufferView());
122 : }
123 :
124 764 : static Object* SliceHelper(BuiltinArguments args, Isolate* isolate,
125 : const char* kMethodName, bool is_shared) {
126 : HandleScope scope(isolate);
127 : Handle<Object> start = args.at(1);
128 : Handle<Object> end = args.atOrUndefined(isolate, 2);
129 :
130 : // * If Type(O) is not Object, throw a TypeError exception.
131 : // * If O does not have an [[ArrayBufferData]] internal slot, throw a
132 : // TypeError exception.
133 764 : CHECK_RECEIVER(JSArrayBuffer, array_buffer, kMethodName);
134 : // * [AB] If IsSharedArrayBuffer(O) is true, throw a TypeError exception.
135 : // * [SAB] If IsSharedArrayBuffer(O) is false, throw a TypeError exception.
136 764 : CHECK_SHARED(is_shared, array_buffer, kMethodName);
137 :
138 : // * [AB] If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
139 1528 : if (!is_shared && array_buffer->was_neutered()) {
140 0 : THROW_NEW_ERROR_RETURN_FAILURE(
141 : isolate, NewTypeError(MessageTemplate::kDetachedOperation,
142 : isolate->factory()->NewStringFromAsciiChecked(
143 : kMethodName)));
144 : }
145 :
146 : // * [AB] Let len be O.[[ArrayBufferByteLength]].
147 : // * [SAB] Let len be O.[[ArrayBufferByteLength]].
148 : double const len = array_buffer->byte_length()->Number();
149 :
150 : // * Let relativeStart be ? ToInteger(start).
151 : Handle<Object> relative_start;
152 764 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, relative_start,
153 : Object::ToInteger(isolate, start));
154 :
155 : // * If relativeStart < 0, let first be max((len + relativeStart), 0); else
156 : // let first be min(relativeStart, len).
157 : double const first = (relative_start->Number() < 0)
158 112 : ? Max(len + relative_start->Number(), 0.0)
159 764 : : Min(relative_start->Number(), len);
160 764 : Handle<Object> first_obj = isolate->factory()->NewNumber(first);
161 :
162 : // * If end is undefined, let relativeEnd be len; else let relativeEnd be ?
163 : // ToInteger(end).
164 : double relative_end;
165 764 : if (end->IsUndefined(isolate)) {
166 : relative_end = len;
167 : } else {
168 : Handle<Object> relative_end_obj;
169 592 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, relative_end_obj,
170 : Object::ToInteger(isolate, end));
171 : relative_end = relative_end_obj->Number();
172 : }
173 :
174 : // * If relativeEnd < 0, let final be max((len + relativeEnd), 0); else let
175 : // final be min(relativeEnd, len).
176 56 : double const final_ = (relative_end < 0) ? Max(len + relative_end, 0.0)
177 764 : : Min(relative_end, len);
178 :
179 : // * Let newLen be max(final-first, 0).
180 764 : double const new_len = Max(final_ - first, 0.0);
181 764 : Handle<Object> new_len_obj = isolate->factory()->NewNumber(new_len);
182 :
183 : // * [AB] Let ctor be ? SpeciesConstructor(O, %ArrayBuffer%).
184 : // * [SAB] Let ctor be ? SpeciesConstructor(O, %SharedArrayBuffer%).
185 : Handle<JSFunction> constructor_fun = is_shared
186 : ? isolate->shared_array_buffer_fun()
187 764 : : isolate->array_buffer_fun();
188 : Handle<Object> ctor;
189 1528 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
190 : isolate, ctor,
191 : Object::SpeciesConstructor(
192 : isolate, Handle<JSReceiver>::cast(args.receiver()), constructor_fun));
193 :
194 : // * Let new be ? Construct(ctor, newLen).
195 : Handle<JSReceiver> new_;
196 : {
197 : const int argc = 1;
198 :
199 : ScopedVector<Handle<Object>> argv(argc);
200 764 : argv[0] = new_len_obj;
201 :
202 : Handle<Object> new_obj;
203 1528 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
204 : isolate, new_obj,
205 : Execution::New(Handle<JSFunction>::cast(ctor), argc, argv.start()));
206 :
207 : new_ = Handle<JSReceiver>::cast(new_obj);
208 : }
209 :
210 : // * If new does not have an [[ArrayBufferData]] internal slot, throw a
211 : // TypeError exception.
212 764 : if (!new_->IsJSArrayBuffer()) {
213 0 : THROW_NEW_ERROR_RETURN_FAILURE(
214 : isolate,
215 : NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
216 : isolate->factory()->NewStringFromAsciiChecked(kMethodName),
217 : new_));
218 : }
219 :
220 : // * [AB] If IsSharedArrayBuffer(new) is true, throw a TypeError exception.
221 : // * [SAB] If IsSharedArrayBuffer(new) is false, throw a TypeError exception.
222 : Handle<JSArrayBuffer> new_array_buffer = Handle<JSArrayBuffer>::cast(new_);
223 764 : CHECK_SHARED(is_shared, new_array_buffer, kMethodName);
224 :
225 : // * [AB] If IsDetachedBuffer(new) is true, throw a TypeError exception.
226 1528 : if (!is_shared && new_array_buffer->was_neutered()) {
227 45 : THROW_NEW_ERROR_RETURN_FAILURE(
228 : isolate, NewTypeError(MessageTemplate::kDetachedOperation,
229 : isolate->factory()->NewStringFromAsciiChecked(
230 : kMethodName)));
231 : }
232 :
233 : // * [AB] If SameValue(new, O) is true, throw a TypeError exception.
234 1498 : if (!is_shared && new_->SameValue(*args.receiver())) {
235 28 : THROW_NEW_ERROR_RETURN_FAILURE(
236 : isolate, NewTypeError(MessageTemplate::kArrayBufferSpeciesThis));
237 : }
238 :
239 : // * [SAB] If new.[[ArrayBufferData]] and O.[[ArrayBufferData]] are the same
240 : // Shared Data Block values, throw a TypeError exception.
241 735 : if (is_shared &&
242 : new_array_buffer->backing_store() == array_buffer->backing_store()) {
243 0 : THROW_NEW_ERROR_RETURN_FAILURE(
244 : isolate, NewTypeError(MessageTemplate::kSharedArrayBufferSpeciesThis));
245 : }
246 :
247 : // * If new.[[ArrayBufferByteLength]] < newLen, throw a TypeError exception.
248 735 : if (new_array_buffer->byte_length()->Number() < new_len) {
249 28 : THROW_NEW_ERROR_RETURN_FAILURE(
250 : isolate,
251 : NewTypeError(is_shared ? MessageTemplate::kSharedArrayBufferTooShort
252 : : MessageTemplate::kArrayBufferTooShort));
253 : }
254 :
255 : // * [AB] NOTE: Side-effects of the above steps may have detached O.
256 : // * [AB] If IsDetachedBuffer(O) is true, throw a TypeError exception.
257 1442 : if (!is_shared && array_buffer->was_neutered()) {
258 135 : THROW_NEW_ERROR_RETURN_FAILURE(
259 : isolate, NewTypeError(MessageTemplate::kDetachedOperation,
260 : isolate->factory()->NewStringFromAsciiChecked(
261 : kMethodName)));
262 : }
263 :
264 : // * Let fromBuf be O.[[ArrayBufferData]].
265 : // * Let toBuf be new.[[ArrayBufferData]].
266 : // * Perform CopyDataBlockBytes(toBuf, 0, fromBuf, first, newLen).
267 : size_t first_size = 0, new_len_size = 0;
268 676 : CHECK(TryNumberToSize(*first_obj, &first_size));
269 676 : CHECK(TryNumberToSize(*new_len_obj, &new_len_size));
270 : DCHECK(NumberToSize(new_array_buffer->byte_length()) >= new_len_size);
271 :
272 676 : if (new_len_size != 0) {
273 521 : size_t from_byte_length = NumberToSize(array_buffer->byte_length());
274 : USE(from_byte_length);
275 : DCHECK(first_size <= from_byte_length);
276 : DCHECK(from_byte_length - first_size >= new_len_size);
277 : uint8_t* from_data =
278 : reinterpret_cast<uint8_t*>(array_buffer->backing_store());
279 : uint8_t* to_data =
280 : reinterpret_cast<uint8_t*>(new_array_buffer->backing_store());
281 521 : CopyBytes(to_data, from_data + first_size, new_len_size);
282 : }
283 :
284 676 : return *new_;
285 : }
286 :
287 : // ES #sec-sharedarraybuffer.prototype.slice
288 0 : BUILTIN(SharedArrayBufferPrototypeSlice) {
289 : const char* const kMethodName = "SharedArrayBuffer.prototype.slice";
290 0 : return SliceHelper(args, isolate, kMethodName, true);
291 : }
292 :
293 : // ES #sec-arraybuffer.prototype.slice
294 : // ArrayBuffer.prototype.slice ( start, end )
295 1528 : BUILTIN(ArrayBufferPrototypeSlice) {
296 : const char* const kMethodName = "ArrayBuffer.prototype.slice";
297 764 : return SliceHelper(args, isolate, kMethodName, false);
298 : }
299 :
300 : } // namespace internal
301 : } // namespace v8
|