OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 7204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7215 | 7215 |
7216 | 7216 |
7217 void String::PrintOn(FILE* file) { | 7217 void String::PrintOn(FILE* file) { |
7218 int length = this->length(); | 7218 int length = this->length(); |
7219 for (int i = 0; i < length; i++) { | 7219 for (int i = 0; i < length; i++) { |
7220 fprintf(file, "%c", Get(i)); | 7220 fprintf(file, "%c", Get(i)); |
7221 } | 7221 } |
7222 } | 7222 } |
7223 | 7223 |
7224 | 7224 |
7225 void Map::CreateOneBackPointer(Map* target) { | 7225 void Map::CreateOneBackPointer(Object* transition_target) { |
| 7226 if (!transition_target->IsMap()) return; |
| 7227 Map* target = Map::cast(transition_target); |
7226 #ifdef DEBUG | 7228 #ifdef DEBUG |
7227 // Verify target. | 7229 // Verify target. |
7228 Object* source_prototype = prototype(); | 7230 Object* source_prototype = prototype(); |
7229 Object* target_prototype = target->prototype(); | 7231 Object* target_prototype = target->prototype(); |
7230 ASSERT(source_prototype->IsJSReceiver() || | 7232 ASSERT(source_prototype->IsJSReceiver() || |
7231 source_prototype->IsMap() || | 7233 source_prototype->IsMap() || |
7232 source_prototype->IsNull()); | 7234 source_prototype->IsNull()); |
7233 ASSERT(target_prototype->IsJSReceiver() || | 7235 ASSERT(target_prototype->IsJSReceiver() || |
7234 target_prototype->IsNull()); | 7236 target_prototype->IsNull()); |
7235 ASSERT(source_prototype->IsMap() || | 7237 ASSERT(source_prototype->IsMap() || |
7236 source_prototype == target_prototype); | 7238 source_prototype == target_prototype); |
7237 #endif | 7239 #endif |
7238 // Point target back to source. set_prototype() will not let us set | 7240 // Point target back to source. set_prototype() will not let us set |
7239 // the prototype to a map, as we do here. | 7241 // the prototype to a map, as we do here. |
7240 *RawField(target, kPrototypeOffset) = this; | 7242 *RawField(target, kPrototypeOffset) = this; |
7241 } | 7243 } |
7242 | 7244 |
7243 | 7245 |
7244 void Map::CreateBackPointers() { | 7246 void Map::CreateBackPointers() { |
7245 DescriptorArray* descriptors = instance_descriptors(); | 7247 DescriptorArray* descriptors = instance_descriptors(); |
7246 for (int i = 0; i < descriptors->number_of_descriptors(); i++) { | 7248 for (int i = 0; i < descriptors->number_of_descriptors(); i++) { |
7247 if (descriptors->IsTransition(i)) { | 7249 switch (descriptors->GetType(i)) { |
7248 Object* object = reinterpret_cast<Object*>(descriptors->GetValue(i)); | 7250 case MAP_TRANSITION: |
7249 if (object->IsMap()) { | 7251 case CONSTANT_TRANSITION: |
7250 CreateOneBackPointer(reinterpret_cast<Map*>(object)); | 7252 CreateOneBackPointer(descriptors->GetValue(i)); |
7251 } else { | 7253 break; |
7252 ASSERT(object->IsFixedArray()); | 7254 case ELEMENTS_TRANSITION: { |
7253 ASSERT(descriptors->GetType(i) == ELEMENTS_TRANSITION); | 7255 Object* object = descriptors->GetValue(i); |
7254 FixedArray* array = reinterpret_cast<FixedArray*>(object); | 7256 if (object->IsMap()) { |
7255 for (int i = 0; i < array->length(); ++i) { | 7257 CreateOneBackPointer(object); |
7256 Map* target = reinterpret_cast<Map*>(array->get(i)); | 7258 } else { |
7257 if (!target->IsUndefined()) { | 7259 FixedArray* array = FixedArray::cast(object); |
7258 CreateOneBackPointer(target); | 7260 for (int i = 0; i < array->length(); ++i) { |
| 7261 CreateOneBackPointer(array->get(i)); |
7259 } | 7262 } |
7260 } | 7263 } |
| 7264 break; |
7261 } | 7265 } |
| 7266 case CALLBACKS: { |
| 7267 Object* object = descriptors->GetValue(i); |
| 7268 if (object->IsAccessorPair()) { |
| 7269 AccessorPair* accessors = AccessorPair::cast(object); |
| 7270 CreateOneBackPointer(accessors->getter()); |
| 7271 CreateOneBackPointer(accessors->setter()); |
| 7272 } |
| 7273 break; |
| 7274 } |
| 7275 case NORMAL: |
| 7276 case FIELD: |
| 7277 case CONSTANT_FUNCTION: |
| 7278 case HANDLER: |
| 7279 case INTERCEPTOR: |
| 7280 case NULL_DESCRIPTOR: |
| 7281 break; |
7262 } | 7282 } |
7263 } | 7283 } |
7264 } | 7284 } |
7265 | 7285 |
7266 | 7286 |
| 7287 bool Map::RestoreOneBackPointer(Object* object, |
| 7288 Object* real_prototype, |
| 7289 bool* keep_entry) { |
| 7290 if (!object->IsMap()) return false; |
| 7291 Map* map = Map::cast(object); |
| 7292 if (Marking::MarkBitFrom(map).Get()) { |
| 7293 *keep_entry = true; |
| 7294 return false; |
| 7295 } |
| 7296 ASSERT(map->prototype() == this || map->prototype() == real_prototype); |
| 7297 // Getter prototype() is read-only, set_prototype() has side effects. |
| 7298 *RawField(map, Map::kPrototypeOffset) = real_prototype; |
| 7299 return true; |
| 7300 } |
| 7301 |
| 7302 |
7267 void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { | 7303 void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { |
7268 // Live DescriptorArray objects will be marked, so we must use | 7304 DescriptorArray* d = DescriptorArray::cast( |
7269 // low-level accessors to get and modify their data. | |
7270 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( | |
7271 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset)); | 7305 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset)); |
7272 if (d->IsEmpty()) return; | 7306 if (d->IsEmpty()) return; |
7273 Smi* NullDescriptorDetails = | 7307 Smi* NullDescriptorDetails = |
7274 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi(); | 7308 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi(); |
7275 FixedArray* contents = reinterpret_cast<FixedArray*>( | 7309 FixedArray* contents = FixedArray::cast( |
7276 d->get(DescriptorArray::kContentArrayIndex)); | 7310 d->get(DescriptorArray::kContentArrayIndex)); |
7277 ASSERT(contents->length() >= 2); | 7311 ASSERT(contents->length() >= 2); |
7278 for (int i = 0; i < contents->length(); i += 2) { | 7312 for (int i = 0; i < contents->length(); i += 2) { |
7279 // If the pair (value, details) is a map transition, | 7313 // If the pair (value, details) is a map transition, check if the target is |
7280 // check if the target is live. If not, null the descriptor. | 7314 // live. If not, null the descriptor. Also drop the back pointer for that |
7281 // Also drop the back pointer for that map transition, so that this | 7315 // map transition, so that this map is not reached again by following a back |
7282 // map is not reached again by following a back pointer from a | 7316 // pointer from a non-live object. |
7283 // non-live object. | 7317 bool keep_entry = false; |
7284 PropertyDetails details(Smi::cast(contents->get(i + 1))); | 7318 PropertyDetails details(Smi::cast(contents->get(i + 1))); |
7285 if (IsTransitionType(details.type())) { | 7319 switch (details.type()) { |
7286 Object* object = reinterpret_cast<Object*>(contents->get(i)); | 7320 case MAP_TRANSITION: |
7287 if (object->IsMap()) { | 7321 case CONSTANT_TRANSITION: |
7288 Map* target = reinterpret_cast<Map*>(object); | 7322 RestoreOneBackPointer(contents->get(i), real_prototype, &keep_entry); |
7289 ASSERT(target->IsHeapObject()); | 7323 break; |
7290 MarkBit map_mark = Marking::MarkBitFrom(target); | 7324 case ELEMENTS_TRANSITION: { |
7291 if (!map_mark.Get()) { | 7325 Object* object = contents->get(i); |
7292 ASSERT(target->IsMap()); | 7326 if (object->IsMap()) { |
7293 contents->set_unchecked(i + 1, NullDescriptorDetails); | 7327 RestoreOneBackPointer(object, real_prototype, &keep_entry); |
7294 contents->set_null_unchecked(heap, i); | 7328 } else { |
7295 ASSERT(target->prototype() == this || | 7329 FixedArray* array = FixedArray::cast(object); |
7296 target->prototype() == real_prototype); | 7330 for (int j = 0; j < array->length(); ++j) { |
7297 // Getter prototype() is read-only, set_prototype() has side effects. | 7331 if (RestoreOneBackPointer(array->get(j), |
7298 *RawField(target, Map::kPrototypeOffset) = real_prototype; | 7332 real_prototype, |
7299 } | 7333 &keep_entry)) { |
7300 } else { | 7334 array->set_undefined(j); |
7301 ASSERT(object->IsFixedArray()); | 7335 } |
7302 ASSERT(details.type() == ELEMENTS_TRANSITION); | |
7303 FixedArray* array = reinterpret_cast<FixedArray*>(object); | |
7304 bool reachable_map_found = false; | |
7305 for (int j = 0; j < array->length(); ++j) { | |
7306 Map* target = reinterpret_cast<Map*>(array->get(j)); | |
7307 ASSERT(target->IsHeapObject()); | |
7308 MarkBit map_mark = Marking::MarkBitFrom(target); | |
7309 if (!map_mark.Get()) { | |
7310 ASSERT(target->IsMap()); | |
7311 array->set_undefined(j); | |
7312 ASSERT(target->prototype() == this || | |
7313 target->prototype() == real_prototype); | |
7314 // Getter prototype() is read-only, set_prototype() has side | |
7315 // effects. | |
7316 *RawField(target, Map::kPrototypeOffset) = real_prototype; | |
7317 } else if (target->IsMap()) { | |
7318 reachable_map_found = true; | |
7319 } | 7336 } |
7320 } | 7337 } |
7321 // If no map was found, make sure the FixedArray also gets collected. | 7338 break; |
7322 if (!reachable_map_found) { | 7339 } |
7323 contents->set_unchecked(i + 1, NullDescriptorDetails); | 7340 case CALLBACKS: { |
7324 contents->set_null_unchecked(heap, i); | 7341 Object* object = contents->get(i); |
| 7342 if (object->IsAccessorPair()) { |
| 7343 AccessorPair* accessors = AccessorPair::cast(object); |
| 7344 if (RestoreOneBackPointer(accessors->getter(), |
| 7345 real_prototype, |
| 7346 &keep_entry)) { |
| 7347 accessors->set_getter(heap->the_hole_value()); |
| 7348 } |
| 7349 if (RestoreOneBackPointer(accessors->setter(), |
| 7350 real_prototype, |
| 7351 &keep_entry)) { |
| 7352 accessors->set_setter(heap->the_hole_value()); |
| 7353 } |
| 7354 } else { |
| 7355 keep_entry = true; |
7325 } | 7356 } |
| 7357 break; |
7326 } | 7358 } |
| 7359 case NORMAL: |
| 7360 case FIELD: |
| 7361 case CONSTANT_FUNCTION: |
| 7362 case HANDLER: |
| 7363 case INTERCEPTOR: |
| 7364 case NULL_DESCRIPTOR: |
| 7365 keep_entry = true; |
| 7366 break; |
| 7367 } |
| 7368 // Make sure that an entry containing only dead transitions gets collected. |
| 7369 // What we *really* want to do here is removing this entry completely, but |
| 7370 // for technical reasons we can't do this, so we zero it out instead. |
| 7371 if (!keep_entry) { |
| 7372 contents->set_unchecked(i + 1, NullDescriptorDetails); |
| 7373 contents->set_null_unchecked(heap, i); |
7327 } | 7374 } |
7328 } | 7375 } |
7329 } | 7376 } |
7330 | 7377 |
7331 | 7378 |
7332 int Map::Hash() { | 7379 int Map::Hash() { |
7333 // For performance reasons we only hash the 3 most variable fields of a map: | 7380 // For performance reasons we only hash the 3 most variable fields of a map: |
7334 // constructor, prototype and bit_field2. | 7381 // constructor, prototype and bit_field2. |
7335 | 7382 |
7336 // Shift away the tag. | 7383 // Shift away the tag. |
(...skipping 5639 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12976 if (break_point_objects()->IsUndefined()) return 0; | 13023 if (break_point_objects()->IsUndefined()) return 0; |
12977 // Single break point. | 13024 // Single break point. |
12978 if (!break_point_objects()->IsFixedArray()) return 1; | 13025 if (!break_point_objects()->IsFixedArray()) return 1; |
12979 // Multiple break points. | 13026 // Multiple break points. |
12980 return FixedArray::cast(break_point_objects())->length(); | 13027 return FixedArray::cast(break_point_objects())->length(); |
12981 } | 13028 } |
12982 #endif // ENABLE_DEBUGGER_SUPPORT | 13029 #endif // ENABLE_DEBUGGER_SUPPORT |
12983 | 13030 |
12984 | 13031 |
12985 } } // namespace v8::internal | 13032 } } // namespace v8::internal |
OLD | NEW |