OLD | NEW |
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 3876 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3887 | 3887 |
3888 void Map::RemoveFromCodeCache(String* name, Code* code, int index) { | 3888 void Map::RemoveFromCodeCache(String* name, Code* code, int index) { |
3889 // No GC is supposed to happen between a call to IndexInCodeCache and | 3889 // No GC is supposed to happen between a call to IndexInCodeCache and |
3890 // RemoveFromCodeCache so the code cache must be there. | 3890 // RemoveFromCodeCache so the code cache must be there. |
3891 ASSERT(!code_cache()->IsFixedArray()); | 3891 ASSERT(!code_cache()->IsFixedArray()); |
3892 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index); | 3892 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index); |
3893 } | 3893 } |
3894 | 3894 |
3895 | 3895 |
3896 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { | 3896 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { |
| 3897 // Traverse the transition tree without using a stack. We do this by |
| 3898 // reversing the pointers in the maps and descriptor arrays. |
3897 Map* current = this; | 3899 Map* current = this; |
3898 Map* meta_map = heap()->meta_map(); | 3900 Map* meta_map = heap()->meta_map(); |
| 3901 Object** map_or_index_field = NULL; |
3899 while (current != meta_map) { | 3902 while (current != meta_map) { |
3900 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( | 3903 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( |
3901 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset)); | 3904 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset)); |
3902 if (d->IsEmpty()) { | 3905 if (!d->IsEmpty()) { |
3903 Map* prev = current->map(); | 3906 FixedArray* contents = reinterpret_cast<FixedArray*>( |
3904 current->set_map(meta_map); | 3907 d->get(DescriptorArray::kContentArrayIndex)); |
3905 callback(current, data); | 3908 map_or_index_field = RawField(contents, HeapObject::kMapOffset); |
3906 current = prev; | 3909 Object* map_or_index = *map_or_index_field; |
3907 continue; | 3910 bool map_done = true; // Controls a nested continue statement. |
| 3911 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0; |
| 3912 i < contents->length(); |
| 3913 i += 2) { |
| 3914 PropertyDetails details(Smi::cast(contents->get(i + 1))); |
| 3915 if (details.IsTransition()) { |
| 3916 // Found a map in the transition array. We record our progress in |
| 3917 // the transition array by recording the current map in the map field |
| 3918 // of the next map and recording the index in the transition array in |
| 3919 // the map field of the array. |
| 3920 Map* next = Map::cast(contents->get(i)); |
| 3921 next->set_map(current); |
| 3922 *map_or_index_field = Smi::FromInt(i + 2); |
| 3923 current = next; |
| 3924 map_done = false; |
| 3925 break; |
| 3926 } |
| 3927 } |
| 3928 if (!map_done) continue; |
| 3929 } |
| 3930 // That was the regular transitions, now for the prototype transitions. |
| 3931 FixedArray* prototype_transitions = |
| 3932 current->unchecked_prototype_transitions(); |
| 3933 Object** proto_map_or_index_field = |
| 3934 RawField(prototype_transitions, HeapObject::kMapOffset); |
| 3935 Object* map_or_index = *proto_map_or_index_field; |
| 3936 const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset; |
| 3937 int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start; |
| 3938 if (i < prototype_transitions->length()) { |
| 3939 // Found a map in the prototype transition array. Record progress in |
| 3940 // an analogous way to the regular transitions array above. |
| 3941 Object* perhaps_map = prototype_transitions->get(i); |
| 3942 if (perhaps_map->IsMap()) { |
| 3943 Map* next = Map::cast(perhaps_map); |
| 3944 next->set_map(current); |
| 3945 *proto_map_or_index_field = |
| 3946 Smi::FromInt(i + kProtoTransitionElementsPerEntry); |
| 3947 current = next; |
| 3948 continue; |
| 3949 } |
| 3950 } |
| 3951 *proto_map_or_index_field = heap()->fixed_array_map(); |
| 3952 if (map_or_index_field != NULL) { |
| 3953 *map_or_index_field = heap()->fixed_array_map(); |
3908 } | 3954 } |
3909 | 3955 |
3910 FixedArray* contents = reinterpret_cast<FixedArray*>( | 3956 // The callback expects a map to have a real map as its map, so we save |
3911 d->get(DescriptorArray::kContentArrayIndex)); | 3957 // the map field, which is being used to track the traversal and put the |
3912 Object** map_or_index_field = RawField(contents, HeapObject::kMapOffset); | 3958 // correct map (the meta_map) in place while we do the callback. |
3913 Object* map_or_index = *map_or_index_field; | |
3914 bool map_done = true; | |
3915 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0; | |
3916 i < contents->length(); | |
3917 i += 2) { | |
3918 PropertyDetails details(Smi::cast(contents->get(i + 1))); | |
3919 if (details.IsTransition()) { | |
3920 Map* next = reinterpret_cast<Map*>(contents->get(i)); | |
3921 next->set_map(current); | |
3922 *map_or_index_field = Smi::FromInt(i + 2); | |
3923 current = next; | |
3924 map_done = false; | |
3925 break; | |
3926 } | |
3927 } | |
3928 if (!map_done) continue; | |
3929 *map_or_index_field = heap()->fixed_array_map(); | |
3930 Map* prev = current->map(); | 3959 Map* prev = current->map(); |
3931 current->set_map(meta_map); | 3960 current->set_map(meta_map); |
3932 callback(current, data); | 3961 callback(current, data); |
3933 current = prev; | 3962 current = prev; |
3934 } | 3963 } |
3935 } | 3964 } |
3936 | 3965 |
3937 | 3966 |
3938 MaybeObject* CodeCache::Update(String* name, Code* code) { | 3967 MaybeObject* CodeCache::Update(String* name, Code* code) { |
3939 // The number of monomorphic stubs for normal load/store/call IC's can grow to | 3968 // The number of monomorphic stubs for normal load/store/call IC's can grow to |
(...skipping 2417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6357 Builtins* builtins = heap->isolate()->builtins(); | 6386 Builtins* builtins = heap->isolate()->builtins(); |
6358 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown), | 6387 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown), |
6359 construct_stub()); | 6388 construct_stub()); |
6360 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric)); | 6389 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric)); |
6361 | 6390 |
6362 int slack = map->unused_property_fields(); | 6391 int slack = map->unused_property_fields(); |
6363 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack); | 6392 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack); |
6364 if (slack != 0) { | 6393 if (slack != 0) { |
6365 // Resize the initial map and all maps in its transition tree. | 6394 // Resize the initial map and all maps in its transition tree. |
6366 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack); | 6395 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack); |
| 6396 |
6367 // Give the correct expected_nof_properties to initial maps created later. | 6397 // Give the correct expected_nof_properties to initial maps created later. |
6368 ASSERT(expected_nof_properties() >= slack); | 6398 ASSERT(expected_nof_properties() >= slack); |
6369 set_expected_nof_properties(expected_nof_properties() - slack); | 6399 set_expected_nof_properties(expected_nof_properties() - slack); |
6370 } | 6400 } |
6371 } | 6401 } |
6372 | 6402 |
6373 | 6403 |
6374 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) { | 6404 void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) { |
6375 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); | 6405 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode())); |
6376 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); | 6406 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); |
(...skipping 699 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7076 } | 7106 } |
7077 FixedArray::cast(obj)->set(0, len); | 7107 FixedArray::cast(obj)->set(0, len); |
7078 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1)); | 7108 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1)); |
7079 set_elements(FixedArray::cast(obj)); | 7109 set_elements(FixedArray::cast(obj)); |
7080 return this; | 7110 return this; |
7081 } | 7111 } |
7082 | 7112 |
7083 | 7113 |
7084 Object* Map::GetPrototypeTransition(Object* prototype) { | 7114 Object* Map::GetPrototypeTransition(Object* prototype) { |
7085 FixedArray* cache = prototype_transitions(); | 7115 FixedArray* cache = prototype_transitions(); |
7086 int capacity = cache->length(); | 7116 int number_of_transitions = NumberOfProtoTransitions(); |
7087 if (capacity == 0) return NULL; | 7117 const int proto_offset = |
7088 int finger = Smi::cast(cache->get(0))->value(); | 7118 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset; |
7089 for (int i = 1; i < finger; i += 2) { | 7119 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset; |
7090 if (cache->get(i) == prototype) return cache->get(i + 1); | 7120 const int step = kProtoTransitionElementsPerEntry; |
| 7121 for (int i = 0; i < number_of_transitions; i++) { |
| 7122 if (cache->get(proto_offset + i * step) == prototype) { |
| 7123 Object* map = cache->get(map_offset + i * step); |
| 7124 ASSERT(map->IsMap()); |
| 7125 return map; |
| 7126 } |
7091 } | 7127 } |
7092 return NULL; | 7128 return NULL; |
7093 } | 7129 } |
7094 | 7130 |
7095 | 7131 |
7096 MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) { | 7132 MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) { |
| 7133 ASSERT(map->IsMap()); |
| 7134 ASSERT(HeapObject::cast(prototype)->map()->IsMap()); |
7097 // Don't cache prototype transition if this map is shared. | 7135 // Don't cache prototype transition if this map is shared. |
7098 if (is_shared() || !FLAG_cache_prototype_transitions) return this; | 7136 if (is_shared() || !FLAG_cache_prototype_transitions) return this; |
7099 | 7137 |
7100 FixedArray* cache = prototype_transitions(); | 7138 FixedArray* cache = prototype_transitions(); |
7101 | 7139 |
7102 int capacity = cache->length(); | 7140 const int step = kProtoTransitionElementsPerEntry; |
| 7141 const int header = kProtoTransitionHeaderSize; |
7103 | 7142 |
7104 int finger = (capacity == 0) ? 1 : Smi::cast(cache->get(0))->value(); | 7143 int capacity = (cache->length() - header) / step; |
7105 | 7144 |
7106 if (finger >= capacity) { | 7145 int transitions = NumberOfProtoTransitions() + 1; |
| 7146 |
| 7147 if (transitions > capacity) { |
7107 if (capacity > kMaxCachedPrototypeTransitions) return this; | 7148 if (capacity > kMaxCachedPrototypeTransitions) return this; |
7108 | 7149 |
7109 FixedArray* new_cache; | 7150 FixedArray* new_cache; |
7110 { MaybeObject* maybe_cache = heap()->AllocateFixedArray(finger * 2 + 1); | 7151 // Grow array by factor 2 over and above what we need. |
| 7152 { MaybeObject* maybe_cache = |
| 7153 heap()->AllocateFixedArray(transitions * 2 * step + header); |
7111 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache; | 7154 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache; |
7112 } | 7155 } |
7113 | 7156 |
7114 for (int i = 1; i < capacity; i++) new_cache->set(i, cache->get(i)); | 7157 for (int i = 0; i < capacity * step; i++) { |
| 7158 new_cache->set(i + header, cache->get(i + header)); |
| 7159 } |
7115 cache = new_cache; | 7160 cache = new_cache; |
7116 set_prototype_transitions(cache); | 7161 set_prototype_transitions(cache); |
7117 } | 7162 } |
7118 | 7163 |
7119 cache->set(finger, prototype); | 7164 int last = transitions - 1; |
7120 cache->set(finger + 1, map); | 7165 |
7121 cache->set(0, Smi::FromInt(finger + 2)); | 7166 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype); |
| 7167 cache->set(header + last * step + kProtoTransitionMapOffset, map); |
| 7168 SetNumberOfProtoTransitions(transitions); |
7122 | 7169 |
7123 return cache; | 7170 return cache; |
7124 } | 7171 } |
7125 | 7172 |
7126 | 7173 |
7127 MaybeObject* JSReceiver::SetPrototype(Object* value, | 7174 MaybeObject* JSReceiver::SetPrototype(Object* value, |
7128 bool skip_hidden_prototypes) { | 7175 bool skip_hidden_prototypes) { |
| 7176 #ifdef DEBUG |
| 7177 int size = Size(); |
| 7178 #endif |
| 7179 |
7129 Heap* heap = GetHeap(); | 7180 Heap* heap = GetHeap(); |
7130 // Silently ignore the change if value is not a JSObject or null. | 7181 // Silently ignore the change if value is not a JSObject or null. |
7131 // SpiderMonkey behaves this way. | 7182 // SpiderMonkey behaves this way. |
7132 if (!value->IsJSReceiver() && !value->IsNull()) return value; | 7183 if (!value->IsJSReceiver() && !value->IsNull()) return value; |
7133 | 7184 |
7134 // From 8.6.2 Object Internal Methods | 7185 // From 8.6.2 Object Internal Methods |
7135 // ... | 7186 // ... |
7136 // In addition, if [[Extensible]] is false the value of the [[Class]] and | 7187 // In addition, if [[Extensible]] is false the value of the [[Class]] and |
7137 // [[Prototype]] internal properties of the object may not be modified. | 7188 // [[Prototype]] internal properties of the object may not be modified. |
7138 // ... | 7189 // ... |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7189 map->PutPrototypeTransition(value, Map::cast(new_map)); | 7240 map->PutPrototypeTransition(value, Map::cast(new_map)); |
7190 if (maybe_new_cache->IsFailure()) return maybe_new_cache; | 7241 if (maybe_new_cache->IsFailure()) return maybe_new_cache; |
7191 } | 7242 } |
7192 | 7243 |
7193 Map::cast(new_map)->set_prototype(value); | 7244 Map::cast(new_map)->set_prototype(value); |
7194 } | 7245 } |
7195 ASSERT(Map::cast(new_map)->prototype() == value); | 7246 ASSERT(Map::cast(new_map)->prototype() == value); |
7196 real_receiver->set_map(Map::cast(new_map)); | 7247 real_receiver->set_map(Map::cast(new_map)); |
7197 | 7248 |
7198 heap->ClearInstanceofCache(); | 7249 heap->ClearInstanceofCache(); |
7199 | 7250 ASSERT(size == Size()); |
7200 return value; | 7251 return value; |
7201 } | 7252 } |
7202 | 7253 |
7203 | 7254 |
7204 bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) { | 7255 bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) { |
7205 switch (GetElementsKind()) { | 7256 switch (GetElementsKind()) { |
7206 case FAST_ELEMENTS: { | 7257 case FAST_ELEMENTS: { |
7207 uint32_t length = IsJSArray() ? | 7258 uint32_t length = IsJSArray() ? |
7208 static_cast<uint32_t> | 7259 static_cast<uint32_t> |
7209 (Smi::cast(JSArray::cast(this)->length())->value()) : | 7260 (Smi::cast(JSArray::cast(this)->length())->value()) : |
(...skipping 3500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10710 if (break_point_objects()->IsUndefined()) return 0; | 10761 if (break_point_objects()->IsUndefined()) return 0; |
10711 // Single beak point. | 10762 // Single beak point. |
10712 if (!break_point_objects()->IsFixedArray()) return 1; | 10763 if (!break_point_objects()->IsFixedArray()) return 1; |
10713 // Multiple break points. | 10764 // Multiple break points. |
10714 return FixedArray::cast(break_point_objects())->length(); | 10765 return FixedArray::cast(break_point_objects())->length(); |
10715 } | 10766 } |
10716 #endif | 10767 #endif |
10717 | 10768 |
10718 | 10769 |
10719 } } // namespace v8::internal | 10770 } } // namespace v8::internal |
OLD | NEW |