OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 4415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4426 accessors->SetComponents(getter, setter); | 4426 accessors->SetComponents(getter, setter); |
4427 | 4427 |
4428 return SetElementCallback(index, accessors, attributes); | 4428 return SetElementCallback(index, accessors, attributes); |
4429 } | 4429 } |
4430 | 4430 |
4431 | 4431 |
4432 MaybeObject* JSObject::CreateAccessorPairFor(String* name) { | 4432 MaybeObject* JSObject::CreateAccessorPairFor(String* name) { |
4433 LookupResult result(GetHeap()->isolate()); | 4433 LookupResult result(GetHeap()->isolate()); |
4434 LocalLookupRealNamedProperty(name, &result); | 4434 LocalLookupRealNamedProperty(name, &result); |
4435 if (result.IsProperty() && result.type() == CALLBACKS) { | 4435 if (result.IsProperty() && result.type() == CALLBACKS) { |
4436 ASSERT(!result.IsDontDelete()); | 4436 // Note that the result can actually have IsDontDelete() == true when we |
| 4437 // e.g. have to fall back to the slow case while adding a setter after |
| 4438 // successfully reusing a map transition for a getter. Nevertheless, this is |
| 4439 // OK, because the assertion only holds for the whole addition of both |
| 4440 // accessors, not for the addition of each part. See first comment in |
| 4441 // DefinePropertyAccessor below. |
4437 Object* obj = result.GetCallbackObject(); | 4442 Object* obj = result.GetCallbackObject(); |
4438 if (obj->IsAccessorPair()) { | 4443 if (obj->IsAccessorPair()) { |
4439 return AccessorPair::cast(obj)->CopyWithoutTransitions(); | 4444 return AccessorPair::cast(obj)->CopyWithoutTransitions(); |
4440 } | 4445 } |
4441 } | 4446 } |
4442 return GetHeap()->AllocateAccessorPair(); | 4447 return GetHeap()->AllocateAccessorPair(); |
4443 } | 4448 } |
4444 | 4449 |
4445 | 4450 |
4446 MaybeObject* JSObject::DefinePropertyAccessor(String* name, | 4451 MaybeObject* JSObject::DefinePropertyAccessor(String* name, |
4447 Object* getter, | 4452 Object* getter, |
4448 Object* setter, | 4453 Object* setter, |
4449 PropertyAttributes attributes) { | 4454 PropertyAttributes attributes) { |
| 4455 // We could assert that the property is configurable here, but we would need |
| 4456 // to do a lookup, which seems to be a bit of overkill. |
| 4457 Heap* heap = GetHeap(); |
| 4458 bool only_attribute_changes = getter->IsNull() && setter->IsNull(); |
| 4459 if (FLAG_fast_accessor_properties && |
| 4460 HasFastProperties() && !only_attribute_changes) { |
| 4461 MaybeObject* getterOk = heap->undefined_value(); |
| 4462 if (!getter->IsNull()) { |
| 4463 getterOk = DefineFastAccessor(name, ACCESSOR_GETTER, getter, attributes); |
| 4464 if (getterOk->IsFailure()) return getterOk; |
| 4465 } |
| 4466 |
| 4467 MaybeObject* setterOk = heap->undefined_value(); |
| 4468 if (getterOk != heap->null_value() && !setter->IsNull()) { |
| 4469 setterOk = DefineFastAccessor(name, ACCESSOR_SETTER, setter, attributes); |
| 4470 if (setterOk->IsFailure()) return setterOk; |
| 4471 } |
| 4472 |
| 4473 if (getterOk != heap->null_value() && setterOk != heap->null_value()) { |
| 4474 return heap->undefined_value(); |
| 4475 } |
| 4476 } |
| 4477 |
4450 AccessorPair* accessors; | 4478 AccessorPair* accessors; |
4451 { MaybeObject* maybe_accessors = CreateAccessorPairFor(name); | 4479 { MaybeObject* maybe_accessors = CreateAccessorPairFor(name); |
4452 if (!maybe_accessors->To(&accessors)) return maybe_accessors; | 4480 if (!maybe_accessors->To(&accessors)) return maybe_accessors; |
4453 } | 4481 } |
4454 accessors->SetComponents(getter, setter); | 4482 accessors->SetComponents(getter, setter); |
4455 return SetPropertyCallback(name, accessors, attributes); | 4483 return SetPropertyCallback(name, accessors, attributes); |
4456 } | 4484 } |
4457 | 4485 |
4458 | 4486 |
4459 bool JSObject::CanSetCallback(String* name) { | 4487 bool JSObject::CanSetCallback(String* name) { |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4589 | 4617 |
4590 if (!CanSetCallback(name)) return isolate->heap()->undefined_value(); | 4618 if (!CanSetCallback(name)) return isolate->heap()->undefined_value(); |
4591 | 4619 |
4592 uint32_t index = 0; | 4620 uint32_t index = 0; |
4593 return name->AsArrayIndex(&index) ? | 4621 return name->AsArrayIndex(&index) ? |
4594 DefineElementAccessor(index, getter, setter, attributes) : | 4622 DefineElementAccessor(index, getter, setter, attributes) : |
4595 DefinePropertyAccessor(name, getter, setter, attributes); | 4623 DefinePropertyAccessor(name, getter, setter, attributes); |
4596 } | 4624 } |
4597 | 4625 |
4598 | 4626 |
| 4627 static MaybeObject* CreateFreshAccessor(JSObject* obj, |
| 4628 String* name, |
| 4629 AccessorComponent component, |
| 4630 Object* accessor, |
| 4631 PropertyAttributes attributes) { |
| 4632 // step 1: create a new getter/setter pair with only the accessor in it |
| 4633 Heap* heap = obj->GetHeap(); |
| 4634 AccessorPair* accessors2; |
| 4635 { MaybeObject* maybe_accessors2 = heap->AllocateAccessorPair(); |
| 4636 if (!maybe_accessors2->To(&accessors2)) return maybe_accessors2; |
| 4637 } |
| 4638 accessors2->set(component, accessor); |
| 4639 |
| 4640 // step 2: create a copy of the descriptors, incl. the new getter/setter pair |
| 4641 Map* map1 = obj->map(); |
| 4642 CallbacksDescriptor callbacks_descr2(name, accessors2, attributes); |
| 4643 DescriptorArray* descriptors2; |
| 4644 { MaybeObject* maybe_descriptors2 = |
| 4645 map1->instance_descriptors()->CopyInsert(&callbacks_descr2, |
| 4646 REMOVE_TRANSITIONS); |
| 4647 if (!maybe_descriptors2->To(&descriptors2)) return maybe_descriptors2; |
| 4648 } |
| 4649 |
| 4650 // step 3: create a new map with the new descriptors |
| 4651 Map* map2; |
| 4652 { MaybeObject* maybe_map2 = map1->CopyDropDescriptors(); |
| 4653 if (!maybe_map2->To(&map2)) return maybe_map2; |
| 4654 } |
| 4655 map2->set_instance_descriptors(descriptors2); |
| 4656 |
| 4657 // step 4: create a new getter/setter pair with a transition to the new map |
| 4658 AccessorPair* accessors1; |
| 4659 { MaybeObject* maybe_accessors1 = heap->AllocateAccessorPair(); |
| 4660 if (!maybe_accessors1->To(&accessors1)) return maybe_accessors1; |
| 4661 } |
| 4662 accessors1->set(component, map2); |
| 4663 |
| 4664 // step 5: create a copy of the descriptors, incl. the new getter/setter pair |
| 4665 // with the transition |
| 4666 CallbacksDescriptor callbacks_descr1(name, accessors1, attributes); |
| 4667 DescriptorArray* descriptors1; |
| 4668 { MaybeObject* maybe_descriptors1 = |
| 4669 map1->instance_descriptors()->CopyInsert(&callbacks_descr1, |
| 4670 KEEP_TRANSITIONS); |
| 4671 if (!maybe_descriptors1->To(&descriptors1)) return maybe_descriptors1; |
| 4672 } |
| 4673 |
| 4674 // step 6: everything went well so far, so we make our changes visible |
| 4675 obj->set_map(map2); |
| 4676 map1->set_instance_descriptors(descriptors1); |
| 4677 map2->SetBackPointer(map1); |
| 4678 return obj; |
| 4679 } |
| 4680 |
| 4681 |
| 4682 static bool TransitionToSameAccessor(Object* map, |
| 4683 String* name, |
| 4684 AccessorComponent component, |
| 4685 Object* accessor, |
| 4686 PropertyAttributes attributes ) { |
| 4687 DescriptorArray* descs = Map::cast(map)->instance_descriptors(); |
| 4688 int number = descs->SearchWithCache(name); |
| 4689 ASSERT(number != DescriptorArray::kNotFound); |
| 4690 Object* target_accessor = |
| 4691 AccessorPair::cast(descs->GetCallbacksObject(number))->get(component); |
| 4692 PropertyAttributes target_attributes = descs->GetDetails(number).attributes(); |
| 4693 return target_accessor == accessor && target_attributes == attributes; |
| 4694 } |
| 4695 |
| 4696 |
| 4697 static MaybeObject* NewCallbackTransition(JSObject* obj, |
| 4698 String* name, |
| 4699 AccessorComponent component, |
| 4700 Object* accessor, |
| 4701 PropertyAttributes attributes, |
| 4702 AccessorPair* accessors2) { |
| 4703 // step 1: copy the old getter/setter pair and set the new accessor |
| 4704 AccessorPair* accessors3; |
| 4705 { MaybeObject* maybe_accessors3 = accessors2->CopyWithoutTransitions(); |
| 4706 if (!maybe_accessors3->To(&accessors3)) return maybe_accessors3; |
| 4707 } |
| 4708 accessors3->set(component, accessor); |
| 4709 |
| 4710 // step 2: create a copy of the descriptors, incl. the new getter/setter pair |
| 4711 Map* map2 = obj->map(); |
| 4712 CallbacksDescriptor callbacks_descr3(name, accessors3, attributes); |
| 4713 DescriptorArray* descriptors3; |
| 4714 { MaybeObject* maybe_descriptors3 = |
| 4715 map2->instance_descriptors()->CopyInsert(&callbacks_descr3, |
| 4716 REMOVE_TRANSITIONS); |
| 4717 if (!maybe_descriptors3->To(&descriptors3)) return maybe_descriptors3; |
| 4718 } |
| 4719 |
| 4720 // step 3: create a new map with the new descriptors |
| 4721 Map* map3; |
| 4722 { MaybeObject* maybe_map3 = map2->CopyDropDescriptors(); |
| 4723 if (!maybe_map3->To(&map3)) return maybe_map3; |
| 4724 } |
| 4725 map3->set_instance_descriptors(descriptors3); |
| 4726 |
| 4727 // step 4: everything went well so far, so we make our changes visible |
| 4728 obj->set_map(map3); |
| 4729 accessors2->set(component, map3); |
| 4730 map3->SetBackPointer(map2); |
| 4731 return obj; |
| 4732 } |
| 4733 |
| 4734 |
| 4735 MaybeObject* JSObject::DefineFastAccessor(String* name, |
| 4736 AccessorComponent component, |
| 4737 Object* accessor, |
| 4738 PropertyAttributes attributes) { |
| 4739 ASSERT(accessor->IsSpecFunction() || accessor->IsUndefined()); |
| 4740 LookupResult result(GetIsolate()); |
| 4741 LocalLookup(name, &result); |
| 4742 |
| 4743 // If we have a new property, create a fresh accessor plus a transition to it. |
| 4744 if (!result.IsFound()) { |
| 4745 return CreateFreshAccessor(this, name, component, accessor, attributes); |
| 4746 } |
| 4747 |
| 4748 // If the property is not a JavaScript accessor, fall back to the slow case. |
| 4749 if (result.type() != CALLBACKS) return GetHeap()->null_value(); |
| 4750 Object* callback_value = result.GetCallbackObject(); |
| 4751 if (!callback_value->IsAccessorPair()) return GetHeap()->null_value(); |
| 4752 AccessorPair* accessors = AccessorPair::cast(callback_value); |
| 4753 |
| 4754 // Follow a callback transition, if there is a fitting one. |
| 4755 Object* entry = accessors->get(component); |
| 4756 if (entry->IsMap() && |
| 4757 TransitionToSameAccessor(entry, name, component, accessor, attributes)) { |
| 4758 set_map(Map::cast(entry)); |
| 4759 return this; |
| 4760 } |
| 4761 |
| 4762 // When we re-add the same accessor again, there is nothing to do. |
| 4763 if (entry == accessor && result.GetAttributes() == attributes) return this; |
| 4764 |
| 4765 // Only the other accessor has been set so far, create a new transition. |
| 4766 if (entry->IsTheHole()) { |
| 4767 return NewCallbackTransition(this, |
| 4768 name, |
| 4769 component, |
| 4770 accessor, |
| 4771 attributes, |
| 4772 accessors); |
| 4773 } |
| 4774 |
| 4775 // Nothing from the above worked, so we have to fall back to the slow case. |
| 4776 return GetHeap()->null_value(); |
| 4777 } |
| 4778 |
| 4779 |
4599 MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { | 4780 MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { |
4600 Isolate* isolate = GetIsolate(); | 4781 Isolate* isolate = GetIsolate(); |
4601 String* name = String::cast(info->name()); | 4782 String* name = String::cast(info->name()); |
4602 // Check access rights if needed. | 4783 // Check access rights if needed. |
4603 if (IsAccessCheckNeeded() && | 4784 if (IsAccessCheckNeeded() && |
4604 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { | 4785 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { |
4605 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); | 4786 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); |
4606 return isolate->heap()->undefined_value(); | 4787 return isolate->heap()->undefined_value(); |
4607 } | 4788 } |
4608 | 4789 |
(...skipping 1138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5747 if (IsNullDescriptor(i)) continue; | 5928 if (IsNullDescriptor(i)) continue; |
5748 if (remove_transitions && IsTransitionOnly(i)) continue; | 5929 if (remove_transitions && IsTransitionOnly(i)) continue; |
5749 new_size++; | 5930 new_size++; |
5750 } | 5931 } |
5751 | 5932 |
5752 // If key is in descriptor, we replace it in-place when filtering. | 5933 // If key is in descriptor, we replace it in-place when filtering. |
5753 // Count a null descriptor for key as inserted, not replaced. | 5934 // Count a null descriptor for key as inserted, not replaced. |
5754 int index = Search(descriptor->GetKey()); | 5935 int index = Search(descriptor->GetKey()); |
5755 const bool replacing = (index != kNotFound); | 5936 const bool replacing = (index != kNotFound); |
5756 bool keep_enumeration_index = false; | 5937 bool keep_enumeration_index = false; |
5757 if (replacing) { | 5938 if (!replacing) { |
5758 // We are replacing an existing descriptor. We keep the enumeration | 5939 ++new_size; |
5759 // index of a visible property. | 5940 } else if (!IsTransitionOnly(index)) { |
5760 PropertyType t = GetDetails(index).type(); | 5941 // We are replacing an existing descriptor. We keep the enumeration index |
5761 if (t == CONSTANT_FUNCTION || | 5942 // of a visible property. |
5762 t == FIELD || | 5943 keep_enumeration_index = true; |
5763 t == CALLBACKS || | 5944 } else if (remove_transitions) { |
5764 t == INTERCEPTOR) { | 5945 // Replaced descriptor has been counted as removed if it is a transition |
5765 keep_enumeration_index = true; | 5946 // that will be replaced. Adjust count in this case. |
5766 } else if (remove_transitions) { | |
5767 // Replaced descriptor has been counted as removed if it is | |
5768 // a transition that will be replaced. Adjust count in this case. | |
5769 ++new_size; | |
5770 } | |
5771 } else { | |
5772 ++new_size; | 5947 ++new_size; |
5773 } | 5948 } |
5774 | 5949 |
5775 DescriptorArray* new_descriptors; | 5950 DescriptorArray* new_descriptors; |
5776 { MaybeObject* maybe_result = Allocate(new_size); | 5951 { MaybeObject* maybe_result = Allocate(new_size); |
5777 if (!maybe_result->To(&new_descriptors)) return maybe_result; | 5952 if (!maybe_result->To(&new_descriptors)) return maybe_result; |
5778 } | 5953 } |
5779 | 5954 |
5780 DescriptorArray::WhitenessWitness witness(new_descriptors); | 5955 DescriptorArray::WhitenessWitness witness(new_descriptors); |
5781 | 5956 |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5959 { MaybeObject* maybe_copy = heap->AllocateAccessorPair(); | 6134 { MaybeObject* maybe_copy = heap->AllocateAccessorPair(); |
5960 if (!maybe_copy->To(©)) return maybe_copy; | 6135 if (!maybe_copy->To(©)) return maybe_copy; |
5961 } | 6136 } |
5962 copy->set_getter(getter()->IsMap() ? heap->the_hole_value() : getter()); | 6137 copy->set_getter(getter()->IsMap() ? heap->the_hole_value() : getter()); |
5963 copy->set_setter(setter()->IsMap() ? heap->the_hole_value() : setter()); | 6138 copy->set_setter(setter()->IsMap() ? heap->the_hole_value() : setter()); |
5964 return copy; | 6139 return copy; |
5965 } | 6140 } |
5966 | 6141 |
5967 | 6142 |
5968 Object* AccessorPair::GetComponent(AccessorComponent component) { | 6143 Object* AccessorPair::GetComponent(AccessorComponent component) { |
5969 Object* accessor = (component == ACCESSOR_GETTER) ? getter() : setter(); | 6144 Object* accessor = get(component); |
5970 return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor; | 6145 return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor; |
5971 } | 6146 } |
5972 | 6147 |
5973 | 6148 |
5974 MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count, | 6149 MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count, |
5975 PretenureFlag pretenure) { | 6150 PretenureFlag pretenure) { |
5976 ASSERT(deopt_entry_count > 0); | 6151 ASSERT(deopt_entry_count > 0); |
5977 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count), | 6152 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count), |
5978 pretenure); | 6153 pretenure); |
5979 } | 6154 } |
5980 | 6155 |
(...skipping 7040 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13021 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); | 13196 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); |
13022 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); | 13197 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); |
13023 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); | 13198 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); |
13024 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); | 13199 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); |
13025 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); | 13200 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); |
13026 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); | 13201 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); |
13027 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); | 13202 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); |
13028 } | 13203 } |
13029 | 13204 |
13030 } } // namespace v8::internal | 13205 } } // namespace v8::internal |
OLD | NEW |