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 |