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

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: address Mads' comments 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
« no previous file with comments | « src/objects.h ('k') | src/objects-debug.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 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() &&
2495 Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
2495 #ifdef DEBUG 2496 #ifdef DEBUG
2497 Map::cast(result)->SharedMapVerify();
2496 if (FLAG_enable_slow_asserts) { 2498 if (FLAG_enable_slow_asserts) {
2497 // The cached map should match newly created normalized map bit-by-bit. 2499 // The cached map should match newly created normalized map bit-by-bit.
2498 Object* fresh; 2500 Object* fresh;
2499 { MaybeObject* maybe_fresh = 2501 { MaybeObject* maybe_fresh =
2500 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP); 2502 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2501 if (maybe_fresh->ToObject(&fresh)) { 2503 if (maybe_fresh->ToObject(&fresh)) {
2502 ASSERT(memcmp(Map::cast(fresh)->address(), 2504 ASSERT(memcmp(Map::cast(fresh)->address(),
2503 Map::cast(result)->address(), 2505 Map::cast(result)->address(),
2504 Map::kSize) == 0); 2506 Map::kSize) == 0);
2505 } 2507 }
(...skipping 15 matching lines...) Expand all
2521 2523
2522 2524
2523 void NormalizedMapCache::Clear() { 2525 void NormalizedMapCache::Clear() {
2524 int entries = length(); 2526 int entries = length();
2525 for (int i = 0; i != entries; i++) { 2527 for (int i = 0; i != entries; i++) {
2526 set_undefined(i); 2528 set_undefined(i);
2527 } 2529 }
2528 } 2530 }
2529 2531
2530 2532
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();
2565 }
2566
2567
2568 MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) { 2533 MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
2569 if (map()->is_shared()) { 2534 if (map()->is_shared()) {
2570 // Fast case maps are never marked as shared. 2535 // Fast case maps are never marked as shared.
2571 ASSERT(!HasFastProperties()); 2536 ASSERT(!HasFastProperties());
2572 // Replace the map with an identical copy that can be safely modified. 2537 // Replace the map with an identical copy that can be safely modified.
2573 Object* obj; 2538 Object* obj;
2574 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES, 2539 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
2575 UNIQUE_NORMALIZED_MAP); 2540 UNIQUE_NORMALIZED_MAP);
2576 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2541 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2577 } 2542 }
(...skipping 1473 matching lines...) Expand 10 before | Expand all | Expand 10 after
4051 } 4016 }
4052 FixedArray* pair = FixedArray::cast(obj); 4017 FixedArray* pair = FixedArray::cast(obj);
4053 pair->set(0, name_); 4018 pair->set(0, name_);
4054 pair->set(1, code_); 4019 pair->set(1, code_);
4055 return pair; 4020 return pair;
4056 } 4021 }
4057 4022
4058 private: 4023 private:
4059 String* name_; 4024 String* name_;
4060 Code::Flags flags_; 4025 Code::Flags flags_;
4026 // TODO(jkummerow): We should be able to get by without this.
4061 Code* code_; 4027 Code* code_;
4062 }; 4028 };
4063 4029
4064 4030
4065 Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) { 4031 Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
4066 CodeCacheHashTableKey key(name, flags); 4032 CodeCacheHashTableKey key(name, flags);
4067 int entry = FindEntry(&key); 4033 int entry = FindEntry(&key);
4068 if (entry == kNotFound) return GetHeap()->undefined_value(); 4034 if (entry == kNotFound) return GetHeap()->undefined_value();
4069 return get(EntryToIndex(entry) + 1); 4035 return get(EntryToIndex(entry) + 1);
4070 } 4036 }
4071 4037
4072 4038
4073 MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) { 4039 MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
4074 CodeCacheHashTableKey key(name, code); 4040 CodeCacheHashTableKey key(name, code);
4075 Object* obj; 4041 Object* obj;
4076 { MaybeObject* maybe_obj = EnsureCapacity(1, &key); 4042 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4077 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 4043 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4078 } 4044 }
4079 4045
4080 // Don't use this, as the table might have grown. 4046 // Don't use |this|, as the table might have grown.
4081 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj); 4047 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
4082 4048
4083 int entry = cache->FindInsertionEntry(key.Hash()); 4049 int entry = cache->FindInsertionEntry(key.Hash());
4084 Object* k; 4050 Object* k;
4085 { MaybeObject* maybe_k = key.AsObject(); 4051 { MaybeObject* maybe_k = key.AsObject();
4086 if (!maybe_k->ToObject(&k)) return maybe_k; 4052 if (!maybe_k->ToObject(&k)) return maybe_k;
4087 } 4053 }
4088 4054
4089 cache->set(EntryToIndex(entry), k); 4055 cache->set(EntryToIndex(entry), k);
4090 cache->set(EntryToIndex(entry) + 1, code); 4056 cache->set(EntryToIndex(entry) + 1, code);
(...skipping 25 matching lines...) Expand all
4116 if (element->IsSmi() && key->IsSmi() && (element == key)) return true; 4082 if (element->IsSmi() && key->IsSmi() && (element == key)) return true;
4117 if (element->IsString() && 4083 if (element->IsString() &&
4118 key->IsString() && String::cast(element)->Equals(String::cast(key))) { 4084 key->IsString() && String::cast(element)->Equals(String::cast(key))) {
4119 return true; 4085 return true;
4120 } 4086 }
4121 } 4087 }
4122 return false; 4088 return false;
4123 } 4089 }
4124 4090
4125 4091
4092 MaybeObject* PolymorphicCodeCache::Update(MapList* maps,
4093 Code::Flags flags,
4094 Code* code) {
4095 // Initialize cache if necessary.
4096 if (cache()->IsUndefined()) {
4097 Object* result;
4098 { MaybeObject* maybe_result =
4099 PolymorphicCodeCacheHashTable::Allocate(
4100 PolymorphicCodeCacheHashTable::kInitialSize);
4101 if (!maybe_result->ToObject(&result)) return maybe_result;
4102 }
4103 set_cache(result);
4104 } else {
4105 // This entry shouldn't be contained in the cache yet.
4106 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
4107 ->Lookup(maps, flags)->IsUndefined());
4108 }
4109 PolymorphicCodeCacheHashTable* hash_table =
4110 PolymorphicCodeCacheHashTable::cast(cache());
4111 Object* new_cache;
4112 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
4113 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
4114 }
4115 set_cache(new_cache);
4116 return this;
4117 }
4118
4119
4120 Object* PolymorphicCodeCache::Lookup(MapList* maps, Code::Flags flags) {
4121 if (!cache()->IsUndefined()) {
4122 PolymorphicCodeCacheHashTable* hash_table =
4123 PolymorphicCodeCacheHashTable::cast(cache());
4124 return hash_table->Lookup(maps, flags);
4125 } else {
4126 return GetHeap()->undefined_value();
4127 }
4128 }
4129
4130
4131 // Despite their name, object of this class are not stored in the actual
4132 // hash table; instead they're temporarily used for lookups. It is therefore
4133 // safe to have a weak (non-owning) pointer to a MapList as a member field.
4134 class PolymorphicCodeCacheHashTableKey : public HashTableKey {
4135 public:
4136 // Callers must ensure that |maps| outlives the newly constructed object.
4137 PolymorphicCodeCacheHashTableKey(MapList* maps, int code_flags)
4138 : maps_(maps),
4139 code_flags_(code_flags) {}
4140
4141 bool IsMatch(Object* other) {
4142 MapList other_maps(kDefaultListAllocationSize);
4143 int other_flags;
4144 FromObject(other, &other_flags, &other_maps);
4145 if (code_flags_ != other_flags) return false;
4146 if (maps_->length() != other_maps.length()) return false;
4147 // Compare just the hashes first because it's faster.
4148 int this_hash = MapsHashHelper(maps_, code_flags_);
4149 int other_hash = MapsHashHelper(&other_maps, other_flags);
4150 if (this_hash != other_hash) return false;
4151
4152 // Full comparison: for each map in maps_, look for an equivalent map in
4153 // other_maps. This implementation is slow, but probably good enough for
4154 // now because the lists are short (<= 4 elements currently).
4155 for (int i = 0; i < maps_->length(); ++i) {
4156 bool match_found = false;
4157 for (int j = 0; j < other_maps.length(); ++j) {
4158 if (maps_->at(i)->EquivalentTo(other_maps.at(j))) {
4159 match_found = true;
4160 break;
4161 }
4162 }
4163 if (!match_found) return false;
4164 }
4165 return true;
4166 }
4167
4168 static uint32_t MapsHashHelper(MapList* maps, int code_flags) {
4169 uint32_t hash = code_flags;
4170 for (int i = 0; i < maps->length(); ++i) {
4171 hash ^= maps->at(i)->Hash();
4172 }
4173 return hash;
4174 }
4175
4176 uint32_t Hash() {
4177 return MapsHashHelper(maps_, code_flags_);
4178 }
4179
4180 uint32_t HashForObject(Object* obj) {
4181 MapList other_maps(kDefaultListAllocationSize);
4182 int other_flags;
4183 FromObject(obj, &other_flags, &other_maps);
4184 return MapsHashHelper(&other_maps, other_flags);
4185 }
4186
4187 MUST_USE_RESULT MaybeObject* AsObject() {
4188 Object* obj;
4189 // The maps in |maps_| must be copied to a newly allocated FixedArray,
4190 // both because the referenced MapList is short-lived, and because C++
4191 // objects can't be stored in the heap anyway.
4192 { MaybeObject* maybe_obj =
4193 HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
4194 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4195 }
4196 FixedArray* list = FixedArray::cast(obj);
4197 list->set(0, Smi::FromInt(code_flags_));
4198 for (int i = 0; i < maps_->length(); ++i) {
4199 list->set(i + 1, maps_->at(i));
4200 }
4201 return list;
4202 }
4203
4204 private:
4205 static MapList* FromObject(Object* obj, int* code_flags, MapList* maps) {
4206 FixedArray* list = FixedArray::cast(obj);
4207 maps->Rewind(0);
4208 *code_flags = Smi::cast(list->get(0))->value();
4209 for (int i = 1; i < list->length(); ++i) {
4210 maps->Add(Map::cast(list->get(i)));
4211 }
4212 return maps;
4213 }
4214
4215 MapList* maps_; // weak.
4216 int code_flags_;
4217 static const int kDefaultListAllocationSize =
4218 KeyedIC::kMaxKeyedPolymorphism + 1;
4219 };
4220
4221
4222 Object* PolymorphicCodeCacheHashTable::Lookup(MapList* maps, int code_flags) {
4223 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
4224 int entry = FindEntry(&key);
4225 if (entry == kNotFound) return GetHeap()->undefined_value();
4226 return get(EntryToIndex(entry) + 1);
4227 }
4228
4229
4230 MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps,
4231 int code_flags,
4232 Code* code) {
4233 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
4234 Object* obj;
4235 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4236 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4237 }
4238 PolymorphicCodeCacheHashTable* cache =
4239 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
4240 int entry = cache->FindInsertionEntry(key.Hash());
4241 { MaybeObject* maybe_obj = key.AsObject();
4242 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4243 }
4244 cache->set(EntryToIndex(entry), obj);
4245 cache->set(EntryToIndex(entry) + 1, code);
4246 cache->ElementAdded();
4247 return cache;
4248 }
4249
4250
4126 MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) { 4251 MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
4127 ASSERT(!array->HasExternalArrayElements()); 4252 ASSERT(!array->HasExternalArrayElements());
4128 switch (array->GetElementsKind()) { 4253 switch (array->GetElementsKind()) {
4129 case JSObject::FAST_ELEMENTS: 4254 case JSObject::FAST_ELEMENTS:
4130 return UnionOfKeys(FixedArray::cast(array->elements())); 4255 return UnionOfKeys(FixedArray::cast(array->elements()));
4131 case JSObject::DICTIONARY_ELEMENTS: { 4256 case JSObject::DICTIONARY_ELEMENTS: {
4132 NumberDictionary* dict = array->element_dictionary(); 4257 NumberDictionary* dict = array->element_dictionary();
4133 int size = dict->NumberOfElements(); 4258 int size = dict->NumberOfElements();
4134 4259
4135 // Allocate a temporary fixed array. 4260 // Allocate a temporary fixed array.
(...skipping 1625 matching lines...) Expand 10 before | Expand all | Expand 10 after
5761 ASSERT(target->prototype() == this || 5886 ASSERT(target->prototype() == this ||
5762 target->prototype() == real_prototype); 5887 target->prototype() == real_prototype);
5763 // Getter prototype() is read-only, set_prototype() has side effects. 5888 // Getter prototype() is read-only, set_prototype() has side effects.
5764 *RawField(target, Map::kPrototypeOffset) = real_prototype; 5889 *RawField(target, Map::kPrototypeOffset) = real_prototype;
5765 } 5890 }
5766 } 5891 }
5767 } 5892 }
5768 } 5893 }
5769 5894
5770 5895
5896 int Map::Hash() {
5897 // For performance reasons we only hash the 3 most variable fields of a map:
5898 // constructor, prototype and bit_field2.
5899
5900 // Shift away the tag.
5901 int hash = (static_cast<uint32_t>(
5902 reinterpret_cast<uintptr_t>(constructor())) >> 2);
5903
5904 // XOR-ing the prototype and constructor directly yields too many zero bits
5905 // when the two pointers are close (which is fairly common).
5906 // To avoid this we shift the prototype 4 bits relatively to the constructor.
5907 hash ^= (static_cast<uint32_t>(
5908 reinterpret_cast<uintptr_t>(prototype())) << 2);
5909
5910 return hash ^ (hash >> 16) ^ bit_field2();
5911 }
5912
5913
5914 bool Map::EquivalentToForNormalization(Map* other,
5915 PropertyNormalizationMode mode) {
5916 return
5917 constructor() == other->constructor() &&
5918 prototype() == other->prototype() &&
5919 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
5920 0 :
5921 other->inobject_properties()) &&
5922 instance_type() == other->instance_type() &&
5923 bit_field() == other->bit_field() &&
5924 bit_field2() == other->bit_field2() &&
5925 (bit_field3() & ~(1<<Map::kIsShared)) ==
5926 (other->bit_field3() & ~(1<<Map::kIsShared));
5927 }
5928
5929
5771 void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) { 5930 void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
5772 // Iterate over all fields in the body but take care in dealing with 5931 // Iterate over all fields in the body but take care in dealing with
5773 // the code entry. 5932 // the code entry.
5774 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset); 5933 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
5775 v->VisitCodeEntry(this->address() + kCodeEntryOffset); 5934 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
5776 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size); 5935 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
5777 } 5936 }
5778 5937
5779 5938
5780 void JSFunction::MarkForLazyRecompilation() { 5939 void JSFunction::MarkForLazyRecompilation() {
(...skipping 4831 matching lines...) Expand 10 before | Expand all | Expand 10 after
10612 if (break_point_objects()->IsUndefined()) return 0; 10771 if (break_point_objects()->IsUndefined()) return 0;
10613 // Single beak point. 10772 // Single beak point.
10614 if (!break_point_objects()->IsFixedArray()) return 1; 10773 if (!break_point_objects()->IsFixedArray()) return 1;
10615 // Multiple break points. 10774 // Multiple break points.
10616 return FixedArray::cast(break_point_objects())->length(); 10775 return FixedArray::cast(break_point_objects())->length();
10617 } 10776 }
10618 #endif 10777 #endif
10619 10778
10620 10779
10621 } } // namespace v8::internal 10780 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects.h ('k') | src/objects-debug.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698