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

Side by Side Diff: src/objects.cc

Issue 10238005: Use map transitions when defining accessor properties. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 8 years, 8 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
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 4395 matching lines...) Expand 10 before | Expand all | Expand 10 after
4406 accessors->SetComponents(getter, setter); 4406 accessors->SetComponents(getter, setter);
4407 4407
4408 return SetElementCallback(index, accessors, attributes); 4408 return SetElementCallback(index, accessors, attributes);
4409 } 4409 }
4410 4410
4411 4411
4412 MaybeObject* JSObject::CreateAccessorPairFor(String* name) { 4412 MaybeObject* JSObject::CreateAccessorPairFor(String* name) {
4413 LookupResult result(GetHeap()->isolate()); 4413 LookupResult result(GetHeap()->isolate());
4414 LocalLookupRealNamedProperty(name, &result); 4414 LocalLookupRealNamedProperty(name, &result);
4415 if (result.IsProperty() && result.type() == CALLBACKS) { 4415 if (result.IsProperty() && result.type() == CALLBACKS) {
4416 ASSERT(!result.IsDontDelete()); 4416 // Note that the result can actually have IsDontDelete() == true when we
4417 // e.g. have to fall back to the slow case while adding a setter after
4418 // successfully reusing a map transition for a getter. Nevertheless, this is
4419 // OK, because the assertion only holds for the whole addition of both
4420 // accessors, not for the addition of each part.
4417 Object* obj = result.GetCallbackObject(); 4421 Object* obj = result.GetCallbackObject();
4418 if (obj->IsAccessorPair()) { 4422 if (obj->IsAccessorPair()) {
4419 return AccessorPair::cast(obj)->CopyWithoutTransitions(); 4423 return AccessorPair::cast(obj)->CopyWithoutTransitions();
4420 } 4424 }
4421 } 4425 }
4422 return GetHeap()->AllocateAccessorPair(); 4426 return GetHeap()->AllocateAccessorPair();
4423 } 4427 }
4424 4428
4425 4429
4426 MaybeObject* JSObject::DefinePropertyAccessor(String* name, 4430 MaybeObject* JSObject::DefinePropertyAccessor(String* name,
4427 Object* getter, 4431 Object* getter,
4428 Object* setter, 4432 Object* setter,
4429 PropertyAttributes attributes) { 4433 PropertyAttributes attributes) {
4434 bool only_attribute_changes = getter->IsNull() && setter->IsNull();
4435 if (HasFastProperties() && !only_attribute_changes) {
4436 MaybeObject* getterOk = GetHeap()->undefined_value();
Michael Starzinger 2012/05/02 13:30:14 Can we move the result of "GetHeap()" into a local
Sven Panne 2012/05/03 09:39:02 Done for the occurrences where it is actually used
4437 if (!getter->IsNull()) {
4438 getterOk = DefineFastAccessor(name, ACCESSOR_GETTER, getter, attributes);
4439 if (getterOk->IsFailure()) return getterOk;
4440 }
4441
4442 MaybeObject* setterOk = GetHeap()->undefined_value();
4443 if (getterOk != GetHeap()->null_value() && !setter->IsNull()) {
4444 setterOk = DefineFastAccessor(name, ACCESSOR_SETTER, setter, attributes);
4445 if (setterOk->IsFailure()) return setterOk;
4446 }
4447
4448 if (getterOk != GetHeap()->null_value() &&
4449 setterOk != GetHeap()->null_value()) {
4450 return GetHeap()->undefined_value();
4451 }
4452 }
4453
4430 AccessorPair* accessors; 4454 AccessorPair* accessors;
4431 { MaybeObject* maybe_accessors = CreateAccessorPairFor(name); 4455 { MaybeObject* maybe_accessors = CreateAccessorPairFor(name);
4432 if (!maybe_accessors->To(&accessors)) return maybe_accessors; 4456 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
4433 } 4457 }
4434 accessors->SetComponents(getter, setter); 4458 accessors->SetComponents(getter, setter);
4435 return SetPropertyCallback(name, accessors, attributes); 4459 return SetPropertyCallback(name, accessors, attributes);
4436 } 4460 }
4437 4461
4438 4462
4439 bool JSObject::CanSetCallback(String* name) { 4463 bool JSObject::CanSetCallback(String* name) {
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
4569 4593
4570 if (!CanSetCallback(name)) return isolate->heap()->undefined_value(); 4594 if (!CanSetCallback(name)) return isolate->heap()->undefined_value();
4571 4595
4572 uint32_t index = 0; 4596 uint32_t index = 0;
4573 return name->AsArrayIndex(&index) ? 4597 return name->AsArrayIndex(&index) ?
4574 DefineElementAccessor(index, getter, setter, attributes) : 4598 DefineElementAccessor(index, getter, setter, attributes) :
4575 DefinePropertyAccessor(name, getter, setter, attributes); 4599 DefinePropertyAccessor(name, getter, setter, attributes);
4576 } 4600 }
4577 4601
4578 4602
4603 static bool TransitionToSameAccessor(Object* map,
4604 String* name,
4605 AccessorComponent component,
4606 Object* accessor,
4607 PropertyAttributes attributes ) {
4608 DescriptorArray* descs = Map::cast(map)->instance_descriptors();
4609 int number = descs->SearchWithCache(name);
4610 ASSERT(number != DescriptorArray::kNotFound);
4611 Object* target_accessor =
4612 AccessorPair::cast(descs->GetCallbacksObject(number))->get(component);
4613 PropertyAttributes target_attributes = descs->GetDetails(number).attributes();
4614 return target_accessor == accessor && target_attributes == attributes;
4615 }
4616
4617
4618 MaybeObject* JSObject::DefineFastAccessor(String* name,
4619 AccessorComponent component,
4620 Object* accessor,
4621 PropertyAttributes attributes) {
4622 LookupResult result(GetIsolate());
4623 LocalLookup(name, &result);
4624
4625 // If we have a new property, create a fresh accessor plus a transition to it.
4626 if (!result.IsFound()) {
4627 return CreateFreshAccessor(name, component, accessor, attributes);
4628 }
4629
4630 // If the property is not a JavaScript accessor, fall back to the slow case.
4631 if (result.type() != CALLBACKS) return GetHeap()->null_value();
4632 Object* callback_value = result.GetValue();
4633 if (!callback_value->IsAccessorPair()) return GetHeap()->null_value();
4634 AccessorPair* accessors = AccessorPair::cast(callback_value);
4635
4636 // Follow a callback transition, if there is a fitting one.
4637 Object* entry = accessors->get(component);
4638 if (entry->IsMap() &&
4639 TransitionToSameAccessor(entry, name, component, accessor, attributes)) {
4640 set_map(Map::cast(entry));
4641 return this;
4642 }
4643
4644 // When we re-add the same accessor again, there is nothing to do.
4645 if (entry == accessor && result.GetAttributes() == attributes) return this;
4646
4647 // Only the other accessor has been set so far, create a new transition.
4648 if (entry->IsTheHole()) {
4649 return NewCallbackTrans(name, component, accessor, attributes, accessors);
Michael Starzinger 2012/05/02 13:30:14 Can we add an assertion to the top of this method
Sven Panne 2012/05/03 09:39:02 I'll add a slightly stronger assertion, checking t
4650 }
4651
4652 // Nothing from the above worked, so we have to fall back to the slow case.
4653 return GetHeap()->null_value();
4654 }
4655
4656
4657 MaybeObject* JSObject::CreateFreshAccessor(String* name,
Michael Starzinger 2012/05/02 13:30:14 Can we turn this method into a static helper that
Sven Panne 2012/05/03 09:39:02 As discussed offline, let's just simply pass 'this
4658 AccessorComponent component,
4659 Object* accessor,
4660 PropertyAttributes attributes) {
4661 // step 1: create a new getter/setter pair with only the accessor in it
4662 AccessorPair* accessors2;
4663 { MaybeObject* maybe_accessors2 = GetHeap()->AllocateAccessorPair();
4664 if (!maybe_accessors2->To(&accessors2)) return maybe_accessors2;
4665 }
4666 accessors2->set(component, accessor);
4667
4668 // step 2: create a copy of the descriptors, incl. the new getter/setter pair
4669 Map* map1 = map();
4670 CallbacksDescriptor callbacks_descr2(name, accessors2, attributes);
4671 DescriptorArray* descriptors2;
4672 { MaybeObject* maybe_descriptors2 =
4673 map1->instance_descriptors()->CopyInsert(&callbacks_descr2,
4674 REMOVE_TRANSITIONS);
4675 if (!maybe_descriptors2->To(&descriptors2)) return maybe_descriptors2;
4676 }
4677
4678 // step 3: create a new map with the new descriptors
4679 Map* map2;
4680 { MaybeObject* maybe_map2 = map1->CopyDropDescriptors();
4681 if (!maybe_map2->To(&map2)) return maybe_map2;
4682 }
4683 map2->set_instance_descriptors(descriptors2);
4684
4685 // step 4: create a new getter/setter pair with a transition to the new map
4686 AccessorPair* accessors1;
4687 { MaybeObject* maybe_accessors1 = GetHeap()->AllocateAccessorPair();
4688 if (!maybe_accessors1->To(&accessors1)) return maybe_accessors1;
4689 }
4690 accessors1->set(component, map2);
4691
4692 // step 5: create a copy of the descriptors, incl. the new getter/setter pair
4693 // with the transition
4694 CallbacksDescriptor callbacks_descr1(name, accessors1, attributes);
4695 DescriptorArray* descriptors1;
4696 { MaybeObject* maybe_descriptors1 =
4697 map1->instance_descriptors()->CopyInsert(&callbacks_descr1,
4698 KEEP_TRANSITIONS);
4699 if (!maybe_descriptors1->To(&descriptors1)) return maybe_descriptors1;
4700 }
4701
4702 // step 6: everything went well so far, so we make our changes visible
4703 set_map(map2);
4704 map1->set_instance_descriptors(descriptors1);
4705 return this;
4706 }
4707
4708
4709 MaybeObject* JSObject::NewCallbackTrans(String* name,
Michael Starzinger 2012/05/02 13:30:14 Likewise. Also the full name "NewCallbackTransitio
Sven Panne 2012/05/03 09:39:02 It was because of our 80-column limit. :-) Done.
4710 AccessorComponent component,
4711 Object* accessor,
4712 PropertyAttributes attributes,
4713 AccessorPair* accessors2) {
4714 // step 1: copy the old getter/setter pair and set the new accessor
4715 AccessorPair* accessors3;
4716 { MaybeObject* maybe_accessors3 = accessors2->CopyWithoutTransitions();
4717 if (!maybe_accessors3->To(&accessors3)) return maybe_accessors3;
4718 }
4719 accessors3->set(component, accessor);
4720
4721 // step 2: create a copy of the descriptors, incl. the new getter/setter pair
4722 Map* map2 = map();
4723 CallbacksDescriptor callbacks_descr3(name, accessors3, attributes);
4724 DescriptorArray* descriptors3;
4725 { MaybeObject* maybe_descriptors3 =
4726 map2->instance_descriptors()->CopyInsert(&callbacks_descr3,
4727 REMOVE_TRANSITIONS);
4728 if (!maybe_descriptors3->To(&descriptors3)) return maybe_descriptors3;
4729 }
4730
4731 // step 3: create a new map with the new descriptors
4732 Map* map3;
4733 { MaybeObject* maybe_map3 = map2->CopyDropDescriptors();
4734 if (!maybe_map3->To(&map3)) return maybe_map3;
4735 }
4736 map3->set_instance_descriptors(descriptors3);
4737
4738 // step 4: everything went well so far, so we make our changes visible
4739 set_map(map3);
4740 accessors2->set(component, map3);
4741 return this;
4742 }
4743
4744
4579 MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { 4745 MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
4580 Isolate* isolate = GetIsolate(); 4746 Isolate* isolate = GetIsolate();
4581 String* name = String::cast(info->name()); 4747 String* name = String::cast(info->name());
4582 // Check access rights if needed. 4748 // Check access rights if needed.
4583 if (IsAccessCheckNeeded() && 4749 if (IsAccessCheckNeeded() &&
4584 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { 4750 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4585 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); 4751 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4586 return isolate->heap()->undefined_value(); 4752 return isolate->heap()->undefined_value();
4587 } 4753 }
4588 4754
(...skipping 1343 matching lines...) Expand 10 before | Expand all | Expand 10 after
5932 { MaybeObject* maybe_copy = heap->AllocateAccessorPair(); 6098 { MaybeObject* maybe_copy = heap->AllocateAccessorPair();
5933 if (!maybe_copy->To(&copy)) return maybe_copy; 6099 if (!maybe_copy->To(&copy)) return maybe_copy;
5934 } 6100 }
5935 copy->set_getter(getter()->IsMap() ? heap->the_hole_value() : getter()); 6101 copy->set_getter(getter()->IsMap() ? heap->the_hole_value() : getter());
5936 copy->set_setter(setter()->IsMap() ? heap->the_hole_value() : setter()); 6102 copy->set_setter(setter()->IsMap() ? heap->the_hole_value() : setter());
5937 return copy; 6103 return copy;
5938 } 6104 }
5939 6105
5940 6106
5941 Object* AccessorPair::GetComponent(AccessorComponent component) { 6107 Object* AccessorPair::GetComponent(AccessorComponent component) {
5942 Object* accessor = (component == ACCESSOR_GETTER) ? getter() : setter(); 6108 Object* accessor = get(component);
5943 return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor; 6109 return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
5944 } 6110 }
5945 6111
5946 6112
5947 MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count, 6113 MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
5948 PretenureFlag pretenure) { 6114 PretenureFlag pretenure) {
5949 ASSERT(deopt_entry_count > 0); 6115 ASSERT(deopt_entry_count > 0);
5950 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count), 6116 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
5951 pretenure); 6117 pretenure);
5952 } 6118 }
5953 6119
(...skipping 7010 matching lines...) Expand 10 before | Expand all | Expand 10 after
12964 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); 13130 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
12965 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); 13131 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
12966 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); 13132 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
12967 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); 13133 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
12968 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); 13134 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
12969 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); 13135 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
12970 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); 13136 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
12971 } 13137 }
12972 13138
12973 } } // namespace v8::internal 13139 } } // namespace v8::internal
OLDNEW
« src/objects.h ('K') | « src/objects.h ('k') | test/mjsunit/accessor-map-sharing.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698