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/builtins/builtins-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/code-stub-assembler.h" | 8 #include "src/code-stub-assembler.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 a.Bind(&u32); | 259 a.Bind(&u32); |
260 a.AtomicStore(MachineRepresentation::kWord32, backing_store, | 260 a.AtomicStore(MachineRepresentation::kWord32, backing_store, |
261 a.WordShl(index_word, 2), value_word32); | 261 a.WordShl(index_word, 2), value_word32); |
262 a.Return(value_integer); | 262 a.Return(value_integer); |
263 | 263 |
264 // This shouldn't happen, we've already validated the type. | 264 // This shouldn't happen, we've already validated the type. |
265 a.Bind(&other); | 265 a.Bind(&other); |
266 a.Return(a.SmiConstant(0)); | 266 a.Return(a.SmiConstant(0)); |
267 } | 267 } |
268 | 268 |
| 269 #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 |
| 270 // The helper functions are duplicated from runtime-atomics.cc |
| 271 template <typename T> |
| 272 T FromObject(Handle<Object> number); |
| 273 |
| 274 template <> |
| 275 inline uint8_t FromObject<uint8_t>(Handle<Object> number) { |
| 276 return NumberToUint32(*number); |
| 277 } |
| 278 |
| 279 template <> |
| 280 inline int8_t FromObject<int8_t>(Handle<Object> number) { |
| 281 return NumberToInt32(*number); |
| 282 } |
| 283 |
| 284 template <> |
| 285 inline uint16_t FromObject<uint16_t>(Handle<Object> number) { |
| 286 return NumberToUint32(*number); |
| 287 } |
| 288 |
| 289 template <> |
| 290 inline int16_t FromObject<int16_t>(Handle<Object> number) { |
| 291 return NumberToInt32(*number); |
| 292 } |
| 293 |
| 294 template <> |
| 295 inline uint32_t FromObject<uint32_t>(Handle<Object> number) { |
| 296 return NumberToUint32(*number); |
| 297 } |
| 298 |
| 299 template <> |
| 300 inline int32_t FromObject<int32_t>(Handle<Object> number) { |
| 301 return NumberToInt32(*number); |
| 302 } |
| 303 |
| 304 inline Object* ToObject(Isolate* isolate, int8_t t) { return Smi::FromInt(t); } |
| 305 |
| 306 inline Object* ToObject(Isolate* isolate, uint8_t t) { return Smi::FromInt(t); } |
| 307 |
| 308 inline Object* ToObject(Isolate* isolate, int16_t t) { return Smi::FromInt(t); } |
| 309 |
| 310 inline Object* ToObject(Isolate* isolate, uint16_t t) { |
| 311 return Smi::FromInt(t); |
| 312 } |
| 313 |
| 314 inline Object* ToObject(Isolate* isolate, int32_t t) { |
| 315 return *isolate->factory()->NewNumber(t); |
| 316 } |
| 317 |
| 318 inline Object* ToObject(Isolate* isolate, uint32_t t) { |
| 319 return *isolate->factory()->NewNumber(t); |
| 320 } |
| 321 |
| 322 template <typename T> |
| 323 inline T ExchangeSeqCst(T* p, T value) { |
| 324 return __atomic_exchange_n(p, value, __ATOMIC_SEQ_CST); |
| 325 } |
| 326 |
| 327 template <typename T> |
| 328 inline Object* DoExchange(Isolate* isolate, void* buffer, size_t index, |
| 329 Handle<Object> obj) { |
| 330 T value = FromObject<T>(obj); |
| 331 T result = ExchangeSeqCst(static_cast<T*>(buffer) + index, value); |
| 332 return ToObject(isolate, result); |
| 333 } |
| 334 |
| 335 // ES #sec-validatesharedintegertypedarray |
| 336 MUST_USE_RESULT MaybeHandle<JSTypedArray> ValidateSharedIntegerTypedArray( |
| 337 Isolate* isolate, Handle<Object> object, bool only_int32 = false) { |
| 338 if (object->IsJSTypedArray()) { |
| 339 Handle<JSTypedArray> typedArray = Handle<JSTypedArray>::cast(object); |
| 340 if (typedArray->GetBuffer()->is_shared()) { |
| 341 if (only_int32) { |
| 342 if (typedArray->type() == kExternalInt32Array) return typedArray; |
| 343 } else { |
| 344 if (typedArray->type() != kExternalFloat32Array && |
| 345 typedArray->type() != kExternalFloat64Array && |
| 346 typedArray->type() != kExternalUint8ClampedArray) |
| 347 return typedArray; |
| 348 } |
| 349 } |
| 350 } |
| 351 |
| 352 THROW_NEW_ERROR( |
| 353 isolate, |
| 354 NewTypeError(only_int32 ? MessageTemplate::kNotInt32SharedTypedArray |
| 355 : MessageTemplate::kNotIntegerSharedTypedArray, |
| 356 object), |
| 357 JSTypedArray); |
| 358 } |
| 359 |
| 360 // ES #sec-validateatomicaccess |
| 361 MUST_USE_RESULT Maybe<size_t> ValidateAtomicAccess( |
| 362 Isolate* isolate, Handle<JSTypedArray> typedArray, |
| 363 Handle<Object> requestIndex) { |
| 364 // TOOD(v8:5961): Use ToIndex for indexes |
| 365 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 366 isolate, requestIndex, Object::ToNumber(requestIndex), Nothing<size_t>()); |
| 367 Handle<Object> offset; |
| 368 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, offset, |
| 369 Object::ToInteger(isolate, requestIndex), |
| 370 Nothing<size_t>()); |
| 371 if (!requestIndex->SameValue(*offset)) { |
| 372 isolate->Throw(*isolate->factory()->NewRangeError( |
| 373 MessageTemplate::kInvalidAtomicAccessIndex)); |
| 374 return Nothing<size_t>(); |
| 375 } |
| 376 size_t accessIndex; |
| 377 uint32_t length = typedArray->length_value(); |
| 378 if (!TryNumberToSize(*requestIndex, &accessIndex) || accessIndex >= length) { |
| 379 isolate->Throw(*isolate->factory()->NewRangeError( |
| 380 MessageTemplate::kInvalidAtomicAccessIndex)); |
| 381 return Nothing<size_t>(); |
| 382 } |
| 383 return Just<size_t>(accessIndex); |
| 384 } |
| 385 |
| 386 #define INTEGER_TYPED_ARRAYS(V) \ |
| 387 V(Uint8, uint8, UINT8, uint8_t, 1) \ |
| 388 V(Int8, int8, INT8, int8_t, 1) \ |
| 389 V(Uint16, uint16, UINT16, uint16_t, 2) \ |
| 390 V(Int16, int16, INT16, int16_t, 2) \ |
| 391 V(Uint32, uint32, UINT32, uint32_t, 4) \ |
| 392 V(Int32, int32, INT32, int32_t, 4) |
| 393 |
| 394 BUILTIN(AtomicsExchange) { |
| 395 HandleScope scope(isolate); |
| 396 Handle<Object> array = args.atOrUndefined(isolate, 1); |
| 397 Handle<Object> index = args.atOrUndefined(isolate, 2); |
| 398 Handle<Object> value = args.atOrUndefined(isolate, 3); |
| 399 |
| 400 Handle<JSTypedArray> sta; |
| 401 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 402 isolate, sta, ValidateSharedIntegerTypedArray(isolate, array)); |
| 403 |
| 404 Maybe<size_t> maybeIndex = ValidateAtomicAccess(isolate, sta, index); |
| 405 if (maybeIndex.IsNothing()) return isolate->heap()->exception(); |
| 406 size_t i = maybeIndex.FromJust(); |
| 407 |
| 408 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, |
| 409 Object::ToInteger(isolate, value)); |
| 410 |
| 411 uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) + |
| 412 NumberToSize(sta->byte_offset()); |
| 413 |
| 414 switch (sta->type()) { |
| 415 #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \ |
| 416 case kExternal##Type##Array: \ |
| 417 return DoExchange<ctype>(isolate, source, i, value); |
| 418 |
| 419 INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE) |
| 420 #undef TYPED_ARRAY_CASE |
| 421 |
| 422 default: |
| 423 break; |
| 424 } |
| 425 |
| 426 UNREACHABLE(); |
| 427 return isolate->heap()->undefined_value(); |
| 428 } |
| 429 #else |
| 430 void Builtins::Generate_AtomicsExchange(compiler::CodeAssemblerState* state) { |
| 431 using compiler::Node; |
| 432 CodeStubAssembler a(state); |
| 433 Node* array = a.Parameter(1); |
| 434 Node* index = a.Parameter(2); |
| 435 Node* value = a.Parameter(3); |
| 436 Node* context = a.Parameter(4 + 2); |
| 437 |
| 438 Node* instance_type; |
| 439 Node* backing_store; |
| 440 ValidateSharedTypedArray(&a, array, context, &instance_type, &backing_store); |
| 441 |
| 442 Node* index_word32 = ConvertTaggedAtomicIndexToWord32(&a, index, context); |
| 443 Node* array_length_word32 = a.TruncateTaggedToWord32( |
| 444 context, a.LoadObjectField(array, JSTypedArray::kLengthOffset)); |
| 445 ValidateAtomicIndex(&a, index_word32, array_length_word32, context); |
| 446 Node* index_word = a.ChangeUint32ToWord(index_word32); |
| 447 |
| 448 Node* value_integer = a.ToInteger(context, value); |
| 449 Node* value_word32 = a.TruncateTaggedToWord32(context, value_integer); |
| 450 |
| 451 CodeStubAssembler::Label i8(&a), u8(&a), i16(&a), u16(&a), i32(&a), u32(&a), |
| 452 other(&a); |
| 453 int32_t case_values[] = { |
| 454 FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE, |
| 455 FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE, |
| 456 }; |
| 457 CodeStubAssembler::Label* case_labels[] = { |
| 458 &i8, &u8, &i16, &u16, &i32, &u32, |
| 459 }; |
| 460 a.Switch(instance_type, &other, case_values, case_labels, |
| 461 arraysize(case_labels)); |
| 462 |
| 463 a.Bind(&i8); |
| 464 a.Return(a.SmiFromWord32(a.AtomicExchange(MachineType::Int8(), backing_store, |
| 465 index_word, value_word32))); |
| 466 |
| 467 a.Bind(&u8); |
| 468 a.Return(a.SmiFromWord32(a.AtomicExchange(MachineType::Uint8(), backing_store, |
| 469 index_word, value_word32))); |
| 470 |
| 471 a.Bind(&i16); |
| 472 a.Return(a.SmiFromWord32(a.AtomicExchange(MachineType::Int16(), backing_store, |
| 473 a.WordShl(index_word, 1), |
| 474 value_word32))); |
| 475 |
| 476 a.Bind(&u16); |
| 477 a.Return(a.SmiFromWord32( |
| 478 a.AtomicExchange(MachineType::Uint16(), backing_store, |
| 479 a.WordShl(index_word, 1), value_word32))); |
| 480 |
| 481 a.Bind(&i32); |
| 482 a.Return(a.ChangeInt32ToTagged( |
| 483 a.AtomicExchange(MachineType::Int32(), backing_store, |
| 484 a.WordShl(index_word, 2), value_word32))); |
| 485 |
| 486 a.Bind(&u32); |
| 487 a.Return(a.ChangeUint32ToTagged( |
| 488 a.AtomicExchange(MachineType::Uint32(), backing_store, |
| 489 a.WordShl(index_word, 2), value_word32))); |
| 490 |
| 491 // This shouldn't happen, we've already validated the type. |
| 492 a.Bind(&other); |
| 493 a.Return(a.SmiConstant(0)); |
| 494 } |
| 495 #endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 |
| 496 |
269 } // namespace internal | 497 } // namespace internal |
270 } // namespace v8 | 498 } // namespace v8 |
OLD | NEW |