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 171 : 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 171 : THROW_NEW_ERROR_RETURN_FAILURE(
33 : isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
34 : handle(target->shared()->name(), isolate)));
35 : }
36 :
37 : namespace {
38 :
39 228284 : Object* ConstructBuffer(Isolate* isolate, Handle<JSFunction> target,
40 : Handle<JSReceiver> new_target, Handle<Object> length,
41 : bool initialize) {
42 : Handle<JSObject> result;
43 456568 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
44 : JSObject::New(target, new_target));
45 : size_t byte_length;
46 228284 : 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 228284 : : SharedFlag::kShared;
54 228284 : if (!JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer>::cast(result),
55 : isolate, byte_length, initialize,
56 228284 : shared_flag)) {
57 0 : THROW_NEW_ERROR_RETURN_FAILURE(
58 : isolate, NewRangeError(MessageTemplate::kArrayBufferAllocationFailed));
59 : }
60 228284 : return *result;
61 : }
62 :
63 : } // namespace
64 :
65 : // ES6 section 24.1.2.1 ArrayBuffer ( length ) for the [[Construct]] case.
66 682212 : BUILTIN(ArrayBufferConstructor_ConstructStub) {
67 : HandleScope scope(isolate);
68 227404 : Handle<JSFunction> target = args.target();
69 227404 : 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 227404 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_length,
76 : Object::ToInteger(isolate, length));
77 227404 : if (number_length->Number() < 0.0) {
78 128 : THROW_NEW_ERROR_RETURN_FAILURE(
79 : isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength));
80 : }
81 :
82 227340 : 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 2832 : BUILTIN(ArrayBufferConstructor_DoNotInitialize) {
89 : HandleScope scope(isolate);
90 1888 : Handle<JSFunction> target(isolate->native_context()->array_buffer_fun());
91 944 : Handle<Object> length = args.atOrUndefined(isolate, 1);
92 1888 : return ConstructBuffer(isolate, target, target, length, false);
93 : }
94 :
95 : // ES6 section 24.1.4.1 get ArrayBuffer.prototype.byteLength
96 40329 : BUILTIN(ArrayBufferPrototypeGetByteLength) {
97 : const char* const kMethodName = "get ArrayBuffer.prototype.byteLength";
98 : HandleScope scope(isolate);
99 13497 : CHECK_RECEIVER(JSArrayBuffer, array_buffer, kMethodName);
100 13452 : 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 13416 : return array_buffer->byte_length();
104 : }
105 :
106 : // ES7 sharedmem 6.3.4.1 get SharedArrayBuffer.prototype.byteLength
107 212280 : BUILTIN(SharedArrayBufferPrototypeGetByteLength) {
108 : const char* const kMethodName = "get SharedArrayBuffer.prototype.byteLength";
109 : HandleScope scope(isolate);
110 70814 : CHECK_RECEIVER(JSArrayBuffer, array_buffer,
111 : "get SharedArrayBuffer.prototype.byteLength");
112 70769 : CHECK_SHARED(true, array_buffer, kMethodName);
113 70733 : return array_buffer->byte_length();
114 : }
115 :
116 : // ES6 section 24.1.3.1 ArrayBuffer.isView ( arg )
117 783 : BUILTIN(ArrayBufferIsView) {
118 : SealHandleScope shs(isolate);
119 : DCHECK_EQ(2, args.length());
120 261 : Object* arg = args[1];
121 261 : return isolate->heap()->ToBoolean(arg->IsJSArrayBufferView());
122 : }
123 :
124 504 : 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 504 : 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 504 : CHECK_SHARED(is_shared, array_buffer, kMethodName);
137 :
138 : // * [AB] If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
139 1008 : 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 504 : 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 72 : ? Max(len + relative_start->Number(), 0.0)
159 504 : : Min(relative_start->Number(), len);
160 504 : 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 504 : if (end->IsUndefined(isolate)) {
166 : relative_end = len;
167 : } else {
168 : Handle<Object> relative_end_obj;
169 392 : 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 36 : double const final_ = (relative_end < 0) ? Max(len + relative_end, 0.0)
177 504 : : Min(relative_end, len);
178 :
179 : // * Let newLen be max(final-first, 0).
180 504 : double const new_len = Max(final_ - first, 0.0);
181 504 : 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 504 : : isolate->array_buffer_fun();
188 : Handle<Object> ctor;
189 1008 : 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 504 : argv[0] = new_len_obj;
201 :
202 : Handle<Object> new_obj;
203 1008 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
204 : isolate, new_obj, Execution::New(isolate, ctor, argc, argv.start()));
205 :
206 : new_ = Handle<JSReceiver>::cast(new_obj);
207 : }
208 :
209 : // * If new does not have an [[ArrayBufferData]] internal slot, throw a
210 : // TypeError exception.
211 504 : if (!new_->IsJSArrayBuffer()) {
212 0 : THROW_NEW_ERROR_RETURN_FAILURE(
213 : isolate,
214 : NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
215 : isolate->factory()->NewStringFromAsciiChecked(kMethodName),
216 : new_));
217 : }
218 :
219 : // * [AB] If IsSharedArrayBuffer(new) is true, throw a TypeError exception.
220 : // * [SAB] If IsSharedArrayBuffer(new) is false, throw a TypeError exception.
221 : Handle<JSArrayBuffer> new_array_buffer = Handle<JSArrayBuffer>::cast(new_);
222 504 : CHECK_SHARED(is_shared, new_array_buffer, kMethodName);
223 :
224 : // * [AB] If IsDetachedBuffer(new) is true, throw a TypeError exception.
225 1008 : if (!is_shared && new_array_buffer->was_neutered()) {
226 30 : THROW_NEW_ERROR_RETURN_FAILURE(
227 : isolate, NewTypeError(MessageTemplate::kDetachedOperation,
228 : isolate->factory()->NewStringFromAsciiChecked(
229 : kMethodName)));
230 : }
231 :
232 : // * [AB] If SameValue(new, O) is true, throw a TypeError exception.
233 988 : if (!is_shared && new_->SameValue(*args.receiver())) {
234 18 : THROW_NEW_ERROR_RETURN_FAILURE(
235 : isolate, NewTypeError(MessageTemplate::kArrayBufferSpeciesThis));
236 : }
237 :
238 : // * [SAB] If new.[[ArrayBufferData]] and O.[[ArrayBufferData]] are the same
239 : // Shared Data Block values, throw a TypeError exception.
240 485 : if (is_shared &&
241 : new_array_buffer->backing_store() == array_buffer->backing_store()) {
242 0 : THROW_NEW_ERROR_RETURN_FAILURE(
243 : isolate, NewTypeError(MessageTemplate::kSharedArrayBufferSpeciesThis));
244 : }
245 :
246 : // * If new.[[ArrayBufferByteLength]] < newLen, throw a TypeError exception.
247 485 : if (new_array_buffer->byte_length()->Number() < new_len) {
248 18 : THROW_NEW_ERROR_RETURN_FAILURE(
249 : isolate,
250 : NewTypeError(is_shared ? MessageTemplate::kSharedArrayBufferTooShort
251 : : MessageTemplate::kArrayBufferTooShort));
252 : }
253 :
254 : // * [AB] NOTE: Side-effects of the above steps may have detached O.
255 : // * [AB] If IsDetachedBuffer(O) is true, throw a TypeError exception.
256 952 : if (!is_shared && array_buffer->was_neutered()) {
257 90 : THROW_NEW_ERROR_RETURN_FAILURE(
258 : isolate, NewTypeError(MessageTemplate::kDetachedOperation,
259 : isolate->factory()->NewStringFromAsciiChecked(
260 : kMethodName)));
261 : }
262 :
263 : // * Let fromBuf be O.[[ArrayBufferData]].
264 : // * Let toBuf be new.[[ArrayBufferData]].
265 : // * Perform CopyDataBlockBytes(toBuf, 0, fromBuf, first, newLen).
266 : size_t first_size = 0, new_len_size = 0;
267 446 : CHECK(TryNumberToSize(*first_obj, &first_size));
268 446 : CHECK(TryNumberToSize(*new_len_obj, &new_len_size));
269 : DCHECK(NumberToSize(new_array_buffer->byte_length()) >= new_len_size);
270 :
271 446 : if (new_len_size != 0) {
272 346 : size_t from_byte_length = NumberToSize(array_buffer->byte_length());
273 : USE(from_byte_length);
274 : DCHECK(first_size <= from_byte_length);
275 : DCHECK(from_byte_length - first_size >= new_len_size);
276 : uint8_t* from_data =
277 : reinterpret_cast<uint8_t*>(array_buffer->backing_store());
278 : uint8_t* to_data =
279 : reinterpret_cast<uint8_t*>(new_array_buffer->backing_store());
280 346 : CopyBytes(to_data, from_data + first_size, new_len_size);
281 : }
282 :
283 446 : return *new_;
284 : }
285 :
286 : // ES #sec-sharedarraybuffer.prototype.slice
287 0 : BUILTIN(SharedArrayBufferPrototypeSlice) {
288 : const char* const kMethodName = "SharedArrayBuffer.prototype.slice";
289 0 : return SliceHelper(args, isolate, kMethodName, true);
290 : }
291 :
292 : // ES #sec-arraybuffer.prototype.slice
293 : // ArrayBuffer.prototype.slice ( start, end )
294 1008 : BUILTIN(ArrayBufferPrototypeSlice) {
295 : const char* const kMethodName = "ArrayBuffer.prototype.slice";
296 504 : return SliceHelper(args, isolate, kMethodName, false);
297 : }
298 :
299 : } // namespace internal
300 : } // namespace v8
|