OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/base/macros.h" | 5 #include "src/base/macros.h" |
6 #include "src/base/platform/mutex.h" | 6 #include "src/base/platform/mutex.h" |
7 #include "src/base/platform/time.h" | 7 #include "src/base/platform/time.h" |
8 #include "src/builtins/builtins-utils.h" | 8 #include "src/builtins/builtins-utils.h" |
9 #include "src/builtins/builtins.h" | 9 #include "src/builtins/builtins.h" |
10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
162 isolate, NewTypeError(MessageTemplate::kAtomicsWaitNotAllowed)); | 162 isolate, NewTypeError(MessageTemplate::kAtomicsWaitNotAllowed)); |
163 } | 163 } |
164 | 164 |
165 Handle<JSArrayBuffer> array_buffer = sta->GetBuffer(); | 165 Handle<JSArrayBuffer> array_buffer = sta->GetBuffer(); |
166 size_t addr = (i << 2) + NumberToSize(sta->byte_offset()); | 166 size_t addr = (i << 2) + NumberToSize(sta->byte_offset()); |
167 | 167 |
168 return FutexEmulation::Wait(isolate, array_buffer, addr, value_int32, | 168 return FutexEmulation::Wait(isolate, array_buffer, addr, value_int32, |
169 timeout_number); | 169 timeout_number); |
170 } | 170 } |
171 | 171 |
172 namespace { | |
173 | |
174 #if V8_CC_GNU | |
175 | |
176 template <typename T> | |
177 inline T AddSeqCst(T* p, T value) { | |
178 return __atomic_fetch_add(p, value, __ATOMIC_SEQ_CST); | |
179 } | |
180 | |
181 template <typename T> | |
182 inline T SubSeqCst(T* p, T value) { | |
183 return __atomic_fetch_sub(p, value, __ATOMIC_SEQ_CST); | |
184 } | |
185 | |
186 template <typename T> | |
187 inline T AndSeqCst(T* p, T value) { | |
188 return __atomic_fetch_and(p, value, __ATOMIC_SEQ_CST); | |
189 } | |
190 | |
191 template <typename T> | |
192 inline T OrSeqCst(T* p, T value) { | |
193 return __atomic_fetch_or(p, value, __ATOMIC_SEQ_CST); | |
194 } | |
195 | |
196 template <typename T> | |
197 inline T XorSeqCst(T* p, T value) { | |
198 return __atomic_fetch_xor(p, value, __ATOMIC_SEQ_CST); | |
199 } | |
200 | |
201 #elif V8_CC_MSVC | |
202 | |
203 #define InterlockedExchangeAdd32 _InterlockedExchangeAdd | |
204 #define InterlockedAnd32 _InterlockedAnd | |
205 #define InterlockedOr32 _InterlockedOr | |
206 #define InterlockedXor32 _InterlockedXor | |
207 #define InterlockedExchangeAdd16 _InterlockedExchangeAdd16 | |
208 #define InterlockedExchangeAdd8 _InterlockedExchangeAdd8 | |
209 | |
210 #define ATOMIC_OPS(type, suffix, vctype) \ | |
211 inline type AddSeqCst(type* p, type value) { \ | |
212 return InterlockedExchangeAdd##suffix(reinterpret_cast<vctype*>(p), \ | |
213 bit_cast<vctype>(value)); \ | |
214 } \ | |
215 inline type SubSeqCst(type* p, type value) { \ | |
216 return InterlockedExchangeAdd##suffix(reinterpret_cast<vctype*>(p), \ | |
217 -bit_cast<vctype>(value)); \ | |
218 } \ | |
219 inline type AndSeqCst(type* p, type value) { \ | |
220 return InterlockedAnd##suffix(reinterpret_cast<vctype*>(p), \ | |
221 bit_cast<vctype>(value)); \ | |
222 } \ | |
223 inline type OrSeqCst(type* p, type value) { \ | |
224 return InterlockedOr##suffix(reinterpret_cast<vctype*>(p), \ | |
225 bit_cast<vctype>(value)); \ | |
226 } \ | |
227 inline type XorSeqCst(type* p, type value) { \ | |
228 return InterlockedXor##suffix(reinterpret_cast<vctype*>(p), \ | |
229 bit_cast<vctype>(value)); \ | |
230 } | |
231 | |
232 ATOMIC_OPS(int8_t, 8, char) | |
233 ATOMIC_OPS(uint8_t, 8, char) | |
234 ATOMIC_OPS(int16_t, 16, short) /* NOLINT(runtime/int) */ | |
235 ATOMIC_OPS(uint16_t, 16, short) /* NOLINT(runtime/int) */ | |
236 ATOMIC_OPS(int32_t, 32, long) /* NOLINT(runtime/int) */ | |
237 ATOMIC_OPS(uint32_t, 32, long) /* NOLINT(runtime/int) */ | |
238 | |
239 #undef ATOMIC_OPS_INTEGER | |
240 #undef ATOMIC_OPS | |
241 | |
242 #undef InterlockedExchangeAdd32 | |
243 #undef InterlockedAnd32 | |
244 #undef InterlockedOr32 | |
245 #undef InterlockedXor32 | |
246 #undef InterlockedExchangeAdd16 | |
247 #undef InterlockedExchangeAdd8 | |
248 | |
249 #else | |
250 | |
251 #error Unsupported platform! | |
252 | |
253 #endif | |
254 | |
255 template <typename T> | |
256 T FromObject(Handle<Object> number); | |
257 | |
258 template <> | |
259 inline uint8_t FromObject<uint8_t>(Handle<Object> number) { | |
260 return NumberToUint32(*number); | |
261 } | |
262 | |
263 template <> | |
264 inline int8_t FromObject<int8_t>(Handle<Object> number) { | |
265 return NumberToInt32(*number); | |
266 } | |
267 | |
268 template <> | |
269 inline uint16_t FromObject<uint16_t>(Handle<Object> number) { | |
270 return NumberToUint32(*number); | |
271 } | |
272 | |
273 template <> | |
274 inline int16_t FromObject<int16_t>(Handle<Object> number) { | |
275 return NumberToInt32(*number); | |
276 } | |
277 | |
278 template <> | |
279 inline uint32_t FromObject<uint32_t>(Handle<Object> number) { | |
280 return NumberToUint32(*number); | |
281 } | |
282 | |
283 template <> | |
284 inline int32_t FromObject<int32_t>(Handle<Object> number) { | |
285 return NumberToInt32(*number); | |
286 } | |
287 | |
288 inline Object* ToObject(Isolate* isolate, int8_t t) { return Smi::FromInt(t); } | |
289 | |
290 inline Object* ToObject(Isolate* isolate, uint8_t t) { return Smi::FromInt(t); } | |
291 | |
292 inline Object* ToObject(Isolate* isolate, int16_t t) { return Smi::FromInt(t); } | |
293 | |
294 inline Object* ToObject(Isolate* isolate, uint16_t t) { | |
295 return Smi::FromInt(t); | |
296 } | |
297 | |
298 inline Object* ToObject(Isolate* isolate, int32_t t) { | |
299 return *isolate->factory()->NewNumber(t); | |
300 } | |
301 | |
302 inline Object* ToObject(Isolate* isolate, uint32_t t) { | |
303 return *isolate->factory()->NewNumber(t); | |
304 } | |
305 | |
306 template <typename T> | |
307 inline Object* DoAdd(Isolate* isolate, void* buffer, size_t index, | |
308 Handle<Object> obj) { | |
309 T value = FromObject<T>(obj); | |
310 T result = AddSeqCst(static_cast<T*>(buffer) + index, value); | |
311 return ToObject(isolate, result); | |
312 } | |
313 | |
314 template <typename T> | |
315 inline Object* DoSub(Isolate* isolate, void* buffer, size_t index, | |
316 Handle<Object> obj) { | |
317 T value = FromObject<T>(obj); | |
318 T result = SubSeqCst(static_cast<T*>(buffer) + index, value); | |
319 return ToObject(isolate, result); | |
320 } | |
321 | |
322 template <typename T> | |
323 inline Object* DoAnd(Isolate* isolate, void* buffer, size_t index, | |
324 Handle<Object> obj) { | |
325 T value = FromObject<T>(obj); | |
326 T result = AndSeqCst(static_cast<T*>(buffer) + index, value); | |
327 return ToObject(isolate, result); | |
328 } | |
329 | |
330 template <typename T> | |
331 inline Object* DoOr(Isolate* isolate, void* buffer, size_t index, | |
332 Handle<Object> obj) { | |
333 T value = FromObject<T>(obj); | |
334 T result = OrSeqCst(static_cast<T*>(buffer) + index, value); | |
335 return ToObject(isolate, result); | |
336 } | |
337 | |
338 template <typename T> | |
339 inline Object* DoXor(Isolate* isolate, void* buffer, size_t index, | |
340 Handle<Object> obj) { | |
341 T value = FromObject<T>(obj); | |
342 T result = XorSeqCst(static_cast<T*>(buffer) + index, value); | |
343 return ToObject(isolate, result); | |
344 } | |
345 | |
346 } // anonymous namespace | |
347 | |
348 // Duplicated from objects.h | |
349 // V has parameters (Type, type, TYPE, C type, element_size) | |
350 #define INTEGER_TYPED_ARRAYS(V) \ | |
351 V(Uint8, uint8, UINT8, uint8_t, 1) \ | |
352 V(Int8, int8, INT8, int8_t, 1) \ | |
353 V(Uint16, uint16, UINT16, uint16_t, 2) \ | |
354 V(Int16, int16, INT16, int16_t, 2) \ | |
355 V(Uint32, uint32, UINT32, uint32_t, 4) \ | |
356 V(Int32, int32, INT32, int32_t, 4) | |
357 | |
358 // ES #sec-atomics.add | |
359 // Atomics.add( typedArray, index, value ) | |
360 BUILTIN(AtomicsAdd) { | |
361 HandleScope scope(isolate); | |
362 Handle<Object> array = args.atOrUndefined(isolate, 1); | |
363 Handle<Object> index = args.atOrUndefined(isolate, 2); | |
364 Handle<Object> value = args.atOrUndefined(isolate, 3); | |
365 | |
366 Handle<JSTypedArray> sta; | |
367 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
368 isolate, sta, ValidateSharedIntegerTypedArray(isolate, array)); | |
369 | |
370 Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index); | |
371 if (maybe_index.IsNothing()) return isolate->heap()->exception(); | |
372 size_t i = maybe_index.FromJust(); | |
373 | |
374 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, | |
375 Object::ToInteger(isolate, value)); | |
376 | |
377 uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) + | |
378 NumberToSize(sta->byte_offset()); | |
379 | |
380 switch (sta->type()) { | |
381 #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \ | |
382 case kExternal##Type##Array: \ | |
383 return DoAdd<ctype>(isolate, source, i, value); | |
384 | |
385 INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) | |
386 #undef TYPED_ARRAY_CASE | |
387 | |
388 default: | |
389 break; | |
390 } | |
391 | |
392 UNREACHABLE(); | |
393 return isolate->heap()->undefined_value(); | |
394 } | |
395 | |
396 // ES #sec-atomics.sub | |
397 // Atomics.sub( typedArray, index, value ) | |
398 BUILTIN(AtomicsSub) { | |
399 HandleScope scope(isolate); | |
400 Handle<Object> array = args.atOrUndefined(isolate, 1); | |
401 Handle<Object> index = args.atOrUndefined(isolate, 2); | |
402 Handle<Object> value = args.atOrUndefined(isolate, 3); | |
403 | |
404 Handle<JSTypedArray> sta; | |
405 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
406 isolate, sta, ValidateSharedIntegerTypedArray(isolate, array)); | |
407 | |
408 Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index); | |
409 if (maybe_index.IsNothing()) return isolate->heap()->exception(); | |
410 size_t i = maybe_index.FromJust(); | |
411 | |
412 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, | |
413 Object::ToInteger(isolate, value)); | |
414 | |
415 uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) + | |
416 NumberToSize(sta->byte_offset()); | |
417 | |
418 switch (sta->type()) { | |
419 #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \ | |
420 case kExternal##Type##Array: \ | |
421 return DoSub<ctype>(isolate, source, i, value); | |
422 | |
423 INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) | |
424 #undef TYPED_ARRAY_CASE | |
425 | |
426 default: | |
427 break; | |
428 } | |
429 | |
430 UNREACHABLE(); | |
431 return isolate->heap()->undefined_value(); | |
432 } | |
433 | |
434 // ES #sec-atomics.and | |
435 // Atomics.and( typedArray, index, value ) | |
436 BUILTIN(AtomicsAnd) { | |
437 HandleScope scope(isolate); | |
438 Handle<Object> array = args.atOrUndefined(isolate, 1); | |
439 Handle<Object> index = args.atOrUndefined(isolate, 2); | |
440 Handle<Object> value = args.atOrUndefined(isolate, 3); | |
441 | |
442 Handle<JSTypedArray> sta; | |
443 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
444 isolate, sta, ValidateSharedIntegerTypedArray(isolate, array)); | |
445 | |
446 Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index); | |
447 if (maybe_index.IsNothing()) return isolate->heap()->exception(); | |
448 size_t i = maybe_index.FromJust(); | |
449 | |
450 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, | |
451 Object::ToInteger(isolate, value)); | |
452 | |
453 uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) + | |
454 NumberToSize(sta->byte_offset()); | |
455 | |
456 switch (sta->type()) { | |
457 #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \ | |
458 case kExternal##Type##Array: \ | |
459 return DoAnd<ctype>(isolate, source, i, value); | |
460 | |
461 INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) | |
462 #undef TYPED_ARRAY_CASE | |
463 | |
464 default: | |
465 break; | |
466 } | |
467 | |
468 UNREACHABLE(); | |
469 return isolate->heap()->undefined_value(); | |
470 } | |
471 | |
472 // ES #sec-atomics.or | |
473 // Atomics.or( typedArray, index, value ) | |
474 BUILTIN(AtomicsOr) { | |
475 HandleScope scope(isolate); | |
476 Handle<Object> array = args.atOrUndefined(isolate, 1); | |
477 Handle<Object> index = args.atOrUndefined(isolate, 2); | |
478 Handle<Object> value = args.atOrUndefined(isolate, 3); | |
479 | |
480 Handle<JSTypedArray> sta; | |
481 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
482 isolate, sta, ValidateSharedIntegerTypedArray(isolate, array)); | |
483 | |
484 Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index); | |
485 if (maybe_index.IsNothing()) return isolate->heap()->exception(); | |
486 size_t i = maybe_index.FromJust(); | |
487 | |
488 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, | |
489 Object::ToInteger(isolate, value)); | |
490 | |
491 uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) + | |
492 NumberToSize(sta->byte_offset()); | |
493 | |
494 switch (sta->type()) { | |
495 #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \ | |
496 case kExternal##Type##Array: \ | |
497 return DoOr<ctype>(isolate, source, i, value); | |
498 | |
499 INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) | |
500 #undef TYPED_ARRAY_CASE | |
501 | |
502 default: | |
503 break; | |
504 } | |
505 | |
506 UNREACHABLE(); | |
507 return isolate->heap()->undefined_value(); | |
508 } | |
509 | |
510 // ES #sec-atomics.xor | |
511 // Atomics.xor( typedArray, index, value ) | |
512 BUILTIN(AtomicsXor) { | |
513 HandleScope scope(isolate); | |
514 Handle<Object> array = args.atOrUndefined(isolate, 1); | |
515 Handle<Object> index = args.atOrUndefined(isolate, 2); | |
516 Handle<Object> value = args.atOrUndefined(isolate, 3); | |
517 | |
518 Handle<JSTypedArray> sta; | |
519 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
520 isolate, sta, ValidateSharedIntegerTypedArray(isolate, array)); | |
521 | |
522 Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index); | |
523 if (maybe_index.IsNothing()) return isolate->heap()->exception(); | |
524 size_t i = maybe_index.FromJust(); | |
525 | |
526 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, | |
527 Object::ToInteger(isolate, value)); | |
528 | |
529 uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) + | |
530 NumberToSize(sta->byte_offset()); | |
531 | |
532 switch (sta->type()) { | |
533 #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \ | |
534 case kExternal##Type##Array: \ | |
535 return DoXor<ctype>(isolate, source, i, value); | |
536 | |
537 INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) | |
538 #undef TYPED_ARRAY_CASE | |
539 | |
540 default: | |
541 break; | |
542 } | |
543 | |
544 UNREACHABLE(); | |
545 return isolate->heap()->undefined_value(); | |
546 } | |
547 | |
548 } // namespace internal | 172 } // namespace internal |
549 } // namespace v8 | 173 } // namespace v8 |
OLD | NEW |