Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(470)

Side by Side Diff: src/objects.cc

Issue 10830005: In-place trimming of descriptor array when appending callbacks. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed comments. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/objects.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 2088 matching lines...) Expand 10 before | Expand all | Expand 10 after
2099 TransitionArray* transition_array = transitions(); 2099 TransitionArray* transition_array = transitions();
2100 int number = transition_array->Search(name); 2100 int number = transition_array->Search(name);
2101 if (number != TransitionArray::kNotFound) { 2101 if (number != TransitionArray::kNotFound) {
2102 return result->TransitionResult(holder, number); 2102 return result->TransitionResult(holder, number);
2103 } 2103 }
2104 } 2104 }
2105 result->NotFound(); 2105 result->NotFound();
2106 } 2106 }
2107 2107
2108 2108
2109 enum RightTrimMode { FROM_GC, FROM_MUTATOR };
2110
2111
2112 static void ZapEndOfFixedArray(Address new_end, int to_trim) {
2113 // If we are doing a big trim in old space then we zap the space.
2114 Object** zap = reinterpret_cast<Object**>(new_end);
2115 for (int i = 1; i < to_trim; i++) {
2116 *zap++ = Smi::FromInt(0);
2117 }
2118 }
2119
2120 template<RightTrimMode trim_mode>
2121 static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) {
2122 ASSERT(elms->map() != HEAP->fixed_cow_array_map());
2123 // For now this trick is only applied to fixed arrays in new and paged space.
2124 // In large object space the object's start must coincide with chunk
2125 // and thus the trick is just not applicable.
2126 ASSERT(!HEAP->lo_space()->Contains(elms));
2127
2128 const int len = elms->length();
2129
2130 ASSERT(to_trim < len);
2131
2132 Address new_end = elms->address() + FixedArray::SizeFor(len - to_trim);
2133
2134 if (trim_mode == FROM_GC) {
2135 #ifdef DEBUG
2136 ZapEndOfFixedArray(new_end, to_trim);
2137 #endif
2138 } else {
2139 ZapEndOfFixedArray(new_end, to_trim);
2140 }
2141
2142 int size_delta = to_trim * kPointerSize;
2143
2144 // Technically in new space this write might be omitted (except for
2145 // debug mode which iterates through the heap), but to play safer
2146 // we still do it.
2147 heap->CreateFillerObjectAt(new_end, size_delta);
2148
2149 elms->set_length(len - to_trim);
2150
2151 // Maintain marking consistency for IncrementalMarking.
2152 if (Marking::IsBlack(Marking::MarkBitFrom(elms))) {
2153 if (trim_mode == FROM_GC) {
2154 MemoryChunk::IncrementLiveBytesFromGC(elms->address(), -size_delta);
2155 } else {
2156 MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta);
2157 }
2158 }
2159 }
2160
2161
2162 void Map::CopyAppendCallbackDescriptors(Handle<Map> map,
2163 Handle<Object> descriptors) {
2164 Isolate* isolate = map->GetIsolate();
2165 Handle<DescriptorArray> array(map->instance_descriptors());
2166 v8::NeanderArray callbacks(descriptors);
2167 int nof_callbacks = callbacks.length();
2168 int descriptor_count = array->number_of_descriptors();
2169
2170 // Ensure the keys are symbols before writing them into the instance
2171 // descriptor. Since it may cause a GC, it has to be done before we
2172 // temporarily put the heap in an invalid state while appending descriptors.
2173 for (int i = 0; i < nof_callbacks; ++i) {
2174 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks.get(i)));
2175 Handle<String> key =
2176 isolate->factory()->SymbolFromString(
2177 Handle<String>(String::cast(entry->name())));
2178 entry->set_name(*key);
2179 }
2180
2181 Handle<DescriptorArray> result =
2182 isolate->factory()->NewDescriptorArray(descriptor_count + nof_callbacks);
2183
2184 // Ensure that marking will not progress and change color of objects.
2185 DescriptorArray::WhitenessWitness witness(*result);
2186
2187 // Copy the descriptors from the array.
2188 if (0 < descriptor_count) {
2189 for (int i = 0; i < descriptor_count; i++) {
2190 result->CopyFrom(i, *array, i, witness);
2191 }
2192 }
2193
2194 // After this point the GC is not allowed to run anymore until the map is in a
2195 // consistent state again, i.e., all the descriptors are appended and the
2196 // descriptor array is trimmed to the right size.
2197 map->set_instance_descriptors(*result);
2198
2199 // Fill in new callback descriptors. Process the callbacks from
2200 // back to front so that the last callback with a given name takes
2201 // precedence over previously added callbacks with that name.
2202 for (int i = nof_callbacks - 1; i >= 0; i--) {
2203 AccessorInfo* entry = AccessorInfo::cast(callbacks.get(i));
2204 String* key = String::cast(entry->name());
2205 // Check if a descriptor with this name already exists before writing.
2206 if (LinearSearch(*result, key, map->NumberOfSetDescriptors()) ==
2207 DescriptorArray::kNotFound) {
2208 CallbacksDescriptor desc(key, entry, entry->property_attributes());
2209 map->AppendDescriptor(&desc, witness);
2210 }
2211 }
2212
2213 int new_number_of_descriptors = map->NumberOfSetDescriptors();
2214 // Reinstall the original descriptor array if no new elements were added.
2215 if (new_number_of_descriptors == descriptor_count) {
2216 map->set_instance_descriptors(*array);
2217 return;
2218 }
2219
2220 // If duplicates were detected, trim the descriptor array to the right size.
2221 int new_array_size = DescriptorArray::SizeFor(new_number_of_descriptors);
2222 if (new_array_size < result->length()) {
2223 RightTrimFixedArray<FROM_MUTATOR>(
2224 isolate->heap(), *result, result->length() - new_array_size);
2225 }
2226 }
2227
2228
2109 static bool ContainsMap(MapHandleList* maps, Handle<Map> map) { 2229 static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
2110 ASSERT(!map.is_null()); 2230 ASSERT(!map.is_null());
2111 for (int i = 0; i < maps->length(); ++i) { 2231 for (int i = 0; i < maps->length(); ++i) {
2112 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true; 2232 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
2113 } 2233 }
2114 return false; 2234 return false;
2115 } 2235 }
2116 2236
2117 2237
2118 template <class T> 2238 template <class T>
(...skipping 3597 matching lines...) Expand 10 before | Expand all | Expand 10 after
5716 5836
5717 MaybeObject* DescriptorArray::Allocate(int number_of_descriptors, 5837 MaybeObject* DescriptorArray::Allocate(int number_of_descriptors,
5718 SharedMode shared_mode) { 5838 SharedMode shared_mode) {
5719 Heap* heap = Isolate::Current()->heap(); 5839 Heap* heap = Isolate::Current()->heap();
5720 // Do not use DescriptorArray::cast on incomplete object. 5840 // Do not use DescriptorArray::cast on incomplete object.
5721 FixedArray* result; 5841 FixedArray* result;
5722 if (number_of_descriptors == 0 && shared_mode == MAY_BE_SHARED) { 5842 if (number_of_descriptors == 0 && shared_mode == MAY_BE_SHARED) {
5723 return heap->empty_descriptor_array(); 5843 return heap->empty_descriptor_array();
5724 } 5844 }
5725 // Allocate the array of keys. 5845 // Allocate the array of keys.
5726 { MaybeObject* maybe_array = 5846 MaybeObject* maybe_array =
5727 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors)); 5847 heap->AllocateFixedArray(SizeFor(number_of_descriptors));
5728 if (!maybe_array->To(&result)) return maybe_array; 5848 if (!maybe_array->To(&result)) return maybe_array;
5729 }
5730 5849
5731 result->set(kEnumCacheIndex, Smi::FromInt(0)); 5850 result->set(kEnumCacheIndex, Smi::FromInt(0));
5732 result->set(kTransitionsIndex, Smi::FromInt(0)); 5851 result->set(kTransitionsIndex, Smi::FromInt(0));
5733 return result; 5852 return result;
5734 } 5853 }
5735 5854
5736 5855
5737 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, 5856 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
5738 FixedArray* new_cache, 5857 FixedArray* new_cache,
5739 Object* new_index_cache) { 5858 Object* new_index_cache) {
(...skipping 1336 matching lines...) Expand 10 before | Expand all | Expand 10 after
7076 7195
7077 7196
7078 void String::PrintOn(FILE* file) { 7197 void String::PrintOn(FILE* file) {
7079 int length = this->length(); 7198 int length = this->length();
7080 for (int i = 0; i < length; i++) { 7199 for (int i = 0; i < length; i++) {
7081 fprintf(file, "%c", Get(i)); 7200 fprintf(file, "%c", Get(i));
7082 } 7201 }
7083 } 7202 }
7084 7203
7085 7204
7086 // This function should only be called from within the GC, since it uses
7087 // IncrementLiveBytesFromGC. If called from anywhere else, this results in an
7088 // inconsistent live-bytes count.
7089 static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) {
7090 ASSERT(elms->map() != HEAP->fixed_cow_array_map());
7091 // For now this trick is only applied to fixed arrays in new and paged space.
7092 // In large object space the object's start must coincide with chunk
7093 // and thus the trick is just not applicable.
7094 ASSERT(!HEAP->lo_space()->Contains(elms));
7095
7096 const int len = elms->length();
7097
7098 ASSERT(to_trim < len);
7099
7100 Address new_end = elms->address() + FixedArray::SizeFor(len - to_trim);
7101
7102 #ifdef DEBUG
7103 // If we are doing a big trim in old space then we zap the space.
7104 Object** zap = reinterpret_cast<Object**>(new_end);
7105 for (int i = 1; i < to_trim; i++) {
7106 *zap++ = Smi::FromInt(0);
7107 }
7108 #endif
7109
7110 int size_delta = to_trim * kPointerSize;
7111
7112 // Technically in new space this write might be omitted (except for
7113 // debug mode which iterates through the heap), but to play safer
7114 // we still do it.
7115 heap->CreateFillerObjectAt(new_end, size_delta);
7116
7117 elms->set_length(len - to_trim);
7118
7119 // Maintain marking consistency for IncrementalMarking.
7120 if (Marking::IsBlack(Marking::MarkBitFrom(elms))) {
7121 MemoryChunk::IncrementLiveBytesFromGC(elms->address(), -size_delta);
7122 }
7123 }
7124
7125
7126 // Clear a possible back pointer in case the transition leads to a dead map. 7205 // Clear a possible back pointer in case the transition leads to a dead map.
7127 // Return true in case a back pointer has been cleared and false otherwise. 7206 // Return true in case a back pointer has been cleared and false otherwise.
7128 static bool ClearBackPointer(Heap* heap, Object* target) { 7207 static bool ClearBackPointer(Heap* heap, Object* target) {
7129 ASSERT(target->IsMap()); 7208 ASSERT(target->IsMap());
7130 Map* map = Map::cast(target); 7209 Map* map = Map::cast(target);
7131 if (Marking::MarkBitFrom(map).Get()) return false; 7210 if (Marking::MarkBitFrom(map).Get()) return false;
7132 map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER); 7211 map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER);
7133 return true; 7212 return true;
7134 } 7213 }
7135 7214
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
7178 // If the final transition array does not contain any live transitions, remove 7257 // If the final transition array does not contain any live transitions, remove
7179 // the transition array from the map. 7258 // the transition array from the map.
7180 if (transition_index == 0 && 7259 if (transition_index == 0 &&
7181 !t->HasElementsTransition() && 7260 !t->HasElementsTransition() &&
7182 !t->HasPrototypeTransitions()) { 7261 !t->HasPrototypeTransitions()) {
7183 return ClearTransitions(heap); 7262 return ClearTransitions(heap);
7184 } 7263 }
7185 7264
7186 int trim = t->number_of_transitions() - transition_index; 7265 int trim = t->number_of_transitions() - transition_index;
7187 if (trim > 0) { 7266 if (trim > 0) {
7188 RightTrimFixedArray(heap, t, trim * TransitionArray::kTransitionSize); 7267 RightTrimFixedArray<FROM_GC>(
7268 heap, t, trim * TransitionArray::kTransitionSize);
7189 } 7269 }
7190 } 7270 }
7191 7271
7192 7272
7193 int Map::Hash() { 7273 int Map::Hash() {
7194 // For performance reasons we only hash the 3 most variable fields of a map: 7274 // For performance reasons we only hash the 3 most variable fields of a map:
7195 // constructor, prototype and bit_field2. 7275 // constructor, prototype and bit_field2.
7196 7276
7197 // Shift away the tag. 7277 // Shift away the tag.
7198 int hash = (static_cast<uint32_t>( 7278 int hash = (static_cast<uint32_t>(
(...skipping 5855 matching lines...) Expand 10 before | Expand all | Expand 10 after
13054 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); 13134 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
13055 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); 13135 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
13056 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); 13136 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
13057 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); 13137 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
13058 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); 13138 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
13059 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); 13139 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
13060 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); 13140 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
13061 } 13141 }
13062 13142
13063 } } // namespace v8::internal 13143 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698