OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |