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. | 3036 ASSERT(code->ic_state() == MONOMORPHIC); |
3037 if (code_cache()->IsUndefined()) { | 3037 FixedArray* cache = code_cache(); |
3038 Object* result = Heap::AllocateCodeCache(); | |
3039 if (result->IsFailure()) return result; | |
3040 set_code_cache(result); | |
3041 } | |
3042 | 3038 |
3043 // Update the code cache. | 3039 // When updating the code cache we disregard the type encoded in the |
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()->IsUndefined()) { | |
3051 return CodeCache::cast(code_cache())->Lookup(name, flags); | |
3052 } else { | |
3053 return Heap::undefined_value(); | |
3054 } | |
3055 } | |
3056 | |
3057 | |
3058 int Map::IndexInCodeCache(Code* code) { | |
3059 // Get the internal index if a code cache exists. | |
3060 if (!code_cache()->IsUndefined()) { | |
3061 return CodeCache::cast(code_cache())->GetIndex(code); | |
3062 } | |
3063 return -1; | |
3064 } | |
3065 | |
3066 | |
3067 void Map::RemoveFromCodeCache(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()->IsUndefined()); | |
3071 return CodeCache::cast(code_cache())->RemoveByIndex(index); | |
3072 } | |
3073 | |
3074 | |
3075 Object* CodeCache::Update(String* name, Code* code) { | |
3076 ASSERT(code->ic_state() == MONOMORPHIC); | |
3077 | |
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 | |
3099 // flags. This allows call constant stubs to overwrite call field | 3040 // flags. This allows call constant stubs to overwrite call field |
3100 // stubs, etc. | 3041 // stubs, etc. |
3101 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags()); | 3042 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags()); |
3102 | 3043 |
3103 // First check whether we can update existing code cache without | 3044 // First check whether we can update existing code cache without |
3104 // extending it. | 3045 // extending it. |
3105 FixedArray* cache = default_cache(); | |
3106 int length = cache->length(); | 3046 int length = cache->length(); |
3107 int deleted_index = -1; | 3047 int deleted_index = -1; |
3108 for (int i = 0; i < length; i += kCodeCacheEntrySize) { | 3048 for (int i = 0; i < length; i += 2) { |
3109 Object* key = cache->get(i); | 3049 Object* key = cache->get(i); |
3110 if (key->IsNull()) { | 3050 if (key->IsNull()) { |
3111 if (deleted_index < 0) deleted_index = i; | 3051 if (deleted_index < 0) deleted_index = i; |
3112 continue; | 3052 continue; |
3113 } | 3053 } |
3114 if (key->IsUndefined()) { | 3054 if (key->IsUndefined()) { |
3115 if (deleted_index >= 0) i = deleted_index; | 3055 if (deleted_index >= 0) i = deleted_index; |
3116 cache->set(i + kCodeCacheEntryNameOffset, name); | 3056 cache->set(i + 0, name); |
3117 cache->set(i + kCodeCacheEntryCodeOffset, code); | 3057 cache->set(i + 1, code); |
3118 return this; | 3058 return this; |
3119 } | 3059 } |
3120 if (name->Equals(String::cast(key))) { | 3060 if (name->Equals(String::cast(key))) { |
3121 Code::Flags found = | 3061 Code::Flags found = Code::cast(cache->get(i + 1))->flags(); |
3122 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags(); | |
3123 if (Code::RemoveTypeFromFlags(found) == flags) { | 3062 if (Code::RemoveTypeFromFlags(found) == flags) { |
3124 cache->set(i + kCodeCacheEntryCodeOffset, code); | 3063 cache->set(i + 1, code); |
3125 return this; | 3064 return this; |
3126 } | 3065 } |
3127 } | 3066 } |
3128 } | 3067 } |
3129 | 3068 |
3130 // Reached the end of the code cache. If there were deleted | 3069 // Reached the end of the code cache. If there were deleted |
3131 // elements, reuse the space for the first of them. | 3070 // elements, reuse the space for the first of them. |
3132 if (deleted_index >= 0) { | 3071 if (deleted_index >= 0) { |
3133 cache->set(deleted_index + kCodeCacheEntryNameOffset, name); | 3072 cache->set(deleted_index + 0, name); |
3134 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code); | 3073 cache->set(deleted_index + 1, code); |
3135 return this; | 3074 return this; |
3136 } | 3075 } |
3137 | 3076 |
3138 // Extend the code cache with some new entries (at least one). Must be a | 3077 // Extend the code cache with some new entries (at least one). |
3139 // multiple of the entry size. | 3078 int new_length = length + ((length >> 1) & ~1) + 2; |
3140 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize; | 3079 ASSERT((new_length & 1) == 0); // must be a multiple of two |
3141 new_length = new_length - new_length % kCodeCacheEntrySize; | |
3142 ASSERT((new_length % kCodeCacheEntrySize) == 0); | |
3143 Object* result = cache->CopySize(new_length); | 3080 Object* result = cache->CopySize(new_length); |
3144 if (result->IsFailure()) return result; | 3081 if (result->IsFailure()) return result; |
3145 | 3082 |
3146 // Add the (name, code) pair to the new cache. | 3083 // Add the (name, code) pair to the new cache. |
3147 cache = FixedArray::cast(result); | 3084 cache = FixedArray::cast(result); |
3148 cache->set(length + kCodeCacheEntryNameOffset, name); | 3085 cache->set(length + 0, name); |
3149 cache->set(length + kCodeCacheEntryCodeOffset, code); | 3086 cache->set(length + 1, code); |
3150 set_default_cache(cache); | 3087 set_code_cache(cache); |
3151 return this; | 3088 return this; |
3152 } | 3089 } |
3153 | 3090 |
3154 | 3091 |
3155 Object* CodeCache::UpdateNormalTypeCache(String* name, Code* code) { | 3092 Object* Map::FindInCodeCache(String* name, Code::Flags flags) { |
3156 // Adding a new entry can cause a new cache to be allocated. | 3093 FixedArray* cache = code_cache(); |
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(); | |
3176 int length = cache->length(); | 3094 int length = cache->length(); |
3177 for (int i = 0; i < length; i += kCodeCacheEntrySize) { | 3095 for (int i = 0; i < length; i += 2) { |
3178 Object* key = cache->get(i + kCodeCacheEntryNameOffset); | 3096 Object* key = cache->get(i); |
3179 // Skip deleted elements. | 3097 // Skip deleted elements. |
3180 if (key->IsNull()) continue; | 3098 if (key->IsNull()) continue; |
3181 if (key->IsUndefined()) return key; | 3099 if (key->IsUndefined()) return key; |
3182 if (name->Equals(String::cast(key))) { | 3100 if (name->Equals(String::cast(key))) { |
3183 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset)); | 3101 Code* code = Code::cast(cache->get(i + 1)); |
3184 if (code->flags() == flags) { | 3102 if (code->flags() == flags) return code; |
3185 return code; | |
3186 } | |
3187 } | 3103 } |
3188 } | 3104 } |
3189 return Heap::undefined_value(); | 3105 return Heap::undefined_value(); |
3190 } | 3106 } |
3191 | 3107 |
3192 | 3108 |
3193 Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) { | 3109 int Map::IndexInCodeCache(Code* code) { |
3194 if (!normal_type_cache()->IsUndefined()) { | 3110 FixedArray* array = code_cache(); |
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(Code* code) { | |
3204 // This is not used for normal load/store/call IC's. | |
3205 ASSERT(code->type() != NORMAL); | |
3206 | |
3207 FixedArray* array = default_cache(); | |
3208 int len = array->length(); | 3111 int len = array->length(); |
3209 for (int i = 0; i < len; i += kCodeCacheEntrySize) { | 3112 for (int i = 0; i < len; i += 2) { |
3210 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1; | 3113 if (array->get(i + 1) == code) return i + 1; |
3211 } | 3114 } |
3212 return -1; | 3115 return -1; |
3213 } | 3116 } |
3214 | 3117 |
3215 | 3118 |
3216 void CodeCache::RemoveByIndex(int index) { | 3119 void Map::RemoveFromCodeCache(int index) { |
3217 FixedArray* array = default_cache(); | 3120 FixedArray* array = code_cache(); |
3218 ASSERT(array->length() >= index && array->get(index)->IsCode()); | 3121 ASSERT(array->length() >= index && array->get(index)->IsCode()); |
3219 // Use null instead of undefined for deleted elements to distinguish | 3122 // Use null instead of undefined for deleted elements to distinguish |
3220 // deleted elements from unused elements. This distinction is used | 3123 // deleted elements from unused elements. This distinction is used |
3221 // when looking up in the cache and when updating the cache. | 3124 // when looking up in the cache and when updating the cache. |
3222 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset); | 3125 array->set_null(index - 1); // key |
3223 array->set_null(index - 1); // Name. | 3126 array->set_null(index); // code |
3224 array->set_null(index); // Code. | |
3225 } | |
3226 | |
3227 | |
3228 // The key in the code cache hash table consists of the property name and the | |
3229 // code object. The actual match is on the name and the code flags. If a key | |
3230 // is created using the flags and not a code object it can only be used for | |
3231 // lookup not to create a new entry. | |
3232 class CodeCacheHashTableKey : public HashTableKey { | |
3233 public: | |
3234 CodeCacheHashTableKey(String* name, Code::Flags flags) | |
3235 : name_(name), flags_(flags), code_(NULL) { } | |
3236 | |
3237 CodeCacheHashTableKey(String* name, Code* code) | |
3238 : name_(name), | |
3239 flags_(code->flags()), | |
3240 code_(code) { } | |
3241 | |
3242 | |
3243 bool IsMatch(Object* other) { | |
3244 if (!other->IsFixedArray()) return false; | |
3245 FixedArray* pair = FixedArray::cast(other); | |
3246 String* name = String::cast(pair->get(0)); | |
3247 Code::Flags flags = Code::cast(pair->get(1))->flags(); | |
3248 if (flags != flags_) { | |
3249 return false; | |
3250 } | |
3251 return name_->Equals(name); | |
3252 } | |
3253 | |
3254 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) { | |
3255 return name->Hash() ^ flags; | |
3256 } | |
3257 | |
3258 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); } | |
3259 | |
3260 uint32_t HashForObject(Object* obj) { | |
3261 FixedArray* pair = FixedArray::cast(obj); | |
3262 String* name = String::cast(pair->get(0)); | |
3263 Code* code = Code::cast(pair->get(1)); | |
3264 return NameFlagsHashHelper(name, code->flags()); | |
3265 } | |
3266 | |
3267 Object* AsObject() { | |
3268 ASSERT(code_ != NULL); | |
3269 Object* obj = Heap::AllocateFixedArray(2); | |
3270 if (obj->IsFailure()) return obj; | |
3271 FixedArray* pair = FixedArray::cast(obj); | |
3272 pair->set(0, name_); | |
3273 pair->set(1, code_); | |
3274 return pair; | |
3275 } | |
3276 | |
3277 private: | |
3278 String* name_; | |
3279 Code::Flags flags_; | |
3280 Code* code_; | |
3281 }; | |
3282 | |
3283 | |
3284 Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) { | |
3285 CodeCacheHashTableKey key(name, flags); | |
3286 int entry = FindEntry(&key); | |
3287 if (entry == kNotFound) return Heap::undefined_value(); | |
3288 return get(EntryToIndex(entry) + 1); | |
3289 } | |
3290 | |
3291 | |
3292 Object* CodeCacheHashTable::Put(String* name, Code* code) { | |
3293 CodeCacheHashTableKey key(name, code); | |
3294 Object* obj = EnsureCapacity(1, &key); | |
3295 | |
3296 // Don't use this, as the table might have grown. | |
3297 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj); | |
3298 | |
3299 int entry = cache->FindInsertionEntry(key.Hash()); | |
3300 Object* k = key.AsObject(); | |
3301 if (k->IsFailure()) return k; | |
3302 | |
3303 cache->set(EntryToIndex(entry), k); | |
3304 cache->set(EntryToIndex(entry) + 1, code); | |
3305 cache->ElementAdded(); | |
3306 return cache; | |
3307 } | 3127 } |
3308 | 3128 |
3309 | 3129 |
3310 void FixedArray::FixedArrayIterateBody(ObjectVisitor* v) { | 3130 void FixedArray::FixedArrayIterateBody(ObjectVisitor* v) { |
3311 IteratePointers(v, kHeaderSize, kHeaderSize + length() * kPointerSize); | 3131 IteratePointers(v, kHeaderSize, kHeaderSize + length() * kPointerSize); |
3312 } | 3132 } |
3313 | 3133 |
3314 | 3134 |
3315 static bool HasKey(FixedArray* array, Object* key) { | 3135 static bool HasKey(FixedArray* array, Object* key) { |
3316 int len0 = array->length(); | 3136 int len0 = array->length(); |
(...skipping 3837 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7154 table->set(insertion_index + j, get(from_index + j), mode); | 6974 table->set(insertion_index + j, get(from_index + j), mode); |
7155 } | 6975 } |
7156 } | 6976 } |
7157 } | 6977 } |
7158 table->SetNumberOfElements(NumberOfElements()); | 6978 table->SetNumberOfElements(NumberOfElements()); |
7159 table->SetNumberOfDeletedElements(0); | 6979 table->SetNumberOfDeletedElements(0); |
7160 return table; | 6980 return table; |
7161 } | 6981 } |
7162 | 6982 |
7163 | 6983 |
| 6984 |
7164 template<typename Shape, typename Key> | 6985 template<typename Shape, typename Key> |
7165 uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) { | 6986 uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) { |
7166 uint32_t capacity = Capacity(); | 6987 uint32_t capacity = Capacity(); |
7167 uint32_t entry = FirstProbe(hash, capacity); | 6988 uint32_t entry = FirstProbe(hash, capacity); |
7168 uint32_t count = 1; | 6989 uint32_t count = 1; |
7169 // EnsureCapacity will guarantee the hash table is never full. | 6990 // EnsureCapacity will guarantee the hash table is never full. |
7170 while (true) { | 6991 while (true) { |
7171 Object* element = KeyAt(entry); | 6992 Object* element = KeyAt(entry); |
7172 if (element->IsUndefined() || element->IsNull()) break; | 6993 if (element->IsUndefined() || element->IsNull()) break; |
7173 entry = NextProbe(entry, count++, capacity); | 6994 entry = NextProbe(entry, count++, capacity); |
(...skipping 1366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8540 if (break_point_objects()->IsUndefined()) return 0; | 8361 if (break_point_objects()->IsUndefined()) return 0; |
8541 // Single beak point. | 8362 // Single beak point. |
8542 if (!break_point_objects()->IsFixedArray()) return 1; | 8363 if (!break_point_objects()->IsFixedArray()) return 1; |
8543 // Multiple break points. | 8364 // Multiple break points. |
8544 return FixedArray::cast(break_point_objects())->length(); | 8365 return FixedArray::cast(break_point_objects())->length(); |
8545 } | 8366 } |
8546 #endif | 8367 #endif |
8547 | 8368 |
8548 | 8369 |
8549 } } // namespace v8::internal | 8370 } } // namespace v8::internal |
OLD | NEW |