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

Side by Side Diff: src/objects.cc

Issue 7094003: Per-Isolate cache for polymorphic stubs (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 6 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 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 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 2471 matching lines...) Expand 10 before | Expand all | Expand 10 after
2482 LookupResult result; 2482 LookupResult result;
2483 LocalLookup(name, &result); 2483 LocalLookup(name, &result);
2484 return GetPropertyAttribute(this, &result, name, false); 2484 return GetPropertyAttribute(this, &result, name, false);
2485 } 2485 }
2486 2486
2487 2487
2488 MaybeObject* NormalizedMapCache::Get(JSObject* obj, 2488 MaybeObject* NormalizedMapCache::Get(JSObject* obj,
2489 PropertyNormalizationMode mode) { 2489 PropertyNormalizationMode mode) {
2490 Isolate* isolate = obj->GetIsolate(); 2490 Isolate* isolate = obj->GetIsolate();
2491 Map* fast = obj->map(); 2491 Map* fast = obj->map();
2492 int index = Hash(fast) % kEntries; 2492 int index = fast->Hash() % kEntries;
2493 Object* result = get(index); 2493 Object* result = get(index);
2494 if (result->IsMap() && CheckHit(Map::cast(result), fast, mode)) { 2494 if (result->IsMap() && Map::cast(result)->Equals(fast, mode)) {
2495 #ifdef DEBUG 2495 #ifdef DEBUG
2496 Map::cast(result)->SharedMapVerify();
2496 if (FLAG_enable_slow_asserts) { 2497 if (FLAG_enable_slow_asserts) {
2497 // The cached map should match newly created normalized map bit-by-bit. 2498 // The cached map should match newly created normalized map bit-by-bit.
2498 Object* fresh; 2499 Object* fresh;
2499 { MaybeObject* maybe_fresh = 2500 { MaybeObject* maybe_fresh =
2500 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); 2501 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2501 if (maybe_fresh->ToObject(&fresh)) { 2502 if (maybe_fresh->ToObject(&fresh)) {
2502 ASSERT(memcmp(Map::cast(fresh)->address(), 2503 ASSERT(memcmp(Map::cast(fresh)->address(),
2503 Map::cast(result)->address(), 2504 Map::cast(result)->address(),
2504 Map::kSize) == 0); 2505 Map::kSize) == 0);
2505 } 2506 }
(...skipping 15 matching lines...) Expand all
2521 2522
2522 2523
2523 void NormalizedMapCache::Clear() { 2524 void NormalizedMapCache::Clear() {
2524 int entries = length(); 2525 int entries = length();
2525 for (int i = 0; i != entries; i++) { 2526 for (int i = 0; i != entries; i++) {
2526 set_undefined(i); 2527 set_undefined(i);
2527 } 2528 }
2528 } 2529 }
2529 2530
2530 2531
2531 int NormalizedMapCache::Hash(Map* fast) {
2532 // For performance reasons we only hash the 3 most variable fields of a map:
2533 // constructor, prototype and bit_field2.
2534
2535 // Shift away the tag.
2536 int hash = (static_cast<uint32_t>(
2537 reinterpret_cast<uintptr_t>(fast->constructor())) >> 2);
2538
2539 // XOR-ing the prototype and constructor directly yields too many zero bits
2540 // when the two pointers are close (which is fairly common).
2541 // To avoid this we shift the prototype 4 bits relatively to the constructor.
2542 hash ^= (static_cast<uint32_t>(
2543 reinterpret_cast<uintptr_t>(fast->prototype())) << 2);
2544
2545 return hash ^ (hash >> 16) ^ fast->bit_field2();
2546 }
2547
2548
2549 bool NormalizedMapCache::CheckHit(Map* slow,
2550 Map* fast,
2551 PropertyNormalizationMode mode) {
2552 #ifdef DEBUG
2553 slow->SharedMapVerify();
2554 #endif
2555 return
2556 slow->constructor() == fast->constructor() &&
2557 slow->prototype() == fast->prototype() &&
2558 slow->inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
2559 0 :
2560 fast->inobject_properties()) &&
2561 slow->instance_type() == fast->instance_type() &&
2562 slow->bit_field() == fast->bit_field() &&
2563 slow->bit_field2() == fast->bit_field2() &&
2564 (slow->bit_field3() & ~(1<<Map::kIsShared)) == fast->bit_field3();
Mads Ager (chromium) 2011/06/01 08:45:53 Here we only ignore the shared bit on |slow|. Is t
Jakob Kummerow 2011/06/01 10:15:27 If I understand the code correctly, for all cases
2565 }
2566
2567
2568 MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) { 2532 MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
2569 if (map()->is_shared()) { 2533 if (map()->is_shared()) {
2570 // Fast case maps are never marked as shared. 2534 // Fast case maps are never marked as shared.
2571 ASSERT(!HasFastProperties()); 2535 ASSERT(!HasFastProperties());
2572 // Replace the map with an identical copy that can be safely modified. 2536 // Replace the map with an identical copy that can be safely modified.
2573 Object* obj; 2537 Object* obj;
2574 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES, 2538 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
2575 UNIQUE_NORMALIZED_MAP); 2539 UNIQUE_NORMALIZED_MAP);
2576 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2540 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2577 } 2541 }
(...skipping 1473 matching lines...) Expand 10 before | Expand all | Expand 10 after
4051 } 4015 }
4052 FixedArray* pair = FixedArray::cast(obj); 4016 FixedArray* pair = FixedArray::cast(obj);
4053 pair->set(0, name_); 4017 pair->set(0, name_);
4054 pair->set(1, code_); 4018 pair->set(1, code_);
4055 return pair; 4019 return pair;
4056 } 4020 }
4057 4021
4058 private: 4022 private:
4059 String* name_; 4023 String* name_;
4060 Code::Flags flags_; 4024 Code::Flags flags_;
4025 // TODO(jkummerow): We should be able to get by without this.
4061 Code* code_; 4026 Code* code_;
4062 }; 4027 };
4063 4028
4064 4029
4065 Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) { 4030 Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
4066 CodeCacheHashTableKey key(name, flags); 4031 CodeCacheHashTableKey key(name, flags);
4067 int entry = FindEntry(&key); 4032 int entry = FindEntry(&key);
4068 if (entry == kNotFound) return GetHeap()->undefined_value(); 4033 if (entry == kNotFound) return GetHeap()->undefined_value();
4069 return get(EntryToIndex(entry) + 1); 4034 return get(EntryToIndex(entry) + 1);
4070 } 4035 }
4071 4036
4072 4037
4073 MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) { 4038 MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
4074 CodeCacheHashTableKey key(name, code); 4039 CodeCacheHashTableKey key(name, code);
4075 Object* obj; 4040 Object* obj;
4076 { MaybeObject* maybe_obj = EnsureCapacity(1, &key); 4041 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4077 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 4042 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4078 } 4043 }
4079 4044
4080 // Don't use this, as the table might have grown. 4045 // Don't use |this|, as the table might have grown.
4081 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj); 4046 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
4082 4047
4083 int entry = cache->FindInsertionEntry(key.Hash()); 4048 int entry = cache->FindInsertionEntry(key.Hash());
4084 Object* k; 4049 Object* k;
4085 { MaybeObject* maybe_k = key.AsObject(); 4050 { MaybeObject* maybe_k = key.AsObject();
4086 if (!maybe_k->ToObject(&k)) return maybe_k; 4051 if (!maybe_k->ToObject(&k)) return maybe_k;
4087 } 4052 }
4088 4053
4089 cache->set(EntryToIndex(entry), k); 4054 cache->set(EntryToIndex(entry), k);
4090 cache->set(EntryToIndex(entry) + 1, code); 4055 cache->set(EntryToIndex(entry) + 1, code);
(...skipping 25 matching lines...) Expand all
4116 if (element->IsSmi() && key->IsSmi() && (element == key)) return true; 4081 if (element->IsSmi() && key->IsSmi() && (element == key)) return true;
4117 if (element->IsString() && 4082 if (element->IsString() &&
4118 key->IsString() && String::cast(element)->Equals(String::cast(key))) { 4083 key->IsString() && String::cast(element)->Equals(String::cast(key))) {
4119 return true; 4084 return true;
4120 } 4085 }
4121 } 4086 }
4122 return false; 4087 return false;
4123 } 4088 }
4124 4089
4125 4090
4091 MaybeObject* PolymorphicCodeCache::Update(MapList* maps,
4092 Code::Flags flags,
4093 Code* code) {
4094 // Initialize cache if necessary.
4095 if (cache()->IsUndefined()) {
4096 Object* result;
4097 { MaybeObject* maybe_result =
4098 PolymorphicCodeCacheHashTable::Allocate(
4099 PolymorphicCodeCacheHashTable::kInitialSize);
4100 if (!maybe_result->ToObject(&result)) return maybe_result;
4101 }
4102 set_cache(result);
4103 } else {
4104 // This entry shouldn't be contained in the cache yet.
4105 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
4106 ->Lookup(maps, flags)->IsUndefined());
4107 }
4108 PolymorphicCodeCacheHashTable* hash_table =
4109 PolymorphicCodeCacheHashTable::cast(cache());
4110 Object* new_cache;
4111 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
4112 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
4113 }
4114 set_cache(new_cache);
4115 return this;
4116 }
4117
4118
4119 Object* PolymorphicCodeCache::Lookup(MapList* maps, Code::Flags flags) {
4120 if (!cache()->IsUndefined()) {
4121 PolymorphicCodeCacheHashTable* hash_table =
4122 PolymorphicCodeCacheHashTable::cast(cache());
4123 return hash_table->Lookup(maps, flags);
4124 } else {
4125 return GetHeap()->undefined_value();
4126 }
4127 }
4128
4129
4130 class PolymorphicCodeCacheHashTableKey : public HashTableKey {
4131 public:
4132 PolymorphicCodeCacheHashTableKey(MapList* maps, int code_flags)
4133 : maps_(maps),
Mads Ager (chromium) 2011/06/01 08:45:53 This looks unsafe. I think you have to copy the ma
Jakob Kummerow 2011/06/01 10:15:27 Note how the |key| objects constructed from this c
Mads Ager (chromium) 2011/06/01 10:36:54 Ah, yeah. Sorry I forgot how this works. You are a
Jakob Kummerow 2011/06/01 12:03:09 Done.
4134 code_flags_(code_flags) {}
4135
4136 bool IsMatch(Object* other) {
4137 MapList other_maps(kDefaultListAllocationSize);
4138 int other_flags;
4139 FromObject(other, &other_flags, &other_maps);
4140 if (code_flags_ != other_flags) return false;
4141 if (maps_->length() != other_maps.length()) return false;
4142 // Compare just the hashes first because it's faster.
4143 int this_hash = MapsHashHelper(maps_, code_flags_);
4144 int other_hash = MapsHashHelper(&other_maps, other_flags);
4145 if (this_hash != other_hash) return false;
4146
4147 // Full comparison: for each map in maps_, look for an equivalent map in
4148 // other_maps. This implementation is slow, but probably good enough for
4149 // now because the lists are short (<= 4 elements currently).
4150 for (int i = 0; i < maps_->length(); ++i) {
4151 bool match_found = false;
4152 for (int j = 0; j < other_maps.length(); ++j) {
4153 if (maps_->at(i)->Equals(other_maps.at(j), KEEP_INOBJECT_PROPERTIES)) {
4154 match_found = true;
4155 break;
4156 }
4157 }
4158 if (!match_found) return false;
4159 }
4160 return true;
4161 }
4162
4163 static uint32_t MapsHashHelper(MapList* maps, int code_flags) {
4164 uint32_t hash = code_flags;
4165 for (int i = 0; i < maps->length(); ++i) {
4166 hash ^= maps->at(i)->Hash();
4167 }
4168 return hash;
4169 }
4170
4171 uint32_t Hash() {
4172 return MapsHashHelper(maps_, code_flags_);
4173 }
4174
4175 uint32_t HashForObject(Object* obj) {
4176 MapList other_maps(kDefaultListAllocationSize);
4177 int other_flags;
4178 FromObject(obj, &other_flags, &other_maps);
4179 return MapsHashHelper(&other_maps, other_flags);
4180 }
4181
4182 MUST_USE_RESULT MaybeObject* AsObject() {
4183 Object* obj;
4184 { MaybeObject* maybe_obj =
4185 HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
4186 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4187 }
4188 FixedArray* list = FixedArray::cast(obj);
4189 list->set(0, Smi::FromInt(code_flags_));
4190 for (int i = 0; i < maps_->length(); ++i) {
4191 list->set(i + 1, maps_->at(i));
4192 }
4193 return list;
4194 }
4195
4196 private:
4197 static MapList* FromObject(Object* obj, int* code_flags, MapList* maps) {
4198 FixedArray* list = FixedArray::cast(obj);
4199 maps->Rewind(0);
4200 *code_flags = Smi::cast(list->get(0))->value();
4201 for (int i = 1; i < list->length(); ++i) {
4202 maps->Add(Map::cast(list->get(i)));
4203 }
4204 return maps;
4205 }
4206
4207 MapList* maps_;
4208 int code_flags_;
4209 static const int kDefaultListAllocationSize =
4210 KeyedIC::kMaxKeyedPolymorphism + 1;
4211 };
4212
4213
4214 Object* PolymorphicCodeCacheHashTable::Lookup(MapList* maps, int code_flags) {
4215 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
4216 int entry = FindEntry(&key);
4217 if (entry == kNotFound) return GetHeap()->undefined_value();
4218 return get(EntryToIndex(entry) + 1);
4219 }
4220
4221
4222 MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps,
4223 int code_flags,
4224 Code* code) {
4225 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
4226 Object* obj;
4227 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4228 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4229 }
4230 PolymorphicCodeCacheHashTable* cache =
4231 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
4232 int entry = cache->FindInsertionEntry(key.Hash());
4233 { MaybeObject* maybe_obj = key.AsObject();
4234 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4235 }
4236 cache->set(EntryToIndex(entry), obj);
4237 cache->set(EntryToIndex(entry) + 1, code);
4238 cache->ElementAdded();
4239 return cache;
4240 }
4241
4242
4126 MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) { 4243 MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
4127 ASSERT(!array->HasExternalArrayElements()); 4244 ASSERT(!array->HasExternalArrayElements());
4128 switch (array->GetElementsKind()) { 4245 switch (array->GetElementsKind()) {
4129 case JSObject::FAST_ELEMENTS: 4246 case JSObject::FAST_ELEMENTS:
4130 return UnionOfKeys(FixedArray::cast(array->elements())); 4247 return UnionOfKeys(FixedArray::cast(array->elements()));
4131 case JSObject::DICTIONARY_ELEMENTS: { 4248 case JSObject::DICTIONARY_ELEMENTS: {
4132 NumberDictionary* dict = array->element_dictionary(); 4249 NumberDictionary* dict = array->element_dictionary();
4133 int size = dict->NumberOfElements(); 4250 int size = dict->NumberOfElements();
4134 4251
4135 // Allocate a temporary fixed array. 4252 // Allocate a temporary fixed array.
(...skipping 1625 matching lines...) Expand 10 before | Expand all | Expand 10 after
5761 ASSERT(target->prototype() == this || 5878 ASSERT(target->prototype() == this ||
5762 target->prototype() == real_prototype); 5879 target->prototype() == real_prototype);
5763 // Getter prototype() is read-only, set_prototype() has side effects. 5880 // Getter prototype() is read-only, set_prototype() has side effects.
5764 *RawField(target, Map::kPrototypeOffset) = real_prototype; 5881 *RawField(target, Map::kPrototypeOffset) = real_prototype;
5765 } 5882 }
5766 } 5883 }
5767 } 5884 }
5768 } 5885 }
5769 5886
5770 5887
5888 int Map::Hash() {
5889 // For performance reasons we only hash the 3 most variable fields of a map:
5890 // constructor, prototype and bit_field2.
5891
5892 // Shift away the tag.
5893 int hash = (static_cast<uint32_t>(
5894 reinterpret_cast<uintptr_t>(constructor())) >> 2);
5895
5896 // XOR-ing the prototype and constructor directly yields too many zero bits
5897 // when the two pointers are close (which is fairly common).
5898 // To avoid this we shift the prototype 4 bits relatively to the constructor.
5899 hash ^= (static_cast<uint32_t>(
5900 reinterpret_cast<uintptr_t>(prototype())) << 2);
5901
5902 return hash ^ (hash >> 16) ^ bit_field2();
5903 }
5904
5905
5906 bool Map::Equals(Map* other, PropertyNormalizationMode mode) {
5907 return
5908 constructor() == other->constructor() &&
5909 prototype() == other->prototype() &&
5910 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
5911 0 :
5912 other->inobject_properties()) &&
5913 instance_type() == other->instance_type() &&
5914 bit_field() == other->bit_field() &&
5915 bit_field2() == other->bit_field2() &&
5916 (bit_field3() & ~(1<<Map::kIsShared)) ==
5917 (other->bit_field3() & ~(1<<Map::kIsShared));
5918 }
5919
5920
5771 void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) { 5921 void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
5772 // Iterate over all fields in the body but take care in dealing with 5922 // Iterate over all fields in the body but take care in dealing with
5773 // the code entry. 5923 // the code entry.
5774 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset); 5924 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
5775 v->VisitCodeEntry(this->address() + kCodeEntryOffset); 5925 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
5776 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size); 5926 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
5777 } 5927 }
5778 5928
5779 5929
5780 void JSFunction::MarkForLazyRecompilation() { 5930 void JSFunction::MarkForLazyRecompilation() {
(...skipping 4831 matching lines...) Expand 10 before | Expand all | Expand 10 after
10612 if (break_point_objects()->IsUndefined()) return 0; 10762 if (break_point_objects()->IsUndefined()) return 0;
10613 // Single beak point. 10763 // Single beak point.
10614 if (!break_point_objects()->IsFixedArray()) return 1; 10764 if (!break_point_objects()->IsFixedArray()) return 1;
10615 // Multiple break points. 10765 // Multiple break points.
10616 return FixedArray::cast(break_point_objects())->length(); 10766 return FixedArray::cast(break_point_objects())->length();
10617 } 10767 }
10618 #endif 10768 #endif
10619 10769
10620 10770
10621 } } // namespace v8::internal 10771 } } // namespace v8::internal
OLDNEW
« src/objects.h ('K') | « src/objects.h ('k') | src/objects-debug.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698