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