| 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 675 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 686 } | 686 } |
| 687 | 687 |
| 688 bool Heap::PerformGarbageCollection(GarbageCollector collector, | 688 bool Heap::PerformGarbageCollection(GarbageCollector collector, |
| 689 GCTracer* tracer) { | 689 GCTracer* tracer) { |
| 690 bool next_gc_likely_to_collect_more = false; | 690 bool next_gc_likely_to_collect_more = false; |
| 691 | 691 |
| 692 if (collector != SCAVENGER) { | 692 if (collector != SCAVENGER) { |
| 693 PROFILE(isolate_, CodeMovingGCEvent()); | 693 PROFILE(isolate_, CodeMovingGCEvent()); |
| 694 } | 694 } |
| 695 | 695 |
| 696 VerifySymbolTable(); | 696 if (FLAG_verify_heap) { |
| 697 VerifySymbolTable(); |
| 698 } |
| 697 if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) { | 699 if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) { |
| 698 ASSERT(!allocation_allowed_); | 700 ASSERT(!allocation_allowed_); |
| 699 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); | 701 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); |
| 700 global_gc_prologue_callback_(); | 702 global_gc_prologue_callback_(); |
| 701 } | 703 } |
| 702 | 704 |
| 703 GCType gc_type = | 705 GCType gc_type = |
| 704 collector == MARK_COMPACTOR ? kGCTypeMarkSweepCompact : kGCTypeScavenge; | 706 collector == MARK_COMPACTOR ? kGCTypeMarkSweepCompact : kGCTypeScavenge; |
| 705 | 707 |
| 706 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) { | 708 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 782 if (gc_type & gc_epilogue_callbacks_[i].gc_type) { | 784 if (gc_type & gc_epilogue_callbacks_[i].gc_type) { |
| 783 gc_epilogue_callbacks_[i].callback(gc_type, callback_flags); | 785 gc_epilogue_callbacks_[i].callback(gc_type, callback_flags); |
| 784 } | 786 } |
| 785 } | 787 } |
| 786 | 788 |
| 787 if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) { | 789 if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) { |
| 788 ASSERT(!allocation_allowed_); | 790 ASSERT(!allocation_allowed_); |
| 789 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); | 791 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL); |
| 790 global_gc_epilogue_callback_(); | 792 global_gc_epilogue_callback_(); |
| 791 } | 793 } |
| 792 VerifySymbolTable(); | 794 if (FLAG_verify_heap) { |
| 795 VerifySymbolTable(); |
| 796 } |
| 793 | 797 |
| 794 return next_gc_likely_to_collect_more; | 798 return next_gc_likely_to_collect_more; |
| 795 } | 799 } |
| 796 | 800 |
| 797 | 801 |
| 798 void Heap::MarkCompact(GCTracer* tracer) { | 802 void Heap::MarkCompact(GCTracer* tracer) { |
| 799 gc_state_ = MARK_COMPACT; | 803 gc_state_ = MARK_COMPACT; |
| 800 LOG(isolate_, ResourceEvent("markcompact", "begin")); | 804 LOG(isolate_, ResourceEvent("markcompact", "begin")); |
| 801 | 805 |
| 802 mark_compact_collector_.Prepare(tracer); | 806 mark_compact_collector_.Prepare(tracer); |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 976 store_buffer_->SetTop(start_of_current_page_); | 980 store_buffer_->SetTop(start_of_current_page_); |
| 977 } | 981 } |
| 978 } else { | 982 } else { |
| 979 UNREACHABLE(); | 983 UNREACHABLE(); |
| 980 } | 984 } |
| 981 } | 985 } |
| 982 | 986 |
| 983 | 987 |
| 984 void Heap::Scavenge() { | 988 void Heap::Scavenge() { |
| 985 #ifdef DEBUG | 989 #ifdef DEBUG |
| 986 if (FLAG_enable_slow_asserts) VerifyNonPointerSpacePointers(); | 990 if (FLAG_verify_heap) VerifyNonPointerSpacePointers(); |
| 987 #endif | 991 #endif |
| 988 | 992 |
| 989 gc_state_ = SCAVENGE; | 993 gc_state_ = SCAVENGE; |
| 990 | 994 |
| 991 // Implements Cheney's copying algorithm | 995 // Implements Cheney's copying algorithm |
| 992 LOG(isolate_, ResourceEvent("scavenge", "begin")); | 996 LOG(isolate_, ResourceEvent("scavenge", "begin")); |
| 993 | 997 |
| 994 // Clear descriptor cache. | 998 // Clear descriptor cache. |
| 995 isolate_->descriptor_lookup_cache()->Clear(); | 999 isolate_->descriptor_lookup_cache()->Clear(); |
| 996 | 1000 |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1105 return NULL; | 1109 return NULL; |
| 1106 } | 1110 } |
| 1107 | 1111 |
| 1108 // String is still reachable. | 1112 // String is still reachable. |
| 1109 return String::cast(first_word.ToForwardingAddress()); | 1113 return String::cast(first_word.ToForwardingAddress()); |
| 1110 } | 1114 } |
| 1111 | 1115 |
| 1112 | 1116 |
| 1113 void Heap::UpdateNewSpaceReferencesInExternalStringTable( | 1117 void Heap::UpdateNewSpaceReferencesInExternalStringTable( |
| 1114 ExternalStringTableUpdaterCallback updater_func) { | 1118 ExternalStringTableUpdaterCallback updater_func) { |
| 1115 external_string_table_.Verify(); | 1119 if (FLAG_verify_heap) { |
| 1120 external_string_table_.Verify(); |
| 1121 } |
| 1116 | 1122 |
| 1117 if (external_string_table_.new_space_strings_.is_empty()) return; | 1123 if (external_string_table_.new_space_strings_.is_empty()) return; |
| 1118 | 1124 |
| 1119 Object** start = &external_string_table_.new_space_strings_[0]; | 1125 Object** start = &external_string_table_.new_space_strings_[0]; |
| 1120 Object** end = start + external_string_table_.new_space_strings_.length(); | 1126 Object** end = start + external_string_table_.new_space_strings_.length(); |
| 1121 Object** last = start; | 1127 Object** last = start; |
| 1122 | 1128 |
| 1123 for (Object** p = start; p < end; ++p) { | 1129 for (Object** p = start; p < end; ++p) { |
| 1124 ASSERT(InFromSpace(*p)); | 1130 ASSERT(InFromSpace(*p)); |
| 1125 String* target = updater_func(this, p); | 1131 String* target = updater_func(this, p); |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1436 } | 1442 } |
| 1437 | 1443 |
| 1438 return target; | 1444 return target; |
| 1439 } | 1445 } |
| 1440 | 1446 |
| 1441 template<ObjectContents object_contents, SizeRestriction size_restriction> | 1447 template<ObjectContents object_contents, SizeRestriction size_restriction> |
| 1442 static inline void EvacuateObject(Map* map, | 1448 static inline void EvacuateObject(Map* map, |
| 1443 HeapObject** slot, | 1449 HeapObject** slot, |
| 1444 HeapObject* object, | 1450 HeapObject* object, |
| 1445 int object_size) { | 1451 int object_size) { |
| 1446 ASSERT((size_restriction != SMALL) || | 1452 SLOW_ASSERT((size_restriction != SMALL) || |
| 1447 (object_size <= Page::kMaxHeapObjectSize)); | 1453 (object_size <= Page::kMaxHeapObjectSize)); |
| 1448 ASSERT(object->Size() == object_size); | 1454 SLOW_ASSERT(object->Size() == object_size); |
| 1449 | 1455 |
| 1450 Heap* heap = map->GetHeap(); | 1456 Heap* heap = map->GetHeap(); |
| 1451 if (heap->ShouldBePromoted(object->address(), object_size)) { | 1457 if (heap->ShouldBePromoted(object->address(), object_size)) { |
| 1452 MaybeObject* maybe_result; | 1458 MaybeObject* maybe_result; |
| 1453 | 1459 |
| 1454 if ((size_restriction != SMALL) && | 1460 if ((size_restriction != SMALL) && |
| 1455 (object_size > Page::kMaxHeapObjectSize)) { | 1461 (object_size > Page::kMaxHeapObjectSize)) { |
| 1456 maybe_result = heap->lo_space()->AllocateRaw(object_size, | 1462 maybe_result = heap->lo_space()->AllocateRaw(object_size, |
| 1457 NOT_EXECUTABLE); | 1463 NOT_EXECUTABLE); |
| 1458 } else { | 1464 } else { |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1671 scavenging_visitors_table_.Register( | 1677 scavenging_visitors_table_.Register( |
| 1672 StaticVisitorBase::kVisitShortcutCandidate, | 1678 StaticVisitorBase::kVisitShortcutCandidate, |
| 1673 scavenging_visitors_table_.GetVisitorById( | 1679 scavenging_visitors_table_.GetVisitorById( |
| 1674 StaticVisitorBase::kVisitConsString)); | 1680 StaticVisitorBase::kVisitConsString)); |
| 1675 } | 1681 } |
| 1676 } | 1682 } |
| 1677 } | 1683 } |
| 1678 | 1684 |
| 1679 | 1685 |
| 1680 void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) { | 1686 void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) { |
| 1681 ASSERT(HEAP->InFromSpace(object)); | 1687 SLOW_ASSERT(HEAP->InFromSpace(object)); |
| 1682 MapWord first_word = object->map_word(); | 1688 MapWord first_word = object->map_word(); |
| 1683 ASSERT(!first_word.IsForwardingAddress()); | 1689 SLOW_ASSERT(!first_word.IsForwardingAddress()); |
| 1684 Map* map = first_word.ToMap(); | 1690 Map* map = first_word.ToMap(); |
| 1685 map->GetHeap()->DoScavengeObject(map, p, object); | 1691 map->GetHeap()->DoScavengeObject(map, p, object); |
| 1686 } | 1692 } |
| 1687 | 1693 |
| 1688 | 1694 |
| 1689 MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type, | 1695 MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type, |
| 1690 int instance_size) { | 1696 int instance_size) { |
| 1691 Object* result; | 1697 Object* result; |
| 1692 { MaybeObject* maybe_result = AllocateRawMap(); | 1698 { MaybeObject* maybe_result = AllocateRawMap(); |
| 1693 if (!maybe_result->ToObject(&result)) return maybe_result; | 1699 if (!maybe_result->ToObject(&result)) return maybe_result; |
| (...skipping 1209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2903 } else { | 2909 } else { |
| 2904 ASSERT(string_result->IsTwoByteRepresentation()); | 2910 ASSERT(string_result->IsTwoByteRepresentation()); |
| 2905 uc16* dest = SeqTwoByteString::cast(string_result)->GetChars(); | 2911 uc16* dest = SeqTwoByteString::cast(string_result)->GetChars(); |
| 2906 String::WriteToFlat(buffer, dest, start, end); | 2912 String::WriteToFlat(buffer, dest, start, end); |
| 2907 } | 2913 } |
| 2908 return result; | 2914 return result; |
| 2909 } | 2915 } |
| 2910 | 2916 |
| 2911 ASSERT(buffer->IsFlat()); | 2917 ASSERT(buffer->IsFlat()); |
| 2912 #if DEBUG | 2918 #if DEBUG |
| 2913 buffer->StringVerify(); | 2919 if (FLAG_verify_heap) { |
| 2920 buffer->StringVerify(); |
| 2921 } |
| 2914 #endif | 2922 #endif |
| 2915 | 2923 |
| 2916 Object* result; | 2924 Object* result; |
| 2917 // When slicing an indirect string we use its encoding for a newly created | 2925 // When slicing an indirect string we use its encoding for a newly created |
| 2918 // slice and don't check the encoding of the underlying string. This is safe | 2926 // slice and don't check the encoding of the underlying string. This is safe |
| 2919 // even if the encodings are different because of externalization. If an | 2927 // even if the encodings are different because of externalization. If an |
| 2920 // indirect ASCII string is pointing to a two-byte string, the two-byte char | 2928 // indirect ASCII string is pointing to a two-byte string, the two-byte char |
| 2921 // codes of the underlying string must still fit into ASCII (because | 2929 // codes of the underlying string must still fit into ASCII (because |
| 2922 // externalization must not change char codes). | 2930 // externalization must not change char codes). |
| 2923 { Map* map = buffer->IsAsciiRepresentation() | 2931 { Map* map = buffer->IsAsciiRepresentation() |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3149 *(self_reference.location()) = code; | 3157 *(self_reference.location()) = code; |
| 3150 } | 3158 } |
| 3151 // Migrate generated code. | 3159 // Migrate generated code. |
| 3152 // The generated code can contain Object** values (typically from handles) | 3160 // The generated code can contain Object** values (typically from handles) |
| 3153 // that are dereferenced during the copy to point directly to the actual heap | 3161 // that are dereferenced during the copy to point directly to the actual heap |
| 3154 // objects. These pointers can include references to the code object itself, | 3162 // objects. These pointers can include references to the code object itself, |
| 3155 // through the self_reference parameter. | 3163 // through the self_reference parameter. |
| 3156 code->CopyFrom(desc); | 3164 code->CopyFrom(desc); |
| 3157 | 3165 |
| 3158 #ifdef DEBUG | 3166 #ifdef DEBUG |
| 3159 code->Verify(); | 3167 if (FLAG_verify_heap) { |
| 3168 code->Verify(); |
| 3169 } |
| 3160 #endif | 3170 #endif |
| 3161 return code; | 3171 return code; |
| 3162 } | 3172 } |
| 3163 | 3173 |
| 3164 | 3174 |
| 3165 MaybeObject* Heap::CopyCode(Code* code) { | 3175 MaybeObject* Heap::CopyCode(Code* code) { |
| 3166 // Allocate an object the same size as the code object. | 3176 // Allocate an object the same size as the code object. |
| 3167 int obj_size = code->Size(); | 3177 int obj_size = code->Size(); |
| 3168 MaybeObject* maybe_result; | 3178 MaybeObject* maybe_result; |
| 3169 if (obj_size > MaxObjectSizeInPagedSpace()) { | 3179 if (obj_size > MaxObjectSizeInPagedSpace()) { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3229 | 3239 |
| 3230 // Copy patched rinfo. | 3240 // Copy patched rinfo. |
| 3231 memcpy(new_code->relocation_start(), reloc_info.start(), reloc_info.length()); | 3241 memcpy(new_code->relocation_start(), reloc_info.start(), reloc_info.length()); |
| 3232 | 3242 |
| 3233 // Relocate the copy. | 3243 // Relocate the copy. |
| 3234 ASSERT(!isolate_->code_range()->exists() || | 3244 ASSERT(!isolate_->code_range()->exists() || |
| 3235 isolate_->code_range()->contains(code->address())); | 3245 isolate_->code_range()->contains(code->address())); |
| 3236 new_code->Relocate(new_addr - old_addr); | 3246 new_code->Relocate(new_addr - old_addr); |
| 3237 | 3247 |
| 3238 #ifdef DEBUG | 3248 #ifdef DEBUG |
| 3239 code->Verify(); | 3249 if (FLAG_verify_heap) { |
| 3250 code->Verify(); |
| 3251 } |
| 3240 #endif | 3252 #endif |
| 3241 return new_code; | 3253 return new_code; |
| 3242 } | 3254 } |
| 3243 | 3255 |
| 3244 | 3256 |
| 3245 MaybeObject* Heap::Allocate(Map* map, AllocationSpace space) { | 3257 MaybeObject* Heap::Allocate(Map* map, AllocationSpace space) { |
| 3246 ASSERT(gc_state_ == NOT_IN_GC); | 3258 ASSERT(gc_state_ == NOT_IN_GC); |
| 3247 ASSERT(map->instance_type() != MAP_TYPE); | 3259 ASSERT(map->instance_type() != MAP_TYPE); |
| 3248 // If allocation failures are disallowed, we may allocate in a different | 3260 // If allocation failures are disallowed, we may allocate in a different |
| 3249 // space when new space is full and the object is not a large object. | 3261 // space when new space is full and the object is not a large object. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3262 void Heap::InitializeFunction(JSFunction* function, | 3274 void Heap::InitializeFunction(JSFunction* function, |
| 3263 SharedFunctionInfo* shared, | 3275 SharedFunctionInfo* shared, |
| 3264 Object* prototype) { | 3276 Object* prototype) { |
| 3265 ASSERT(!prototype->IsMap()); | 3277 ASSERT(!prototype->IsMap()); |
| 3266 function->initialize_properties(); | 3278 function->initialize_properties(); |
| 3267 function->initialize_elements(); | 3279 function->initialize_elements(); |
| 3268 function->set_shared(shared); | 3280 function->set_shared(shared); |
| 3269 function->set_code(shared->code()); | 3281 function->set_code(shared->code()); |
| 3270 function->set_prototype_or_initial_map(prototype); | 3282 function->set_prototype_or_initial_map(prototype); |
| 3271 function->set_context(undefined_value()); | 3283 function->set_context(undefined_value()); |
| 3272 function->set_literals(empty_fixed_array()); | 3284 function->set_literals_or_bindings(empty_fixed_array()); |
| 3273 function->set_next_function_link(undefined_value()); | 3285 function->set_next_function_link(undefined_value()); |
| 3274 } | 3286 } |
| 3275 | 3287 |
| 3276 | 3288 |
| 3277 MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) { | 3289 MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) { |
| 3278 // Allocate the prototype. Make sure to use the object function | 3290 // Allocate the prototype. Make sure to use the object function |
| 3279 // from the function's context, since the function can be from a | 3291 // from the function's context, since the function can be from a |
| 3280 // different context. | 3292 // different context. |
| 3281 JSFunction* object_function = | 3293 JSFunction* object_function = |
| 3282 function->context()->global_context()->object_function(); | 3294 function->context()->global_context()->object_function(); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3427 // cannot be constructed without having these properties. Guard by | 3439 // cannot be constructed without having these properties. Guard by |
| 3428 // the inline_new flag so we only change the map if we generate a | 3440 // the inline_new flag so we only change the map if we generate a |
| 3429 // specialized construct stub. | 3441 // specialized construct stub. |
| 3430 ASSERT(in_object_properties <= Map::kMaxPreAllocatedPropertyFields); | 3442 ASSERT(in_object_properties <= Map::kMaxPreAllocatedPropertyFields); |
| 3431 if (fun->shared()->CanGenerateInlineConstructor(prototype)) { | 3443 if (fun->shared()->CanGenerateInlineConstructor(prototype)) { |
| 3432 int count = fun->shared()->this_property_assignments_count(); | 3444 int count = fun->shared()->this_property_assignments_count(); |
| 3433 if (count > in_object_properties) { | 3445 if (count > in_object_properties) { |
| 3434 // Inline constructor can only handle inobject properties. | 3446 // Inline constructor can only handle inobject properties. |
| 3435 fun->shared()->ForbidInlineConstructor(); | 3447 fun->shared()->ForbidInlineConstructor(); |
| 3436 } else { | 3448 } else { |
| 3437 Object* descriptors_obj; | 3449 DescriptorArray* descriptors; |
| 3438 { MaybeObject* maybe_descriptors_obj = DescriptorArray::Allocate(count); | 3450 { MaybeObject* maybe_descriptors_obj = DescriptorArray::Allocate(count); |
| 3439 if (!maybe_descriptors_obj->ToObject(&descriptors_obj)) { | 3451 if (!maybe_descriptors_obj->To<DescriptorArray>(&descriptors)) { |
| 3440 return maybe_descriptors_obj; | 3452 return maybe_descriptors_obj; |
| 3441 } | 3453 } |
| 3442 } | 3454 } |
| 3443 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_obj); | 3455 DescriptorArray::WhitenessWitness witness(descriptors); |
| 3444 for (int i = 0; i < count; i++) { | 3456 for (int i = 0; i < count; i++) { |
| 3445 String* name = fun->shared()->GetThisPropertyAssignmentName(i); | 3457 String* name = fun->shared()->GetThisPropertyAssignmentName(i); |
| 3446 ASSERT(name->IsSymbol()); | 3458 ASSERT(name->IsSymbol()); |
| 3447 FieldDescriptor field(name, i, NONE); | 3459 FieldDescriptor field(name, i, NONE); |
| 3448 field.SetEnumerationIndex(i); | 3460 field.SetEnumerationIndex(i); |
| 3449 descriptors->Set(i, &field); | 3461 descriptors->Set(i, &field, witness); |
| 3450 } | 3462 } |
| 3451 descriptors->SetNextEnumerationIndex(count); | 3463 descriptors->SetNextEnumerationIndex(count); |
| 3452 descriptors->SortUnchecked(); | 3464 descriptors->SortUnchecked(witness); |
| 3453 | 3465 |
| 3454 // The descriptors may contain duplicates because the compiler does not | 3466 // The descriptors may contain duplicates because the compiler does not |
| 3455 // guarantee the uniqueness of property names (it would have required | 3467 // guarantee the uniqueness of property names (it would have required |
| 3456 // quadratic time). Once the descriptors are sorted we can check for | 3468 // quadratic time). Once the descriptors are sorted we can check for |
| 3457 // duplicates in linear time. | 3469 // duplicates in linear time. |
| 3458 if (HasDuplicates(descriptors)) { | 3470 if (HasDuplicates(descriptors)) { |
| 3459 fun->shared()->ForbidInlineConstructor(); | 3471 fun->shared()->ForbidInlineConstructor(); |
| 3460 } else { | 3472 } else { |
| 3461 map->set_instance_descriptors(descriptors); | 3473 map->set_instance_descriptors(descriptors); |
| 3462 map->set_pre_allocated_property_fields(count); | 3474 map->set_pre_allocated_property_fields(count); |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3681 // Make sure result is a global object with properties in dictionary. | 3693 // Make sure result is a global object with properties in dictionary. |
| 3682 ASSERT(global->IsGlobalObject()); | 3694 ASSERT(global->IsGlobalObject()); |
| 3683 ASSERT(!global->HasFastProperties()); | 3695 ASSERT(!global->HasFastProperties()); |
| 3684 return global; | 3696 return global; |
| 3685 } | 3697 } |
| 3686 | 3698 |
| 3687 | 3699 |
| 3688 MaybeObject* Heap::CopyJSObject(JSObject* source) { | 3700 MaybeObject* Heap::CopyJSObject(JSObject* source) { |
| 3689 // Never used to copy functions. If functions need to be copied we | 3701 // Never used to copy functions. If functions need to be copied we |
| 3690 // have to be careful to clear the literals array. | 3702 // have to be careful to clear the literals array. |
| 3691 ASSERT(!source->IsJSFunction()); | 3703 SLOW_ASSERT(!source->IsJSFunction()); |
| 3692 | 3704 |
| 3693 // Make the clone. | 3705 // Make the clone. |
| 3694 Map* map = source->map(); | 3706 Map* map = source->map(); |
| 3695 int object_size = map->instance_size(); | 3707 int object_size = map->instance_size(); |
| 3696 Object* clone; | 3708 Object* clone; |
| 3697 | 3709 |
| 3710 WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER; |
| 3711 |
| 3698 // If we're forced to always allocate, we use the general allocation | 3712 // If we're forced to always allocate, we use the general allocation |
| 3699 // functions which may leave us with an object in old space. | 3713 // functions which may leave us with an object in old space. |
| 3700 if (always_allocate()) { | 3714 if (always_allocate()) { |
| 3701 { MaybeObject* maybe_clone = | 3715 { MaybeObject* maybe_clone = |
| 3702 AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE); | 3716 AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE); |
| 3703 if (!maybe_clone->ToObject(&clone)) return maybe_clone; | 3717 if (!maybe_clone->ToObject(&clone)) return maybe_clone; |
| 3704 } | 3718 } |
| 3705 Address clone_address = HeapObject::cast(clone)->address(); | 3719 Address clone_address = HeapObject::cast(clone)->address(); |
| 3706 CopyBlock(clone_address, | 3720 CopyBlock(clone_address, |
| 3707 source->address(), | 3721 source->address(), |
| 3708 object_size); | 3722 object_size); |
| 3709 // Update write barrier for all fields that lie beyond the header. | 3723 // Update write barrier for all fields that lie beyond the header. |
| 3710 RecordWrites(clone_address, | 3724 RecordWrites(clone_address, |
| 3711 JSObject::kHeaderSize, | 3725 JSObject::kHeaderSize, |
| 3712 (object_size - JSObject::kHeaderSize) / kPointerSize); | 3726 (object_size - JSObject::kHeaderSize) / kPointerSize); |
| 3713 } else { | 3727 } else { |
| 3728 wb_mode = SKIP_WRITE_BARRIER; |
| 3714 { MaybeObject* maybe_clone = new_space_.AllocateRaw(object_size); | 3729 { MaybeObject* maybe_clone = new_space_.AllocateRaw(object_size); |
| 3715 if (!maybe_clone->ToObject(&clone)) return maybe_clone; | 3730 if (!maybe_clone->ToObject(&clone)) return maybe_clone; |
| 3716 } | 3731 } |
| 3717 ASSERT(InNewSpace(clone)); | 3732 SLOW_ASSERT(InNewSpace(clone)); |
| 3718 // Since we know the clone is allocated in new space, we can copy | 3733 // Since we know the clone is allocated in new space, we can copy |
| 3719 // the contents without worrying about updating the write barrier. | 3734 // the contents without worrying about updating the write barrier. |
| 3720 CopyBlock(HeapObject::cast(clone)->address(), | 3735 CopyBlock(HeapObject::cast(clone)->address(), |
| 3721 source->address(), | 3736 source->address(), |
| 3722 object_size); | 3737 object_size); |
| 3723 } | 3738 } |
| 3724 | 3739 |
| 3725 ASSERT(JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind()); | 3740 SLOW_ASSERT( |
| 3741 JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind()); |
| 3726 FixedArrayBase* elements = FixedArrayBase::cast(source->elements()); | 3742 FixedArrayBase* elements = FixedArrayBase::cast(source->elements()); |
| 3727 FixedArray* properties = FixedArray::cast(source->properties()); | 3743 FixedArray* properties = FixedArray::cast(source->properties()); |
| 3728 // Update elements if necessary. | 3744 // Update elements if necessary. |
| 3729 if (elements->length() > 0) { | 3745 if (elements->length() > 0) { |
| 3730 Object* elem; | 3746 Object* elem; |
| 3731 { MaybeObject* maybe_elem; | 3747 { MaybeObject* maybe_elem; |
| 3732 if (elements->map() == fixed_cow_array_map()) { | 3748 if (elements->map() == fixed_cow_array_map()) { |
| 3733 maybe_elem = FixedArray::cast(elements); | 3749 maybe_elem = FixedArray::cast(elements); |
| 3734 } else if (source->HasFastDoubleElements()) { | 3750 } else if (source->HasFastDoubleElements()) { |
| 3735 maybe_elem = CopyFixedDoubleArray(FixedDoubleArray::cast(elements)); | 3751 maybe_elem = CopyFixedDoubleArray(FixedDoubleArray::cast(elements)); |
| 3736 } else { | 3752 } else { |
| 3737 maybe_elem = CopyFixedArray(FixedArray::cast(elements)); | 3753 maybe_elem = CopyFixedArray(FixedArray::cast(elements)); |
| 3738 } | 3754 } |
| 3739 if (!maybe_elem->ToObject(&elem)) return maybe_elem; | 3755 if (!maybe_elem->ToObject(&elem)) return maybe_elem; |
| 3740 } | 3756 } |
| 3741 JSObject::cast(clone)->set_elements(FixedArrayBase::cast(elem)); | 3757 JSObject::cast(clone)->set_elements(FixedArrayBase::cast(elem), wb_mode); |
| 3742 } | 3758 } |
| 3743 // Update properties if necessary. | 3759 // Update properties if necessary. |
| 3744 if (properties->length() > 0) { | 3760 if (properties->length() > 0) { |
| 3745 Object* prop; | 3761 Object* prop; |
| 3746 { MaybeObject* maybe_prop = CopyFixedArray(properties); | 3762 { MaybeObject* maybe_prop = CopyFixedArray(properties); |
| 3747 if (!maybe_prop->ToObject(&prop)) return maybe_prop; | 3763 if (!maybe_prop->ToObject(&prop)) return maybe_prop; |
| 3748 } | 3764 } |
| 3749 JSObject::cast(clone)->set_properties(FixedArray::cast(prop)); | 3765 JSObject::cast(clone)->set_properties(FixedArray::cast(prop), wb_mode); |
| 3750 } | 3766 } |
| 3751 // Return the new clone. | 3767 // Return the new clone. |
| 3752 return clone; | 3768 return clone; |
| 3753 } | 3769 } |
| 3754 | 3770 |
| 3755 | 3771 |
| 3756 MaybeObject* Heap::ReinitializeJSReceiver( | 3772 MaybeObject* Heap::ReinitializeJSReceiver( |
| 3757 JSReceiver* object, InstanceType type, int size) { | 3773 JSReceiver* object, InstanceType type, int size) { |
| 3758 ASSERT(type >= FIRST_JS_OBJECT_TYPE); | 3774 ASSERT(type >= FIRST_JS_OBJECT_TYPE); |
| 3759 | 3775 |
| (...skipping 1035 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4795 // If the store buffer becomes overfull we mark pages as being exempt from | 4811 // If the store buffer becomes overfull we mark pages as being exempt from |
| 4796 // the store buffer. These pages are scanned to find pointers that point | 4812 // the store buffer. These pages are scanned to find pointers that point |
| 4797 // to the new space. In that case we may hit newly promoted objects and | 4813 // to the new space. In that case we may hit newly promoted objects and |
| 4798 // fix the pointers before the promotion queue gets to them. Thus the 'if'. | 4814 // fix the pointers before the promotion queue gets to them. Thus the 'if'. |
| 4799 if (object->IsHeapObject()) { | 4815 if (object->IsHeapObject()) { |
| 4800 if (Heap::InFromSpace(object)) { | 4816 if (Heap::InFromSpace(object)) { |
| 4801 callback(reinterpret_cast<HeapObject**>(slot), | 4817 callback(reinterpret_cast<HeapObject**>(slot), |
| 4802 HeapObject::cast(object)); | 4818 HeapObject::cast(object)); |
| 4803 Object* new_object = *slot; | 4819 Object* new_object = *slot; |
| 4804 if (InNewSpace(new_object)) { | 4820 if (InNewSpace(new_object)) { |
| 4805 ASSERT(Heap::InToSpace(new_object)); | 4821 SLOW_ASSERT(Heap::InToSpace(new_object)); |
| 4806 ASSERT(new_object->IsHeapObject()); | 4822 SLOW_ASSERT(new_object->IsHeapObject()); |
| 4807 store_buffer_.EnterDirectlyIntoStoreBuffer( | 4823 store_buffer_.EnterDirectlyIntoStoreBuffer( |
| 4808 reinterpret_cast<Address>(slot)); | 4824 reinterpret_cast<Address>(slot)); |
| 4809 } | 4825 } |
| 4810 ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_object)); | 4826 SLOW_ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_object)); |
| 4811 } else if (record_slots && | 4827 } else if (record_slots && |
| 4812 MarkCompactCollector::IsOnEvacuationCandidate(object)) { | 4828 MarkCompactCollector::IsOnEvacuationCandidate(object)) { |
| 4813 mark_compact_collector()->RecordSlot(slot, slot, object); | 4829 mark_compact_collector()->RecordSlot(slot, slot, object); |
| 4814 } | 4830 } |
| 4815 } | 4831 } |
| 4816 slot_address += kPointerSize; | 4832 slot_address += kPointerSize; |
| 4817 } | 4833 } |
| 4818 } | 4834 } |
| 4819 | 4835 |
| 4820 | 4836 |
| (...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5354 List<Object*> object_stack_; | 5370 List<Object*> object_stack_; |
| 5355 Heap* heap_; | 5371 Heap* heap_; |
| 5356 | 5372 |
| 5357 friend class Heap; | 5373 friend class Heap; |
| 5358 }; | 5374 }; |
| 5359 | 5375 |
| 5360 #endif | 5376 #endif |
| 5361 | 5377 |
| 5362 bool Heap::Setup(bool create_heap_objects) { | 5378 bool Heap::Setup(bool create_heap_objects) { |
| 5363 #ifdef DEBUG | 5379 #ifdef DEBUG |
| 5380 allocation_timeout_ = FLAG_gc_interval; |
| 5364 debug_utils_ = new HeapDebugUtils(this); | 5381 debug_utils_ = new HeapDebugUtils(this); |
| 5365 #endif | 5382 #endif |
| 5366 | 5383 |
| 5367 // Initialize heap spaces and initial maps and objects. Whenever something | 5384 // Initialize heap spaces and initial maps and objects. Whenever something |
| 5368 // goes wrong, just return false. The caller should check the results and | 5385 // goes wrong, just return false. The caller should check the results and |
| 5369 // call Heap::TearDown() to release allocated memory. | 5386 // call Heap::TearDown() to release allocated memory. |
| 5370 // | 5387 // |
| 5371 // If the heap is not yet configured (eg, through the API), configure it. | 5388 // If the heap is not yet configured (eg, through the API), configure it. |
| 5372 // Configuration is based on the flags new-space-size (really the semispace | 5389 // Configuration is based on the flags new-space-size (really the semispace |
| 5373 // size) and old-space-size if set or the initial values of semispace_size_ | 5390 // size) and old-space-size if set or the initial values of semispace_size_ |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5439 if (!map_space_->Setup()) return false; | 5456 if (!map_space_->Setup()) return false; |
| 5440 | 5457 |
| 5441 // Initialize global property cell space. | 5458 // Initialize global property cell space. |
| 5442 cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE); | 5459 cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE); |
| 5443 if (cell_space_ == NULL) return false; | 5460 if (cell_space_ == NULL) return false; |
| 5444 if (!cell_space_->Setup()) return false; | 5461 if (!cell_space_->Setup()) return false; |
| 5445 | 5462 |
| 5446 // The large object code space may contain code or data. We set the memory | 5463 // The large object code space may contain code or data. We set the memory |
| 5447 // to be non-executable here for safety, but this means we need to enable it | 5464 // to be non-executable here for safety, but this means we need to enable it |
| 5448 // explicitly when allocating large code objects. | 5465 // explicitly when allocating large code objects. |
| 5449 lo_space_ = new LargeObjectSpace(this, LO_SPACE); | 5466 lo_space_ = new LargeObjectSpace(this, max_old_generation_size_, LO_SPACE); |
| 5450 if (lo_space_ == NULL) return false; | 5467 if (lo_space_ == NULL) return false; |
| 5451 if (!lo_space_->Setup()) return false; | 5468 if (!lo_space_->Setup()) return false; |
| 5452 if (create_heap_objects) { | 5469 if (create_heap_objects) { |
| 5453 // Create initial maps. | 5470 // Create initial maps. |
| 5454 if (!CreateInitialMaps()) return false; | 5471 if (!CreateInitialMaps()) return false; |
| 5455 if (!CreateApiObjects()) return false; | 5472 if (!CreateApiObjects()) return false; |
| 5456 | 5473 |
| 5457 // Create initial objects | 5474 // Create initial objects |
| 5458 if (!CreateInitialObjects()) return false; | 5475 if (!CreateInitialObjects()) return false; |
| 5459 | 5476 |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5755 class HeapObjectsFilter { | 5772 class HeapObjectsFilter { |
| 5756 public: | 5773 public: |
| 5757 virtual ~HeapObjectsFilter() {} | 5774 virtual ~HeapObjectsFilter() {} |
| 5758 virtual bool SkipObject(HeapObject* object) = 0; | 5775 virtual bool SkipObject(HeapObject* object) = 0; |
| 5759 }; | 5776 }; |
| 5760 | 5777 |
| 5761 | 5778 |
| 5762 class UnreachableObjectsFilter : public HeapObjectsFilter { | 5779 class UnreachableObjectsFilter : public HeapObjectsFilter { |
| 5763 public: | 5780 public: |
| 5764 UnreachableObjectsFilter() { | 5781 UnreachableObjectsFilter() { |
| 5765 MarkUnreachableObjects(); | 5782 MarkReachableObjects(); |
| 5783 } |
| 5784 |
| 5785 ~UnreachableObjectsFilter() { |
| 5786 Isolate::Current()->heap()->mark_compact_collector()->ClearMarkbits(); |
| 5766 } | 5787 } |
| 5767 | 5788 |
| 5768 bool SkipObject(HeapObject* object) { | 5789 bool SkipObject(HeapObject* object) { |
| 5769 if (IntrusiveMarking::IsMarked(object)) { | 5790 MarkBit mark_bit = Marking::MarkBitFrom(object); |
| 5770 IntrusiveMarking::ClearMark(object); | 5791 return !mark_bit.Get(); |
| 5771 return true; | |
| 5772 } else { | |
| 5773 return false; | |
| 5774 } | |
| 5775 } | 5792 } |
| 5776 | 5793 |
| 5777 private: | 5794 private: |
| 5778 class UnmarkingVisitor : public ObjectVisitor { | 5795 class MarkingVisitor : public ObjectVisitor { |
| 5779 public: | 5796 public: |
| 5780 UnmarkingVisitor() : list_(10) {} | 5797 MarkingVisitor() : marking_stack_(10) {} |
| 5781 | 5798 |
| 5782 void VisitPointers(Object** start, Object** end) { | 5799 void VisitPointers(Object** start, Object** end) { |
| 5783 for (Object** p = start; p < end; p++) { | 5800 for (Object** p = start; p < end; p++) { |
| 5784 if (!(*p)->IsHeapObject()) continue; | 5801 if (!(*p)->IsHeapObject()) continue; |
| 5785 HeapObject* obj = HeapObject::cast(*p); | 5802 HeapObject* obj = HeapObject::cast(*p); |
| 5786 if (IntrusiveMarking::IsMarked(obj)) { | 5803 MarkBit mark_bit = Marking::MarkBitFrom(obj); |
| 5787 IntrusiveMarking::ClearMark(obj); | 5804 if (!mark_bit.Get()) { |
| 5788 list_.Add(obj); | 5805 mark_bit.Set(); |
| 5806 marking_stack_.Add(obj); |
| 5789 } | 5807 } |
| 5790 } | 5808 } |
| 5791 } | 5809 } |
| 5792 | 5810 |
| 5793 bool can_process() { return !list_.is_empty(); } | 5811 void TransitiveClosure() { |
| 5794 | 5812 while (!marking_stack_.is_empty()) { |
| 5795 void ProcessNext() { | 5813 HeapObject* obj = marking_stack_.RemoveLast(); |
| 5796 HeapObject* obj = list_.RemoveLast(); | 5814 obj->Iterate(this); |
| 5797 obj->Iterate(this); | 5815 } |
| 5798 } | 5816 } |
| 5799 | 5817 |
| 5800 private: | 5818 private: |
| 5801 List<HeapObject*> list_; | 5819 List<HeapObject*> marking_stack_; |
| 5802 }; | 5820 }; |
| 5803 | 5821 |
| 5804 void MarkUnreachableObjects() { | 5822 void MarkReachableObjects() { |
| 5805 HeapIterator iterator; | 5823 Heap* heap = Isolate::Current()->heap(); |
| 5806 for (HeapObject* obj = iterator.next(); | 5824 MarkingVisitor visitor; |
| 5807 obj != NULL; | 5825 heap->IterateRoots(&visitor, VISIT_ALL); |
| 5808 obj = iterator.next()) { | 5826 visitor.TransitiveClosure(); |
| 5809 IntrusiveMarking::SetMark(obj); | |
| 5810 } | |
| 5811 UnmarkingVisitor visitor; | |
| 5812 HEAP->IterateRoots(&visitor, VISIT_ALL); | |
| 5813 while (visitor.can_process()) | |
| 5814 visitor.ProcessNext(); | |
| 5815 } | 5827 } |
| 5816 | 5828 |
| 5817 AssertNoAllocation no_alloc; | 5829 AssertNoAllocation no_alloc; |
| 5818 }; | 5830 }; |
| 5819 | 5831 |
| 5820 | 5832 |
| 5821 HeapIterator::HeapIterator() | 5833 HeapIterator::HeapIterator() |
| 5822 : filtering_(HeapIterator::kNoFiltering), | 5834 : filtering_(HeapIterator::kNoFiltering), |
| 5823 filter_(NULL) { | 5835 filter_(NULL) { |
| 5824 Init(); | 5836 Init(); |
| 5825 } | 5837 } |
| 5826 | 5838 |
| 5827 | 5839 |
| 5828 HeapIterator::HeapIterator(HeapIterator::HeapObjectsFiltering filtering) | 5840 HeapIterator::HeapIterator(HeapIterator::HeapObjectsFiltering filtering) |
| 5829 : filtering_(filtering), | 5841 : filtering_(filtering), |
| 5830 filter_(NULL) { | 5842 filter_(NULL) { |
| 5831 Init(); | 5843 Init(); |
| 5832 } | 5844 } |
| 5833 | 5845 |
| 5834 | 5846 |
| 5835 HeapIterator::~HeapIterator() { | 5847 HeapIterator::~HeapIterator() { |
| 5836 Shutdown(); | 5848 Shutdown(); |
| 5837 } | 5849 } |
| 5838 | 5850 |
| 5839 | 5851 |
| 5840 void HeapIterator::Init() { | 5852 void HeapIterator::Init() { |
| 5841 // Start the iteration. | 5853 // Start the iteration. |
| 5842 space_iterator_ = filtering_ == kNoFiltering ? new SpaceIterator : | 5854 space_iterator_ = new SpaceIterator; |
| 5843 new SpaceIterator(Isolate::Current()->heap()-> | |
| 5844 GcSafeSizeOfOldObjectFunction()); | |
| 5845 switch (filtering_) { | 5855 switch (filtering_) { |
| 5846 case kFilterFreeListNodes: | |
| 5847 // TODO(gc): Not handled. | |
| 5848 break; | |
| 5849 case kFilterUnreachable: | 5856 case kFilterUnreachable: |
| 5850 filter_ = new UnreachableObjectsFilter; | 5857 filter_ = new UnreachableObjectsFilter; |
| 5851 break; | 5858 break; |
| 5852 default: | 5859 default: |
| 5853 break; | 5860 break; |
| 5854 } | 5861 } |
| 5855 object_iterator_ = space_iterator_->next(); | 5862 object_iterator_ = space_iterator_->next(); |
| 5856 } | 5863 } |
| 5857 | 5864 |
| 5858 | 5865 |
| (...skipping 484 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6343 } | 6350 } |
| 6344 } | 6351 } |
| 6345 new_space_strings_.Rewind(last); | 6352 new_space_strings_.Rewind(last); |
| 6346 last = 0; | 6353 last = 0; |
| 6347 for (int i = 0; i < old_space_strings_.length(); ++i) { | 6354 for (int i = 0; i < old_space_strings_.length(); ++i) { |
| 6348 if (old_space_strings_[i] == heap_->raw_unchecked_null_value()) continue; | 6355 if (old_space_strings_[i] == heap_->raw_unchecked_null_value()) continue; |
| 6349 ASSERT(!heap_->InNewSpace(old_space_strings_[i])); | 6356 ASSERT(!heap_->InNewSpace(old_space_strings_[i])); |
| 6350 old_space_strings_[last++] = old_space_strings_[i]; | 6357 old_space_strings_[last++] = old_space_strings_[i]; |
| 6351 } | 6358 } |
| 6352 old_space_strings_.Rewind(last); | 6359 old_space_strings_.Rewind(last); |
| 6353 Verify(); | 6360 if (FLAG_verify_heap) { |
| 6361 Verify(); |
| 6362 } |
| 6354 } | 6363 } |
| 6355 | 6364 |
| 6356 | 6365 |
| 6357 void ExternalStringTable::TearDown() { | 6366 void ExternalStringTable::TearDown() { |
| 6358 new_space_strings_.Free(); | 6367 new_space_strings_.Free(); |
| 6359 old_space_strings_.Free(); | 6368 old_space_strings_.Free(); |
| 6360 } | 6369 } |
| 6361 | 6370 |
| 6362 | 6371 |
| 6363 void Heap::QueueMemoryChunkForFree(MemoryChunk* chunk) { | 6372 void Heap::QueueMemoryChunkForFree(MemoryChunk* chunk) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6402 isolate_->heap()->store_buffer()->Compact(); | 6411 isolate_->heap()->store_buffer()->Compact(); |
| 6403 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED); | 6412 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED); |
| 6404 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) { | 6413 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) { |
| 6405 next = chunk->next_chunk(); | 6414 next = chunk->next_chunk(); |
| 6406 isolate_->memory_allocator()->Free(chunk); | 6415 isolate_->memory_allocator()->Free(chunk); |
| 6407 } | 6416 } |
| 6408 chunks_queued_for_free_ = NULL; | 6417 chunks_queued_for_free_ = NULL; |
| 6409 } | 6418 } |
| 6410 | 6419 |
| 6411 } } // namespace v8::internal | 6420 } } // namespace v8::internal |
| OLD | NEW |