Chromium Code Reviews| 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/code-stub-assembler.h" | 5 #include "src/code-stub-assembler.h" |
| 6 #include "src/code-factory.h" | 6 #include "src/code-factory.h" |
| 7 #include "src/frames-inl.h" | 7 #include "src/frames-inl.h" |
| 8 #include "src/frames.h" | 8 #include "src/frames.h" |
| 9 #include "src/ic/handler-configuration.h" | 9 #include "src/ic/handler-configuration.h" |
| 10 #include "src/ic/stub-cache.h" | 10 #include "src/ic/stub-cache.h" |
| (...skipping 3336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3347 Goto(&return_result); | 3347 Goto(&return_result); |
| 3348 | 3348 |
| 3349 Bind(&return_result); | 3349 Bind(&return_result); |
| 3350 return var_result.value(); | 3350 return var_result.value(); |
| 3351 } | 3351 } |
| 3352 | 3352 |
| 3353 compiler::Node* CodeStubAssembler::ElementOffsetFromIndex(Node* index_node, | 3353 compiler::Node* CodeStubAssembler::ElementOffsetFromIndex(Node* index_node, |
| 3354 ElementsKind kind, | 3354 ElementsKind kind, |
| 3355 ParameterMode mode, | 3355 ParameterMode mode, |
| 3356 int base_size) { | 3356 int base_size) { |
| 3357 bool is_double = IsFastDoubleElementsKind(kind); | 3357 int element_size_shift = ElementsKindToShiftSize(kind); |
| 3358 int element_size_shift = is_double ? kDoubleSizeLog2 : kPointerSizeLog2; | |
| 3359 int element_size = 1 << element_size_shift; | 3358 int element_size = 1 << element_size_shift; |
| 3360 int const kSmiShiftBits = kSmiShiftSize + kSmiTagSize; | 3359 int const kSmiShiftBits = kSmiShiftSize + kSmiTagSize; |
| 3361 intptr_t index = 0; | 3360 intptr_t index = 0; |
| 3362 bool constant_index = false; | 3361 bool constant_index = false; |
| 3363 if (mode == SMI_PARAMETERS) { | 3362 if (mode == SMI_PARAMETERS) { |
| 3364 element_size_shift -= kSmiShiftBits; | 3363 element_size_shift -= kSmiShiftBits; |
| 3365 constant_index = ToIntPtrConstant(index_node, index); | 3364 constant_index = ToIntPtrConstant(index_node, index); |
| 3366 index = index >> kSmiShiftBits; | 3365 index = index >> kSmiShiftBits; |
| 3367 } else if (mode == INTEGER_PARAMETERS) { | 3366 } else if (mode == INTEGER_PARAMETERS) { |
| 3368 int32_t temp = 0; | 3367 int32_t temp = 0; |
| (...skipping 1080 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4449 Node* native_context = LoadNativeContext(context); | 4448 Node* native_context = LoadNativeContext(context); |
| 4450 Node* script_context_table = | 4449 Node* script_context_table = |
| 4451 LoadContextElement(native_context, Context::SCRIPT_CONTEXT_TABLE_INDEX); | 4450 LoadContextElement(native_context, Context::SCRIPT_CONTEXT_TABLE_INDEX); |
| 4452 | 4451 |
| 4453 int offset = | 4452 int offset = |
| 4454 ScriptContextTable::GetContextOffset(context_index) - kHeapObjectTag; | 4453 ScriptContextTable::GetContextOffset(context_index) - kHeapObjectTag; |
| 4455 return Load(MachineType::AnyTagged(), script_context_table, | 4454 return Load(MachineType::AnyTagged(), script_context_table, |
| 4456 IntPtrConstant(offset)); | 4455 IntPtrConstant(offset)); |
| 4457 } | 4456 } |
| 4458 | 4457 |
| 4458 Node* CodeStubAssembler::ClampedToUint8(Node* int32_value) { | |
| 4459 Label done(this); | |
| 4460 Node* int32_zero = Int32Constant(0); | |
| 4461 Node* int32_255 = Int32Constant(255); | |
| 4462 Variable var_value(this, MachineRepresentation::kWord32); | |
| 4463 var_value.Bind(int32_value); | |
| 4464 GotoIf(Uint32LessThanOrEqual(int32_value, int32_255), &done); | |
| 4465 var_value.Bind(int32_zero); | |
| 4466 GotoIf(Int32LessThan(int32_value, int32_zero), &done); | |
| 4467 var_value.Bind(int32_255); | |
| 4468 Goto(&done); | |
| 4469 Bind(&done); | |
| 4470 return var_value.value(); | |
| 4471 } | |
| 4472 | |
| 4473 namespace { | |
|
Benedikt Meurer
2016/09/13 09:08:00
Nit: add empty line.
Igor Sheludko
2016/09/13 10:33:16
Done.
| |
| 4474 // Converts typed array elements kind to a machine representations. | |
| 4475 MachineRepresentation ElementsKindToMachineRepresentation(ElementsKind kind) { | |
| 4476 switch (kind) { | |
| 4477 case UINT8_CLAMPED_ELEMENTS: | |
| 4478 case UINT8_ELEMENTS: | |
| 4479 case INT8_ELEMENTS: | |
| 4480 return MachineRepresentation::kWord8; | |
| 4481 case UINT16_ELEMENTS: | |
| 4482 case INT16_ELEMENTS: | |
| 4483 return MachineRepresentation::kWord16; | |
| 4484 case UINT32_ELEMENTS: | |
| 4485 case INT32_ELEMENTS: | |
| 4486 return MachineRepresentation::kWord32; | |
| 4487 case FLOAT32_ELEMENTS: | |
| 4488 return MachineRepresentation::kFloat32; | |
| 4489 case FLOAT64_ELEMENTS: | |
| 4490 return MachineRepresentation::kFloat64; | |
| 4491 default: | |
| 4492 UNREACHABLE(); | |
| 4493 return MachineRepresentation::kNone; | |
| 4494 } | |
| 4495 } | |
| 4496 } // namespace | |
|
Benedikt Meurer
2016/09/13 09:08:00
Nit: add empty line.
Igor Sheludko
2016/09/13 10:33:16
Done.
| |
| 4497 | |
| 4498 void CodeStubAssembler::StoreElement(Node* elements, ElementsKind kind, | |
| 4499 Node* index, Node* value, | |
| 4500 ParameterMode mode) { | |
| 4501 if (IsFixedTypedArrayElementsKind(kind)) { | |
| 4502 if (kind == UINT8_CLAMPED_ELEMENTS) { | |
| 4503 value = ClampedToUint8(value); | |
| 4504 } | |
| 4505 Node* offset = ElementOffsetFromIndex(index, kind, mode, 0); | |
| 4506 MachineRepresentation rep = ElementsKindToMachineRepresentation(kind); | |
| 4507 StoreNoWriteBarrier(rep, elements, offset, value); | |
| 4508 return; | |
| 4509 } | |
| 4510 | |
| 4511 WriteBarrierMode barrier_mode = | |
| 4512 IsFastSmiElementsKind(kind) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER; | |
| 4513 if (IsFastDoubleElementsKind(kind)) { | |
| 4514 // Make sure we do not store signalling NaNs into double arrays. | |
| 4515 value = Float64SilenceNaN(value); | |
| 4516 StoreFixedDoubleArrayElement(elements, index, value, mode); | |
| 4517 } else { | |
| 4518 StoreFixedArrayElement(elements, index, value, barrier_mode, mode); | |
| 4519 } | |
| 4520 } | |
| 4521 | |
| 4522 void CodeStubAssembler::StoreObjectElement(Node* object, Node* key, Node* value, | |
| 4523 bool is_jsarray, | |
| 4524 ElementsKind elements_kind, | |
| 4525 KeyedAccessStoreMode store_mode, | |
| 4526 Label* bailout) { | |
| 4527 Node* elements = LoadElements(object); | |
| 4528 if (IsFastSmiOrObjectElementsKind(elements_kind) && | |
| 4529 store_mode != STORE_NO_TRANSITION_HANDLE_COW) { | |
| 4530 // Bailout in case of COW elements. | |
| 4531 GotoIf(WordNotEqual(LoadMap(elements), | |
| 4532 LoadRoot(Heap::kFixedArrayMapRootIndex)), | |
| 4533 bailout); | |
| 4534 } | |
| 4535 // TODO(ishell): introduce TryToIntPtrOrSmi() and use OptimalParameterMode(). | |
| 4536 ParameterMode parameter_mode = INTPTR_PARAMETERS; | |
| 4537 key = TryToIntptr(key, bailout); | |
| 4538 | |
| 4539 if (IsFixedTypedArrayElementsKind(elements_kind)) { | |
| 4540 // Check if buffer has been neutered. | |
| 4541 Node* buffer = LoadObjectField(object, JSArrayBufferView::kBufferOffset); | |
| 4542 Node* bitfield = LoadObjectField(buffer, JSArrayBuffer::kBitFieldOffset, | |
| 4543 MachineType::Uint32()); | |
| 4544 Node* neutered_bit = | |
| 4545 Word32And(bitfield, Int32Constant(JSArrayBuffer::WasNeutered::kMask)); | |
| 4546 GotoUnless(Word32Equal(neutered_bit, Int32Constant(0)), bailout); | |
| 4547 | |
| 4548 // Bounds check. | |
| 4549 Node* length = UntagParameter( | |
| 4550 LoadObjectField(object, JSTypedArray::kLengthOffset), parameter_mode); | |
| 4551 | |
| 4552 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { | |
| 4553 GotoUnless(IntPtrLessThan(key, IntPtrOrSmiConstant(0, parameter_mode)), | |
| 4554 bailout); | |
|
Benedikt Meurer
2016/09/13 09:08:00
Maybe you want to check the upper bound as well, a
Igor Sheludko
2016/09/13 10:33:17
Done. Thanks!
| |
| 4555 } else { | |
| 4556 DCHECK(store_mode == STANDARD_STORE); | |
|
Benedikt Meurer
2016/09/13 09:08:00
Nit: DCHECK_EQ
Igor Sheludko
2016/09/13 10:33:16
Done.
| |
| 4557 GotoUnless(UintPtrLessThan(key, length), bailout); | |
| 4558 } | |
| 4559 // Backing store = external_pointer + base_pointer. | |
| 4560 Node* external_pointer = | |
| 4561 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, | |
| 4562 MachineType::Pointer()); | |
| 4563 Node* base_pointer = | |
| 4564 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); | |
| 4565 Node* backing_store = IntPtrAdd(external_pointer, base_pointer); | |
|
Benedikt Meurer
2016/09/13 09:08:00
You must not have a GC afterwards before you store
Igor Sheludko
2016/09/13 10:33:17
Done.
| |
| 4566 | |
| 4567 if (IsFixedFloatElementsKind(elements_kind)) { | |
| 4568 // TODO(ishell): move float32 truncation into PrepareValueForWrite. | |
| 4569 value = PrepareValueForWrite(value, Representation::Double(), bailout); | |
| 4570 if (elements_kind == FLOAT32_ELEMENTS) { | |
| 4571 value = TruncateFloat64ToFloat32(value); | |
| 4572 } | |
| 4573 } else { | |
| 4574 value = TryToIntptr(value, bailout); | |
|
Benedikt Meurer
2016/09/13 09:08:00
Maybe add a TODO here, that JS truncation would be
Igor Sheludko
2016/09/13 10:33:16
Done.
| |
| 4575 } | |
| 4576 return StoreElement(backing_store, elements_kind, key, value, | |
| 4577 parameter_mode); | |
|
Benedikt Meurer
2016/09/13 09:08:00
You probably need to insert a Retain for the buffe
Igor Sheludko
2016/09/13 10:33:16
I rearranged the code so that the value preparatio
| |
| 4578 } | |
| 4579 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || | |
| 4580 IsFastDoubleElementsKind(elements_kind)); | |
| 4581 | |
| 4582 Node* length = is_jsarray ? LoadObjectField(object, JSArray::kLengthOffset) | |
| 4583 : LoadFixedArrayBaseLength(elements); | |
| 4584 length = UntagParameter(length, parameter_mode); | |
| 4585 | |
| 4586 // In case value is stored into a fast smi array, assure that the value is | |
| 4587 // a smi before manipulating the backing store. Otherwise the backing store | |
| 4588 // may be left in an invalid state. | |
| 4589 if (IsFastSmiElementsKind(elements_kind)) { | |
| 4590 GotoUnless(WordIsSmi(value), bailout); | |
| 4591 } else if (IsFastDoubleElementsKind(elements_kind)) { | |
| 4592 value = PrepareValueForWrite(value, Representation::Double(), bailout); | |
| 4593 } | |
| 4594 | |
| 4595 if (IsGrowStoreMode(store_mode)) { | |
| 4596 elements = CheckForCapacityGrow(object, elements, elements_kind, length, | |
| 4597 key, parameter_mode, is_jsarray, bailout); | |
| 4598 } else { | |
| 4599 GotoUnless(UintPtrLessThan(key, length), bailout); | |
| 4600 | |
| 4601 if ((store_mode == STORE_NO_TRANSITION_HANDLE_COW) && | |
| 4602 IsFastSmiOrObjectElementsKind(elements_kind)) { | |
| 4603 elements = CopyElementsOnWrite(object, elements, elements_kind, length, | |
| 4604 parameter_mode, bailout); | |
| 4605 } | |
| 4606 } | |
| 4607 StoreElement(elements, elements_kind, key, value, parameter_mode); | |
| 4608 } | |
| 4609 | |
| 4610 Node* CodeStubAssembler::CheckForCapacityGrow(Node* object, Node* elements, | |
| 4611 ElementsKind kind, Node* length, | |
| 4612 Node* key, ParameterMode mode, | |
| 4613 bool is_js_array, | |
| 4614 Label* bailout) { | |
| 4615 Variable checked_elements(this, MachineRepresentation::kTagged); | |
| 4616 Label grow_case(this), no_grow_case(this), done(this); | |
| 4617 | |
| 4618 Node* condition; | |
| 4619 if (IsHoleyElementsKind(kind)) { | |
| 4620 condition = UintPtrGreaterThanOrEqual(key, length); | |
| 4621 } else { | |
| 4622 condition = WordEqual(key, length); | |
| 4623 } | |
| 4624 Branch(condition, &grow_case, &no_grow_case); | |
| 4625 | |
| 4626 Bind(&grow_case); | |
| 4627 { | |
| 4628 Node* current_capacity = | |
| 4629 UntagParameter(LoadFixedArrayBaseLength(elements), mode); | |
| 4630 | |
| 4631 checked_elements.Bind(elements); | |
| 4632 | |
| 4633 Label fits_capacity(this); | |
| 4634 GotoIf(UintPtrLessThan(key, current_capacity), &fits_capacity); | |
| 4635 { | |
| 4636 Node* new_elements = TryGrowElementsCapacity( | |
| 4637 object, elements, kind, key, current_capacity, mode, bailout); | |
| 4638 | |
| 4639 checked_elements.Bind(new_elements); | |
| 4640 Goto(&fits_capacity); | |
| 4641 } | |
| 4642 Bind(&fits_capacity); | |
| 4643 | |
| 4644 if (is_js_array) { | |
| 4645 Node* new_length = IntPtrAdd(key, IntPtrOrSmiConstant(1, mode)); | |
| 4646 StoreObjectFieldNoWriteBarrier(object, JSArray::kLengthOffset, | |
| 4647 TagParameter(new_length, mode)); | |
| 4648 } | |
| 4649 | |
| 4650 if (kind == FAST_SMI_ELEMENTS) { | |
|
Benedikt Meurer
2016/09/13 09:08:00
This shouldn't be necessary, it was only necessary
Igor Sheludko
2016/09/13 10:33:16
Indeed, it's not necessary. Thanks!
| |
| 4651 // Write zero to ensure that the new element is initialized with some smi. | |
| 4652 Node* zero = SmiConstant(Smi::FromInt(0)); | |
| 4653 StoreFixedArrayElement(checked_elements.value(), key, zero, | |
| 4654 SKIP_WRITE_BARRIER, mode); | |
| 4655 } | |
| 4656 | |
| 4657 Goto(&done); | |
| 4658 } | |
| 4659 | |
| 4660 Bind(&no_grow_case); | |
| 4661 { | |
| 4662 GotoUnless(UintPtrLessThan(key, length), bailout); | |
| 4663 checked_elements.Bind(elements); | |
| 4664 Goto(&done); | |
| 4665 } | |
| 4666 | |
| 4667 Bind(&done); | |
| 4668 return checked_elements.value(); | |
| 4669 } | |
| 4670 | |
| 4671 Node* CodeStubAssembler::CopyElementsOnWrite(Node* object, Node* elements, | |
| 4672 ElementsKind kind, Node* length, | |
| 4673 ParameterMode mode, | |
| 4674 Label* bailout) { | |
| 4675 Variable new_elements_var(this, MachineRepresentation::kTagged); | |
| 4676 Label done(this); | |
| 4677 | |
| 4678 new_elements_var.Bind(elements); | |
| 4679 GotoUnless( | |
| 4680 WordEqual(LoadMap(elements), LoadRoot(Heap::kFixedCOWArrayMapRootIndex)), | |
| 4681 &done); | |
| 4682 { | |
| 4683 Node* capacity = UntagParameter(LoadFixedArrayBaseLength(elements), mode); | |
| 4684 Node* new_elements = GrowElementsCapacity(object, elements, kind, kind, | |
| 4685 length, capacity, mode, bailout); | |
| 4686 | |
| 4687 new_elements_var.Bind(new_elements); | |
| 4688 Goto(&done); | |
| 4689 } | |
| 4690 | |
| 4691 Bind(&done); | |
| 4692 return new_elements_var.value(); | |
| 4693 } | |
| 4694 | |
| 4459 Node* CodeStubAssembler::EnumLength(Node* map) { | 4695 Node* CodeStubAssembler::EnumLength(Node* map) { |
| 4460 Node* bitfield_3 = LoadMapBitField3(map); | 4696 Node* bitfield_3 = LoadMapBitField3(map); |
| 4461 Node* enum_length = BitFieldDecode<Map::EnumLengthBits>(bitfield_3); | 4697 Node* enum_length = BitFieldDecode<Map::EnumLengthBits>(bitfield_3); |
| 4462 return SmiTag(enum_length); | 4698 return SmiTag(enum_length); |
| 4463 } | 4699 } |
| 4464 | 4700 |
| 4465 void CodeStubAssembler::CheckEnumCache(Node* receiver, Label* use_cache, | 4701 void CodeStubAssembler::CheckEnumCache(Node* receiver, Label* use_cache, |
| 4466 Label* use_runtime) { | 4702 Label* use_runtime) { |
| 4467 Variable current_js_object(this, MachineRepresentation::kTagged); | 4703 Variable current_js_object(this, MachineRepresentation::kTagged); |
| 4468 current_js_object.Bind(receiver); | 4704 current_js_object.Bind(receiver); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4536 Heap::kTheHoleValueRootIndex); | 4772 Heap::kTheHoleValueRootIndex); |
| 4537 | 4773 |
| 4538 // Store the WeakCell in the feedback vector. | 4774 // Store the WeakCell in the feedback vector. |
| 4539 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, | 4775 StoreFixedArrayElement(feedback_vector, slot, cell, UPDATE_WRITE_BARRIER, |
| 4540 CodeStubAssembler::SMI_PARAMETERS); | 4776 CodeStubAssembler::SMI_PARAMETERS); |
| 4541 return cell; | 4777 return cell; |
| 4542 } | 4778 } |
| 4543 | 4779 |
| 4544 } // namespace internal | 4780 } // namespace internal |
| 4545 } // namespace v8 | 4781 } // namespace v8 |
| OLD | NEW |