blob: fc4e666b9696fd34ff7bc2c29748f8d595fb2419 [file] [log] [blame]
ager@chromium.org71daaf62009-04-01 07:22:49 +00001// Copyright 2009 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "accessors.h"
31#include "api.h"
32#include "bootstrapper.h"
33#include "codegen-inl.h"
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000034#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include "debug.h"
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000036#include "heap-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "mark-compact.h"
39#include "natives.h"
40#include "scanner.h"
41#include "scopeinfo.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000042#include "snapshot.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "v8threads.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000044#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP
45#include "regexp-macro-assembler.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000046#include "arm/regexp-macro-assembler-arm.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000047#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048
kasperl@chromium.org71affb52009-05-26 05:44:31 +000049namespace v8 {
50namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052
ager@chromium.org3b45ab52009-03-19 22:21:34 +000053String* Heap::hidden_symbol_;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000054Object* Heap::roots_[Heap::kRootListLength];
55
ager@chromium.org3b45ab52009-03-19 22:21:34 +000056
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000057NewSpace Heap::new_space_;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000058OldSpace* Heap::old_pointer_space_ = NULL;
59OldSpace* Heap::old_data_space_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060OldSpace* Heap::code_space_ = NULL;
61MapSpace* Heap::map_space_ = NULL;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000062CellSpace* Heap::cell_space_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063LargeObjectSpace* Heap::lo_space_ = NULL;
64
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000065static const int kMinimumPromotionLimit = 2*MB;
66static const int kMinimumAllocationLimit = 8*MB;
67
68int Heap::old_gen_promotion_limit_ = kMinimumPromotionLimit;
69int Heap::old_gen_allocation_limit_ = kMinimumAllocationLimit;
70
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000071int Heap::old_gen_exhausted_ = false;
72
kasper.lund7276f142008-07-30 08:49:36 +000073int Heap::amount_of_external_allocated_memory_ = 0;
74int Heap::amount_of_external_allocated_memory_at_last_global_gc_ = 0;
75
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000076// semispace_size_ should be a power of 2 and old_generation_size_ should be
77// a multiple of Page::kPageSize.
kasperl@chromium.orge959c182009-07-27 08:59:04 +000078#if defined(ANDROID)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000079int Heap::max_semispace_size_ = 2*MB;
80int Heap::max_old_generation_size_ = 192*MB;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000081int Heap::initial_semispace_size_ = 128*KB;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000082size_t Heap::code_range_size_ = 0;
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000083#elif defined(V8_TARGET_ARCH_X64)
ager@chromium.org3811b432009-10-28 14:53:37 +000084int Heap::max_semispace_size_ = 16*MB;
85int Heap::max_old_generation_size_ = 1*GB;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000086int Heap::initial_semispace_size_ = 1*MB;
sgjesse@chromium.org152a0b02009-10-07 13:50:16 +000087size_t Heap::code_range_size_ = 512*MB;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000088#else
ager@chromium.org3811b432009-10-28 14:53:37 +000089int Heap::max_semispace_size_ = 8*MB;
90int Heap::max_old_generation_size_ = 512*MB;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000091int Heap::initial_semispace_size_ = 512*KB;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000092size_t Heap::code_range_size_ = 0;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000093#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000094
ager@chromium.org3811b432009-10-28 14:53:37 +000095// The snapshot semispace size will be the default semispace size if
96// snapshotting is used and will be the requested semispace size as
97// set up by ConfigureHeap otherwise.
98int Heap::reserved_semispace_size_ = Heap::max_semispace_size_;
99
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100GCCallback Heap::global_gc_prologue_callback_ = NULL;
101GCCallback Heap::global_gc_epilogue_callback_ = NULL;
102
103// Variables set based on semispace_size_ and old_generation_size_ in
104// ConfigureHeap.
ager@chromium.org3811b432009-10-28 14:53:37 +0000105
106// Will be 4 * reserved_semispace_size_ to ensure that young
107// generation can be aligned to its size.
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000108int Heap::survived_since_last_expansion_ = 0;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000109int Heap::external_allocation_limit_ = 0;
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000110
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000111Heap::HeapState Heap::gc_state_ = NOT_IN_GC;
112
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000113int Heap::mc_count_ = 0;
114int Heap::gc_count_ = 0;
115
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000116int Heap::always_allocate_scope_depth_ = 0;
ager@chromium.org3811b432009-10-28 14:53:37 +0000117int Heap::linear_allocation_scope_depth_ = 0;
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000118bool Heap::context_disposed_pending_ = false;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000119
kasper.lund7276f142008-07-30 08:49:36 +0000120#ifdef DEBUG
121bool Heap::allocation_allowed_ = true;
122
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123int Heap::allocation_timeout_ = 0;
124bool Heap::disallow_allocation_failure_ = false;
125#endif // DEBUG
126
127
128int Heap::Capacity() {
129 if (!HasBeenSetup()) return 0;
130
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000131 return new_space_.Capacity() +
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000132 old_pointer_space_->Capacity() +
133 old_data_space_->Capacity() +
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000134 code_space_->Capacity() +
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000135 map_space_->Capacity() +
136 cell_space_->Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000137}
138
139
ager@chromium.org3811b432009-10-28 14:53:37 +0000140int Heap::CommittedMemory() {
141 if (!HasBeenSetup()) return 0;
142
143 return new_space_.CommittedMemory() +
144 old_pointer_space_->CommittedMemory() +
145 old_data_space_->CommittedMemory() +
146 code_space_->CommittedMemory() +
147 map_space_->CommittedMemory() +
148 cell_space_->CommittedMemory() +
149 lo_space_->Size();
150}
151
152
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000153int Heap::Available() {
154 if (!HasBeenSetup()) return 0;
155
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000156 return new_space_.Available() +
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000157 old_pointer_space_->Available() +
158 old_data_space_->Available() +
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159 code_space_->Available() +
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000160 map_space_->Available() +
161 cell_space_->Available();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000162}
163
164
165bool Heap::HasBeenSetup() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000166 return old_pointer_space_ != NULL &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000167 old_data_space_ != NULL &&
168 code_space_ != NULL &&
169 map_space_ != NULL &&
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000170 cell_space_ != NULL &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000171 lo_space_ != NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000172}
173
174
175GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) {
176 // Is global GC requested?
177 if (space != NEW_SPACE || FLAG_gc_global) {
178 Counters::gc_compactor_caused_by_request.Increment();
179 return MARK_COMPACTOR;
180 }
181
182 // Is enough data promoted to justify a global GC?
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000183 if (OldGenerationPromotionLimitReached()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000184 Counters::gc_compactor_caused_by_promoted_data.Increment();
185 return MARK_COMPACTOR;
186 }
187
188 // Have allocation in OLD and LO failed?
189 if (old_gen_exhausted_) {
190 Counters::gc_compactor_caused_by_oldspace_exhaustion.Increment();
191 return MARK_COMPACTOR;
192 }
193
194 // Is there enough space left in OLD to guarantee that a scavenge can
195 // succeed?
196 //
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000197 // Note that MemoryAllocator->MaxAvailable() undercounts the memory available
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000198 // for object promotion. It counts only the bytes that the memory
199 // allocator has not yet allocated from the OS and assigned to any space,
200 // and does not count available bytes already in the old space or code
201 // space. Undercounting is safe---we may get an unrequested full GC when
202 // a scavenge would have succeeded.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000203 if (MemoryAllocator::MaxAvailable() <= new_space_.Size()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000204 Counters::gc_compactor_caused_by_oldspace_exhaustion.Increment();
205 return MARK_COMPACTOR;
206 }
207
208 // Default
209 return SCAVENGER;
210}
211
212
213// TODO(1238405): Combine the infrastructure for --heap-stats and
214// --log-gc to avoid the complicated preprocessor and flag testing.
215#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
216void Heap::ReportStatisticsBeforeGC() {
217 // Heap::ReportHeapStatistics will also log NewSpace statistics when
218 // compiled with ENABLE_LOGGING_AND_PROFILING and --log-gc is set. The
219 // following logic is used to avoid double logging.
220#if defined(DEBUG) && defined(ENABLE_LOGGING_AND_PROFILING)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000221 if (FLAG_heap_stats || FLAG_log_gc) new_space_.CollectStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222 if (FLAG_heap_stats) {
223 ReportHeapStatistics("Before GC");
224 } else if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000225 new_space_.ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000226 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000227 if (FLAG_heap_stats || FLAG_log_gc) new_space_.ClearHistograms();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000228#elif defined(DEBUG)
229 if (FLAG_heap_stats) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000230 new_space_.CollectStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000231 ReportHeapStatistics("Before GC");
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000232 new_space_.ClearHistograms();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000233 }
234#elif defined(ENABLE_LOGGING_AND_PROFILING)
235 if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000236 new_space_.CollectStatistics();
237 new_space_.ReportStatistics();
238 new_space_.ClearHistograms();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239 }
240#endif
241}
242
243
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000244#if defined(ENABLE_LOGGING_AND_PROFILING)
245void Heap::PrintShortHeapStatistics() {
246 if (!FLAG_trace_gc_verbose) return;
247 PrintF("Memory allocator, used: %8d, available: %8d\n",
ager@chromium.org3811b432009-10-28 14:53:37 +0000248 MemoryAllocator::Size(),
249 MemoryAllocator::Available());
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000250 PrintF("New space, used: %8d, available: %8d\n",
ager@chromium.org3811b432009-10-28 14:53:37 +0000251 Heap::new_space_.Size(),
252 new_space_.Available());
253 PrintF("Old pointers, used: %8d, available: %8d, waste: %8d\n",
254 old_pointer_space_->Size(),
255 old_pointer_space_->Available(),
256 old_pointer_space_->Waste());
257 PrintF("Old data space, used: %8d, available: %8d, waste: %8d\n",
258 old_data_space_->Size(),
259 old_data_space_->Available(),
260 old_data_space_->Waste());
261 PrintF("Code space, used: %8d, available: %8d, waste: %8d\n",
262 code_space_->Size(),
263 code_space_->Available(),
264 code_space_->Waste());
265 PrintF("Map space, used: %8d, available: %8d, waste: %8d\n",
266 map_space_->Size(),
267 map_space_->Available(),
268 map_space_->Waste());
269 PrintF("Cell space, used: %8d, available: %8d, waste: %8d\n",
270 cell_space_->Size(),
271 cell_space_->Available(),
272 cell_space_->Waste());
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000273 PrintF("Large object space, used: %8d, avaialble: %8d\n",
ager@chromium.org3811b432009-10-28 14:53:37 +0000274 lo_space_->Size(),
275 lo_space_->Available());
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000276}
277#endif
278
279
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000280// TODO(1238405): Combine the infrastructure for --heap-stats and
281// --log-gc to avoid the complicated preprocessor and flag testing.
282void Heap::ReportStatisticsAfterGC() {
283 // Similar to the before GC, we use some complicated logic to ensure that
284 // NewSpace statistics are logged exactly once when --log-gc is turned on.
285#if defined(DEBUG) && defined(ENABLE_LOGGING_AND_PROFILING)
286 if (FLAG_heap_stats) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000287 new_space_.CollectStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000288 ReportHeapStatistics("After GC");
289 } else if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000290 new_space_.ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000291 }
292#elif defined(DEBUG)
293 if (FLAG_heap_stats) ReportHeapStatistics("After GC");
294#elif defined(ENABLE_LOGGING_AND_PROFILING)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000295 if (FLAG_log_gc) new_space_.ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000296#endif
297}
298#endif // defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
299
300
301void Heap::GarbageCollectionPrologue() {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000302 TranscendentalCache::Clear();
kasper.lund7276f142008-07-30 08:49:36 +0000303 gc_count_++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000304#ifdef DEBUG
305 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
306 allow_allocation(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000307
308 if (FLAG_verify_heap) {
309 Verify();
310 }
311
312 if (FLAG_gc_verbose) Print();
313
314 if (FLAG_print_rset) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000315 // Not all spaces have remembered set bits that we care about.
316 old_pointer_space_->PrintRSet();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317 map_space_->PrintRSet();
318 lo_space_->PrintRSet();
319 }
320#endif
321
322#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
323 ReportStatisticsBeforeGC();
324#endif
325}
326
327int Heap::SizeOfObjects() {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000328 int total = 0;
329 AllSpaces spaces;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000330 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000331 total += space->Size();
332 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000333 return total;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000334}
335
336void Heap::GarbageCollectionEpilogue() {
337#ifdef DEBUG
338 allow_allocation(true);
339 ZapFromSpace();
340
341 if (FLAG_verify_heap) {
342 Verify();
343 }
344
345 if (FLAG_print_global_handles) GlobalHandles::Print();
346 if (FLAG_print_handles) PrintHandles();
347 if (FLAG_gc_verbose) Print();
348 if (FLAG_code_stats) ReportCodeStatistics("After GC");
349#endif
350
351 Counters::alive_after_last_gc.Set(SizeOfObjects());
352
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000353 Counters::symbol_table_capacity.Set(symbol_table()->Capacity());
354 Counters::number_of_symbols.Set(symbol_table()->NumberOfElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
356 ReportStatisticsAfterGC();
357#endif
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000358#ifdef ENABLE_DEBUGGER_SUPPORT
359 Debug::AfterGarbageCollection();
360#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361}
362
363
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000364void Heap::CollectAllGarbage(bool force_compaction) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000365 // Since we are ignoring the return value, the exact choice of space does
366 // not matter, so long as we do not specify NEW_SPACE, which would not
367 // cause a full GC.
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000368 MarkCompactCollector::SetForceCompaction(force_compaction);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000369 CollectGarbage(0, OLD_POINTER_SPACE);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000370 MarkCompactCollector::SetForceCompaction(false);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000371}
372
373
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000374void Heap::CollectAllGarbageIfContextDisposed() {
kasperl@chromium.orgd55d36b2009-03-05 08:03:28 +0000375 // If the garbage collector interface is exposed through the global
376 // gc() function, we avoid being clever about forcing GCs when
377 // contexts are disposed and leave it to the embedder to make
378 // informed decisions about when to force a collection.
379 if (!FLAG_expose_gc && context_disposed_pending_) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000380 HistogramTimerScope scope(&Counters::gc_context);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000381 CollectAllGarbage(false);
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000382 }
kasperl@chromium.orgd55d36b2009-03-05 08:03:28 +0000383 context_disposed_pending_ = false;
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000384}
385
386
387void Heap::NotifyContextDisposed() {
388 context_disposed_pending_ = true;
389}
390
391
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000392bool Heap::CollectGarbage(int requested_size, AllocationSpace space) {
393 // The VM is in the GC state until exiting this function.
394 VMState state(GC);
395
396#ifdef DEBUG
397 // Reset the allocation timeout to the GC interval, but make sure to
398 // allow at least a few allocations after a collection. The reason
399 // for this is that we have a lot of allocation sequences and we
400 // assume that a garbage collection will allow the subsequent
401 // allocation attempts to go through.
402 allocation_timeout_ = Max(6, FLAG_gc_interval);
403#endif
404
405 { GCTracer tracer;
406 GarbageCollectionPrologue();
kasper.lund7276f142008-07-30 08:49:36 +0000407 // The GC count was incremented in the prologue. Tell the tracer about
408 // it.
409 tracer.set_gc_count(gc_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410
411 GarbageCollector collector = SelectGarbageCollector(space);
kasper.lund7276f142008-07-30 08:49:36 +0000412 // Tell the tracer which collector we've selected.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 tracer.set_collector(collector);
414
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000415 HistogramTimer* rate = (collector == SCAVENGER)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000416 ? &Counters::gc_scavenger
417 : &Counters::gc_compactor;
418 rate->Start();
kasper.lund7276f142008-07-30 08:49:36 +0000419 PerformGarbageCollection(space, collector, &tracer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000420 rate->Stop();
421
422 GarbageCollectionEpilogue();
423 }
424
425
426#ifdef ENABLE_LOGGING_AND_PROFILING
427 if (FLAG_log_gc) HeapProfiler::WriteSample();
428#endif
429
430 switch (space) {
431 case NEW_SPACE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000432 return new_space_.Available() >= requested_size;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000433 case OLD_POINTER_SPACE:
434 return old_pointer_space_->Available() >= requested_size;
435 case OLD_DATA_SPACE:
436 return old_data_space_->Available() >= requested_size;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437 case CODE_SPACE:
438 return code_space_->Available() >= requested_size;
439 case MAP_SPACE:
440 return map_space_->Available() >= requested_size;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000441 case CELL_SPACE:
442 return cell_space_->Available() >= requested_size;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000443 case LO_SPACE:
444 return lo_space_->Available() >= requested_size;
445 }
446 return false;
447}
448
449
kasper.lund7276f142008-07-30 08:49:36 +0000450void Heap::PerformScavenge() {
451 GCTracer tracer;
452 PerformGarbageCollection(NEW_SPACE, SCAVENGER, &tracer);
453}
454
455
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000456#ifdef DEBUG
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000457// Helper class for verifying the symbol table.
458class SymbolTableVerifier : public ObjectVisitor {
459 public:
460 SymbolTableVerifier() { }
461 void VisitPointers(Object** start, Object** end) {
462 // Visit all HeapObject pointers in [start, end).
463 for (Object** p = start; p < end; p++) {
464 if ((*p)->IsHeapObject()) {
465 // Check that the symbol is actually a symbol.
466 ASSERT((*p)->IsNull() || (*p)->IsUndefined() || (*p)->IsSymbol());
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000467 }
468 }
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000469 }
470};
471#endif // DEBUG
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000472
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000473
474static void VerifySymbolTable() {
475#ifdef DEBUG
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000476 SymbolTableVerifier verifier;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000477 Heap::symbol_table()->IterateElements(&verifier);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000478#endif // DEBUG
479}
480
481
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000482void Heap::ReserveSpace(
483 int new_space_size,
484 int pointer_space_size,
485 int data_space_size,
486 int code_space_size,
487 int map_space_size,
488 int cell_space_size,
489 int large_object_size) {
490 NewSpace* new_space = Heap::new_space();
491 PagedSpace* old_pointer_space = Heap::old_pointer_space();
492 PagedSpace* old_data_space = Heap::old_data_space();
493 PagedSpace* code_space = Heap::code_space();
494 PagedSpace* map_space = Heap::map_space();
495 PagedSpace* cell_space = Heap::cell_space();
496 LargeObjectSpace* lo_space = Heap::lo_space();
497 bool gc_performed = true;
498 while (gc_performed) {
499 gc_performed = false;
500 if (!new_space->ReserveSpace(new_space_size)) {
501 Heap::CollectGarbage(new_space_size, NEW_SPACE);
502 gc_performed = true;
503 }
504 if (!old_pointer_space->ReserveSpace(pointer_space_size)) {
505 Heap::CollectGarbage(pointer_space_size, OLD_POINTER_SPACE);
506 gc_performed = true;
507 }
508 if (!(old_data_space->ReserveSpace(data_space_size))) {
509 Heap::CollectGarbage(data_space_size, OLD_DATA_SPACE);
510 gc_performed = true;
511 }
512 if (!(code_space->ReserveSpace(code_space_size))) {
513 Heap::CollectGarbage(code_space_size, CODE_SPACE);
514 gc_performed = true;
515 }
516 if (!(map_space->ReserveSpace(map_space_size))) {
517 Heap::CollectGarbage(map_space_size, MAP_SPACE);
518 gc_performed = true;
519 }
520 if (!(cell_space->ReserveSpace(cell_space_size))) {
521 Heap::CollectGarbage(cell_space_size, CELL_SPACE);
522 gc_performed = true;
523 }
524 // We add a slack-factor of 2 in order to have space for the remembered
525 // set and a series of large-object allocations that are only just larger
526 // than the page size.
527 large_object_size *= 2;
528 // The ReserveSpace method on the large object space checks how much
529 // we can expand the old generation. This includes expansion caused by
530 // allocation in the other spaces.
531 large_object_size += cell_space_size + map_space_size + code_space_size +
532 data_space_size + pointer_space_size;
533 if (!(lo_space->ReserveSpace(large_object_size))) {
534 Heap::CollectGarbage(large_object_size, LO_SPACE);
535 gc_performed = true;
536 }
537 }
538}
539
540
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000541void Heap::EnsureFromSpaceIsCommitted() {
542 if (new_space_.CommitFromSpaceIfNeeded()) return;
543
544 // Committing memory to from space failed.
545 // Try shrinking and try again.
546 Shrink();
547 if (new_space_.CommitFromSpaceIfNeeded()) return;
548
549 // Committing memory to from space failed again.
550 // Memory is exhausted and we will die.
551 V8::FatalProcessOutOfMemory("Committing semi space failed.");
552}
553
554
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000555void Heap::PerformGarbageCollection(AllocationSpace space,
kasper.lund7276f142008-07-30 08:49:36 +0000556 GarbageCollector collector,
557 GCTracer* tracer) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000558 VerifySymbolTable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559 if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) {
560 ASSERT(!allocation_allowed_);
561 global_gc_prologue_callback_();
562 }
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000563 EnsureFromSpaceIsCommitted();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000564 if (collector == MARK_COMPACTOR) {
kasper.lund7276f142008-07-30 08:49:36 +0000565 MarkCompact(tracer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000567 int old_gen_size = PromotedSpaceSize();
568 old_gen_promotion_limit_ =
569 old_gen_size + Max(kMinimumPromotionLimit, old_gen_size / 3);
570 old_gen_allocation_limit_ =
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000571 old_gen_size + Max(kMinimumAllocationLimit, old_gen_size / 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000572 old_gen_exhausted_ = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000573 }
ager@chromium.org439e85a2009-08-26 13:15:29 +0000574 Scavenge();
575
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000576 Counters::objs_since_last_young.Set(0);
577
ager@chromium.org3811b432009-10-28 14:53:37 +0000578 if (collector == MARK_COMPACTOR) {
579 DisableAssertNoAllocation allow_allocation;
580 GlobalHandles::PostGarbageCollectionProcessing();
581 }
582
583 // Update relocatables.
584 Relocatable::PostGarbageCollectionProcessing();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000585
kasper.lund7276f142008-07-30 08:49:36 +0000586 if (collector == MARK_COMPACTOR) {
587 // Register the amount of external allocated memory.
588 amount_of_external_allocated_memory_at_last_global_gc_ =
589 amount_of_external_allocated_memory_;
590 }
591
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000592 if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) {
593 ASSERT(!allocation_allowed_);
594 global_gc_epilogue_callback_();
595 }
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000596 VerifySymbolTable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000597}
598
599
kasper.lund7276f142008-07-30 08:49:36 +0000600void Heap::MarkCompact(GCTracer* tracer) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000601 gc_state_ = MARK_COMPACT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000602 mc_count_++;
kasper.lund7276f142008-07-30 08:49:36 +0000603 tracer->set_full_gc_count(mc_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000604 LOG(ResourceEvent("markcompact", "begin"));
605
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000606 MarkCompactCollector::Prepare(tracer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000607
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000608 bool is_compacting = MarkCompactCollector::IsCompacting();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000609
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000610 MarkCompactPrologue(is_compacting);
611
612 MarkCompactCollector::CollectGarbage();
613
614 MarkCompactEpilogue(is_compacting);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615
616 LOG(ResourceEvent("markcompact", "end"));
617
618 gc_state_ = NOT_IN_GC;
619
620 Shrink();
621
622 Counters::objs_since_last_full.Set(0);
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000623 context_disposed_pending_ = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624}
625
626
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000627void Heap::MarkCompactPrologue(bool is_compacting) {
628 // At any old GC clear the keyed lookup cache to enable collection of unused
629 // maps.
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000630 KeyedLookupCache::Clear();
631 ContextSlotCache::Clear();
632 DescriptorLookupCache::Clear();
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000633
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000634 CompilationCache::MarkCompactPrologue();
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000635
636 Top::MarkCompactPrologue(is_compacting);
637 ThreadManager::MarkCompactPrologue(is_compacting);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000638
639 if (is_compacting) FlushNumberStringCache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640}
641
642
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000643void Heap::MarkCompactEpilogue(bool is_compacting) {
644 Top::MarkCompactEpilogue(is_compacting);
645 ThreadManager::MarkCompactEpilogue(is_compacting);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000646}
647
648
649Object* Heap::FindCodeObject(Address a) {
650 Object* obj = code_space_->FindObject(a);
651 if (obj->IsFailure()) {
652 obj = lo_space_->FindObject(a);
653 }
kasper.lund7276f142008-07-30 08:49:36 +0000654 ASSERT(!obj->IsFailure());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000655 return obj;
656}
657
658
659// Helper class for copying HeapObjects
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000660class ScavengeVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000661 public:
662
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000663 void VisitPointer(Object** p) { ScavengePointer(p); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000664
665 void VisitPointers(Object** start, Object** end) {
666 // Copy all HeapObject pointers in [start, end)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000667 for (Object** p = start; p < end; p++) ScavengePointer(p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000668 }
669
670 private:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000671 void ScavengePointer(Object** p) {
672 Object* object = *p;
673 if (!Heap::InNewSpace(object)) return;
674 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
675 reinterpret_cast<HeapObject*>(object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000676 }
677};
678
679
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000680// A queue of pointers and maps of to-be-promoted objects during a
681// scavenge collection.
682class PromotionQueue {
683 public:
684 void Initialize(Address start_address) {
685 front_ = rear_ = reinterpret_cast<HeapObject**>(start_address);
686 }
687
688 bool is_empty() { return front_ <= rear_; }
689
690 void insert(HeapObject* object, Map* map) {
691 *(--rear_) = object;
692 *(--rear_) = map;
693 // Assert no overflow into live objects.
694 ASSERT(reinterpret_cast<Address>(rear_) >= Heap::new_space()->top());
695 }
696
697 void remove(HeapObject** object, Map** map) {
698 *object = *(--front_);
699 *map = Map::cast(*(--front_));
700 // Assert no underflow.
701 ASSERT(front_ >= rear_);
702 }
703
704 private:
705 // The front of the queue is higher in memory than the rear.
706 HeapObject** front_;
707 HeapObject** rear_;
708};
709
710
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000711// Shared state read by the scavenge collector and set by ScavengeObject.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000712static PromotionQueue promotion_queue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000713
714
715#ifdef DEBUG
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000716// Visitor class to verify pointers in code or data space do not point into
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000717// new space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000718class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000719 public:
720 void VisitPointers(Object** start, Object**end) {
721 for (Object** current = start; current < end; current++) {
722 if ((*current)->IsHeapObject()) {
723 ASSERT(!Heap::InNewSpace(HeapObject::cast(*current)));
724 }
725 }
726 }
727};
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000728
729
730static void VerifyNonPointerSpacePointers() {
731 // Verify that there are no pointers to new space in spaces where we
732 // do not expect them.
733 VerifyNonPointerSpacePointersVisitor v;
734 HeapObjectIterator code_it(Heap::code_space());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000735 for (HeapObject* object = code_it.next();
736 object != NULL; object = code_it.next())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000737 object->Iterate(&v);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000738
739 HeapObjectIterator data_it(Heap::old_data_space());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000740 for (HeapObject* object = data_it.next();
741 object != NULL; object = data_it.next())
742 object->Iterate(&v);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000743}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000744#endif
745
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000746
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000747void Heap::Scavenge() {
748#ifdef DEBUG
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000749 if (FLAG_enable_slow_asserts) VerifyNonPointerSpacePointers();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000750#endif
751
752 gc_state_ = SCAVENGE;
753
754 // Implements Cheney's copying algorithm
755 LOG(ResourceEvent("scavenge", "begin"));
756
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000757 // Clear descriptor cache.
758 DescriptorLookupCache::Clear();
759
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000760 // Used for updating survived_since_last_expansion_ at function end.
761 int survived_watermark = PromotedSpaceSize();
762
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000763 if (new_space_.Capacity() < new_space_.MaximumCapacity() &&
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000764 survived_since_last_expansion_ > new_space_.Capacity()) {
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000765 // Grow the size of new space if there is room to grow and enough
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000766 // data has survived scavenge since the last expansion.
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000767 new_space_.Grow();
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000768 survived_since_last_expansion_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769 }
770
771 // Flip the semispaces. After flipping, to space is empty, from space has
772 // live objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000773 new_space_.Flip();
774 new_space_.ResetAllocationInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000775
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000776 // We need to sweep newly copied objects which can be either in the
777 // to space or promoted to the old generation. For to-space
778 // objects, we treat the bottom of the to space as a queue. Newly
779 // copied and unswept objects lie between a 'front' mark and the
780 // allocation pointer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000781 //
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000782 // Promoted objects can go into various old-generation spaces, and
783 // can be allocated internally in the spaces (from the free list).
784 // We treat the top of the to space as a queue of addresses of
785 // promoted objects. The addresses of newly promoted and unswept
786 // objects lie between a 'front' mark and a 'rear' mark that is
787 // updated as a side effect of promoting an object.
788 //
789 // There is guaranteed to be enough room at the top of the to space
790 // for the addresses of promoted objects: every object promoted
791 // frees up its size in bytes from the top of the new space, and
792 // objects are at least one pointer in size.
793 Address new_space_front = new_space_.ToSpaceLow();
794 promotion_queue.Initialize(new_space_.ToSpaceHigh());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000795
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000796 ScavengeVisitor scavenge_visitor;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000797 // Copy roots.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000798 IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000799
800 // Copy objects reachable from the old generation. By definition,
801 // there are no intergenerational pointers in code or data spaces.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000802 IterateRSet(old_pointer_space_, &ScavengePointer);
803 IterateRSet(map_space_, &ScavengePointer);
804 lo_space_->IterateRSet(&ScavengePointer);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000805
806 // Copy objects reachable from cells by scavenging cell values directly.
807 HeapObjectIterator cell_iterator(cell_space_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000808 for (HeapObject* cell = cell_iterator.next();
809 cell != NULL; cell = cell_iterator.next()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000810 if (cell->IsJSGlobalPropertyCell()) {
811 Address value_address =
812 reinterpret_cast<Address>(cell) +
813 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag);
814 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address));
815 }
816 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000817
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000818 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
819
820 ScavengeExternalStringTable();
821 ASSERT(new_space_front == new_space_.top());
822
823 // Set age mark.
824 new_space_.set_age_mark(new_space_.top());
825
826 // Update how much has survived scavenge.
827 survived_since_last_expansion_ +=
828 (PromotedSpaceSize() - survived_watermark) + new_space_.Size();
829
830 LOG(ResourceEvent("scavenge", "end"));
831
832 gc_state_ = NOT_IN_GC;
833}
834
835
836void Heap::ScavengeExternalStringTable() {
837 ExternalStringTable::Verify();
838
839 if (ExternalStringTable::new_space_strings_.is_empty()) return;
840
841 Object** start = &ExternalStringTable::new_space_strings_[0];
842 Object** end = start + ExternalStringTable::new_space_strings_.length();
843 Object** last = start;
844
845 for (Object** p = start; p < end; ++p) {
846 ASSERT(Heap::InFromSpace(*p));
847 MapWord first_word = HeapObject::cast(*p)->map_word();
848
849 if (!first_word.IsForwardingAddress()) {
850 // Unreachable external string can be finalized.
851 FinalizeExternalString(String::cast(*p));
852 continue;
853 }
854
855 // String is still reachable.
856 String* target = String::cast(first_word.ToForwardingAddress());
857 ASSERT(target->IsExternalString());
858
859 if (Heap::InNewSpace(target)) {
860 // String is still in new space. Update the table entry.
861 *last = target;
862 ++last;
863 } else {
864 // String got promoted. Move it to the old string list.
865 ExternalStringTable::AddOldString(target);
866 }
867 }
868
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000869 ASSERT(last <= end);
870 ExternalStringTable::ShrinkNewStrings(static_cast<int>(last - start));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000871}
872
873
874Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
875 Address new_space_front) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000876 do {
877 ASSERT(new_space_front <= new_space_.top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000878
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000879 // The addresses new_space_front and new_space_.top() define a
880 // queue of unprocessed copied objects. Process them until the
881 // queue is empty.
882 while (new_space_front < new_space_.top()) {
883 HeapObject* object = HeapObject::FromAddress(new_space_front);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000884 object->Iterate(scavenge_visitor);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000885 new_space_front += object->Size();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000886 }
887
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000888 // Promote and process all the to-be-promoted objects.
889 while (!promotion_queue.is_empty()) {
890 HeapObject* source;
891 Map* map;
892 promotion_queue.remove(&source, &map);
893 // Copy the from-space object to its new location (given by the
894 // forwarding address) and fix its map.
895 HeapObject* target = source->map_word().ToForwardingAddress();
896 CopyBlock(reinterpret_cast<Object**>(target->address()),
897 reinterpret_cast<Object**>(source->address()),
898 source->SizeFromMap(map));
899 target->set_map(map);
900
901#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
902 // Update NewSpace stats if necessary.
903 RecordCopiedObject(target);
904#endif
905 // Visit the newly copied object for pointers to new space.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000906 target->Iterate(scavenge_visitor);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000907 UpdateRSet(target);
908 }
909
910 // Take another spin if there are now unswept objects in new space
911 // (there are currently no more unswept promoted objects).
912 } while (new_space_front < new_space_.top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000913
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000914 return new_space_front;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000915}
916
917
918void Heap::ClearRSetRange(Address start, int size_in_bytes) {
919 uint32_t start_bit;
920 Address start_word_address =
921 Page::ComputeRSetBitPosition(start, 0, &start_bit);
922 uint32_t end_bit;
923 Address end_word_address =
924 Page::ComputeRSetBitPosition(start + size_in_bytes - kIntSize,
925 0,
926 &end_bit);
927
928 // We want to clear the bits in the starting word starting with the
929 // first bit, and in the ending word up to and including the last
930 // bit. Build a pair of bitmasks to do that.
931 uint32_t start_bitmask = start_bit - 1;
932 uint32_t end_bitmask = ~((end_bit << 1) - 1);
933
934 // If the start address and end address are the same, we mask that
935 // word once, otherwise mask the starting and ending word
936 // separately and all the ones in between.
937 if (start_word_address == end_word_address) {
938 Memory::uint32_at(start_word_address) &= (start_bitmask | end_bitmask);
939 } else {
940 Memory::uint32_at(start_word_address) &= start_bitmask;
941 Memory::uint32_at(end_word_address) &= end_bitmask;
942 start_word_address += kIntSize;
943 memset(start_word_address, 0, end_word_address - start_word_address);
944 }
945}
946
947
948class UpdateRSetVisitor: public ObjectVisitor {
949 public:
950
951 void VisitPointer(Object** p) {
952 UpdateRSet(p);
953 }
954
955 void VisitPointers(Object** start, Object** end) {
956 // Update a store into slots [start, end), used (a) to update remembered
957 // set when promoting a young object to old space or (b) to rebuild
958 // remembered sets after a mark-compact collection.
959 for (Object** p = start; p < end; p++) UpdateRSet(p);
960 }
961 private:
962
963 void UpdateRSet(Object** p) {
964 // The remembered set should not be set. It should be clear for objects
965 // newly copied to old space, and it is cleared before rebuilding in the
966 // mark-compact collector.
967 ASSERT(!Page::IsRSetSet(reinterpret_cast<Address>(p), 0));
968 if (Heap::InNewSpace(*p)) {
969 Page::SetRSet(reinterpret_cast<Address>(p), 0);
970 }
971 }
972};
973
974
975int Heap::UpdateRSet(HeapObject* obj) {
976 ASSERT(!InNewSpace(obj));
977 // Special handling of fixed arrays to iterate the body based on the start
978 // address and offset. Just iterating the pointers as in UpdateRSetVisitor
979 // will not work because Page::SetRSet needs to have the start of the
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000980 // object for large object pages.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981 if (obj->IsFixedArray()) {
982 FixedArray* array = FixedArray::cast(obj);
983 int length = array->length();
984 for (int i = 0; i < length; i++) {
985 int offset = FixedArray::kHeaderSize + i * kPointerSize;
986 ASSERT(!Page::IsRSetSet(obj->address(), offset));
987 if (Heap::InNewSpace(array->get(i))) {
988 Page::SetRSet(obj->address(), offset);
989 }
990 }
991 } else if (!obj->IsCode()) {
992 // Skip code object, we know it does not contain inter-generational
993 // pointers.
994 UpdateRSetVisitor v;
995 obj->Iterate(&v);
996 }
997 return obj->Size();
998}
999
1000
1001void Heap::RebuildRSets() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001002 // By definition, we do not care about remembered set bits in code,
1003 // data, or cell spaces.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001004 map_space_->ClearRSet();
1005 RebuildRSets(map_space_);
1006
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001007 old_pointer_space_->ClearRSet();
1008 RebuildRSets(old_pointer_space_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009
1010 Heap::lo_space_->ClearRSet();
1011 RebuildRSets(lo_space_);
1012}
1013
1014
1015void Heap::RebuildRSets(PagedSpace* space) {
1016 HeapObjectIterator it(space);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001017 for (HeapObject* obj = it.next(); obj != NULL; obj = it.next())
1018 Heap::UpdateRSet(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019}
1020
1021
1022void Heap::RebuildRSets(LargeObjectSpace* space) {
1023 LargeObjectIterator it(space);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001024 for (HeapObject* obj = it.next(); obj != NULL; obj = it.next())
1025 Heap::UpdateRSet(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001026}
1027
1028
1029#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
1030void Heap::RecordCopiedObject(HeapObject* obj) {
1031 bool should_record = false;
1032#ifdef DEBUG
1033 should_record = FLAG_heap_stats;
1034#endif
1035#ifdef ENABLE_LOGGING_AND_PROFILING
1036 should_record = should_record || FLAG_log_gc;
1037#endif
1038 if (should_record) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001039 if (new_space_.Contains(obj)) {
1040 new_space_.RecordAllocation(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001041 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001042 new_space_.RecordPromotion(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001043 }
1044 }
1045}
1046#endif // defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
1047
1048
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001049
1050HeapObject* Heap::MigrateObject(HeapObject* source,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051 HeapObject* target,
1052 int size) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001053 // Copy the content of source to target.
1054 CopyBlock(reinterpret_cast<Object**>(target->address()),
1055 reinterpret_cast<Object**>(source->address()),
1056 size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057
kasper.lund7276f142008-07-30 08:49:36 +00001058 // Set the forwarding address.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001059 source->set_map_word(MapWord::FromForwardingAddress(target));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001060
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001061#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001062 // Update NewSpace stats if necessary.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001063 RecordCopiedObject(target);
1064#endif
1065
1066 return target;
1067}
1068
1069
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001070static inline bool IsShortcutCandidate(HeapObject* object, Map* map) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00001071 STATIC_ASSERT(kNotStringTag != 0 && kSymbolTag != 0);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001072 ASSERT(object->map() == map);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00001073 InstanceType type = map->instance_type();
1074 if ((type & kShortcutTypeMask) != kShortcutTypeTag) return false;
1075 ASSERT(object->IsString() && !object->IsSymbol());
1076 return ConsString::cast(object)->unchecked_second() == Heap::empty_string();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001077}
1078
1079
1080void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) {
1081 ASSERT(InFromSpace(object));
1082 MapWord first_word = object->map_word();
1083 ASSERT(!first_word.IsForwardingAddress());
1084
1085 // Optimization: Bypass flattened ConsString objects.
1086 if (IsShortcutCandidate(object, first_word.ToMap())) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001087 object = HeapObject::cast(ConsString::cast(object)->unchecked_first());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088 *p = object;
1089 // After patching *p we have to repeat the checks that object is in the
1090 // active semispace of the young generation and not already copied.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001091 if (!InNewSpace(object)) return;
kasper.lund7276f142008-07-30 08:49:36 +00001092 first_word = object->map_word();
1093 if (first_word.IsForwardingAddress()) {
1094 *p = first_word.ToForwardingAddress();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001095 return;
1096 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001097 }
1098
kasper.lund7276f142008-07-30 08:49:36 +00001099 int object_size = object->SizeFromMap(first_word.ToMap());
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001100 // We rely on live objects in new space to be at least two pointers,
1101 // so we can store the from-space address and map pointer of promoted
1102 // objects in the to space.
1103 ASSERT(object_size >= 2 * kPointerSize);
1104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001105 // If the object should be promoted, we try to copy it to old space.
1106 if (ShouldBePromoted(object->address(), object_size)) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001107 Object* result;
1108 if (object_size > MaxObjectSizeInPagedSpace()) {
1109 result = lo_space_->AllocateRawFixedArray(object_size);
1110 if (!result->IsFailure()) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001111 // Save the from-space object pointer and its map pointer at the
1112 // top of the to space to be swept and copied later. Write the
1113 // forwarding address over the map word of the from-space
1114 // object.
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001115 HeapObject* target = HeapObject::cast(result);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001116 promotion_queue.insert(object, first_word.ToMap());
1117 object->set_map_word(MapWord::FromForwardingAddress(target));
1118
1119 // Give the space allocated for the result a proper map by
1120 // treating it as a free list node (not linked into the free
1121 // list).
1122 FreeListNode* node = FreeListNode::FromAddress(target->address());
1123 node->set_size(object_size);
1124
1125 *p = target;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001126 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001127 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001128 } else {
1129 OldSpace* target_space = Heap::TargetSpace(object);
1130 ASSERT(target_space == Heap::old_pointer_space_ ||
1131 target_space == Heap::old_data_space_);
1132 result = target_space->AllocateRaw(object_size);
1133 if (!result->IsFailure()) {
1134 HeapObject* target = HeapObject::cast(result);
1135 if (target_space == Heap::old_pointer_space_) {
1136 // Save the from-space object pointer and its map pointer at the
1137 // top of the to space to be swept and copied later. Write the
1138 // forwarding address over the map word of the from-space
1139 // object.
1140 promotion_queue.insert(object, first_word.ToMap());
1141 object->set_map_word(MapWord::FromForwardingAddress(target));
1142
1143 // Give the space allocated for the result a proper map by
1144 // treating it as a free list node (not linked into the free
1145 // list).
1146 FreeListNode* node = FreeListNode::FromAddress(target->address());
1147 node->set_size(object_size);
1148
1149 *p = target;
1150 } else {
1151 // Objects promoted to the data space can be copied immediately
1152 // and not revisited---we will never sweep that space for
1153 // pointers and the copied objects do not contain pointers to
1154 // new space objects.
1155 *p = MigrateObject(object, target, object_size);
1156#ifdef DEBUG
1157 VerifyNonPointerSpacePointersVisitor v;
1158 (*p)->Iterate(&v);
1159#endif
1160 }
1161 return;
1162 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163 }
1164 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165 // The object should remain in new space or the old space allocation failed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001166 Object* result = new_space_.AllocateRaw(object_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001167 // Failed allocation at this point is utterly unexpected.
1168 ASSERT(!result->IsFailure());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001169 *p = MigrateObject(object, HeapObject::cast(result), object_size);
1170}
1171
1172
1173void Heap::ScavengePointer(HeapObject** p) {
1174 ScavengeObject(p, *p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175}
1176
1177
1178Object* Heap::AllocatePartialMap(InstanceType instance_type,
1179 int instance_size) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001180 Object* result = AllocateRawMap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001181 if (result->IsFailure()) return result;
1182
1183 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001184 reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185 reinterpret_cast<Map*>(result)->set_instance_type(instance_type);
1186 reinterpret_cast<Map*>(result)->set_instance_size(instance_size);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001187 reinterpret_cast<Map*>(result)->set_inobject_properties(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001188 reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001189 reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001190 reinterpret_cast<Map*>(result)->set_bit_field(0);
1191 reinterpret_cast<Map*>(result)->set_bit_field2(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001192 return result;
1193}
1194
1195
1196Object* Heap::AllocateMap(InstanceType instance_type, int instance_size) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001197 Object* result = AllocateRawMap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001198 if (result->IsFailure()) return result;
1199
1200 Map* map = reinterpret_cast<Map*>(result);
1201 map->set_map(meta_map());
1202 map->set_instance_type(instance_type);
1203 map->set_prototype(null_value());
1204 map->set_constructor(null_value());
1205 map->set_instance_size(instance_size);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001206 map->set_inobject_properties(0);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001207 map->set_pre_allocated_property_fields(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001208 map->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001209 map->set_code_cache(empty_fixed_array());
1210 map->set_unused_property_fields(0);
1211 map->set_bit_field(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001212 map->set_bit_field2(1 << Map::kIsExtensible);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001213
1214 // If the map object is aligned fill the padding area with Smi 0 objects.
1215 if (Map::kPadStart < Map::kSize) {
1216 memset(reinterpret_cast<byte*>(map) + Map::kPadStart - kHeapObjectTag,
1217 0,
1218 Map::kSize - Map::kPadStart);
1219 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001220 return map;
1221}
1222
1223
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001224const Heap::StringTypeTable Heap::string_type_table[] = {
1225#define STRING_TYPE_ELEMENT(type, size, name, camel_name) \
1226 {type, size, k##camel_name##MapRootIndex},
1227 STRING_TYPE_LIST(STRING_TYPE_ELEMENT)
1228#undef STRING_TYPE_ELEMENT
1229};
1230
1231
1232const Heap::ConstantSymbolTable Heap::constant_symbol_table[] = {
1233#define CONSTANT_SYMBOL_ELEMENT(name, contents) \
1234 {contents, k##name##RootIndex},
1235 SYMBOL_LIST(CONSTANT_SYMBOL_ELEMENT)
1236#undef CONSTANT_SYMBOL_ELEMENT
1237};
1238
1239
1240const Heap::StructTable Heap::struct_table[] = {
1241#define STRUCT_TABLE_ELEMENT(NAME, Name, name) \
1242 { NAME##_TYPE, Name::kSize, k##Name##MapRootIndex },
1243 STRUCT_LIST(STRUCT_TABLE_ELEMENT)
1244#undef STRUCT_TABLE_ELEMENT
1245};
1246
1247
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001248bool Heap::CreateInitialMaps() {
1249 Object* obj = AllocatePartialMap(MAP_TYPE, Map::kSize);
1250 if (obj->IsFailure()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001251 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001252 Map* new_meta_map = reinterpret_cast<Map*>(obj);
1253 set_meta_map(new_meta_map);
1254 new_meta_map->set_map(new_meta_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001255
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001256 obj = AllocatePartialMap(FIXED_ARRAY_TYPE, FixedArray::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001258 set_fixed_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001259
1260 obj = AllocatePartialMap(ODDBALL_TYPE, Oddball::kSize);
1261 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001262 set_oddball_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001263
1264 // Allocate the empty array
1265 obj = AllocateEmptyFixedArray();
1266 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001267 set_empty_fixed_array(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001269 obj = Allocate(oddball_map(), OLD_DATA_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001271 set_null_value(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001272
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001273 // Allocate the empty descriptor array.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001274 obj = AllocateEmptyFixedArray();
1275 if (obj->IsFailure()) return false;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001276 set_empty_descriptor_array(DescriptorArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001278 // Fix the instance_descriptors for the existing maps.
1279 meta_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280 meta_map()->set_code_cache(empty_fixed_array());
1281
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001282 fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283 fixed_array_map()->set_code_cache(empty_fixed_array());
1284
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001285 oddball_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 oddball_map()->set_code_cache(empty_fixed_array());
1287
1288 // Fix prototype object for existing maps.
1289 meta_map()->set_prototype(null_value());
1290 meta_map()->set_constructor(null_value());
1291
1292 fixed_array_map()->set_prototype(null_value());
1293 fixed_array_map()->set_constructor(null_value());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001294
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295 oddball_map()->set_prototype(null_value());
1296 oddball_map()->set_constructor(null_value());
1297
1298 obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
1299 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001300 set_heap_number_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001301
1302 obj = AllocateMap(PROXY_TYPE, Proxy::kSize);
1303 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001304 set_proxy_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001306 for (unsigned i = 0; i < ARRAY_SIZE(string_type_table); i++) {
1307 const StringTypeTable& entry = string_type_table[i];
1308 obj = AllocateMap(entry.type, entry.size);
1309 if (obj->IsFailure()) return false;
1310 roots_[entry.index] = Map::cast(obj);
1311 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001313 obj = AllocateMap(STRING_TYPE, SeqTwoByteString::kAlignedSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001314 if (obj->IsFailure()) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001315 set_undetectable_string_map(Map::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001316 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001318 obj = AllocateMap(ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319 if (obj->IsFailure()) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001320 set_undetectable_ascii_string_map(Map::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001321 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001322
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001323 obj = AllocateMap(BYTE_ARRAY_TYPE, ByteArray::kAlignedSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001325 set_byte_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001326
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001327 obj = AllocateMap(PIXEL_ARRAY_TYPE, PixelArray::kAlignedSize);
1328 if (obj->IsFailure()) return false;
1329 set_pixel_array_map(Map::cast(obj));
1330
ager@chromium.org3811b432009-10-28 14:53:37 +00001331 obj = AllocateMap(EXTERNAL_BYTE_ARRAY_TYPE,
1332 ExternalArray::kAlignedSize);
1333 if (obj->IsFailure()) return false;
1334 set_external_byte_array_map(Map::cast(obj));
1335
1336 obj = AllocateMap(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE,
1337 ExternalArray::kAlignedSize);
1338 if (obj->IsFailure()) return false;
1339 set_external_unsigned_byte_array_map(Map::cast(obj));
1340
1341 obj = AllocateMap(EXTERNAL_SHORT_ARRAY_TYPE,
1342 ExternalArray::kAlignedSize);
1343 if (obj->IsFailure()) return false;
1344 set_external_short_array_map(Map::cast(obj));
1345
1346 obj = AllocateMap(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE,
1347 ExternalArray::kAlignedSize);
1348 if (obj->IsFailure()) return false;
1349 set_external_unsigned_short_array_map(Map::cast(obj));
1350
1351 obj = AllocateMap(EXTERNAL_INT_ARRAY_TYPE,
1352 ExternalArray::kAlignedSize);
1353 if (obj->IsFailure()) return false;
1354 set_external_int_array_map(Map::cast(obj));
1355
1356 obj = AllocateMap(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE,
1357 ExternalArray::kAlignedSize);
1358 if (obj->IsFailure()) return false;
1359 set_external_unsigned_int_array_map(Map::cast(obj));
1360
1361 obj = AllocateMap(EXTERNAL_FLOAT_ARRAY_TYPE,
1362 ExternalArray::kAlignedSize);
1363 if (obj->IsFailure()) return false;
1364 set_external_float_array_map(Map::cast(obj));
1365
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001366 obj = AllocateMap(CODE_TYPE, Code::kHeaderSize);
1367 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001368 set_code_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001370 obj = AllocateMap(JS_GLOBAL_PROPERTY_CELL_TYPE,
1371 JSGlobalPropertyCell::kSize);
1372 if (obj->IsFailure()) return false;
1373 set_global_property_cell_map(Map::cast(obj));
1374
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001375 obj = AllocateMap(FILLER_TYPE, kPointerSize);
1376 if (obj->IsFailure()) return false;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001377 set_one_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001378
1379 obj = AllocateMap(FILLER_TYPE, 2 * kPointerSize);
1380 if (obj->IsFailure()) return false;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001381 set_two_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001382
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001383 for (unsigned i = 0; i < ARRAY_SIZE(struct_table); i++) {
1384 const StructTable& entry = struct_table[i];
1385 obj = AllocateMap(entry.type, entry.size);
1386 if (obj->IsFailure()) return false;
1387 roots_[entry.index] = Map::cast(obj);
1388 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389
ager@chromium.org236ad962008-09-25 09:45:57 +00001390 obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001391 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001392 set_hash_table_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393
ager@chromium.org236ad962008-09-25 09:45:57 +00001394 obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001395 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001396 set_context_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001397
ager@chromium.org236ad962008-09-25 09:45:57 +00001398 obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001400 set_catch_context_map(Map::cast(obj));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001401
1402 obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize);
1403 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001404 set_global_context_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405
1406 obj = AllocateMap(JS_FUNCTION_TYPE, JSFunction::kSize);
1407 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001408 set_boilerplate_function_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001409
1410 obj = AllocateMap(SHARED_FUNCTION_INFO_TYPE, SharedFunctionInfo::kSize);
1411 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001412 set_shared_function_info_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001414 ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415 return true;
1416}
1417
1418
1419Object* Heap::AllocateHeapNumber(double value, PretenureFlag pretenure) {
1420 // Statically ensure that it is safe to allocate heap numbers in paged
1421 // spaces.
1422 STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxHeapObjectSize);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001423 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001424
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001425 Object* result = AllocateRaw(HeapNumber::kSize, space, OLD_DATA_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001426 if (result->IsFailure()) return result;
1427
1428 HeapObject::cast(result)->set_map(heap_number_map());
1429 HeapNumber::cast(result)->set_value(value);
1430 return result;
1431}
1432
1433
1434Object* Heap::AllocateHeapNumber(double value) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001435 // Use general version, if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001436 if (always_allocate()) return AllocateHeapNumber(value, TENURED);
1437
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001438 // This version of AllocateHeapNumber is optimized for
1439 // allocation in new space.
1440 STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxHeapObjectSize);
1441 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001442 Object* result = new_space_.AllocateRaw(HeapNumber::kSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001443 if (result->IsFailure()) return result;
1444 HeapObject::cast(result)->set_map(heap_number_map());
1445 HeapNumber::cast(result)->set_value(value);
1446 return result;
1447}
1448
1449
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001450Object* Heap::AllocateJSGlobalPropertyCell(Object* value) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001451 Object* result = AllocateRawCell();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001452 if (result->IsFailure()) return result;
1453 HeapObject::cast(result)->set_map(global_property_cell_map());
1454 JSGlobalPropertyCell::cast(result)->set_value(value);
1455 return result;
1456}
1457
1458
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001459Object* Heap::CreateOddball(Map* map,
1460 const char* to_string,
1461 Object* to_number) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001462 Object* result = Allocate(map, OLD_DATA_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001463 if (result->IsFailure()) return result;
1464 return Oddball::cast(result)->Initialize(to_string, to_number);
1465}
1466
1467
1468bool Heap::CreateApiObjects() {
1469 Object* obj;
1470
1471 obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
1472 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001473 set_neander_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001474
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001475 obj = Heap::AllocateJSObjectFromMap(neander_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001476 if (obj->IsFailure()) return false;
1477 Object* elements = AllocateFixedArray(2);
1478 if (elements->IsFailure()) return false;
1479 FixedArray::cast(elements)->set(0, Smi::FromInt(0));
1480 JSObject::cast(obj)->set_elements(FixedArray::cast(elements));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001481 set_message_listeners(JSObject::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001482
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001483 return true;
1484}
1485
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001486
1487void Heap::CreateCEntryStub() {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001488 CEntryStub stub(1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001489 set_c_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001490}
1491
1492
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001493#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP
1494void Heap::CreateRegExpCEntryStub() {
1495 RegExpCEntryStub stub;
1496 set_re_c_entry_code(*stub.GetCode());
1497}
1498#endif
1499
1500
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001501void Heap::CreateJSEntryStub() {
1502 JSEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001503 set_js_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001504}
1505
1506
1507void Heap::CreateJSConstructEntryStub() {
1508 JSConstructEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001509 set_js_construct_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001510}
1511
1512
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001513void Heap::CreateFixedStubs() {
1514 // Here we create roots for fixed stubs. They are needed at GC
1515 // for cooking and uncooking (check out frames.cc).
1516 // The eliminates the need for doing dictionary lookup in the
1517 // stub cache for these stubs.
1518 HandleScope scope;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001519 // gcc-4.4 has problem generating correct code of following snippet:
1520 // { CEntryStub stub;
1521 // c_entry_code_ = *stub.GetCode();
1522 // }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001523 // { DebuggerStatementStub stub;
1524 // debugger_statement_code_ = *stub.GetCode();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001525 // }
1526 // To workaround the problem, make separate functions without inlining.
1527 Heap::CreateCEntryStub();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001528 Heap::CreateJSEntryStub();
1529 Heap::CreateJSConstructEntryStub();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001530#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP
1531 Heap::CreateRegExpCEntryStub();
1532#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001533}
1534
1535
1536bool Heap::CreateInitialObjects() {
1537 Object* obj;
1538
1539 // The -0 value must be set before NumberFromDouble works.
1540 obj = AllocateHeapNumber(-0.0, TENURED);
1541 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001542 set_minus_zero_value(obj);
1543 ASSERT(signbit(minus_zero_value()->Number()) != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001544
1545 obj = AllocateHeapNumber(OS::nan_value(), TENURED);
1546 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001547 set_nan_value(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001549 obj = Allocate(oddball_map(), OLD_DATA_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001550 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001551 set_undefined_value(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001552 ASSERT(!InNewSpace(undefined_value()));
1553
1554 // Allocate initial symbol table.
1555 obj = SymbolTable::Allocate(kInitialSymbolTableSize);
1556 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001557 // Don't use set_symbol_table() due to asserts.
1558 roots_[kSymbolTableRootIndex] = obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001559
1560 // Assign the print strings for oddballs after creating symboltable.
1561 Object* symbol = LookupAsciiSymbol("undefined");
1562 if (symbol->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001563 Oddball::cast(undefined_value())->set_to_string(String::cast(symbol));
1564 Oddball::cast(undefined_value())->set_to_number(nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001565
1566 // Assign the print strings for oddballs after creating symboltable.
1567 symbol = LookupAsciiSymbol("null");
1568 if (symbol->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001569 Oddball::cast(null_value())->set_to_string(String::cast(symbol));
1570 Oddball::cast(null_value())->set_to_number(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001571
1572 // Allocate the null_value
1573 obj = Oddball::cast(null_value())->Initialize("null", Smi::FromInt(0));
1574 if (obj->IsFailure()) return false;
1575
1576 obj = CreateOddball(oddball_map(), "true", Smi::FromInt(1));
1577 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001578 set_true_value(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001579
1580 obj = CreateOddball(oddball_map(), "false", Smi::FromInt(0));
1581 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001582 set_false_value(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583
1584 obj = CreateOddball(oddball_map(), "hole", Smi::FromInt(-1));
1585 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001586 set_the_hole_value(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001587
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001588 obj = CreateOddball(
1589 oddball_map(), "no_interceptor_result_sentinel", Smi::FromInt(-2));
1590 if (obj->IsFailure()) return false;
1591 set_no_interceptor_result_sentinel(obj);
1592
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00001593 obj = CreateOddball(oddball_map(), "termination_exception", Smi::FromInt(-3));
1594 if (obj->IsFailure()) return false;
1595 set_termination_exception(obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001596
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001597 // Allocate the empty string.
1598 obj = AllocateRawAsciiString(0, TENURED);
1599 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001600 set_empty_string(String::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001602 for (unsigned i = 0; i < ARRAY_SIZE(constant_symbol_table); i++) {
1603 obj = LookupAsciiSymbol(constant_symbol_table[i].contents);
1604 if (obj->IsFailure()) return false;
1605 roots_[constant_symbol_table[i].index] = String::cast(obj);
1606 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001607
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001608 // Allocate the hidden symbol which is used to identify the hidden properties
1609 // in JSObjects. The hash code has a special value so that it will not match
1610 // the empty string when searching for the property. It cannot be part of the
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001611 // loop above because it needs to be allocated manually with the special
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001612 // hash code in place. The hash code for the hidden_symbol is zero to ensure
1613 // that it will always be at the first entry in property descriptors.
1614 obj = AllocateSymbol(CStrVector(""), 0, String::kHashComputedMask);
1615 if (obj->IsFailure()) return false;
1616 hidden_symbol_ = String::cast(obj);
1617
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618 // Allocate the proxy for __proto__.
1619 obj = AllocateProxy((Address) &Accessors::ObjectPrototype);
1620 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001621 set_prototype_accessors(Proxy::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001622
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001623 // Allocate the code_stubs dictionary. The initial size is set to avoid
1624 // expanding the dictionary during bootstrapping.
1625 obj = NumberDictionary::Allocate(128);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001627 set_code_stubs(NumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001628
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001629 // Allocate the non_monomorphic_cache used in stub-cache.cc. The initial size
1630 // is set to avoid expanding the dictionary during bootstrapping.
1631 obj = NumberDictionary::Allocate(64);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001632 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001633 set_non_monomorphic_cache(NumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001634
1635 CreateFixedStubs();
1636
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001637 if (InitializeNumberStringCache()->IsFailure()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638
1639 // Allocate cache for single character strings.
1640 obj = AllocateFixedArray(String::kMaxAsciiCharCode+1);
1641 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001642 set_single_character_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001643
1644 // Allocate cache for external strings pointing to native source code.
1645 obj = AllocateFixedArray(Natives::GetBuiltinsCount());
1646 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001647 set_natives_source_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001648
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001649 // Handling of script id generation is in Factory::NewScript.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001650 set_last_script_id(undefined_value());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001651
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001652 // Initialize keyed lookup cache.
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001653 KeyedLookupCache::Clear();
1654
1655 // Initialize context slot cache.
1656 ContextSlotCache::Clear();
1657
1658 // Initialize descriptor cache.
1659 DescriptorLookupCache::Clear();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001660
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001661 // Initialize compilation cache.
1662 CompilationCache::Clear();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001663
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001664 return true;
1665}
1666
1667
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001668Object* Heap::InitializeNumberStringCache() {
1669 // Compute the size of the number string cache based on the max heap size.
1670 // max_semispace_size_ == 512 KB => number_string_cache_size = 32.
1671 // max_semispace_size_ == 8 MB => number_string_cache_size = 16KB.
1672 int number_string_cache_size = max_semispace_size_ / 512;
1673 number_string_cache_size = Max(32, Min(16*KB, number_string_cache_size));
1674 Object* obj = AllocateFixedArray(number_string_cache_size * 2);
1675 if (!obj->IsFailure()) set_number_string_cache(FixedArray::cast(obj));
1676 return obj;
1677}
1678
1679
1680void Heap::FlushNumberStringCache() {
1681 // Flush the number to string cache.
1682 int len = number_string_cache()->length();
1683 for (int i = 0; i < len; i++) {
1684 number_string_cache()->set_undefined(i);
1685 }
1686}
1687
1688
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689static inline int double_get_hash(double d) {
1690 DoubleRepresentation rep(d);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001691 return static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001692}
1693
1694
1695static inline int smi_get_hash(Smi* smi) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001696 return smi->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001697}
1698
1699
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001700Object* Heap::GetNumberStringCache(Object* number) {
1701 int hash;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001702 int mask = (number_string_cache()->length() >> 1) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001703 if (number->IsSmi()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001704 hash = smi_get_hash(Smi::cast(number)) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001705 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001706 hash = double_get_hash(number->Number()) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001707 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001708 Object* key = number_string_cache()->get(hash * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001709 if (key == number) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001710 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001711 } else if (key->IsHeapNumber() &&
1712 number->IsHeapNumber() &&
1713 key->Number() == number->Number()) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001714 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001715 }
1716 return undefined_value();
1717}
1718
1719
1720void Heap::SetNumberStringCache(Object* number, String* string) {
1721 int hash;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001722 int mask = (number_string_cache()->length() >> 1) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001723 if (number->IsSmi()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001724 hash = smi_get_hash(Smi::cast(number)) & mask;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001725 number_string_cache()->set(hash * 2, Smi::cast(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001726 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001727 hash = double_get_hash(number->Number()) & mask;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001728 number_string_cache()->set(hash * 2, number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001729 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001730 number_string_cache()->set(hash * 2 + 1, string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001731}
1732
1733
1734Object* Heap::SmiOrNumberFromDouble(double value,
1735 bool new_object,
1736 PretenureFlag pretenure) {
1737 // We need to distinguish the minus zero value and this cannot be
1738 // done after conversion to int. Doing this by comparing bit
1739 // patterns is faster than using fpclassify() et al.
1740 static const DoubleRepresentation plus_zero(0.0);
1741 static const DoubleRepresentation minus_zero(-0.0);
1742 static const DoubleRepresentation nan(OS::nan_value());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001743 ASSERT(minus_zero_value() != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001744 ASSERT(sizeof(plus_zero.value) == sizeof(plus_zero.bits));
1745
1746 DoubleRepresentation rep(value);
1747 if (rep.bits == plus_zero.bits) return Smi::FromInt(0); // not uncommon
1748 if (rep.bits == minus_zero.bits) {
1749 return new_object ? AllocateHeapNumber(-0.0, pretenure)
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001750 : minus_zero_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001751 }
1752 if (rep.bits == nan.bits) {
1753 return new_object
1754 ? AllocateHeapNumber(OS::nan_value(), pretenure)
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001755 : nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001756 }
1757
1758 // Try to represent the value as a tagged small integer.
1759 int int_value = FastD2I(value);
1760 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
1761 return Smi::FromInt(int_value);
1762 }
1763
1764 // Materialize the value in the heap.
1765 return AllocateHeapNumber(value, pretenure);
1766}
1767
1768
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001769Object* Heap::NumberToString(Object* number) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001770 Counters::number_to_string_runtime.Increment();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001771 Object* cached = GetNumberStringCache(number);
1772 if (cached != undefined_value()) {
1773 return cached;
1774 }
1775
1776 char arr[100];
1777 Vector<char> buffer(arr, ARRAY_SIZE(arr));
1778 const char* str;
1779 if (number->IsSmi()) {
1780 int num = Smi::cast(number)->value();
1781 str = IntToCString(num, buffer);
1782 } else {
1783 double num = HeapNumber::cast(number)->value();
1784 str = DoubleToCString(num, buffer);
1785 }
1786 Object* result = AllocateStringFromAscii(CStrVector(str));
1787
1788 if (!result->IsFailure()) {
1789 SetNumberStringCache(number, String::cast(result));
1790 }
1791 return result;
1792}
1793
1794
ager@chromium.org3811b432009-10-28 14:53:37 +00001795Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) {
1796 return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]);
1797}
1798
1799
1800Heap::RootListIndex Heap::RootIndexForExternalArrayType(
1801 ExternalArrayType array_type) {
1802 switch (array_type) {
1803 case kExternalByteArray:
1804 return kExternalByteArrayMapRootIndex;
1805 case kExternalUnsignedByteArray:
1806 return kExternalUnsignedByteArrayMapRootIndex;
1807 case kExternalShortArray:
1808 return kExternalShortArrayMapRootIndex;
1809 case kExternalUnsignedShortArray:
1810 return kExternalUnsignedShortArrayMapRootIndex;
1811 case kExternalIntArray:
1812 return kExternalIntArrayMapRootIndex;
1813 case kExternalUnsignedIntArray:
1814 return kExternalUnsignedIntArrayMapRootIndex;
1815 case kExternalFloatArray:
1816 return kExternalFloatArrayMapRootIndex;
1817 default:
1818 UNREACHABLE();
1819 return kUndefinedValueRootIndex;
1820 }
1821}
1822
1823
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001824Object* Heap::NewNumberFromDouble(double value, PretenureFlag pretenure) {
1825 return SmiOrNumberFromDouble(value,
1826 true /* number object must be new */,
1827 pretenure);
1828}
1829
1830
1831Object* Heap::NumberFromDouble(double value, PretenureFlag pretenure) {
1832 return SmiOrNumberFromDouble(value,
1833 false /* use preallocated NaN, -0.0 */,
1834 pretenure);
1835}
1836
1837
1838Object* Heap::AllocateProxy(Address proxy, PretenureFlag pretenure) {
1839 // Statically ensure that it is safe to allocate proxies in paged spaces.
1840 STATIC_ASSERT(Proxy::kSize <= Page::kMaxHeapObjectSize);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001841 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001842 Object* result = Allocate(proxy_map(), space);
1843 if (result->IsFailure()) return result;
1844
1845 Proxy::cast(result)->set_proxy(proxy);
1846 return result;
1847}
1848
1849
1850Object* Heap::AllocateSharedFunctionInfo(Object* name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001851 Object* result = Allocate(shared_function_info_map(), OLD_POINTER_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001852 if (result->IsFailure()) return result;
1853
1854 SharedFunctionInfo* share = SharedFunctionInfo::cast(result);
1855 share->set_name(name);
1856 Code* illegal = Builtins::builtin(Builtins::Illegal);
1857 share->set_code(illegal);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001858 Code* construct_stub = Builtins::builtin(Builtins::JSConstructStubGeneric);
1859 share->set_construct_stub(construct_stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001860 share->set_expected_nof_properties(0);
1861 share->set_length(0);
1862 share->set_formal_parameter_count(0);
1863 share->set_instance_class_name(Object_symbol());
1864 share->set_function_data(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001865 share->set_script(undefined_value());
1866 share->set_start_position_and_type(0);
1867 share->set_debug_info(undefined_value());
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00001868 share->set_inferred_name(empty_string());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001869 share->set_compiler_hints(0);
1870 share->set_this_property_assignments_count(0);
1871 share->set_this_property_assignments(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001872 return result;
1873}
1874
1875
ager@chromium.org6141cbe2009-11-20 12:14:52 +00001876// Returns true for a character in a range. Both limits are inclusive.
1877static inline bool Between(uint32_t character, uint32_t from, uint32_t to) {
1878 // This makes uses of the the unsigned wraparound.
1879 return character - from <= to - from;
1880}
1881
1882
1883static inline Object* MakeOrFindTwoCharacterString(uint32_t c1, uint32_t c2) {
1884 String* symbol;
1885 // Numeric strings have a different hash algorithm not known by
1886 // LookupTwoCharsSymbolIfExists, so we skip this step for such strings.
1887 if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) &&
1888 Heap::symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) {
1889 return symbol;
1890 // Now we know the length is 2, we might as well make use of that fact
1891 // when building the new string.
1892 } else if ((c1 | c2) <= String::kMaxAsciiCharCodeU) { // We can do this
1893 ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1)); // because of this.
1894 Object* result = Heap::AllocateRawAsciiString(2);
1895 if (result->IsFailure()) return result;
1896 char* dest = SeqAsciiString::cast(result)->GetChars();
1897 dest[0] = c1;
1898 dest[1] = c2;
1899 return result;
1900 } else {
1901 Object* result = Heap::AllocateRawTwoByteString(2);
1902 if (result->IsFailure()) return result;
1903 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
1904 dest[0] = c1;
1905 dest[1] = c2;
1906 return result;
1907 }
1908}
1909
1910
ager@chromium.org3e875802009-06-29 08:26:34 +00001911Object* Heap::AllocateConsString(String* first, String* second) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001912 int first_length = first->length();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001913 if (first_length == 0) {
1914 return second;
1915 }
ager@chromium.org3e875802009-06-29 08:26:34 +00001916
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001917 int second_length = second->length();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001918 if (second_length == 0) {
1919 return first;
1920 }
ager@chromium.org3e875802009-06-29 08:26:34 +00001921
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001922 int length = first_length + second_length;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00001923
1924 // Optimization for 2-byte strings often used as keys in a decompression
1925 // dictionary. Check whether we already have the string in the symbol
1926 // table to prevent creation of many unneccesary strings.
1927 if (length == 2) {
1928 unsigned c1 = first->Get(0);
1929 unsigned c2 = second->Get(0);
1930 return MakeOrFindTwoCharacterString(c1, c2);
1931 }
1932
ager@chromium.org5ec48922009-05-05 07:25:34 +00001933 bool is_ascii = first->IsAsciiRepresentation()
1934 && second->IsAsciiRepresentation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001935
ager@chromium.org3e875802009-06-29 08:26:34 +00001936 // Make sure that an out of memory exception is thrown if the length
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001937 // of the new cons string is too large.
1938 if (length > String::kMaxLength || length < 0) {
ager@chromium.org3e875802009-06-29 08:26:34 +00001939 Top::context()->mark_out_of_memory();
1940 return Failure::OutOfMemoryException();
1941 }
1942
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001943 // If the resulting string is small make a flat string.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001944 if (length < String::kMinNonFlatLength) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001945 ASSERT(first->IsFlat());
1946 ASSERT(second->IsFlat());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001947 if (is_ascii) {
1948 Object* result = AllocateRawAsciiString(length);
1949 if (result->IsFailure()) return result;
1950 // Copy the characters into the new object.
1951 char* dest = SeqAsciiString::cast(result)->GetChars();
ager@chromium.org3e875802009-06-29 08:26:34 +00001952 // Copy first part.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001953 const char* src;
1954 if (first->IsExternalString()) {
1955 src = ExternalAsciiString::cast(first)->resource()->data();
1956 } else {
1957 src = SeqAsciiString::cast(first)->GetChars();
1958 }
ager@chromium.org3e875802009-06-29 08:26:34 +00001959 for (int i = 0; i < first_length; i++) *dest++ = src[i];
1960 // Copy second part.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001961 if (second->IsExternalString()) {
1962 src = ExternalAsciiString::cast(second)->resource()->data();
1963 } else {
1964 src = SeqAsciiString::cast(second)->GetChars();
1965 }
ager@chromium.org3e875802009-06-29 08:26:34 +00001966 for (int i = 0; i < second_length; i++) *dest++ = src[i];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001967 return result;
1968 } else {
1969 Object* result = AllocateRawTwoByteString(length);
1970 if (result->IsFailure()) return result;
1971 // Copy the characters into the new object.
1972 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001973 String::WriteToFlat(first, dest, 0, first_length);
1974 String::WriteToFlat(second, dest + first_length, 0, second_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001975 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001976 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001977 }
1978
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001979 Map* map = is_ascii ? cons_ascii_string_map() : cons_string_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001980
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001981 Object* result = Allocate(map, NEW_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001982 if (result->IsFailure()) return result;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001983
1984 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001985 ConsString* cons_string = ConsString::cast(result);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001986 WriteBarrierMode mode = cons_string->GetWriteBarrierMode(no_gc);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001987 cons_string->set_length(length);
1988 cons_string->set_hash_field(String::kEmptyHashField);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001989 cons_string->set_first(first, mode);
1990 cons_string->set_second(second, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001991 return result;
1992}
1993
1994
ager@chromium.org870a0b62008-11-04 11:43:05 +00001995Object* Heap::AllocateSubString(String* buffer,
ager@chromium.org870a0b62008-11-04 11:43:05 +00001996 int start,
1997 int end) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001998 int length = end - start;
1999
ager@chromium.org7c537e22008-10-16 08:43:32 +00002000 if (length == 1) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00002001 return Heap::LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002002 buffer->Get(start));
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002003 } else if (length == 2) {
2004 // Optimization for 2-byte strings often used as keys in a decompression
2005 // dictionary. Check whether we already have the string in the symbol
2006 // table to prevent creation of many unneccesary strings.
2007 unsigned c1 = buffer->Get(start);
2008 unsigned c2 = buffer->Get(start + 1);
2009 return MakeOrFindTwoCharacterString(c1, c2);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002010 }
2011
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002012 // Make an attempt to flatten the buffer to reduce access time.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002013 if (!buffer->IsFlat()) {
2014 buffer->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00002015 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002016
ager@chromium.org5ec48922009-05-05 07:25:34 +00002017 Object* result = buffer->IsAsciiRepresentation()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002018 ? AllocateRawAsciiString(length)
2019 : AllocateRawTwoByteString(length);
2020 if (result->IsFailure()) return result;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002021 String* string_result = String::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002022
2023 // Copy the characters into the new object.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002024 if (buffer->IsAsciiRepresentation()) {
2025 ASSERT(string_result->IsAsciiRepresentation());
2026 char* dest = SeqAsciiString::cast(string_result)->GetChars();
2027 String::WriteToFlat(buffer, dest, start, end);
2028 } else {
2029 ASSERT(string_result->IsTwoByteRepresentation());
2030 uc16* dest = SeqTwoByteString::cast(string_result)->GetChars();
2031 String::WriteToFlat(buffer, dest, start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002032 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002033
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002034 return result;
2035}
2036
2037
2038Object* Heap::AllocateExternalStringFromAscii(
2039 ExternalAsciiString::Resource* resource) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002040 size_t length = resource->length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002041 if (length > static_cast<size_t>(String::kMaxLength)) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002042 Top::context()->mark_out_of_memory();
2043 return Failure::OutOfMemoryException();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 }
2045
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002046 Map* map = external_ascii_string_map();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002047 Object* result = Allocate(map, NEW_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002048 if (result->IsFailure()) return result;
2049
2050 ExternalAsciiString* external_string = ExternalAsciiString::cast(result);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002051 external_string->set_length(static_cast<int>(length));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002052 external_string->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002053 external_string->set_resource(resource);
2054
2055 return result;
2056}
2057
2058
2059Object* Heap::AllocateExternalStringFromTwoByte(
2060 ExternalTwoByteString::Resource* resource) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002061 size_t length = resource->length();
2062 if (length > static_cast<size_t>(String::kMaxLength)) {
2063 Top::context()->mark_out_of_memory();
2064 return Failure::OutOfMemoryException();
2065 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002066
2067 Map* map = Heap::external_string_map();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002068 Object* result = Allocate(map, NEW_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002069 if (result->IsFailure()) return result;
2070
2071 ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002072 external_string->set_length(static_cast<int>(length));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002073 external_string->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002074 external_string->set_resource(resource);
2075
2076 return result;
2077}
2078
2079
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002080Object* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002081 if (code <= String::kMaxAsciiCharCode) {
2082 Object* value = Heap::single_character_string_cache()->get(code);
2083 if (value != Heap::undefined_value()) return value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002084
2085 char buffer[1];
2086 buffer[0] = static_cast<char>(code);
2087 Object* result = LookupSymbol(Vector<const char>(buffer, 1));
2088
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002089 if (result->IsFailure()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002090 Heap::single_character_string_cache()->set(code, result);
2091 return result;
2092 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002093
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002094 Object* result = Heap::AllocateRawTwoByteString(1);
2095 if (result->IsFailure()) return result;
ager@chromium.org870a0b62008-11-04 11:43:05 +00002096 String* answer = String::cast(result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002097 answer->Set(0, code);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002098 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002099}
2100
2101
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002102Object* Heap::AllocateByteArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002103 if (length < 0 || length > ByteArray::kMaxLength) {
2104 return Failure::OutOfMemoryException();
2105 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002106 if (pretenure == NOT_TENURED) {
2107 return AllocateByteArray(length);
2108 }
2109 int size = ByteArray::SizeFor(length);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002110 Object* result = (size <= MaxObjectSizeInPagedSpace())
2111 ? old_data_space_->AllocateRaw(size)
2112 : lo_space_->AllocateRaw(size);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002113 if (result->IsFailure()) return result;
2114
2115 reinterpret_cast<Array*>(result)->set_map(byte_array_map());
2116 reinterpret_cast<Array*>(result)->set_length(length);
2117 return result;
2118}
2119
2120
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002121Object* Heap::AllocateByteArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002122 if (length < 0 || length > ByteArray::kMaxLength) {
2123 return Failure::OutOfMemoryException();
2124 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002125 int size = ByteArray::SizeFor(length);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002126 AllocationSpace space =
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002127 (size > MaxObjectSizeInPagedSpace()) ? LO_SPACE : NEW_SPACE;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002128 Object* result = AllocateRaw(size, space, OLD_DATA_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002129 if (result->IsFailure()) return result;
2130
2131 reinterpret_cast<Array*>(result)->set_map(byte_array_map());
2132 reinterpret_cast<Array*>(result)->set_length(length);
2133 return result;
2134}
2135
2136
ager@chromium.org6f10e412009-02-13 10:11:16 +00002137void Heap::CreateFillerObjectAt(Address addr, int size) {
2138 if (size == 0) return;
2139 HeapObject* filler = HeapObject::FromAddress(addr);
2140 if (size == kPointerSize) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002141 filler->set_map(Heap::one_pointer_filler_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +00002142 } else {
2143 filler->set_map(Heap::byte_array_map());
2144 ByteArray::cast(filler)->set_length(ByteArray::LengthFor(size));
2145 }
2146}
2147
2148
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002149Object* Heap::AllocatePixelArray(int length,
2150 uint8_t* external_pointer,
2151 PretenureFlag pretenure) {
2152 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002153 Object* result = AllocateRaw(PixelArray::kAlignedSize, space, OLD_DATA_SPACE);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002154 if (result->IsFailure()) return result;
2155
2156 reinterpret_cast<PixelArray*>(result)->set_map(pixel_array_map());
2157 reinterpret_cast<PixelArray*>(result)->set_length(length);
2158 reinterpret_cast<PixelArray*>(result)->set_external_pointer(external_pointer);
2159
2160 return result;
2161}
2162
2163
ager@chromium.org3811b432009-10-28 14:53:37 +00002164Object* Heap::AllocateExternalArray(int length,
2165 ExternalArrayType array_type,
2166 void* external_pointer,
2167 PretenureFlag pretenure) {
2168 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
ager@chromium.org3811b432009-10-28 14:53:37 +00002169 Object* result = AllocateRaw(ExternalArray::kAlignedSize,
2170 space,
2171 OLD_DATA_SPACE);
ager@chromium.org3811b432009-10-28 14:53:37 +00002172 if (result->IsFailure()) return result;
2173
2174 reinterpret_cast<ExternalArray*>(result)->set_map(
2175 MapForExternalArrayType(array_type));
2176 reinterpret_cast<ExternalArray*>(result)->set_length(length);
2177 reinterpret_cast<ExternalArray*>(result)->set_external_pointer(
2178 external_pointer);
2179
2180 return result;
2181}
2182
2183
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002184Object* Heap::CreateCode(const CodeDesc& desc,
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002185 ZoneScopeInfo* sinfo,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002186 Code::Flags flags,
kasperl@chromium.org061ef742009-02-27 12:16:20 +00002187 Handle<Object> self_reference) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002188 // Compute size
2189 int body_size = RoundUp(desc.instr_size + desc.reloc_size, kObjectAlignment);
2190 int sinfo_size = 0;
2191 if (sinfo != NULL) sinfo_size = sinfo->Serialize(NULL);
2192 int obj_size = Code::SizeFor(body_size, sinfo_size);
kasperl@chromium.org061ef742009-02-27 12:16:20 +00002193 ASSERT(IsAligned(obj_size, Code::kCodeAlignment));
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002194 Object* result;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002195 if (obj_size > MaxObjectSizeInPagedSpace()) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002196 result = lo_space_->AllocateRawCode(obj_size);
2197 } else {
2198 result = code_space_->AllocateRaw(obj_size);
2199 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002200
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002201 if (result->IsFailure()) return result;
2202
2203 // Initialize the object
2204 HeapObject::cast(result)->set_map(code_map());
2205 Code* code = Code::cast(result);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002206 ASSERT(!CodeRange::exists() || CodeRange::contains(code->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002207 code->set_instruction_size(desc.instr_size);
2208 code->set_relocation_size(desc.reloc_size);
2209 code->set_sinfo_size(sinfo_size);
2210 code->set_flags(flags);
kasperl@chromium.org061ef742009-02-27 12:16:20 +00002211 // Allow self references to created code object by patching the handle to
2212 // point to the newly allocated Code object.
2213 if (!self_reference.is_null()) {
2214 *(self_reference.location()) = code;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002215 }
2216 // Migrate generated code.
2217 // The generated code can contain Object** values (typically from handles)
2218 // that are dereferenced during the copy to point directly to the actual heap
2219 // objects. These pointers can include references to the code object itself,
2220 // through the self_reference parameter.
2221 code->CopyFrom(desc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002222 if (sinfo != NULL) sinfo->Serialize(code); // write scope info
2223
2224#ifdef DEBUG
2225 code->Verify();
2226#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002227 return code;
2228}
2229
2230
2231Object* Heap::CopyCode(Code* code) {
2232 // Allocate an object the same size as the code object.
2233 int obj_size = code->Size();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002234 Object* result;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002235 if (obj_size > MaxObjectSizeInPagedSpace()) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002236 result = lo_space_->AllocateRawCode(obj_size);
2237 } else {
2238 result = code_space_->AllocateRaw(obj_size);
2239 }
2240
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002241 if (result->IsFailure()) return result;
2242
2243 // Copy code object.
2244 Address old_addr = code->address();
2245 Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002246 CopyBlock(reinterpret_cast<Object**>(new_addr),
2247 reinterpret_cast<Object**>(old_addr),
2248 obj_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002249 // Relocate the copy.
2250 Code* new_code = Code::cast(result);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002251 ASSERT(!CodeRange::exists() || CodeRange::contains(code->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002252 new_code->Relocate(new_addr - old_addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002253 return new_code;
2254}
2255
2256
2257Object* Heap::Allocate(Map* map, AllocationSpace space) {
2258 ASSERT(gc_state_ == NOT_IN_GC);
2259 ASSERT(map->instance_type() != MAP_TYPE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002260 // If allocation failures are disallowed, we may allocate in a different
2261 // space when new space is full and the object is not a large object.
2262 AllocationSpace retry_space =
2263 (space != NEW_SPACE) ? space : TargetSpaceId(map->instance_type());
2264 Object* result =
2265 AllocateRaw(map->instance_size(), space, retry_space);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002266 if (result->IsFailure()) return result;
2267 HeapObject::cast(result)->set_map(map);
ager@chromium.org3811b432009-10-28 14:53:37 +00002268#ifdef ENABLE_LOGGING_AND_PROFILING
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002269 ProducerHeapProfile::RecordJSObjectAllocation(result);
ager@chromium.org3811b432009-10-28 14:53:37 +00002270#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002271 return result;
2272}
2273
2274
2275Object* Heap::InitializeFunction(JSFunction* function,
2276 SharedFunctionInfo* shared,
2277 Object* prototype) {
2278 ASSERT(!prototype->IsMap());
2279 function->initialize_properties();
2280 function->initialize_elements();
2281 function->set_shared(shared);
2282 function->set_prototype_or_initial_map(prototype);
2283 function->set_context(undefined_value());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002284 function->set_literals(empty_fixed_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002285 return function;
2286}
2287
2288
2289Object* Heap::AllocateFunctionPrototype(JSFunction* function) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002290 // Allocate the prototype. Make sure to use the object function
2291 // from the function's context, since the function can be from a
2292 // different context.
2293 JSFunction* object_function =
2294 function->context()->global_context()->object_function();
2295 Object* prototype = AllocateJSObject(object_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002296 if (prototype->IsFailure()) return prototype;
2297 // When creating the prototype for the function we must set its
2298 // constructor to the function.
2299 Object* result =
2300 JSObject::cast(prototype)->SetProperty(constructor_symbol(),
2301 function,
2302 DONT_ENUM);
2303 if (result->IsFailure()) return result;
2304 return prototype;
2305}
2306
2307
2308Object* Heap::AllocateFunction(Map* function_map,
2309 SharedFunctionInfo* shared,
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002310 Object* prototype,
2311 PretenureFlag pretenure) {
2312 AllocationSpace space =
2313 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
2314 Object* result = Allocate(function_map, space);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002315 if (result->IsFailure()) return result;
2316 return InitializeFunction(JSFunction::cast(result), shared, prototype);
2317}
2318
2319
2320Object* Heap::AllocateArgumentsObject(Object* callee, int length) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002321 // To get fast allocation and map sharing for arguments objects we
2322 // allocate them based on an arguments boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002323
2324 // This calls Copy directly rather than using Heap::AllocateRaw so we
2325 // duplicate the check here.
2326 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
2327
2328 JSObject* boilerplate =
2329 Top::context()->global_context()->arguments_boilerplate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002330
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002331 // Check that the size of the boilerplate matches our
2332 // expectations. The ArgumentsAccessStub::GenerateNewObject relies
2333 // on the size being a known constant.
2334 ASSERT(kArgumentsObjectSize == boilerplate->map()->instance_size());
2335
2336 // Do the allocation.
2337 Object* result =
2338 AllocateRaw(kArgumentsObjectSize, NEW_SPACE, OLD_POINTER_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002339 if (result->IsFailure()) return result;
2340
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002341 // Copy the content. The arguments boilerplate doesn't have any
2342 // fields that point to new space so it's safe to skip the write
2343 // barrier here.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002344 CopyBlock(reinterpret_cast<Object**>(HeapObject::cast(result)->address()),
2345 reinterpret_cast<Object**>(boilerplate->address()),
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002346 kArgumentsObjectSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002347
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002348 // Set the two properties.
2349 JSObject::cast(result)->InObjectPropertyAtPut(arguments_callee_index,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002350 callee);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002351 JSObject::cast(result)->InObjectPropertyAtPut(arguments_length_index,
2352 Smi::FromInt(length),
2353 SKIP_WRITE_BARRIER);
2354
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002355 // Check the state of the object
2356 ASSERT(JSObject::cast(result)->HasFastProperties());
2357 ASSERT(JSObject::cast(result)->HasFastElements());
2358
2359 return result;
2360}
2361
2362
2363Object* Heap::AllocateInitialMap(JSFunction* fun) {
2364 ASSERT(!fun->has_initial_map());
2365
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002366 // First create a new map with the size and number of in-object properties
2367 // suggested by the function.
2368 int instance_size = fun->shared()->CalculateInstanceSize();
2369 int in_object_properties = fun->shared()->CalculateInObjectProperties();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002370 Object* map_obj = Heap::AllocateMap(JS_OBJECT_TYPE, instance_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002371 if (map_obj->IsFailure()) return map_obj;
2372
2373 // Fetch or allocate prototype.
2374 Object* prototype;
2375 if (fun->has_instance_prototype()) {
2376 prototype = fun->instance_prototype();
2377 } else {
2378 prototype = AllocateFunctionPrototype(fun);
2379 if (prototype->IsFailure()) return prototype;
2380 }
2381 Map* map = Map::cast(map_obj);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002382 map->set_inobject_properties(in_object_properties);
2383 map->set_unused_property_fields(in_object_properties);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002384 map->set_prototype(prototype);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002385
ager@chromium.org5c838252010-02-19 08:53:10 +00002386 // If the function has only simple this property assignments add
2387 // field descriptors for these to the initial map as the object
2388 // cannot be constructed without having these properties. Guard by
2389 // the inline_new flag so we only change the map if we generate a
2390 // specialized construct stub.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002391 ASSERT(in_object_properties <= Map::kMaxPreAllocatedPropertyFields);
ager@chromium.org5c838252010-02-19 08:53:10 +00002392 if (fun->shared()->CanGenerateInlineConstructor(prototype)) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002393 int count = fun->shared()->this_property_assignments_count();
2394 if (count > in_object_properties) {
2395 count = in_object_properties;
2396 }
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00002397 Object* descriptors_obj = DescriptorArray::Allocate(count);
2398 if (descriptors_obj->IsFailure()) return descriptors_obj;
2399 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_obj);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002400 for (int i = 0; i < count; i++) {
2401 String* name = fun->shared()->GetThisPropertyAssignmentName(i);
2402 ASSERT(name->IsSymbol());
2403 FieldDescriptor field(name, i, NONE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002404 field.SetEnumerationIndex(i);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002405 descriptors->Set(i, &field);
2406 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002407 descriptors->SetNextEnumerationIndex(count);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002408 descriptors->Sort();
2409 map->set_instance_descriptors(descriptors);
2410 map->set_pre_allocated_property_fields(count);
2411 map->set_unused_property_fields(in_object_properties - count);
2412 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002413 return map;
2414}
2415
2416
2417void Heap::InitializeJSObjectFromMap(JSObject* obj,
2418 FixedArray* properties,
2419 Map* map) {
2420 obj->set_properties(properties);
2421 obj->initialize_elements();
2422 // TODO(1240798): Initialize the object's body using valid initial values
2423 // according to the object's initial map. For example, if the map's
2424 // instance type is JS_ARRAY_TYPE, the length field should be initialized
2425 // to a number (eg, Smi::FromInt(0)) and the elements initialized to a
2426 // fixed array (eg, Heap::empty_fixed_array()). Currently, the object
2427 // verification code has to cope with (temporarily) invalid objects. See
2428 // for example, JSArray::JSArrayVerify).
2429 obj->InitializeBody(map->instance_size());
2430}
2431
2432
2433Object* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) {
2434 // JSFunctions should be allocated using AllocateFunction to be
2435 // properly initialized.
2436 ASSERT(map->instance_type() != JS_FUNCTION_TYPE);
2437
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002438 // Both types of globla objects should be allocated using
2439 // AllocateGloblaObject to be properly initialized.
2440 ASSERT(map->instance_type() != JS_GLOBAL_OBJECT_TYPE);
2441 ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE);
2442
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002443 // Allocate the backing storage for the properties.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002444 int prop_size =
2445 map->pre_allocated_property_fields() +
2446 map->unused_property_fields() -
2447 map->inobject_properties();
2448 ASSERT(prop_size >= 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002449 Object* properties = AllocateFixedArray(prop_size, pretenure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002450 if (properties->IsFailure()) return properties;
2451
2452 // Allocate the JSObject.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002453 AllocationSpace space =
2454 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002455 if (map->instance_size() > MaxObjectSizeInPagedSpace()) space = LO_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002456 Object* obj = Allocate(map, space);
2457 if (obj->IsFailure()) return obj;
2458
2459 // Initialize the JSObject.
2460 InitializeJSObjectFromMap(JSObject::cast(obj),
2461 FixedArray::cast(properties),
2462 map);
2463 return obj;
2464}
2465
2466
2467Object* Heap::AllocateJSObject(JSFunction* constructor,
2468 PretenureFlag pretenure) {
2469 // Allocate the initial map if absent.
2470 if (!constructor->has_initial_map()) {
2471 Object* initial_map = AllocateInitialMap(constructor);
2472 if (initial_map->IsFailure()) return initial_map;
2473 constructor->set_initial_map(Map::cast(initial_map));
2474 Map::cast(initial_map)->set_constructor(constructor);
2475 }
2476 // Allocate the object based on the constructors initial map.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002477 Object* result =
2478 AllocateJSObjectFromMap(constructor->initial_map(), pretenure);
2479 // Make sure result is NOT a global object if valid.
2480 ASSERT(result->IsFailure() || !result->IsGlobalObject());
2481 return result;
2482}
2483
2484
2485Object* Heap::AllocateGlobalObject(JSFunction* constructor) {
2486 ASSERT(constructor->has_initial_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002487 Map* map = constructor->initial_map();
2488
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002489 // Make sure no field properties are described in the initial map.
2490 // This guarantees us that normalizing the properties does not
2491 // require us to change property values to JSGlobalPropertyCells.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002492 ASSERT(map->NextFreePropertyIndex() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002493
2494 // Make sure we don't have a ton of pre-allocated slots in the
2495 // global objects. They will be unused once we normalize the object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002496 ASSERT(map->unused_property_fields() == 0);
2497 ASSERT(map->inobject_properties() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002498
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002499 // Initial size of the backing store to avoid resize of the storage during
2500 // bootstrapping. The size differs between the JS global object ad the
2501 // builtins object.
2502 int initial_size = map->instance_type() == JS_GLOBAL_OBJECT_TYPE ? 64 : 512;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002503
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002504 // Allocate a dictionary object for backing storage.
2505 Object* obj =
2506 StringDictionary::Allocate(
2507 map->NumberOfDescribedProperties() * 2 + initial_size);
2508 if (obj->IsFailure()) return obj;
2509 StringDictionary* dictionary = StringDictionary::cast(obj);
2510
2511 // The global object might be created from an object template with accessors.
2512 // Fill these accessors into the dictionary.
2513 DescriptorArray* descs = map->instance_descriptors();
2514 for (int i = 0; i < descs->number_of_descriptors(); i++) {
2515 PropertyDetails details = descs->GetDetails(i);
2516 ASSERT(details.type() == CALLBACKS); // Only accessors are expected.
2517 PropertyDetails d =
2518 PropertyDetails(details.attributes(), CALLBACKS, details.index());
2519 Object* value = descs->GetCallbacksObject(i);
2520 value = Heap::AllocateJSGlobalPropertyCell(value);
2521 if (value->IsFailure()) return value;
2522
2523 Object* result = dictionary->Add(descs->GetKey(i), value, d);
2524 if (result->IsFailure()) return result;
2525 dictionary = StringDictionary::cast(result);
2526 }
2527
2528 // Allocate the global object and initialize it with the backing store.
2529 obj = Allocate(map, OLD_POINTER_SPACE);
2530 if (obj->IsFailure()) return obj;
2531 JSObject* global = JSObject::cast(obj);
2532 InitializeJSObjectFromMap(global, dictionary, map);
2533
2534 // Create a new map for the global object.
2535 obj = map->CopyDropDescriptors();
2536 if (obj->IsFailure()) return obj;
2537 Map* new_map = Map::cast(obj);
2538
2539 // Setup the global object as a normalized object.
2540 global->set_map(new_map);
2541 global->map()->set_instance_descriptors(Heap::empty_descriptor_array());
2542 global->set_properties(dictionary);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002543
2544 // Make sure result is a global object with properties in dictionary.
2545 ASSERT(global->IsGlobalObject());
2546 ASSERT(!global->HasFastProperties());
2547 return global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002548}
2549
2550
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002551Object* Heap::CopyJSObject(JSObject* source) {
2552 // Never used to copy functions. If functions need to be copied we
2553 // have to be careful to clear the literals array.
2554 ASSERT(!source->IsJSFunction());
2555
2556 // Make the clone.
2557 Map* map = source->map();
2558 int object_size = map->instance_size();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002559 Object* clone;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002560
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002561 // If we're forced to always allocate, we use the general allocation
2562 // functions which may leave us with an object in old space.
2563 if (always_allocate()) {
2564 clone = AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE);
2565 if (clone->IsFailure()) return clone;
2566 Address clone_address = HeapObject::cast(clone)->address();
2567 CopyBlock(reinterpret_cast<Object**>(clone_address),
2568 reinterpret_cast<Object**>(source->address()),
2569 object_size);
2570 // Update write barrier for all fields that lie beyond the header.
2571 for (int offset = JSObject::kHeaderSize;
2572 offset < object_size;
2573 offset += kPointerSize) {
2574 RecordWrite(clone_address, offset);
2575 }
2576 } else {
2577 clone = new_space_.AllocateRaw(object_size);
2578 if (clone->IsFailure()) return clone;
2579 ASSERT(Heap::InNewSpace(clone));
2580 // Since we know the clone is allocated in new space, we can copy
ager@chromium.org32912102009-01-16 10:38:43 +00002581 // the contents without worrying about updating the write barrier.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002582 CopyBlock(reinterpret_cast<Object**>(HeapObject::cast(clone)->address()),
2583 reinterpret_cast<Object**>(source->address()),
2584 object_size);
2585 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002586
2587 FixedArray* elements = FixedArray::cast(source->elements());
2588 FixedArray* properties = FixedArray::cast(source->properties());
2589 // Update elements if necessary.
2590 if (elements->length()> 0) {
2591 Object* elem = CopyFixedArray(elements);
2592 if (elem->IsFailure()) return elem;
2593 JSObject::cast(clone)->set_elements(FixedArray::cast(elem));
2594 }
2595 // Update properties if necessary.
2596 if (properties->length() > 0) {
2597 Object* prop = CopyFixedArray(properties);
2598 if (prop->IsFailure()) return prop;
2599 JSObject::cast(clone)->set_properties(FixedArray::cast(prop));
2600 }
2601 // Return the new clone.
ager@chromium.org3811b432009-10-28 14:53:37 +00002602#ifdef ENABLE_LOGGING_AND_PROFILING
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002603 ProducerHeapProfile::RecordJSObjectAllocation(clone);
ager@chromium.org3811b432009-10-28 14:53:37 +00002604#endif
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002605 return clone;
2606}
2607
2608
2609Object* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor,
2610 JSGlobalProxy* object) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002611 // Allocate initial map if absent.
2612 if (!constructor->has_initial_map()) {
2613 Object* initial_map = AllocateInitialMap(constructor);
2614 if (initial_map->IsFailure()) return initial_map;
2615 constructor->set_initial_map(Map::cast(initial_map));
2616 Map::cast(initial_map)->set_constructor(constructor);
2617 }
2618
2619 Map* map = constructor->initial_map();
2620
2621 // Check that the already allocated object has the same size as
2622 // objects allocated using the constructor.
2623 ASSERT(map->instance_size() == object->map()->instance_size());
2624
2625 // Allocate the backing storage for the properties.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002626 int prop_size = map->unused_property_fields() - map->inobject_properties();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002627 Object* properties = AllocateFixedArray(prop_size, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002628 if (properties->IsFailure()) return properties;
2629
2630 // Reset the map for the object.
2631 object->set_map(constructor->initial_map());
2632
2633 // Reinitialize the object from the constructor map.
2634 InitializeJSObjectFromMap(object, FixedArray::cast(properties), map);
2635 return object;
2636}
2637
2638
2639Object* Heap::AllocateStringFromAscii(Vector<const char> string,
2640 PretenureFlag pretenure) {
2641 Object* result = AllocateRawAsciiString(string.length(), pretenure);
2642 if (result->IsFailure()) return result;
2643
2644 // Copy the characters into the new object.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002645 SeqAsciiString* string_result = SeqAsciiString::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002646 for (int i = 0; i < string.length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002647 string_result->SeqAsciiStringSet(i, string[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002648 }
2649 return result;
2650}
2651
2652
2653Object* Heap::AllocateStringFromUtf8(Vector<const char> string,
2654 PretenureFlag pretenure) {
2655 // Count the number of characters in the UTF-8 string and check if
2656 // it is an ASCII string.
2657 Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder());
2658 decoder->Reset(string.start(), string.length());
2659 int chars = 0;
2660 bool is_ascii = true;
2661 while (decoder->has_more()) {
2662 uc32 r = decoder->GetNext();
2663 if (r > String::kMaxAsciiCharCode) is_ascii = false;
2664 chars++;
2665 }
2666
2667 // If the string is ascii, we do not need to convert the characters
2668 // since UTF8 is backwards compatible with ascii.
2669 if (is_ascii) return AllocateStringFromAscii(string, pretenure);
2670
2671 Object* result = AllocateRawTwoByteString(chars, pretenure);
2672 if (result->IsFailure()) return result;
2673
2674 // Convert and copy the characters into the new object.
2675 String* string_result = String::cast(result);
2676 decoder->Reset(string.start(), string.length());
2677 for (int i = 0; i < chars; i++) {
2678 uc32 r = decoder->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002679 string_result->Set(i, r);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002680 }
2681 return result;
2682}
2683
2684
2685Object* Heap::AllocateStringFromTwoByte(Vector<const uc16> string,
2686 PretenureFlag pretenure) {
2687 // Check if the string is an ASCII string.
2688 int i = 0;
2689 while (i < string.length() && string[i] <= String::kMaxAsciiCharCode) i++;
2690
2691 Object* result;
2692 if (i == string.length()) { // It's an ASCII string.
2693 result = AllocateRawAsciiString(string.length(), pretenure);
2694 } else { // It's not an ASCII string.
2695 result = AllocateRawTwoByteString(string.length(), pretenure);
2696 }
2697 if (result->IsFailure()) return result;
2698
2699 // Copy the characters into the new object, which may be either ASCII or
2700 // UTF-16.
2701 String* string_result = String::cast(result);
2702 for (int i = 0; i < string.length(); i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002703 string_result->Set(i, string[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002704 }
2705 return result;
2706}
2707
2708
2709Map* Heap::SymbolMapForString(String* string) {
2710 // If the string is in new space it cannot be used as a symbol.
2711 if (InNewSpace(string)) return NULL;
2712
2713 // Find the corresponding symbol map for strings.
2714 Map* map = string->map();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002715 if (map == ascii_string_map()) return ascii_symbol_map();
2716 if (map == string_map()) return symbol_map();
2717 if (map == cons_string_map()) return cons_symbol_map();
2718 if (map == cons_ascii_string_map()) return cons_ascii_symbol_map();
2719 if (map == external_string_map()) return external_symbol_map();
2720 if (map == external_ascii_string_map()) return external_ascii_symbol_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002721
2722 // No match found.
2723 return NULL;
2724}
2725
2726
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002727Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
2728 int chars,
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002729 uint32_t hash_field) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002730 ASSERT(chars >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002731 // Ensure the chars matches the number of characters in the buffer.
2732 ASSERT(static_cast<unsigned>(chars) == buffer->Length());
2733 // Determine whether the string is ascii.
2734 bool is_ascii = true;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002735 while (buffer->has_more()) {
2736 if (buffer->GetNext() > unibrow::Utf8::kMaxOneByteChar) {
2737 is_ascii = false;
2738 break;
2739 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002740 }
2741 buffer->Rewind();
2742
2743 // Compute map and object size.
2744 int size;
2745 Map* map;
2746
2747 if (is_ascii) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002748 if (chars > SeqAsciiString::kMaxLength) {
2749 return Failure::OutOfMemoryException();
2750 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002751 map = ascii_symbol_map();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002752 size = SeqAsciiString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002753 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002754 if (chars > SeqTwoByteString::kMaxLength) {
2755 return Failure::OutOfMemoryException();
2756 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002757 map = symbol_map();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002758 size = SeqTwoByteString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002759 }
2760
2761 // Allocate string.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002762 Object* result = (size > MaxObjectSizeInPagedSpace())
2763 ? lo_space_->AllocateRaw(size)
2764 : old_data_space_->AllocateRaw(size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002765 if (result->IsFailure()) return result;
2766
2767 reinterpret_cast<HeapObject*>(result)->set_map(map);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002768 // Set length and hash fields of the allocated string.
ager@chromium.org870a0b62008-11-04 11:43:05 +00002769 String* answer = String::cast(result);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002770 answer->set_length(chars);
2771 answer->set_hash_field(hash_field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002772
ager@chromium.org870a0b62008-11-04 11:43:05 +00002773 ASSERT_EQ(size, answer->Size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002774
2775 // Fill in the characters.
2776 for (int i = 0; i < chars; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002777 answer->Set(i, buffer->GetNext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002778 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00002779 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002780}
2781
2782
2783Object* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002784 if (length < 0 || length > SeqAsciiString::kMaxLength) {
2785 return Failure::OutOfMemoryException();
2786 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002787
ager@chromium.org7c537e22008-10-16 08:43:32 +00002788 int size = SeqAsciiString::SizeFor(length);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002789 ASSERT(size <= SeqAsciiString::kMaxSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002790
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002791 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
2792 AllocationSpace retry_space = OLD_DATA_SPACE;
2793
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002794 if (space == NEW_SPACE) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002795 if (size > kMaxObjectSizeInNewSpace) {
2796 // Allocate in large object space, retry space will be ignored.
2797 space = LO_SPACE;
2798 } else if (size > MaxObjectSizeInPagedSpace()) {
2799 // Allocate in new space, retry in large object space.
2800 retry_space = LO_SPACE;
2801 }
2802 } else if (space == OLD_DATA_SPACE && size > MaxObjectSizeInPagedSpace()) {
2803 space = LO_SPACE;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002804 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002805 Object* result = AllocateRaw(size, space, retry_space);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002806 if (result->IsFailure()) return result;
2807
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002808 // Partially initialize the object.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002809 HeapObject::cast(result)->set_map(ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002810 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002811 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002812 ASSERT_EQ(size, HeapObject::cast(result)->Size());
2813 return result;
2814}
2815
2816
2817Object* Heap::AllocateRawTwoByteString(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002818 if (length < 0 || length > SeqTwoByteString::kMaxLength) {
2819 return Failure::OutOfMemoryException();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002820 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002821 int size = SeqTwoByteString::SizeFor(length);
2822 ASSERT(size <= SeqTwoByteString::kMaxSize);
2823 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
2824 AllocationSpace retry_space = OLD_DATA_SPACE;
2825
2826 if (space == NEW_SPACE) {
2827 if (size > kMaxObjectSizeInNewSpace) {
2828 // Allocate in large object space, retry space will be ignored.
2829 space = LO_SPACE;
2830 } else if (size > MaxObjectSizeInPagedSpace()) {
2831 // Allocate in new space, retry in large object space.
2832 retry_space = LO_SPACE;
2833 }
2834 } else if (space == OLD_DATA_SPACE && size > MaxObjectSizeInPagedSpace()) {
2835 space = LO_SPACE;
2836 }
2837 Object* result = AllocateRaw(size, space, retry_space);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002838 if (result->IsFailure()) return result;
2839
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002840 // Partially initialize the object.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002841 HeapObject::cast(result)->set_map(string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002842 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002843 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002844 ASSERT_EQ(size, HeapObject::cast(result)->Size());
2845 return result;
2846}
2847
2848
2849Object* Heap::AllocateEmptyFixedArray() {
2850 int size = FixedArray::SizeFor(0);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002851 Object* result = AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002852 if (result->IsFailure()) return result;
2853 // Initialize the object.
2854 reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
2855 reinterpret_cast<Array*>(result)->set_length(0);
2856 return result;
2857}
2858
2859
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002860Object* Heap::AllocateRawFixedArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002861 if (length < 0 || length > FixedArray::kMaxLength) {
2862 return Failure::OutOfMemoryException();
2863 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002864 // Use the general function if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002865 if (always_allocate()) return AllocateFixedArray(length, TENURED);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002866 // Allocate the raw data for a fixed array.
2867 int size = FixedArray::SizeFor(length);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002868 return size <= kMaxObjectSizeInNewSpace
2869 ? new_space_.AllocateRaw(size)
2870 : lo_space_->AllocateRawFixedArray(size);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002871}
2872
2873
2874Object* Heap::CopyFixedArray(FixedArray* src) {
2875 int len = src->length();
2876 Object* obj = AllocateRawFixedArray(len);
2877 if (obj->IsFailure()) return obj;
2878 if (Heap::InNewSpace(obj)) {
2879 HeapObject* dst = HeapObject::cast(obj);
2880 CopyBlock(reinterpret_cast<Object**>(dst->address()),
2881 reinterpret_cast<Object**>(src->address()),
2882 FixedArray::SizeFor(len));
2883 return obj;
2884 }
2885 HeapObject::cast(obj)->set_map(src->map());
2886 FixedArray* result = FixedArray::cast(obj);
2887 result->set_length(len);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002888
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002889 // Copy the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002890 AssertNoAllocation no_gc;
2891 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002892 for (int i = 0; i < len; i++) result->set(i, src->get(i), mode);
2893 return result;
2894}
2895
2896
2897Object* Heap::AllocateFixedArray(int length) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002898 ASSERT(length >= 0);
ager@chromium.org32912102009-01-16 10:38:43 +00002899 if (length == 0) return empty_fixed_array();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002900 Object* result = AllocateRawFixedArray(length);
2901 if (!result->IsFailure()) {
2902 // Initialize header.
2903 reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
2904 FixedArray* array = FixedArray::cast(result);
2905 array->set_length(length);
2906 Object* value = undefined_value();
2907 // Initialize body.
2908 for (int index = 0; index < length; index++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002909 ASSERT(!Heap::InNewSpace(value)); // value = undefined
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002910 array->set(index, value, SKIP_WRITE_BARRIER);
2911 }
2912 }
2913 return result;
2914}
2915
2916
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002917Object* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002918 ASSERT(length >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002919 ASSERT(empty_fixed_array()->IsFixedArray());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002920 if (length < 0 || length > FixedArray::kMaxLength) {
2921 return Failure::OutOfMemoryException();
2922 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002923 if (length == 0) return empty_fixed_array();
2924
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002925 AllocationSpace space =
2926 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002927 int size = FixedArray::SizeFor(length);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002928 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
2929 // Too big for new space.
2930 space = LO_SPACE;
2931 } else if (space == OLD_POINTER_SPACE &&
2932 size > MaxObjectSizeInPagedSpace()) {
2933 // Too big for old pointer space.
2934 space = LO_SPACE;
2935 }
2936
2937 // Specialize allocation for the space.
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002938 Object* result = Failure::OutOfMemoryException();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002939 if (space == NEW_SPACE) {
2940 // We cannot use Heap::AllocateRaw() because it will not properly
2941 // allocate extra remembered set bits if always_allocate() is true and
2942 // new space allocation fails.
2943 result = new_space_.AllocateRaw(size);
2944 if (result->IsFailure() && always_allocate()) {
2945 if (size <= MaxObjectSizeInPagedSpace()) {
2946 result = old_pointer_space_->AllocateRaw(size);
2947 } else {
2948 result = lo_space_->AllocateRawFixedArray(size);
2949 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002950 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002951 } else if (space == OLD_POINTER_SPACE) {
2952 result = old_pointer_space_->AllocateRaw(size);
2953 } else {
2954 ASSERT(space == LO_SPACE);
2955 result = lo_space_->AllocateRawFixedArray(size);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002956 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002957 if (result->IsFailure()) return result;
2958
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002959 // Initialize the object.
2960 reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
2961 FixedArray* array = FixedArray::cast(result);
2962 array->set_length(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002963 Object* value = undefined_value();
2964 for (int index = 0; index < length; index++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002965 ASSERT(!Heap::InNewSpace(value)); // value = undefined
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002966 array->set(index, value, SKIP_WRITE_BARRIER);
2967 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002968 return array;
2969}
2970
2971
2972Object* Heap::AllocateFixedArrayWithHoles(int length) {
2973 if (length == 0) return empty_fixed_array();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002974 Object* result = AllocateRawFixedArray(length);
2975 if (!result->IsFailure()) {
2976 // Initialize header.
2977 reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
2978 FixedArray* array = FixedArray::cast(result);
2979 array->set_length(length);
2980 // Initialize body.
2981 Object* value = the_hole_value();
2982 for (int index = 0; index < length; index++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002983 ASSERT(!Heap::InNewSpace(value)); // value = the hole
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002984 array->set(index, value, SKIP_WRITE_BARRIER);
2985 }
2986 }
2987 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002988}
2989
2990
2991Object* Heap::AllocateHashTable(int length) {
2992 Object* result = Heap::AllocateFixedArray(length);
2993 if (result->IsFailure()) return result;
2994 reinterpret_cast<Array*>(result)->set_map(hash_table_map());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002995 ASSERT(result->IsHashTable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002996 return result;
2997}
2998
2999
3000Object* Heap::AllocateGlobalContext() {
3001 Object* result = Heap::AllocateFixedArray(Context::GLOBAL_CONTEXT_SLOTS);
3002 if (result->IsFailure()) return result;
3003 Context* context = reinterpret_cast<Context*>(result);
3004 context->set_map(global_context_map());
3005 ASSERT(context->IsGlobalContext());
3006 ASSERT(result->IsContext());
3007 return result;
3008}
3009
3010
3011Object* Heap::AllocateFunctionContext(int length, JSFunction* function) {
3012 ASSERT(length >= Context::MIN_CONTEXT_SLOTS);
3013 Object* result = Heap::AllocateFixedArray(length);
3014 if (result->IsFailure()) return result;
3015 Context* context = reinterpret_cast<Context*>(result);
3016 context->set_map(context_map());
3017 context->set_closure(function);
3018 context->set_fcontext(context);
3019 context->set_previous(NULL);
3020 context->set_extension(NULL);
3021 context->set_global(function->context()->global());
3022 ASSERT(!context->IsGlobalContext());
3023 ASSERT(context->is_function_context());
3024 ASSERT(result->IsContext());
3025 return result;
3026}
3027
3028
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003029Object* Heap::AllocateWithContext(Context* previous,
3030 JSObject* extension,
3031 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003032 Object* result = Heap::AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
3033 if (result->IsFailure()) return result;
3034 Context* context = reinterpret_cast<Context*>(result);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003035 context->set_map(is_catch_context ? catch_context_map() : context_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003036 context->set_closure(previous->closure());
3037 context->set_fcontext(previous->fcontext());
3038 context->set_previous(previous);
3039 context->set_extension(extension);
3040 context->set_global(previous->global());
3041 ASSERT(!context->IsGlobalContext());
3042 ASSERT(!context->is_function_context());
3043 ASSERT(result->IsContext());
3044 return result;
3045}
3046
3047
3048Object* Heap::AllocateStruct(InstanceType type) {
3049 Map* map;
3050 switch (type) {
3051#define MAKE_CASE(NAME, Name, name) case NAME##_TYPE: map = name##_map(); break;
3052STRUCT_LIST(MAKE_CASE)
3053#undef MAKE_CASE
3054 default:
3055 UNREACHABLE();
3056 return Failure::InternalError();
3057 }
3058 int size = map->instance_size();
3059 AllocationSpace space =
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003060 (size > MaxObjectSizeInPagedSpace()) ? LO_SPACE : OLD_POINTER_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003061 Object* result = Heap::Allocate(map, space);
3062 if (result->IsFailure()) return result;
3063 Struct::cast(result)->InitializeBody(size);
3064 return result;
3065}
3066
3067
ager@chromium.org96c75b52009-08-26 09:13:16 +00003068bool Heap::IdleNotification() {
ager@chromium.orga1645e22009-09-09 19:27:10 +00003069 static const int kIdlesBeforeScavenge = 4;
3070 static const int kIdlesBeforeMarkSweep = 7;
3071 static const int kIdlesBeforeMarkCompact = 8;
ager@chromium.org96c75b52009-08-26 09:13:16 +00003072 static int number_idle_notifications = 0;
3073 static int last_gc_count = gc_count_;
3074
3075 bool finished = false;
3076
3077 if (last_gc_count == gc_count_) {
3078 number_idle_notifications++;
3079 } else {
3080 number_idle_notifications = 0;
3081 last_gc_count = gc_count_;
3082 }
3083
ager@chromium.orga1645e22009-09-09 19:27:10 +00003084 if (number_idle_notifications == kIdlesBeforeScavenge) {
3085 CollectGarbage(0, NEW_SPACE);
3086 new_space_.Shrink();
ager@chromium.org96c75b52009-08-26 09:13:16 +00003087 last_gc_count = gc_count_;
ager@chromium.orga1645e22009-09-09 19:27:10 +00003088
3089 } else if (number_idle_notifications == kIdlesBeforeMarkSweep) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003090 // Before doing the mark-sweep collections we clear the
3091 // compilation cache to avoid hanging on to source code and
3092 // generated code for cached functions.
3093 CompilationCache::Clear();
3094
ager@chromium.orga1645e22009-09-09 19:27:10 +00003095 CollectAllGarbage(false);
3096 new_space_.Shrink();
3097 last_gc_count = gc_count_;
3098
3099 } else if (number_idle_notifications == kIdlesBeforeMarkCompact) {
3100 CollectAllGarbage(true);
3101 new_space_.Shrink();
3102 last_gc_count = gc_count_;
3103 number_idle_notifications = 0;
3104 finished = true;
ager@chromium.org96c75b52009-08-26 09:13:16 +00003105 }
3106
3107 // Uncommit unused memory in new space.
3108 Heap::UncommitFromSpace();
3109 return finished;
3110}
3111
3112
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003113#ifdef DEBUG
3114
3115void Heap::Print() {
3116 if (!HasBeenSetup()) return;
3117 Top::PrintStack();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003118 AllSpaces spaces;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003119 for (Space* space = spaces.next(); space != NULL; space = spaces.next())
3120 space->Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003121}
3122
3123
3124void Heap::ReportCodeStatistics(const char* title) {
3125 PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title);
3126 PagedSpace::ResetCodeStatistics();
3127 // We do not look for code in new space, map space, or old space. If code
3128 // somehow ends up in those spaces, we would miss it here.
3129 code_space_->CollectCodeStatistics();
3130 lo_space_->CollectCodeStatistics();
3131 PagedSpace::ReportCodeStatistics();
3132}
3133
3134
3135// This function expects that NewSpace's allocated objects histogram is
3136// populated (via a call to CollectStatistics or else as a side effect of a
3137// just-completed scavenge collection).
3138void Heap::ReportHeapStatistics(const char* title) {
3139 USE(title);
3140 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n",
3141 title, gc_count_);
3142 PrintF("mark-compact GC : %d\n", mc_count_);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00003143 PrintF("old_gen_promotion_limit_ %d\n", old_gen_promotion_limit_);
3144 PrintF("old_gen_allocation_limit_ %d\n", old_gen_allocation_limit_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003145
3146 PrintF("\n");
3147 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles());
3148 GlobalHandles::PrintStats();
3149 PrintF("\n");
3150
3151 PrintF("Heap statistics : ");
3152 MemoryAllocator::ReportStatistics();
3153 PrintF("To space : ");
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003154 new_space_.ReportStatistics();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003155 PrintF("Old pointer space : ");
3156 old_pointer_space_->ReportStatistics();
3157 PrintF("Old data space : ");
3158 old_data_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003159 PrintF("Code space : ");
3160 code_space_->ReportStatistics();
3161 PrintF("Map space : ");
3162 map_space_->ReportStatistics();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003163 PrintF("Cell space : ");
3164 cell_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003165 PrintF("Large object space : ");
3166 lo_space_->ReportStatistics();
3167 PrintF(">>>>>> ========================================= >>>>>>\n");
3168}
3169
3170#endif // DEBUG
3171
3172bool Heap::Contains(HeapObject* value) {
3173 return Contains(value->address());
3174}
3175
3176
3177bool Heap::Contains(Address addr) {
3178 if (OS::IsOutsideAllocatedSpace(addr)) return false;
3179 return HasBeenSetup() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003180 (new_space_.ToSpaceContains(addr) ||
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003181 old_pointer_space_->Contains(addr) ||
3182 old_data_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003183 code_space_->Contains(addr) ||
3184 map_space_->Contains(addr) ||
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003185 cell_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003186 lo_space_->SlowContains(addr));
3187}
3188
3189
3190bool Heap::InSpace(HeapObject* value, AllocationSpace space) {
3191 return InSpace(value->address(), space);
3192}
3193
3194
3195bool Heap::InSpace(Address addr, AllocationSpace space) {
3196 if (OS::IsOutsideAllocatedSpace(addr)) return false;
3197 if (!HasBeenSetup()) return false;
3198
3199 switch (space) {
3200 case NEW_SPACE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003201 return new_space_.ToSpaceContains(addr);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003202 case OLD_POINTER_SPACE:
3203 return old_pointer_space_->Contains(addr);
3204 case OLD_DATA_SPACE:
3205 return old_data_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003206 case CODE_SPACE:
3207 return code_space_->Contains(addr);
3208 case MAP_SPACE:
3209 return map_space_->Contains(addr);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003210 case CELL_SPACE:
3211 return cell_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003212 case LO_SPACE:
3213 return lo_space_->SlowContains(addr);
3214 }
3215
3216 return false;
3217}
3218
3219
3220#ifdef DEBUG
3221void Heap::Verify() {
3222 ASSERT(HasBeenSetup());
3223
3224 VerifyPointersVisitor visitor;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003225 IterateRoots(&visitor, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003226
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003227 new_space_.Verify();
3228
3229 VerifyPointersAndRSetVisitor rset_visitor;
3230 old_pointer_space_->Verify(&rset_visitor);
3231 map_space_->Verify(&rset_visitor);
3232
3233 VerifyPointersVisitor no_rset_visitor;
3234 old_data_space_->Verify(&no_rset_visitor);
3235 code_space_->Verify(&no_rset_visitor);
3236 cell_space_->Verify(&no_rset_visitor);
3237
3238 lo_space_->Verify();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003239}
3240#endif // DEBUG
3241
3242
3243Object* Heap::LookupSymbol(Vector<const char> string) {
3244 Object* symbol = NULL;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003245 Object* new_table = symbol_table()->LookupSymbol(string, &symbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003246 if (new_table->IsFailure()) return new_table;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003247 // Can't use set_symbol_table because SymbolTable::cast knows that
3248 // SymbolTable is a singleton and checks for identity.
3249 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003250 ASSERT(symbol != NULL);
3251 return symbol;
3252}
3253
3254
3255Object* Heap::LookupSymbol(String* string) {
3256 if (string->IsSymbol()) return string;
3257 Object* symbol = NULL;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003258 Object* new_table = symbol_table()->LookupString(string, &symbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003259 if (new_table->IsFailure()) return new_table;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003260 // Can't use set_symbol_table because SymbolTable::cast knows that
3261 // SymbolTable is a singleton and checks for identity.
3262 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003263 ASSERT(symbol != NULL);
3264 return symbol;
3265}
3266
3267
ager@chromium.org7c537e22008-10-16 08:43:32 +00003268bool Heap::LookupSymbolIfExists(String* string, String** symbol) {
3269 if (string->IsSymbol()) {
3270 *symbol = string;
3271 return true;
3272 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003273 return symbol_table()->LookupSymbolIfExists(string, symbol);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003274}
3275
3276
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003277#ifdef DEBUG
3278void Heap::ZapFromSpace() {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003279 ASSERT(reinterpret_cast<Object*>(kFromSpaceZapValue)->IsHeapObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003280 for (Address a = new_space_.FromSpaceLow();
3281 a < new_space_.FromSpaceHigh();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003282 a += kPointerSize) {
3283 Memory::Address_at(a) = kFromSpaceZapValue;
3284 }
3285}
3286#endif // DEBUG
3287
3288
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003289int Heap::IterateRSetRange(Address object_start,
3290 Address object_end,
3291 Address rset_start,
3292 ObjectSlotCallback copy_object_func) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003293 Address object_address = object_start;
3294 Address rset_address = rset_start;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003295 int set_bits_count = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003296
3297 // Loop over all the pointers in [object_start, object_end).
3298 while (object_address < object_end) {
3299 uint32_t rset_word = Memory::uint32_at(rset_address);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003300 if (rset_word != 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003301 uint32_t result_rset = rset_word;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003302 for (uint32_t bitmask = 1; bitmask != 0; bitmask = bitmask << 1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003303 // Do not dereference pointers at or past object_end.
3304 if ((rset_word & bitmask) != 0 && object_address < object_end) {
3305 Object** object_p = reinterpret_cast<Object**>(object_address);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003306 if (Heap::InNewSpace(*object_p)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003307 copy_object_func(reinterpret_cast<HeapObject**>(object_p));
3308 }
3309 // If this pointer does not need to be remembered anymore, clear
3310 // the remembered set bit.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003311 if (!Heap::InNewSpace(*object_p)) result_rset &= ~bitmask;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003312 set_bits_count++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003313 }
3314 object_address += kPointerSize;
3315 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003316 // Update the remembered set if it has changed.
3317 if (result_rset != rset_word) {
3318 Memory::uint32_at(rset_address) = result_rset;
3319 }
3320 } else {
3321 // No bits in the word were set. This is the common case.
3322 object_address += kPointerSize * kBitsPerInt;
3323 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003324 rset_address += kIntSize;
3325 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003326 return set_bits_count;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003327}
3328
3329
3330void Heap::IterateRSet(PagedSpace* space, ObjectSlotCallback copy_object_func) {
3331 ASSERT(Page::is_rset_in_use());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003332 ASSERT(space == old_pointer_space_ || space == map_space_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003333
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003334 static void* paged_rset_histogram = StatsTable::CreateHistogram(
3335 "V8.RSetPaged",
3336 0,
3337 Page::kObjectAreaSize / kPointerSize,
3338 30);
3339
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003340 PageIterator it(space, PageIterator::PAGES_IN_USE);
3341 while (it.has_next()) {
3342 Page* page = it.next();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003343 int count = IterateRSetRange(page->ObjectAreaStart(), page->AllocationTop(),
3344 page->RSetStart(), copy_object_func);
3345 if (paged_rset_histogram != NULL) {
3346 StatsTable::AddHistogramSample(paged_rset_histogram, count);
3347 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003348 }
3349}
3350
3351
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003352void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) {
3353 IterateStrongRoots(v, mode);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003354 IterateWeakRoots(v, mode);
3355}
3356
3357
3358void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003359 v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex]));
ager@chromium.org3811b432009-10-28 14:53:37 +00003360 v->Synchronize("symbol_table");
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00003361 if (mode != VISIT_ALL_IN_SCAVENGE) {
3362 // Scavenge collections have special processing for this.
3363 ExternalStringTable::Iterate(v);
3364 }
3365 v->Synchronize("external_string_table");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003366}
3367
3368
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003369void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003370 v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]);
ager@chromium.org3811b432009-10-28 14:53:37 +00003371 v->Synchronize("strong_root_list");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003372
ager@chromium.org3b45ab52009-03-19 22:21:34 +00003373 v->VisitPointer(bit_cast<Object**, String**>(&hidden_symbol_));
ager@chromium.org3811b432009-10-28 14:53:37 +00003374 v->Synchronize("symbol");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003375
3376 Bootstrapper::Iterate(v);
ager@chromium.org3811b432009-10-28 14:53:37 +00003377 v->Synchronize("bootstrapper");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003378 Top::Iterate(v);
ager@chromium.org3811b432009-10-28 14:53:37 +00003379 v->Synchronize("top");
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003380 Relocatable::Iterate(v);
ager@chromium.org3811b432009-10-28 14:53:37 +00003381 v->Synchronize("relocatable");
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003382
3383#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003384 Debug::Iterate(v);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003385#endif
ager@chromium.org3811b432009-10-28 14:53:37 +00003386 v->Synchronize("debug");
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003387 CompilationCache::Iterate(v);
ager@chromium.org3811b432009-10-28 14:53:37 +00003388 v->Synchronize("compilationcache");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003389
3390 // Iterate over local handles in handle scopes.
3391 HandleScopeImplementer::Iterate(v);
ager@chromium.org3811b432009-10-28 14:53:37 +00003392 v->Synchronize("handlescope");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003393
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00003394 // Iterate over the builtin code objects and code stubs in the
3395 // heap. Note that it is not necessary to iterate over code objects
3396 // on scavenge collections.
3397 if (mode != VISIT_ALL_IN_SCAVENGE) {
3398 Builtins::IterateBuiltins(v);
3399 }
ager@chromium.org3811b432009-10-28 14:53:37 +00003400 v->Synchronize("builtins");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401
3402 // Iterate over global handles.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003403 if (mode == VISIT_ONLY_STRONG) {
3404 GlobalHandles::IterateStrongRoots(v);
3405 } else {
3406 GlobalHandles::IterateAllRoots(v);
3407 }
ager@chromium.org3811b432009-10-28 14:53:37 +00003408 v->Synchronize("globalhandles");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003409
3410 // Iterate over pointers being held by inactive threads.
3411 ThreadManager::Iterate(v);
ager@chromium.org3811b432009-10-28 14:53:37 +00003412 v->Synchronize("threadmanager");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003413
3414 // Iterate over the pointers the Serialization/Deserialization code is
3415 // holding.
3416 // During garbage collection this keeps the partial snapshot cache alive.
3417 // During deserialization of the startup snapshot this creates the partial
3418 // snapshot cache and deserializes the objects it refers to. During
3419 // serialization this does nothing, since the partial snapshot cache is
3420 // empty. However the next thing we do is create the partial snapshot,
3421 // filling up the partial snapshot cache with objects it needs as we go.
3422 SerializerDeserializer::Iterate(v);
3423 // We don't do a v->Synchronize call here, because in debug mode that will
3424 // output a flag to the snapshot. However at this point the serializer and
3425 // deserializer are deliberately a little unsynchronized (see above) so the
3426 // checking of the sync flag in the snapshot would fail.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003427}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003428
3429
3430// Flag is set when the heap has been configured. The heap can be repeatedly
3431// configured through the API until it is setup.
3432static bool heap_configured = false;
3433
3434// TODO(1236194): Since the heap size is configurable on the command line
3435// and through the API, we should gracefully handle the case that the heap
3436// size is not big enough to fit all the initial objects.
ager@chromium.org3811b432009-10-28 14:53:37 +00003437bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003438 if (HasBeenSetup()) return false;
3439
ager@chromium.org3811b432009-10-28 14:53:37 +00003440 if (max_semispace_size > 0) max_semispace_size_ = max_semispace_size;
3441
3442 if (Snapshot::IsEnabled()) {
3443 // If we are using a snapshot we always reserve the default amount
3444 // of memory for each semispace because code in the snapshot has
3445 // write-barrier code that relies on the size and alignment of new
3446 // space. We therefore cannot use a larger max semispace size
3447 // than the default reserved semispace size.
3448 if (max_semispace_size_ > reserved_semispace_size_) {
3449 max_semispace_size_ = reserved_semispace_size_;
3450 }
3451 } else {
3452 // If we are not using snapshots we reserve space for the actual
3453 // max semispace size.
3454 reserved_semispace_size_ = max_semispace_size_;
3455 }
3456
3457 if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003458
3459 // The new space size must be a power of two to support single-bit testing
3460 // for containment.
ager@chromium.org3811b432009-10-28 14:53:37 +00003461 max_semispace_size_ = RoundUpToPowerOf2(max_semispace_size_);
3462 reserved_semispace_size_ = RoundUpToPowerOf2(reserved_semispace_size_);
3463 initial_semispace_size_ = Min(initial_semispace_size_, max_semispace_size_);
3464 external_allocation_limit_ = 10 * max_semispace_size_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003465
3466 // The old generation is paged.
ager@chromium.org3811b432009-10-28 14:53:37 +00003467 max_old_generation_size_ = RoundUp(max_old_generation_size_, Page::kPageSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003468
3469 heap_configured = true;
3470 return true;
3471}
3472
3473
kasper.lund7276f142008-07-30 08:49:36 +00003474bool Heap::ConfigureHeapDefault() {
ager@chromium.org3811b432009-10-28 14:53:37 +00003475 return ConfigureHeap(FLAG_max_new_space_size / 2, FLAG_max_old_space_size);
kasper.lund7276f142008-07-30 08:49:36 +00003476}
3477
3478
ager@chromium.org60121232009-12-03 11:25:37 +00003479void Heap::RecordStats(HeapStats* stats) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003480 *stats->start_marker = 0xDECADE00;
3481 *stats->end_marker = 0xDECADE01;
3482 *stats->new_space_size = new_space_.Size();
3483 *stats->new_space_capacity = new_space_.Capacity();
3484 *stats->old_pointer_space_size = old_pointer_space_->Size();
3485 *stats->old_pointer_space_capacity = old_pointer_space_->Capacity();
3486 *stats->old_data_space_size = old_data_space_->Size();
3487 *stats->old_data_space_capacity = old_data_space_->Capacity();
3488 *stats->code_space_size = code_space_->Size();
3489 *stats->code_space_capacity = code_space_->Capacity();
3490 *stats->map_space_size = map_space_->Size();
3491 *stats->map_space_capacity = map_space_->Capacity();
3492 *stats->cell_space_size = cell_space_->Size();
3493 *stats->cell_space_capacity = cell_space_->Capacity();
3494 *stats->lo_space_size = lo_space_->Size();
ager@chromium.org60121232009-12-03 11:25:37 +00003495 GlobalHandles::RecordStats(stats);
3496}
3497
3498
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003499int Heap::PromotedSpaceSize() {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003500 return old_pointer_space_->Size()
3501 + old_data_space_->Size()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003502 + code_space_->Size()
3503 + map_space_->Size()
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003504 + cell_space_->Size()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003505 + lo_space_->Size();
3506}
3507
3508
kasper.lund7276f142008-07-30 08:49:36 +00003509int Heap::PromotedExternalMemorySize() {
3510 if (amount_of_external_allocated_memory_
3511 <= amount_of_external_allocated_memory_at_last_global_gc_) return 0;
3512 return amount_of_external_allocated_memory_
3513 - amount_of_external_allocated_memory_at_last_global_gc_;
3514}
3515
3516
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003517bool Heap::Setup(bool create_heap_objects) {
3518 // Initialize heap spaces and initial maps and objects. Whenever something
3519 // goes wrong, just return false. The caller should check the results and
3520 // call Heap::TearDown() to release allocated memory.
3521 //
3522 // If the heap is not yet configured (eg, through the API), configure it.
3523 // Configuration is based on the flags new-space-size (really the semispace
3524 // size) and old-space-size if set or the initial values of semispace_size_
3525 // and old_generation_size_ otherwise.
3526 if (!heap_configured) {
kasper.lund7276f142008-07-30 08:49:36 +00003527 if (!ConfigureHeapDefault()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003528 }
3529
ager@chromium.orga1645e22009-09-09 19:27:10 +00003530 // Setup memory allocator and reserve a chunk of memory for new
ager@chromium.org3811b432009-10-28 14:53:37 +00003531 // space. The chunk is double the size of the requested reserved
3532 // new space size to ensure that we can find a pair of semispaces that
3533 // are contiguous and aligned to their size.
3534 if (!MemoryAllocator::Setup(MaxReserved())) return false;
ager@chromium.orga1645e22009-09-09 19:27:10 +00003535 void* chunk =
ager@chromium.org3811b432009-10-28 14:53:37 +00003536 MemoryAllocator::ReserveInitialChunk(4 * reserved_semispace_size_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003537 if (chunk == NULL) return false;
3538
ager@chromium.orga1645e22009-09-09 19:27:10 +00003539 // Align the pair of semispaces to their size, which must be a power
3540 // of 2.
ager@chromium.orga1645e22009-09-09 19:27:10 +00003541 Address new_space_start =
ager@chromium.org3811b432009-10-28 14:53:37 +00003542 RoundUp(reinterpret_cast<byte*>(chunk), 2 * reserved_semispace_size_);
3543 if (!new_space_.Setup(new_space_start, 2 * reserved_semispace_size_)) {
3544 return false;
3545 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003546
ager@chromium.orga1645e22009-09-09 19:27:10 +00003547 // Initialize old pointer space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003548 old_pointer_space_ =
ager@chromium.org3811b432009-10-28 14:53:37 +00003549 new OldSpace(max_old_generation_size_, OLD_POINTER_SPACE, NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003550 if (old_pointer_space_ == NULL) return false;
ager@chromium.orga1645e22009-09-09 19:27:10 +00003551 if (!old_pointer_space_->Setup(NULL, 0)) return false;
3552
3553 // Initialize old data space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003554 old_data_space_ =
ager@chromium.org3811b432009-10-28 14:53:37 +00003555 new OldSpace(max_old_generation_size_, OLD_DATA_SPACE, NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003556 if (old_data_space_ == NULL) return false;
ager@chromium.orga1645e22009-09-09 19:27:10 +00003557 if (!old_data_space_->Setup(NULL, 0)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003558
3559 // Initialize the code space, set its maximum capacity to the old
kasper.lund7276f142008-07-30 08:49:36 +00003560 // generation size. It needs executable memory.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003561 // On 64-bit platform(s), we put all code objects in a 2 GB range of
3562 // virtual address space, so that they can call each other with near calls.
3563 if (code_range_size_ > 0) {
3564 if (!CodeRange::Setup(code_range_size_)) {
3565 return false;
3566 }
3567 }
3568
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003569 code_space_ =
ager@chromium.org3811b432009-10-28 14:53:37 +00003570 new OldSpace(max_old_generation_size_, CODE_SPACE, EXECUTABLE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003571 if (code_space_ == NULL) return false;
ager@chromium.orga1645e22009-09-09 19:27:10 +00003572 if (!code_space_->Setup(NULL, 0)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003573
3574 // Initialize map space.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003575 map_space_ = new MapSpace(FLAG_use_big_map_space
3576 ? max_old_generation_size_
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +00003577 : MapSpace::kMaxMapPageIndex * Page::kPageSize,
3578 FLAG_max_map_space_pages,
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003579 MAP_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003580 if (map_space_ == NULL) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003581 if (!map_space_->Setup(NULL, 0)) return false;
3582
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003583 // Initialize global property cell space.
ager@chromium.org3811b432009-10-28 14:53:37 +00003584 cell_space_ = new CellSpace(max_old_generation_size_, CELL_SPACE);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003585 if (cell_space_ == NULL) return false;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003586 if (!cell_space_->Setup(NULL, 0)) return false;
3587
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003588 // The large object code space may contain code or data. We set the memory
3589 // to be non-executable here for safety, but this means we need to enable it
3590 // explicitly when allocating large code objects.
3591 lo_space_ = new LargeObjectSpace(LO_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003592 if (lo_space_ == NULL) return false;
3593 if (!lo_space_->Setup()) return false;
3594
3595 if (create_heap_objects) {
3596 // Create initial maps.
3597 if (!CreateInitialMaps()) return false;
3598 if (!CreateApiObjects()) return false;
3599
3600 // Create initial objects
3601 if (!CreateInitialObjects()) return false;
3602 }
3603
3604 LOG(IntEvent("heap-capacity", Capacity()));
3605 LOG(IntEvent("heap-available", Available()));
3606
ager@chromium.org3811b432009-10-28 14:53:37 +00003607#ifdef ENABLE_LOGGING_AND_PROFILING
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003608 // This should be called only after initial objects have been created.
3609 ProducerHeapProfile::Setup();
ager@chromium.org3811b432009-10-28 14:53:37 +00003610#endif
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003611
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003612 return true;
3613}
3614
3615
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003616void Heap::SetStackLimits() {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003617 // On 64 bit machines, pointers are generally out of range of Smis. We write
3618 // something that looks like an out of range Smi to the GC.
3619
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003620 // Set up the special root array entries containing the stack limits.
3621 // These are actually addresses, but the tag makes the GC ignore it.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003622 roots_[kStackLimitRootIndex] =
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003623 reinterpret_cast<Object*>(
3624 (StackGuard::jslimit() & ~kSmiTagMask) | kSmiTag);
3625 roots_[kRealStackLimitRootIndex] =
3626 reinterpret_cast<Object*>(
3627 (StackGuard::real_jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003628}
3629
3630
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003631void Heap::TearDown() {
3632 GlobalHandles::TearDown();
3633
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00003634 ExternalStringTable::TearDown();
3635
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003636 new_space_.TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003637
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003638 if (old_pointer_space_ != NULL) {
3639 old_pointer_space_->TearDown();
3640 delete old_pointer_space_;
3641 old_pointer_space_ = NULL;
3642 }
3643
3644 if (old_data_space_ != NULL) {
3645 old_data_space_->TearDown();
3646 delete old_data_space_;
3647 old_data_space_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003648 }
3649
3650 if (code_space_ != NULL) {
3651 code_space_->TearDown();
3652 delete code_space_;
3653 code_space_ = NULL;
3654 }
3655
3656 if (map_space_ != NULL) {
3657 map_space_->TearDown();
3658 delete map_space_;
3659 map_space_ = NULL;
3660 }
3661
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003662 if (cell_space_ != NULL) {
3663 cell_space_->TearDown();
3664 delete cell_space_;
3665 cell_space_ = NULL;
3666 }
3667
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003668 if (lo_space_ != NULL) {
3669 lo_space_->TearDown();
3670 delete lo_space_;
3671 lo_space_ = NULL;
3672 }
3673
3674 MemoryAllocator::TearDown();
3675}
3676
3677
3678void Heap::Shrink() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003679 // Try to shrink all paged spaces.
3680 PagedSpaces spaces;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003681 for (PagedSpace* space = spaces.next(); space != NULL; space = spaces.next())
3682 space->Shrink();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003683}
3684
3685
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +00003686#ifdef ENABLE_HEAP_PROTECTION
3687
3688void Heap::Protect() {
ager@chromium.org71daaf62009-04-01 07:22:49 +00003689 if (HasBeenSetup()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003690 AllSpaces spaces;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003691 for (Space* space = spaces.next(); space != NULL; space = spaces.next())
3692 space->Protect();
ager@chromium.org71daaf62009-04-01 07:22:49 +00003693 }
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +00003694}
3695
3696
3697void Heap::Unprotect() {
ager@chromium.org71daaf62009-04-01 07:22:49 +00003698 if (HasBeenSetup()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003699 AllSpaces spaces;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003700 for (Space* space = spaces.next(); space != NULL; space = spaces.next())
3701 space->Unprotect();
ager@chromium.org71daaf62009-04-01 07:22:49 +00003702 }
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +00003703}
3704
3705#endif
3706
3707
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003708#ifdef DEBUG
3709
3710class PrintHandleVisitor: public ObjectVisitor {
3711 public:
3712 void VisitPointers(Object** start, Object** end) {
3713 for (Object** p = start; p < end; p++)
3714 PrintF(" handle %p to %p\n", p, *p);
3715 }
3716};
3717
3718void Heap::PrintHandles() {
3719 PrintF("Handles:\n");
3720 PrintHandleVisitor v;
3721 HandleScopeImplementer::Iterate(&v);
3722}
3723
3724#endif
3725
3726
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003727Space* AllSpaces::next() {
3728 switch (counter_++) {
3729 case NEW_SPACE:
3730 return Heap::new_space();
3731 case OLD_POINTER_SPACE:
3732 return Heap::old_pointer_space();
3733 case OLD_DATA_SPACE:
3734 return Heap::old_data_space();
3735 case CODE_SPACE:
3736 return Heap::code_space();
3737 case MAP_SPACE:
3738 return Heap::map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003739 case CELL_SPACE:
3740 return Heap::cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003741 case LO_SPACE:
3742 return Heap::lo_space();
3743 default:
3744 return NULL;
3745 }
3746}
3747
3748
3749PagedSpace* PagedSpaces::next() {
3750 switch (counter_++) {
3751 case OLD_POINTER_SPACE:
3752 return Heap::old_pointer_space();
3753 case OLD_DATA_SPACE:
3754 return Heap::old_data_space();
3755 case CODE_SPACE:
3756 return Heap::code_space();
3757 case MAP_SPACE:
3758 return Heap::map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003759 case CELL_SPACE:
3760 return Heap::cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003761 default:
3762 return NULL;
3763 }
3764}
3765
3766
3767
3768OldSpace* OldSpaces::next() {
3769 switch (counter_++) {
3770 case OLD_POINTER_SPACE:
3771 return Heap::old_pointer_space();
3772 case OLD_DATA_SPACE:
3773 return Heap::old_data_space();
3774 case CODE_SPACE:
3775 return Heap::code_space();
3776 default:
3777 return NULL;
3778 }
3779}
3780
3781
kasper.lund7276f142008-07-30 08:49:36 +00003782SpaceIterator::SpaceIterator() : current_space_(FIRST_SPACE), iterator_(NULL) {
3783}
3784
3785
3786SpaceIterator::~SpaceIterator() {
3787 // Delete active iterator if any.
3788 delete iterator_;
3789}
3790
3791
3792bool SpaceIterator::has_next() {
3793 // Iterate until no more spaces.
3794 return current_space_ != LAST_SPACE;
3795}
3796
3797
3798ObjectIterator* SpaceIterator::next() {
3799 if (iterator_ != NULL) {
3800 delete iterator_;
3801 iterator_ = NULL;
3802 // Move to the next space
3803 current_space_++;
3804 if (current_space_ > LAST_SPACE) {
3805 return NULL;
3806 }
3807 }
3808
3809 // Return iterator for the new current space.
3810 return CreateIterator();
3811}
3812
3813
3814// Create an iterator for the space to iterate.
3815ObjectIterator* SpaceIterator::CreateIterator() {
3816 ASSERT(iterator_ == NULL);
3817
3818 switch (current_space_) {
3819 case NEW_SPACE:
3820 iterator_ = new SemiSpaceIterator(Heap::new_space());
3821 break;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003822 case OLD_POINTER_SPACE:
3823 iterator_ = new HeapObjectIterator(Heap::old_pointer_space());
3824 break;
3825 case OLD_DATA_SPACE:
3826 iterator_ = new HeapObjectIterator(Heap::old_data_space());
kasper.lund7276f142008-07-30 08:49:36 +00003827 break;
3828 case CODE_SPACE:
3829 iterator_ = new HeapObjectIterator(Heap::code_space());
3830 break;
3831 case MAP_SPACE:
3832 iterator_ = new HeapObjectIterator(Heap::map_space());
3833 break;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003834 case CELL_SPACE:
3835 iterator_ = new HeapObjectIterator(Heap::cell_space());
3836 break;
kasper.lund7276f142008-07-30 08:49:36 +00003837 case LO_SPACE:
3838 iterator_ = new LargeObjectIterator(Heap::lo_space());
3839 break;
3840 }
3841
3842 // Return the newly allocated iterator;
3843 ASSERT(iterator_ != NULL);
3844 return iterator_;
3845}
3846
3847
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003848HeapIterator::HeapIterator() {
3849 Init();
3850}
3851
3852
3853HeapIterator::~HeapIterator() {
3854 Shutdown();
3855}
3856
3857
3858void HeapIterator::Init() {
3859 // Start the iteration.
3860 space_iterator_ = new SpaceIterator();
3861 object_iterator_ = space_iterator_->next();
3862}
3863
3864
3865void HeapIterator::Shutdown() {
3866 // Make sure the last iterator is deallocated.
3867 delete space_iterator_;
3868 space_iterator_ = NULL;
3869 object_iterator_ = NULL;
3870}
3871
3872
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003873HeapObject* HeapIterator::next() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003874 // No iterator means we are done.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003875 if (object_iterator_ == NULL) return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003876
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003877 if (HeapObject* obj = object_iterator_->next_object()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003878 // If the current iterator has more objects we are fine.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003879 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003880 } else {
3881 // Go though the spaces looking for one that has objects.
3882 while (space_iterator_->has_next()) {
3883 object_iterator_ = space_iterator_->next();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003884 if (HeapObject* obj = object_iterator_->next_object()) {
3885 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003886 }
3887 }
3888 }
3889 // Done with the last space.
3890 object_iterator_ = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003891 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003892}
3893
3894
3895void HeapIterator::reset() {
3896 // Restart the iterator.
3897 Shutdown();
3898 Init();
3899}
3900
3901
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003902#ifdef DEBUG
3903
3904static bool search_for_any_global;
3905static Object* search_target;
3906static bool found_target;
3907static List<Object*> object_stack(20);
3908
3909
3910// Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject.
3911static const int kMarkTag = 2;
3912
3913static void MarkObjectRecursively(Object** p);
3914class MarkObjectVisitor : public ObjectVisitor {
3915 public:
3916 void VisitPointers(Object** start, Object** end) {
3917 // Copy all HeapObject pointers in [start, end)
3918 for (Object** p = start; p < end; p++) {
3919 if ((*p)->IsHeapObject())
3920 MarkObjectRecursively(p);
3921 }
3922 }
3923};
3924
3925static MarkObjectVisitor mark_visitor;
3926
3927static void MarkObjectRecursively(Object** p) {
3928 if (!(*p)->IsHeapObject()) return;
3929
3930 HeapObject* obj = HeapObject::cast(*p);
3931
3932 Object* map = obj->map();
3933
3934 if (!map->IsHeapObject()) return; // visited before
3935
3936 if (found_target) return; // stop if target found
3937 object_stack.Add(obj);
3938 if ((search_for_any_global && obj->IsJSGlobalObject()) ||
3939 (!search_for_any_global && (obj == search_target))) {
3940 found_target = true;
3941 return;
3942 }
3943
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003944 // not visited yet
3945 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
3946
3947 Address map_addr = map_p->address();
3948
3949 obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag));
3950
3951 MarkObjectRecursively(&map);
3952
3953 obj->IterateBody(map_p->instance_type(), obj->SizeFromMap(map_p),
3954 &mark_visitor);
3955
3956 if (!found_target) // don't pop if found the target
3957 object_stack.RemoveLast();
3958}
3959
3960
3961static void UnmarkObjectRecursively(Object** p);
3962class UnmarkObjectVisitor : public ObjectVisitor {
3963 public:
3964 void VisitPointers(Object** start, Object** end) {
3965 // Copy all HeapObject pointers in [start, end)
3966 for (Object** p = start; p < end; p++) {
3967 if ((*p)->IsHeapObject())
3968 UnmarkObjectRecursively(p);
3969 }
3970 }
3971};
3972
3973static UnmarkObjectVisitor unmark_visitor;
3974
3975static void UnmarkObjectRecursively(Object** p) {
3976 if (!(*p)->IsHeapObject()) return;
3977
3978 HeapObject* obj = HeapObject::cast(*p);
3979
3980 Object* map = obj->map();
3981
3982 if (map->IsHeapObject()) return; // unmarked already
3983
3984 Address map_addr = reinterpret_cast<Address>(map);
3985
3986 map_addr -= kMarkTag;
3987
3988 ASSERT_TAG_ALIGNED(map_addr);
3989
3990 HeapObject* map_p = HeapObject::FromAddress(map_addr);
3991
3992 obj->set_map(reinterpret_cast<Map*>(map_p));
3993
3994 UnmarkObjectRecursively(reinterpret_cast<Object**>(&map_p));
3995
3996 obj->IterateBody(Map::cast(map_p)->instance_type(),
3997 obj->SizeFromMap(Map::cast(map_p)),
3998 &unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003999}
4000
4001
4002static void MarkRootObjectRecursively(Object** root) {
4003 if (search_for_any_global) {
4004 ASSERT(search_target == NULL);
4005 } else {
4006 ASSERT(search_target->IsHeapObject());
4007 }
4008 found_target = false;
4009 object_stack.Clear();
4010
4011 MarkObjectRecursively(root);
4012 UnmarkObjectRecursively(root);
4013
4014 if (found_target) {
4015 PrintF("=====================================\n");
4016 PrintF("==== Path to object ====\n");
4017 PrintF("=====================================\n\n");
4018
4019 ASSERT(!object_stack.is_empty());
4020 for (int i = 0; i < object_stack.length(); i++) {
4021 if (i > 0) PrintF("\n |\n |\n V\n\n");
4022 Object* obj = object_stack[i];
4023 obj->Print();
4024 }
4025 PrintF("=====================================\n");
4026 }
4027}
4028
4029
4030// Helper class for visiting HeapObjects recursively.
4031class MarkRootVisitor: public ObjectVisitor {
4032 public:
4033 void VisitPointers(Object** start, Object** end) {
4034 // Visit all HeapObject pointers in [start, end)
4035 for (Object** p = start; p < end; p++) {
4036 if ((*p)->IsHeapObject())
4037 MarkRootObjectRecursively(p);
4038 }
4039 }
4040};
4041
4042
4043// Triggers a depth-first traversal of reachable objects from roots
4044// and finds a path to a specific heap object and prints it.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00004045void Heap::TracePathToObject(Object* target) {
4046 search_target = target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004047 search_for_any_global = false;
4048
4049 MarkRootVisitor root_visitor;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004050 IterateRoots(&root_visitor, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004051}
4052
4053
4054// Triggers a depth-first traversal of reachable objects from roots
4055// and finds a path to any global object and prints it. Useful for
4056// determining the source for leaks of global objects.
4057void Heap::TracePathToGlobal() {
4058 search_target = NULL;
4059 search_for_any_global = true;
4060
4061 MarkRootVisitor root_visitor;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004062 IterateRoots(&root_visitor, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063}
4064#endif
4065
4066
kasper.lund7276f142008-07-30 08:49:36 +00004067GCTracer::GCTracer()
4068 : start_time_(0.0),
4069 start_size_(0.0),
4070 gc_count_(0),
4071 full_gc_count_(0),
4072 is_compacting_(false),
4073 marked_count_(0) {
4074 // These two fields reflect the state of the previous full collection.
4075 // Set them before they are changed by the collector.
4076 previous_has_compacted_ = MarkCompactCollector::HasCompacted();
4077 previous_marked_count_ = MarkCompactCollector::previous_marked_count();
4078 if (!FLAG_trace_gc) return;
4079 start_time_ = OS::TimeCurrentMillis();
4080 start_size_ = SizeOfHeapObjects();
4081}
4082
4083
4084GCTracer::~GCTracer() {
4085 if (!FLAG_trace_gc) return;
4086 // Printf ONE line iff flag is set.
4087 PrintF("%s %.1f -> %.1f MB, %d ms.\n",
4088 CollectorString(),
4089 start_size_, SizeOfHeapObjects(),
4090 static_cast<int>(OS::TimeCurrentMillis() - start_time_));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00004091
4092#if defined(ENABLE_LOGGING_AND_PROFILING)
4093 Heap::PrintShortHeapStatistics();
4094#endif
kasper.lund7276f142008-07-30 08:49:36 +00004095}
4096
4097
4098const char* GCTracer::CollectorString() {
4099 switch (collector_) {
4100 case SCAVENGER:
4101 return "Scavenge";
4102 case MARK_COMPACTOR:
4103 return MarkCompactCollector::HasCompacted() ? "Mark-compact"
4104 : "Mark-sweep";
4105 }
4106 return "Unknown GC";
4107}
4108
4109
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004110int KeyedLookupCache::Hash(Map* map, String* name) {
4111 // Uses only lower 32 bits if pointers are larger.
4112 uintptr_t addr_hash =
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00004113 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift;
4114 return (addr_hash ^ name->Hash()) & kCapacityMask;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004115}
4116
4117
4118int KeyedLookupCache::Lookup(Map* map, String* name) {
4119 int index = Hash(map, name);
4120 Key& key = keys_[index];
4121 if ((key.map == map) && key.name->Equals(name)) {
4122 return field_offsets_[index];
4123 }
4124 return -1;
4125}
4126
4127
4128void KeyedLookupCache::Update(Map* map, String* name, int field_offset) {
4129 String* symbol;
4130 if (Heap::LookupSymbolIfExists(name, &symbol)) {
4131 int index = Hash(map, symbol);
4132 Key& key = keys_[index];
4133 key.map = map;
4134 key.name = symbol;
4135 field_offsets_[index] = field_offset;
4136 }
4137}
4138
4139
4140void KeyedLookupCache::Clear() {
4141 for (int index = 0; index < kLength; index++) keys_[index].map = NULL;
4142}
4143
4144
4145KeyedLookupCache::Key KeyedLookupCache::keys_[KeyedLookupCache::kLength];
4146
4147
4148int KeyedLookupCache::field_offsets_[KeyedLookupCache::kLength];
4149
4150
4151void DescriptorLookupCache::Clear() {
4152 for (int index = 0; index < kLength; index++) keys_[index].array = NULL;
4153}
4154
4155
4156DescriptorLookupCache::Key
4157DescriptorLookupCache::keys_[DescriptorLookupCache::kLength];
4158
4159int DescriptorLookupCache::results_[DescriptorLookupCache::kLength];
4160
4161
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004162#ifdef DEBUG
4163bool Heap::GarbageCollectionGreedyCheck() {
4164 ASSERT(FLAG_gc_greedy);
4165 if (Bootstrapper::IsActive()) return true;
4166 if (disallow_allocation_failure()) return true;
4167 return CollectGarbage(0, NEW_SPACE);
4168}
4169#endif
4170
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004171
4172TranscendentalCache::TranscendentalCache(TranscendentalCache::Type t)
4173 : type_(t) {
4174 uint32_t in0 = 0xffffffffu; // Bit-pattern for a NaN that isn't
4175 uint32_t in1 = 0xffffffffu; // generated by the FPU.
4176 for (int i = 0; i < kCacheSize; i++) {
4177 elements_[i].in[0] = in0;
4178 elements_[i].in[1] = in1;
4179 elements_[i].output = NULL;
4180 }
4181}
4182
4183
4184TranscendentalCache* TranscendentalCache::caches_[kNumberOfCaches];
4185
4186
4187void TranscendentalCache::Clear() {
4188 for (int i = 0; i < kNumberOfCaches; i++) {
4189 if (caches_[i] != NULL) {
4190 delete caches_[i];
4191 caches_[i] = NULL;
4192 }
4193 }
4194}
4195
4196
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00004197void ExternalStringTable::CleanUp() {
4198 int last = 0;
4199 for (int i = 0; i < new_space_strings_.length(); ++i) {
4200 if (new_space_strings_[i] == Heap::raw_unchecked_null_value()) continue;
4201 if (Heap::InNewSpace(new_space_strings_[i])) {
4202 new_space_strings_[last++] = new_space_strings_[i];
4203 } else {
4204 old_space_strings_.Add(new_space_strings_[i]);
4205 }
4206 }
4207 new_space_strings_.Rewind(last);
4208 last = 0;
4209 for (int i = 0; i < old_space_strings_.length(); ++i) {
4210 if (old_space_strings_[i] == Heap::raw_unchecked_null_value()) continue;
4211 ASSERT(!Heap::InNewSpace(old_space_strings_[i]));
4212 old_space_strings_[last++] = old_space_strings_[i];
4213 }
4214 old_space_strings_.Rewind(last);
4215 Verify();
4216}
4217
4218
4219void ExternalStringTable::TearDown() {
4220 new_space_strings_.Free();
4221 old_space_strings_.Free();
4222}
4223
4224
4225List<Object*> ExternalStringTable::new_space_strings_;
4226List<Object*> ExternalStringTable::old_space_strings_;
4227
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004228} } // namespace v8::internal