Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(158)

Side by Side Diff: src/objects.cc

Issue 10445009: Re-land: Use map transitions when defining accessor properties. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Fixed bootup memory checks. Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/objects.h ('k') | test/cctest/test-mark-compact.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
5959 { MaybeObject* maybe_copy = heap->AllocateAccessorPair(); 6134 { MaybeObject* maybe_copy = heap->AllocateAccessorPair();
5960 if (!maybe_copy->To(&copy)) return maybe_copy; 6135 if (!maybe_copy->To(&copy)) 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
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
OLDNEW
« no previous file with comments | « src/objects.h ('k') | test/cctest/test-mark-compact.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698