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

Side by Side Diff: src/objects.cc

Issue 717001: Refactor the code cache to handle large number of properties on the global ob... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 9 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 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 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 3015 matching lines...) Expand 10 before | Expand all | Expand 10 after
3026 Object* new_map = CopyDropDescriptors(); 3026 Object* new_map = CopyDropDescriptors();
3027 if (new_map->IsFailure()) return new_map; 3027 if (new_map->IsFailure()) return new_map;
3028 Object* descriptors = instance_descriptors()->RemoveTransitions(); 3028 Object* descriptors = instance_descriptors()->RemoveTransitions();
3029 if (descriptors->IsFailure()) return descriptors; 3029 if (descriptors->IsFailure()) return descriptors;
3030 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors)); 3030 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
3031 return cast(new_map); 3031 return cast(new_map);
3032 } 3032 }
3033 3033
3034 3034
3035 Object* Map::UpdateCodeCache(String* name, Code* code) { 3035 Object* Map::UpdateCodeCache(String* name, Code* code) {
3036 // Allocate the code cache if not present.
3037 if (code_cache()->IsFixedArray()) {
3038 Object* result = Heap::AllocateCodeCache();
3039 if (result->IsFailure()) return result;
3040 set_code_cache(result);
3041 }
3042
3043 // Update the code cache.
3044 return CodeCache::cast(code_cache())->Update(name, code);
3045 }
3046
3047
3048 Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
3049 // Do a lookup if a code cache exists.
3050 if (!code_cache()->IsFixedArray()) {
3051 return CodeCache::cast(code_cache())->Lookup(name, flags);
3052 } else {
3053 return Heap::undefined_value();
3054 }
3055 }
3056
3057
3058 int Map::IndexInCodeCache(String* name, Code* code) {
3059 // Get the internal index if a code cache exists.
3060 if (!code_cache()->IsFixedArray()) {
3061 return CodeCache::cast(code_cache())->GetIndex(name, code);
3062 }
3063 return -1;
3064 }
3065
3066
3067 void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
3068 // No GC is supposed to happen between a call to IndexInCodeCache and
3069 // RemoveFromCodeCache so the code cache must be there.
3070 ASSERT(!code_cache()->IsFixedArray());
3071 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
3072 }
3073
3074
3075 Object* CodeCache::Update(String* name, Code* code) {
3036 ASSERT(code->ic_state() == MONOMORPHIC); 3076 ASSERT(code->ic_state() == MONOMORPHIC);
3037 FixedArray* cache = code_cache();
3038 3077
3039 // When updating the code cache we disregard the type encoded in the 3078 // The number of monomorphic stubs for normal load/store/call IC's can grow to
3079 // a large number and therefore they need to go into a hash table. They are
3080 // used to load global properties from cells.
3081 if (code->type() == NORMAL) {
3082 // Make sure that a hash table is allocated for the normal load code cache.
3083 if (normal_type_cache()->IsUndefined()) {
3084 Object* result =
3085 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
3086 if (result->IsFailure()) return result;
3087 set_normal_type_cache(result);
3088 }
3089 return UpdateNormalTypeCache(name, code);
3090 } else {
3091 ASSERT(default_cache()->IsFixedArray());
3092 return UpdateDefaultCache(name, code);
3093 }
3094 }
3095
3096
3097 Object* CodeCache::UpdateDefaultCache(String* name, Code* code) {
3098 // When updating the default code cache we disregard the type encoded in the
3040 // flags. This allows call constant stubs to overwrite call field 3099 // flags. This allows call constant stubs to overwrite call field
3041 // stubs, etc. 3100 // stubs, etc.
3042 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags()); 3101 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
3043 3102
3044 // First check whether we can update existing code cache without 3103 // First check whether we can update existing code cache without
3045 // extending it. 3104 // extending it.
3105 FixedArray* cache = default_cache();
3046 int length = cache->length(); 3106 int length = cache->length();
3047 int deleted_index = -1; 3107 int deleted_index = -1;
3048 for (int i = 0; i < length; i += 2) { 3108 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
3049 Object* key = cache->get(i); 3109 Object* key = cache->get(i);
3050 if (key->IsNull()) { 3110 if (key->IsNull()) {
3051 if (deleted_index < 0) deleted_index = i; 3111 if (deleted_index < 0) deleted_index = i;
3052 continue; 3112 continue;
3053 } 3113 }
3054 if (key->IsUndefined()) { 3114 if (key->IsUndefined()) {
3055 if (deleted_index >= 0) i = deleted_index; 3115 if (deleted_index >= 0) i = deleted_index;
3056 cache->set(i + 0, name); 3116 cache->set(i + kCodeCacheEntryNameOffset, name);
3057 cache->set(i + 1, code); 3117 cache->set(i + kCodeCacheEntryCodeOffset, code);
3058 return this; 3118 return this;
3059 } 3119 }
3060 if (name->Equals(String::cast(key))) { 3120 if (name->Equals(String::cast(key))) {
3061 Code::Flags found = Code::cast(cache->get(i + 1))->flags(); 3121 Code::Flags found =
3122 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
3062 if (Code::RemoveTypeFromFlags(found) == flags) { 3123 if (Code::RemoveTypeFromFlags(found) == flags) {
3063 cache->set(i + 1, code); 3124 cache->set(i + kCodeCacheEntryCodeOffset, code);
3064 return this; 3125 return this;
3065 } 3126 }
3066 } 3127 }
3067 } 3128 }
3068 3129
3069 // Reached the end of the code cache. If there were deleted 3130 // Reached the end of the code cache. If there were deleted
3070 // elements, reuse the space for the first of them. 3131 // elements, reuse the space for the first of them.
3071 if (deleted_index >= 0) { 3132 if (deleted_index >= 0) {
3072 cache->set(deleted_index + 0, name); 3133 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
3073 cache->set(deleted_index + 1, code); 3134 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
3074 return this; 3135 return this;
3075 } 3136 }
3076 3137
3077 // Extend the code cache with some new entries (at least one). 3138 // Extend the code cache with some new entries (at least one). Must be a
3078 int new_length = length + ((length >> 1) & ~1) + 2; 3139 // multiple of the entry size.
3079 ASSERT((new_length & 1) == 0); // must be a multiple of two 3140 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
3141 new_length = new_length - new_length % kCodeCacheEntrySize;
3142 ASSERT((new_length % kCodeCacheEntrySize) == 0);
3080 Object* result = cache->CopySize(new_length); 3143 Object* result = cache->CopySize(new_length);
3081 if (result->IsFailure()) return result; 3144 if (result->IsFailure()) return result;
3082 3145
3083 // Add the (name, code) pair to the new cache. 3146 // Add the (name, code) pair to the new cache.
3084 cache = FixedArray::cast(result); 3147 cache = FixedArray::cast(result);
3085 cache->set(length + 0, name); 3148 cache->set(length + kCodeCacheEntryNameOffset, name);
3086 cache->set(length + 1, code); 3149 cache->set(length + kCodeCacheEntryCodeOffset, code);
3087 set_code_cache(cache); 3150 set_default_cache(cache);
3088 return this; 3151 return this;
3089 } 3152 }
3090 3153
3091 3154
3092 Object* Map::FindInCodeCache(String* name, Code::Flags flags) { 3155 Object* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
3093 FixedArray* cache = code_cache(); 3156 // Adding a new entry can cause a new cache to be allocated.
3157 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
3158 Object* new_cache = cache->Put(name, code);
3159 if (new_cache->IsFailure()) return new_cache;
3160 set_normal_type_cache(new_cache);
3161 return this;
3162 }
3163
3164
3165 Object* CodeCache::Lookup(String* name, Code::Flags flags) {
3166 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
3167 return LookupNormalTypeCache(name, flags);
3168 } else {
3169 return LookupDefaultCache(name, flags);
3170 }
3171 }
3172
3173
3174 Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
3175 FixedArray* cache = default_cache();
3094 int length = cache->length(); 3176 int length = cache->length();
3095 for (int i = 0; i < length; i += 2) { 3177 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
3096 Object* key = cache->get(i); 3178 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
3097 // Skip deleted elements. 3179 // Skip deleted elements.
3098 if (key->IsNull()) continue; 3180 if (key->IsNull()) continue;
3099 if (key->IsUndefined()) return key; 3181 if (key->IsUndefined()) return key;
3100 if (name->Equals(String::cast(key))) { 3182 if (name->Equals(String::cast(key))) {
3101 Code* code = Code::cast(cache->get(i + 1)); 3183 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
3102 if (code->flags() == flags) return code; 3184 if (code->flags() == flags) {
3185 return code;
3186 }
3103 } 3187 }
3104 } 3188 }
3105 return Heap::undefined_value(); 3189 return Heap::undefined_value();
3106 } 3190 }
3107 3191
3108 3192
3109 int Map::IndexInCodeCache(Code* code) { 3193 Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
3110 FixedArray* array = code_cache(); 3194 if (!normal_type_cache()->IsUndefined()) {
3195 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
3196 return cache->Lookup(name, flags);
3197 } else {
3198 return Heap::undefined_value();
3199 }
3200 }
3201
3202
3203 int CodeCache::GetIndex(String* name, Code* code) {
3204 // This is not used for normal load/store/call IC's.
3205 if (code->type() == NORMAL) {
3206 if (normal_type_cache()->IsUndefined()) return -1;
3207 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
3208 return cache->GetIndex(name, code->flags());
3209 }
3210
3211 FixedArray* array = default_cache();
3111 int len = array->length(); 3212 int len = array->length();
3112 for (int i = 0; i < len; i += 2) { 3213 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
3113 if (array->get(i + 1) == code) return i + 1; 3214 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
3114 } 3215 }
3115 return -1; 3216 return -1;
3116 } 3217 }
3117 3218
3118 3219
3119 void Map::RemoveFromCodeCache(int index) { 3220 void CodeCache::RemoveByIndex(String* name, Code* code, int index) {
3120 FixedArray* array = code_cache(); 3221 if (code->type() == NORMAL) {
3121 ASSERT(array->length() >= index && array->get(index)->IsCode()); 3222 ASSERT(!normal_type_cache()->IsUndefined());
3122 // Use null instead of undefined for deleted elements to distinguish 3223 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
3123 // deleted elements from unused elements. This distinction is used 3224 ASSERT(cache->GetIndex(name, code->flags()) == index);
3124 // when looking up in the cache and when updating the cache. 3225 cache->RemoveByIndex(index);
3125 array->set_null(index - 1); // key 3226 } else {
3126 array->set_null(index); // code 3227 FixedArray* array = default_cache();
3228 ASSERT(array->length() >= index && array->get(index)->IsCode());
3229 // Use null instead of undefined for deleted elements to distinguish
3230 // deleted elements from unused elements. This distinction is used
3231 // when looking up in the cache and when updating the cache.
3232 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
3233 array->set_null(index - 1); // Name.
3234 array->set_null(index); // Code.
3235 }
3236 }
3237
3238
3239 // The key in the code cache hash table consists of the property name and the
3240 // code object. The actual match is on the name and the code flags. If a key
3241 // is created using the flags and not a code object it can only be used for
3242 // lookup not to create a new entry.
3243 class CodeCacheHashTableKey : public HashTableKey {
3244 public:
3245 CodeCacheHashTableKey(String* name, Code::Flags flags)
3246 : name_(name), flags_(flags), code_(NULL) { }
3247
3248 CodeCacheHashTableKey(String* name, Code* code)
3249 : name_(name),
3250 flags_(code->flags()),
3251 code_(code) { }
3252
3253
3254 bool IsMatch(Object* other) {
3255 if (!other->IsFixedArray()) return false;
3256 FixedArray* pair = FixedArray::cast(other);
3257 String* name = String::cast(pair->get(0));
3258 Code::Flags flags = Code::cast(pair->get(1))->flags();
3259 if (flags != flags_) {
3260 return false;
3261 }
3262 return name_->Equals(name);
3263 }
3264
3265 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
3266 return name->Hash() ^ flags;
3267 }
3268
3269 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
3270
3271 uint32_t HashForObject(Object* obj) {
3272 FixedArray* pair = FixedArray::cast(obj);
3273 String* name = String::cast(pair->get(0));
3274 Code* code = Code::cast(pair->get(1));
3275 return NameFlagsHashHelper(name, code->flags());
3276 }
3277
3278 Object* AsObject() {
3279 ASSERT(code_ != NULL);
3280 Object* obj = Heap::AllocateFixedArray(2);
3281 if (obj->IsFailure()) return obj;
3282 FixedArray* pair = FixedArray::cast(obj);
3283 pair->set(0, name_);
3284 pair->set(1, code_);
3285 return pair;
3286 }
3287
3288 private:
3289 String* name_;
3290 Code::Flags flags_;
3291 Code* code_;
3292 };
3293
3294
3295 Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
3296 CodeCacheHashTableKey key(name, flags);
3297 int entry = FindEntry(&key);
3298 if (entry == kNotFound) return Heap::undefined_value();
3299 return get(EntryToIndex(entry) + 1);
3300 }
3301
3302
3303 Object* CodeCacheHashTable::Put(String* name, Code* code) {
3304 CodeCacheHashTableKey key(name, code);
3305 Object* obj = EnsureCapacity(1, &key);
3306 if (obj->IsFailure()) return obj;
3307
3308 // Don't use this, as the table might have grown.
3309 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
3310
3311 int entry = cache->FindInsertionEntry(key.Hash());
3312 Object* k = key.AsObject();
3313 if (k->IsFailure()) return k;
3314
3315 cache->set(EntryToIndex(entry), k);
3316 cache->set(EntryToIndex(entry) + 1, code);
3317 cache->ElementAdded();
3318 return cache;
3319 }
3320
3321
3322 int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
3323 CodeCacheHashTableKey key(name, flags);
3324 int entry = FindEntry(&key);
3325 return (entry == kNotFound) ? -1 : entry;
3326 }
3327
3328
3329 void CodeCacheHashTable::RemoveByIndex(int index) {
3330 ASSERT(index >= 0);
3331 set(EntryToIndex(index), Heap::null_value());
3332 set(EntryToIndex(index) + 1, Heap::null_value());
3333 ElementRemoved();
3127 } 3334 }
3128 3335
3129 3336
3130 void FixedArray::FixedArrayIterateBody(ObjectVisitor* v) { 3337 void FixedArray::FixedArrayIterateBody(ObjectVisitor* v) {
3131 IteratePointers(v, kHeaderSize, kHeaderSize + length() * kPointerSize); 3338 IteratePointers(v, kHeaderSize, kHeaderSize + length() * kPointerSize);
3132 } 3339 }
3133 3340
3134 3341
3135 static bool HasKey(FixedArray* array, Object* key) { 3342 static bool HasKey(FixedArray* array, Object* key) {
3136 int len0 = array->length(); 3343 int len0 = array->length();
(...skipping 3850 matching lines...) Expand 10 before | Expand all | Expand 10 after
6987 table->set(insertion_index + j, get(from_index + j), mode); 7194 table->set(insertion_index + j, get(from_index + j), mode);
6988 } 7195 }
6989 } 7196 }
6990 } 7197 }
6991 table->SetNumberOfElements(NumberOfElements()); 7198 table->SetNumberOfElements(NumberOfElements());
6992 table->SetNumberOfDeletedElements(0); 7199 table->SetNumberOfDeletedElements(0);
6993 return table; 7200 return table;
6994 } 7201 }
6995 7202
6996 7203
6997
6998 template<typename Shape, typename Key> 7204 template<typename Shape, typename Key>
6999 uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) { 7205 uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
7000 uint32_t capacity = Capacity(); 7206 uint32_t capacity = Capacity();
7001 uint32_t entry = FirstProbe(hash, capacity); 7207 uint32_t entry = FirstProbe(hash, capacity);
7002 uint32_t count = 1; 7208 uint32_t count = 1;
7003 // EnsureCapacity will guarantee the hash table is never full. 7209 // EnsureCapacity will guarantee the hash table is never full.
7004 while (true) { 7210 while (true) {
7005 Object* element = KeyAt(entry); 7211 Object* element = KeyAt(entry);
7006 if (element->IsUndefined() || element->IsNull()) break; 7212 if (element->IsUndefined() || element->IsNull()) break;
7007 entry = NextProbe(entry, count++, capacity); 7213 entry = NextProbe(entry, count++, capacity);
(...skipping 1366 matching lines...) Expand 10 before | Expand all | Expand 10 after
8374 if (break_point_objects()->IsUndefined()) return 0; 8580 if (break_point_objects()->IsUndefined()) return 0;
8375 // Single beak point. 8581 // Single beak point.
8376 if (!break_point_objects()->IsFixedArray()) return 1; 8582 if (!break_point_objects()->IsFixedArray()) return 1;
8377 // Multiple break points. 8583 // Multiple break points.
8378 return FixedArray::cast(break_point_objects())->length(); 8584 return FixedArray::cast(break_point_objects())->length();
8379 } 8585 }
8380 #endif 8586 #endif
8381 8587
8382 8588
8383 } } // namespace v8::internal 8589 } } // 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