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/maybe-handles-inl.h"
10 : #include "src/objects-inl.h"
11 : #include "src/objects/js-array-buffer-inl.h"
12 :
13 : namespace v8 {
14 : namespace internal {
15 :
16 : #define CHECK_SHARED(expected, name, method) \
17 : if (name->is_shared() != expected) { \
18 : THROW_NEW_ERROR_RETURN_FAILURE( \
19 : isolate, \
20 : NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, \
21 : isolate->factory()->NewStringFromAsciiChecked(method), \
22 : name)); \
23 : }
24 :
25 : // -----------------------------------------------------------------------------
26 : // ES#sec-arraybuffer-objects
27 :
28 : namespace {
29 :
30 232844 : Object ConstructBuffer(Isolate* isolate, Handle<JSFunction> target,
31 : Handle<JSReceiver> new_target, Handle<Object> length,
32 : bool initialize) {
33 : Handle<JSObject> result;
34 465702 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
35 : isolate, result,
36 : JSObject::New(target, new_target, Handle<AllocationSite>::null()));
37 : size_t byte_length;
38 465716 : if (!TryNumberToSize(*length, &byte_length) ||
39 232858 : byte_length > JSArrayBuffer::kMaxByteLength) {
40 0 : JSArrayBuffer::SetupAsEmpty(Handle<JSArrayBuffer>::cast(result), isolate);
41 0 : THROW_NEW_ERROR_RETURN_FAILURE(
42 : isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength));
43 : }
44 : SharedFlag shared_flag =
45 465716 : (*target == target->native_context()->array_buffer_fun())
46 : ? SharedFlag::kNotShared
47 232858 : : SharedFlag::kShared;
48 232858 : if (!JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer>::cast(result),
49 : isolate, byte_length, initialize,
50 232858 : shared_flag)) {
51 90 : THROW_NEW_ERROR_RETURN_FAILURE(
52 : isolate, NewRangeError(MessageTemplate::kArrayBufferAllocationFailed));
53 : }
54 232807 : return *result;
55 : }
56 :
57 : } // namespace
58 :
59 : // ES #sec-arraybuffer-constructor
60 928030 : BUILTIN(ArrayBufferConstructor) {
61 : HandleScope scope(isolate);
62 232005 : Handle<JSFunction> target = args.target();
63 : DCHECK(*target == target->native_context()->array_buffer_fun() ||
64 : *target == target->native_context()->shared_array_buffer_fun());
65 696036 : if (args.new_target()->IsUndefined(isolate)) { // [[Call]]
66 162 : THROW_NEW_ERROR_RETURN_FAILURE(
67 : isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
68 : handle(target->shared()->Name(), isolate)));
69 : }
70 : // [[Construct]]
71 231960 : Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
72 231958 : Handle<Object> length = args.atOrUndefined(isolate, 1);
73 :
74 : Handle<Object> number_length;
75 463913 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_length,
76 : Object::ToInteger(isolate, length));
77 231955 : if (number_length->Number() < 0.0) {
78 126 : THROW_NEW_ERROR_RETURN_FAILURE(
79 : isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength));
80 : }
81 :
82 231893 : 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 3840 : BUILTIN(ArrayBufferConstructor_DoNotInitialize) {
89 : HandleScope scope(isolate);
90 2880 : Handle<JSFunction> target(isolate->native_context()->array_buffer_fun(),
91 960 : isolate);
92 960 : Handle<Object> length = args.atOrUndefined(isolate, 1);
93 1920 : return ConstructBuffer(isolate, target, target, length, false);
94 : }
95 :
96 : // ES6 section 24.1.4.1 get ArrayBuffer.prototype.byteLength
97 49576 : BUILTIN(ArrayBufferPrototypeGetByteLength) {
98 : const char* const kMethodName = "get ArrayBuffer.prototype.byteLength";
99 : HandleScope scope(isolate);
100 24842 : CHECK_RECEIVER(JSArrayBuffer, array_buffer, kMethodName);
101 12403 : CHECK_SHARED(false, array_buffer, kMethodName);
102 : // TODO(franzih): According to the ES6 spec, we should throw a TypeError
103 : // here if the JSArrayBuffer is detached.
104 24734 : return *isolate->factory()->NewNumberFromSize(array_buffer->byte_length());
105 : }
106 :
107 : // ES7 sharedmem 6.3.4.1 get SharedArrayBuffer.prototype.byteLength
108 264172 : BUILTIN(SharedArrayBufferPrototypeGetByteLength) {
109 : const char* const kMethodName = "get SharedArrayBuffer.prototype.byteLength";
110 : HandleScope scope(isolate);
111 132140 : CHECK_RECEIVER(JSArrayBuffer, array_buffer,
112 : "get SharedArrayBuffer.prototype.byteLength");
113 66052 : CHECK_SHARED(true, array_buffer, kMethodName);
114 132032 : return *isolate->factory()->NewNumberFromSize(array_buffer->byte_length());
115 : }
116 :
117 : // ES6 section 24.1.3.1 ArrayBuffer.isView ( arg )
118 1396 : BUILTIN(ArrayBufferIsView) {
119 : SealHandleScope shs(isolate);
120 : DCHECK_EQ(2, args.length());
121 349 : Object arg = args[1];
122 349 : return isolate->heap()->ToBoolean(arg->IsJSArrayBufferView());
123 : }
124 :
125 504 : static Object SliceHelper(BuiltinArguments args, Isolate* isolate,
126 : const char* kMethodName, bool is_shared) {
127 : HandleScope scope(isolate);
128 504 : Handle<Object> start = args.at(1);
129 : Handle<Object> end = args.atOrUndefined(isolate, 2);
130 :
131 : // * If Type(O) is not Object, throw a TypeError exception.
132 : // * If O does not have an [[ArrayBufferData]] internal slot, throw a
133 : // TypeError exception.
134 1008 : CHECK_RECEIVER(JSArrayBuffer, array_buffer, kMethodName);
135 : // * [AB] If IsSharedArrayBuffer(O) is true, throw a TypeError exception.
136 : // * [SAB] If IsSharedArrayBuffer(O) is false, throw a TypeError exception.
137 504 : CHECK_SHARED(is_shared, array_buffer, kMethodName);
138 :
139 : // * [AB] If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
140 1008 : if (!is_shared && array_buffer->was_detached()) {
141 0 : THROW_NEW_ERROR_RETURN_FAILURE(
142 : isolate, NewTypeError(MessageTemplate::kDetachedOperation,
143 : isolate->factory()->NewStringFromAsciiChecked(
144 : kMethodName)));
145 : }
146 :
147 : // * [AB] Let len be O.[[ArrayBufferByteLength]].
148 : // * [SAB] Let len be O.[[ArrayBufferByteLength]].
149 504 : double const len = array_buffer->byte_length();
150 :
151 : // * Let relativeStart be ? ToInteger(start).
152 : Handle<Object> relative_start;
153 1008 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, relative_start,
154 : Object::ToInteger(isolate, start));
155 :
156 : // * If relativeStart < 0, let first be max((len + relativeStart), 0); else
157 : // let first be min(relativeStart, len).
158 1008 : double const first = (relative_start->Number() < 0)
159 576 : ? Max(len + relative_start->Number(), 0.0)
160 1440 : : Min(relative_start->Number(), len);
161 504 : Handle<Object> first_obj = isolate->factory()->NewNumber(first);
162 :
163 : // * If end is undefined, let relativeEnd be len; else let relativeEnd be ?
164 : // ToInteger(end).
165 : double relative_end;
166 1008 : if (end->IsUndefined(isolate)) {
167 : relative_end = len;
168 : } else {
169 : Handle<Object> relative_end_obj;
170 792 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, relative_end_obj,
171 : Object::ToInteger(isolate, end));
172 396 : relative_end = relative_end_obj->Number();
173 : }
174 :
175 : // * If relativeEnd < 0, let final be max((len + relativeEnd), 0); else let
176 : // final be min(relativeEnd, len).
177 36 : double const final_ = (relative_end < 0) ? Max(len + relative_end, 0.0)
178 504 : : Min(relative_end, len);
179 :
180 : // * Let newLen be max(final-first, 0).
181 504 : double const new_len = Max(final_ - first, 0.0);
182 504 : Handle<Object> new_len_obj = isolate->factory()->NewNumber(new_len);
183 :
184 : // * [AB] Let ctor be ? SpeciesConstructor(O, %ArrayBuffer%).
185 : // * [SAB] Let ctor be ? SpeciesConstructor(O, %SharedArrayBuffer%).
186 : Handle<JSFunction> constructor_fun = is_shared
187 : ? isolate->shared_array_buffer_fun()
188 504 : : isolate->array_buffer_fun();
189 : Handle<Object> ctor;
190 1008 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
191 : isolate, ctor,
192 : Object::SpeciesConstructor(
193 : isolate, Handle<JSReceiver>::cast(args.receiver()), constructor_fun));
194 :
195 : // * Let new be ? Construct(ctor, newLen).
196 : Handle<JSReceiver> new_;
197 : {
198 : const int argc = 1;
199 :
200 : ScopedVector<Handle<Object>> argv(argc);
201 504 : argv[0] = new_len_obj;
202 :
203 : Handle<Object> new_obj;
204 1008 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
205 : isolate, new_obj, Execution::New(isolate, ctor, argc, argv.start()));
206 :
207 504 : new_ = Handle<JSReceiver>::cast(new_obj);
208 : }
209 :
210 : // * If new does not have an [[ArrayBufferData]] internal slot, throw a
211 : // TypeError exception.
212 1008 : 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 504 : Handle<JSArrayBuffer> new_array_buffer = Handle<JSArrayBuffer>::cast(new_);
223 504 : CHECK_SHARED(is_shared, new_array_buffer, kMethodName);
224 :
225 : // * [AB] If IsDetachedBuffer(new) is true, throw a TypeError exception.
226 1008 : if (!is_shared && new_array_buffer->was_detached()) {
227 27 : 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 990 : if (!is_shared && new_->SameValue(*args.receiver())) {
235 18 : 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 486 : 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 486 : if (new_array_buffer->byte_length() < new_len) {
249 18 : 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 954 : if (!is_shared && array_buffer->was_detached()) {
258 81 : 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 450 : size_t first_size = 0, new_len_size = 0;
268 450 : CHECK(TryNumberToSize(*first_obj, &first_size));
269 450 : CHECK(TryNumberToSize(*new_len_obj, &new_len_size));
270 : DCHECK(new_array_buffer->byte_length() >= new_len_size);
271 :
272 450 : if (new_len_size != 0) {
273 : size_t from_byte_length = 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 351 : CopyBytes(to_data, from_data + first_size, new_len_size);
282 : }
283 :
284 450 : 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 504 : BUILTIN(ArrayBufferPrototypeSlice) {
296 : const char* const kMethodName = "ArrayBuffer.prototype.slice";
297 504 : return SliceHelper(args, isolate, kMethodName, false);
298 : }
299 :
300 : } // namespace internal
301 183867 : } // namespace v8
|