blob: 7e73eae69831aaf8a8c3edc418997b5119d3f3a3 [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"
36#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "mark-compact.h"
38#include "natives.h"
39#include "scanner.h"
40#include "scopeinfo.h"
41#include "v8threads.h"
42
kasperl@chromium.org71affb52009-05-26 05:44:31 +000043namespace v8 {
44namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046
ager@chromium.org3b45ab52009-03-19 22:21:34 +000047String* Heap::hidden_symbol_;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000048Object* Heap::roots_[Heap::kRootListLength];
49
ager@chromium.org3b45ab52009-03-19 22:21:34 +000050
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000051NewSpace Heap::new_space_;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000052OldSpace* Heap::old_pointer_space_ = NULL;
53OldSpace* Heap::old_data_space_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054OldSpace* Heap::code_space_ = NULL;
55MapSpace* Heap::map_space_ = NULL;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000056CellSpace* Heap::cell_space_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057LargeObjectSpace* Heap::lo_space_ = NULL;
58
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000059static const int kMinimumPromotionLimit = 2*MB;
60static const int kMinimumAllocationLimit = 8*MB;
61
62int Heap::old_gen_promotion_limit_ = kMinimumPromotionLimit;
63int Heap::old_gen_allocation_limit_ = kMinimumAllocationLimit;
64
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065int Heap::old_gen_exhausted_ = false;
66
kasper.lund7276f142008-07-30 08:49:36 +000067int Heap::amount_of_external_allocated_memory_ = 0;
68int Heap::amount_of_external_allocated_memory_at_last_global_gc_ = 0;
69
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000070// semispace_size_ should be a power of 2 and old_generation_size_ should be
71// a multiple of Page::kPageSize.
kasperl@chromium.orge959c182009-07-27 08:59:04 +000072#if defined(ANDROID)
ager@chromium.orgeadaf222009-06-16 09:43:10 +000073int Heap::semispace_size_ = 512*KB;
74int Heap::old_generation_size_ = 128*MB;
75int Heap::initial_semispace_size_ = 128*KB;
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +000076#elif defined(V8_TARGET_ARCH_X64)
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000077int Heap::semispace_size_ = 8*MB;
78int Heap::old_generation_size_ = 1*GB;
79int Heap::initial_semispace_size_ = 1*MB;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000080#else
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +000081int Heap::semispace_size_ = 4*MB;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000082int Heap::old_generation_size_ = 512*MB;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000083int Heap::initial_semispace_size_ = 512*KB;
84#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000085
86GCCallback Heap::global_gc_prologue_callback_ = NULL;
87GCCallback Heap::global_gc_epilogue_callback_ = NULL;
88
89// Variables set based on semispace_size_ and old_generation_size_ in
90// ConfigureHeap.
91int Heap::young_generation_size_ = 0; // Will be 2 * semispace_size_.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000092int Heap::survived_since_last_expansion_ = 0;
kasperl@chromium.orge959c182009-07-27 08:59:04 +000093int Heap::external_allocation_limit_ = 0;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000094
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000095Heap::HeapState Heap::gc_state_ = NOT_IN_GC;
96
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097int Heap::mc_count_ = 0;
98int Heap::gc_count_ = 0;
99
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000100int Heap::always_allocate_scope_depth_ = 0;
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000101bool Heap::context_disposed_pending_ = false;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000102
kasper.lund7276f142008-07-30 08:49:36 +0000103#ifdef DEBUG
104bool Heap::allocation_allowed_ = true;
105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000106int Heap::allocation_timeout_ = 0;
107bool Heap::disallow_allocation_failure_ = false;
108#endif // DEBUG
109
110
111int Heap::Capacity() {
112 if (!HasBeenSetup()) return 0;
113
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000114 return new_space_.Capacity() +
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000115 old_pointer_space_->Capacity() +
116 old_data_space_->Capacity() +
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000117 code_space_->Capacity() +
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000118 map_space_->Capacity() +
119 cell_space_->Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000120}
121
122
123int Heap::Available() {
124 if (!HasBeenSetup()) return 0;
125
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000126 return new_space_.Available() +
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000127 old_pointer_space_->Available() +
128 old_data_space_->Available() +
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000129 code_space_->Available() +
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000130 map_space_->Available() +
131 cell_space_->Available();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000132}
133
134
135bool Heap::HasBeenSetup() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000136 return old_pointer_space_ != NULL &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000137 old_data_space_ != NULL &&
138 code_space_ != NULL &&
139 map_space_ != NULL &&
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000140 cell_space_ != NULL &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000141 lo_space_ != NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000142}
143
144
145GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) {
146 // Is global GC requested?
147 if (space != NEW_SPACE || FLAG_gc_global) {
148 Counters::gc_compactor_caused_by_request.Increment();
149 return MARK_COMPACTOR;
150 }
151
152 // Is enough data promoted to justify a global GC?
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000153 if (OldGenerationPromotionLimitReached()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000154 Counters::gc_compactor_caused_by_promoted_data.Increment();
155 return MARK_COMPACTOR;
156 }
157
158 // Have allocation in OLD and LO failed?
159 if (old_gen_exhausted_) {
160 Counters::gc_compactor_caused_by_oldspace_exhaustion.Increment();
161 return MARK_COMPACTOR;
162 }
163
164 // Is there enough space left in OLD to guarantee that a scavenge can
165 // succeed?
166 //
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000167 // Note that MemoryAllocator->MaxAvailable() undercounts the memory available
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000168 // for object promotion. It counts only the bytes that the memory
169 // allocator has not yet allocated from the OS and assigned to any space,
170 // and does not count available bytes already in the old space or code
171 // space. Undercounting is safe---we may get an unrequested full GC when
172 // a scavenge would have succeeded.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000173 if (MemoryAllocator::MaxAvailable() <= new_space_.Size()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000174 Counters::gc_compactor_caused_by_oldspace_exhaustion.Increment();
175 return MARK_COMPACTOR;
176 }
177
178 // Default
179 return SCAVENGER;
180}
181
182
183// TODO(1238405): Combine the infrastructure for --heap-stats and
184// --log-gc to avoid the complicated preprocessor and flag testing.
185#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
186void Heap::ReportStatisticsBeforeGC() {
187 // Heap::ReportHeapStatistics will also log NewSpace statistics when
188 // compiled with ENABLE_LOGGING_AND_PROFILING and --log-gc is set. The
189 // following logic is used to avoid double logging.
190#if defined(DEBUG) && defined(ENABLE_LOGGING_AND_PROFILING)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000191 if (FLAG_heap_stats || FLAG_log_gc) new_space_.CollectStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000192 if (FLAG_heap_stats) {
193 ReportHeapStatistics("Before GC");
194 } else if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000195 new_space_.ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000196 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000197 if (FLAG_heap_stats || FLAG_log_gc) new_space_.ClearHistograms();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000198#elif defined(DEBUG)
199 if (FLAG_heap_stats) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000200 new_space_.CollectStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000201 ReportHeapStatistics("Before GC");
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000202 new_space_.ClearHistograms();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000203 }
204#elif defined(ENABLE_LOGGING_AND_PROFILING)
205 if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000206 new_space_.CollectStatistics();
207 new_space_.ReportStatistics();
208 new_space_.ClearHistograms();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000209 }
210#endif
211}
212
213
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000214#if defined(ENABLE_LOGGING_AND_PROFILING)
215void Heap::PrintShortHeapStatistics() {
216 if (!FLAG_trace_gc_verbose) return;
217 PrintF("Memory allocator, used: %8d, available: %8d\n",
218 MemoryAllocator::Size(), MemoryAllocator::Available());
219 PrintF("New space, used: %8d, available: %8d\n",
220 Heap::new_space_.Size(), new_space_.Available());
221 PrintF("Old pointers, used: %8d, available: %8d\n",
222 old_pointer_space_->Size(), old_pointer_space_->Available());
223 PrintF("Old data space, used: %8d, available: %8d\n",
224 old_data_space_->Size(), old_data_space_->Available());
225 PrintF("Code space, used: %8d, available: %8d\n",
226 code_space_->Size(), code_space_->Available());
227 PrintF("Map space, used: %8d, available: %8d\n",
228 map_space_->Size(), map_space_->Available());
229 PrintF("Large object space, used: %8d, avaialble: %8d\n",
230 lo_space_->Size(), lo_space_->Available());
231}
232#endif
233
234
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235// TODO(1238405): Combine the infrastructure for --heap-stats and
236// --log-gc to avoid the complicated preprocessor and flag testing.
237void Heap::ReportStatisticsAfterGC() {
238 // Similar to the before GC, we use some complicated logic to ensure that
239 // NewSpace statistics are logged exactly once when --log-gc is turned on.
240#if defined(DEBUG) && defined(ENABLE_LOGGING_AND_PROFILING)
241 if (FLAG_heap_stats) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000242 new_space_.CollectStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000243 ReportHeapStatistics("After GC");
244 } else if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000245 new_space_.ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000246 }
247#elif defined(DEBUG)
248 if (FLAG_heap_stats) ReportHeapStatistics("After GC");
249#elif defined(ENABLE_LOGGING_AND_PROFILING)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000250 if (FLAG_log_gc) new_space_.ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000251#endif
252}
253#endif // defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
254
255
256void Heap::GarbageCollectionPrologue() {
kasper.lund7276f142008-07-30 08:49:36 +0000257 gc_count_++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000258#ifdef DEBUG
259 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
260 allow_allocation(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000261
262 if (FLAG_verify_heap) {
263 Verify();
264 }
265
266 if (FLAG_gc_verbose) Print();
267
268 if (FLAG_print_rset) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000269 // Not all spaces have remembered set bits that we care about.
270 old_pointer_space_->PrintRSet();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000271 map_space_->PrintRSet();
272 lo_space_->PrintRSet();
273 }
274#endif
275
276#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
277 ReportStatisticsBeforeGC();
278#endif
279}
280
281int Heap::SizeOfObjects() {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000282 int total = 0;
283 AllSpaces spaces;
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000284 while (Space* space = spaces.next()) {
285 total += space->Size();
286 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000287 return total;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000288}
289
290void Heap::GarbageCollectionEpilogue() {
291#ifdef DEBUG
292 allow_allocation(true);
293 ZapFromSpace();
294
295 if (FLAG_verify_heap) {
296 Verify();
297 }
298
299 if (FLAG_print_global_handles) GlobalHandles::Print();
300 if (FLAG_print_handles) PrintHandles();
301 if (FLAG_gc_verbose) Print();
302 if (FLAG_code_stats) ReportCodeStatistics("After GC");
303#endif
304
305 Counters::alive_after_last_gc.Set(SizeOfObjects());
306
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000307 Counters::symbol_table_capacity.Set(symbol_table()->Capacity());
308 Counters::number_of_symbols.Set(symbol_table()->NumberOfElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
310 ReportStatisticsAfterGC();
311#endif
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000312#ifdef ENABLE_DEBUGGER_SUPPORT
313 Debug::AfterGarbageCollection();
314#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000315}
316
317
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000318void Heap::CollectAllGarbage(bool force_compaction) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000319 // Since we are ignoring the return value, the exact choice of space does
320 // not matter, so long as we do not specify NEW_SPACE, which would not
321 // cause a full GC.
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000322 MarkCompactCollector::SetForceCompaction(force_compaction);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000323 CollectGarbage(0, OLD_POINTER_SPACE);
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000324 MarkCompactCollector::SetForceCompaction(false);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000325}
326
327
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000328void Heap::CollectAllGarbageIfContextDisposed() {
kasperl@chromium.orgd55d36b2009-03-05 08:03:28 +0000329 // If the garbage collector interface is exposed through the global
330 // gc() function, we avoid being clever about forcing GCs when
331 // contexts are disposed and leave it to the embedder to make
332 // informed decisions about when to force a collection.
333 if (!FLAG_expose_gc && context_disposed_pending_) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000334 HistogramTimerScope scope(&Counters::gc_context);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000335 CollectAllGarbage(false);
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000336 }
kasperl@chromium.orgd55d36b2009-03-05 08:03:28 +0000337 context_disposed_pending_ = false;
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000338}
339
340
341void Heap::NotifyContextDisposed() {
342 context_disposed_pending_ = true;
343}
344
345
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000346bool Heap::CollectGarbage(int requested_size, AllocationSpace space) {
347 // The VM is in the GC state until exiting this function.
348 VMState state(GC);
349
350#ifdef DEBUG
351 // Reset the allocation timeout to the GC interval, but make sure to
352 // allow at least a few allocations after a collection. The reason
353 // for this is that we have a lot of allocation sequences and we
354 // assume that a garbage collection will allow the subsequent
355 // allocation attempts to go through.
356 allocation_timeout_ = Max(6, FLAG_gc_interval);
357#endif
358
359 { GCTracer tracer;
360 GarbageCollectionPrologue();
kasper.lund7276f142008-07-30 08:49:36 +0000361 // The GC count was incremented in the prologue. Tell the tracer about
362 // it.
363 tracer.set_gc_count(gc_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000364
365 GarbageCollector collector = SelectGarbageCollector(space);
kasper.lund7276f142008-07-30 08:49:36 +0000366 // Tell the tracer which collector we've selected.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367 tracer.set_collector(collector);
368
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000369 HistogramTimer* rate = (collector == SCAVENGER)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000370 ? &Counters::gc_scavenger
371 : &Counters::gc_compactor;
372 rate->Start();
kasper.lund7276f142008-07-30 08:49:36 +0000373 PerformGarbageCollection(space, collector, &tracer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000374 rate->Stop();
375
376 GarbageCollectionEpilogue();
377 }
378
379
380#ifdef ENABLE_LOGGING_AND_PROFILING
381 if (FLAG_log_gc) HeapProfiler::WriteSample();
382#endif
383
384 switch (space) {
385 case NEW_SPACE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000386 return new_space_.Available() >= requested_size;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000387 case OLD_POINTER_SPACE:
388 return old_pointer_space_->Available() >= requested_size;
389 case OLD_DATA_SPACE:
390 return old_data_space_->Available() >= requested_size;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391 case CODE_SPACE:
392 return code_space_->Available() >= requested_size;
393 case MAP_SPACE:
394 return map_space_->Available() >= requested_size;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000395 case CELL_SPACE:
396 return cell_space_->Available() >= requested_size;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000397 case LO_SPACE:
398 return lo_space_->Available() >= requested_size;
399 }
400 return false;
401}
402
403
kasper.lund7276f142008-07-30 08:49:36 +0000404void Heap::PerformScavenge() {
405 GCTracer tracer;
406 PerformGarbageCollection(NEW_SPACE, SCAVENGER, &tracer);
407}
408
409
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000410#ifdef DEBUG
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000411// Helper class for verifying the symbol table.
412class SymbolTableVerifier : public ObjectVisitor {
413 public:
414 SymbolTableVerifier() { }
415 void VisitPointers(Object** start, Object** end) {
416 // Visit all HeapObject pointers in [start, end).
417 for (Object** p = start; p < end; p++) {
418 if ((*p)->IsHeapObject()) {
419 // Check that the symbol is actually a symbol.
420 ASSERT((*p)->IsNull() || (*p)->IsUndefined() || (*p)->IsSymbol());
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000421 }
422 }
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000423 }
424};
425#endif // DEBUG
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000426
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000427
428static void VerifySymbolTable() {
429#ifdef DEBUG
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000430 SymbolTableVerifier verifier;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000431 Heap::symbol_table()->IterateElements(&verifier);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000432#endif // DEBUG
433}
434
435
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000436void Heap::EnsureFromSpaceIsCommitted() {
437 if (new_space_.CommitFromSpaceIfNeeded()) return;
438
439 // Committing memory to from space failed.
440 // Try shrinking and try again.
441 Shrink();
442 if (new_space_.CommitFromSpaceIfNeeded()) return;
443
444 // Committing memory to from space failed again.
445 // Memory is exhausted and we will die.
446 V8::FatalProcessOutOfMemory("Committing semi space failed.");
447}
448
449
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000450void Heap::PerformGarbageCollection(AllocationSpace space,
kasper.lund7276f142008-07-30 08:49:36 +0000451 GarbageCollector collector,
452 GCTracer* tracer) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000453 VerifySymbolTable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000454 if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) {
455 ASSERT(!allocation_allowed_);
456 global_gc_prologue_callback_();
457 }
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000458 EnsureFromSpaceIsCommitted();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000459 if (collector == MARK_COMPACTOR) {
kasper.lund7276f142008-07-30 08:49:36 +0000460 MarkCompact(tracer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000461
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000462 int old_gen_size = PromotedSpaceSize();
463 old_gen_promotion_limit_ =
464 old_gen_size + Max(kMinimumPromotionLimit, old_gen_size / 3);
465 old_gen_allocation_limit_ =
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000466 old_gen_size + Max(kMinimumAllocationLimit, old_gen_size / 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000467 old_gen_exhausted_ = false;
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000468 } else {
469 Scavenge();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000470 }
471 Counters::objs_since_last_young.Set(0);
472
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000473 PostGarbageCollectionProcessing();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000474
kasper.lund7276f142008-07-30 08:49:36 +0000475 if (collector == MARK_COMPACTOR) {
476 // Register the amount of external allocated memory.
477 amount_of_external_allocated_memory_at_last_global_gc_ =
478 amount_of_external_allocated_memory_;
479 }
480
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000481 if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) {
482 ASSERT(!allocation_allowed_);
483 global_gc_epilogue_callback_();
484 }
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000485 VerifySymbolTable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000486}
487
488
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000489void Heap::PostGarbageCollectionProcessing() {
490 // Process weak handles post gc.
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000491 {
492 DisableAssertNoAllocation allow_allocation;
493 GlobalHandles::PostGarbageCollectionProcessing();
494 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000495 // Update flat string readers.
496 FlatStringReader::PostGarbageCollectionProcessing();
497}
498
499
kasper.lund7276f142008-07-30 08:49:36 +0000500void Heap::MarkCompact(GCTracer* tracer) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000501 gc_state_ = MARK_COMPACT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000502 mc_count_++;
kasper.lund7276f142008-07-30 08:49:36 +0000503 tracer->set_full_gc_count(mc_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000504 LOG(ResourceEvent("markcompact", "begin"));
505
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000506 MarkCompactCollector::Prepare(tracer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000507
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000508 bool is_compacting = MarkCompactCollector::IsCompacting();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000510 MarkCompactPrologue(is_compacting);
511
512 MarkCompactCollector::CollectGarbage();
513
514 MarkCompactEpilogue(is_compacting);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000515
516 LOG(ResourceEvent("markcompact", "end"));
517
518 gc_state_ = NOT_IN_GC;
519
520 Shrink();
521
522 Counters::objs_since_last_full.Set(0);
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000523 context_disposed_pending_ = false;
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000524
525 Scavenge();
526
527 // Shrink new space as much as possible after compacting full
528 // garbage collections.
529 if (is_compacting) new_space_.Shrink();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000530}
531
532
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000533void Heap::MarkCompactPrologue(bool is_compacting) {
534 // At any old GC clear the keyed lookup cache to enable collection of unused
535 // maps.
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000536 KeyedLookupCache::Clear();
537 ContextSlotCache::Clear();
538 DescriptorLookupCache::Clear();
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000539
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000540 CompilationCache::MarkCompactPrologue();
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000541
542 Top::MarkCompactPrologue(is_compacting);
543 ThreadManager::MarkCompactPrologue(is_compacting);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000544}
545
546
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000547void Heap::MarkCompactEpilogue(bool is_compacting) {
548 Top::MarkCompactEpilogue(is_compacting);
549 ThreadManager::MarkCompactEpilogue(is_compacting);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000550}
551
552
553Object* Heap::FindCodeObject(Address a) {
554 Object* obj = code_space_->FindObject(a);
555 if (obj->IsFailure()) {
556 obj = lo_space_->FindObject(a);
557 }
kasper.lund7276f142008-07-30 08:49:36 +0000558 ASSERT(!obj->IsFailure());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559 return obj;
560}
561
562
563// Helper class for copying HeapObjects
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000564class ScavengeVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000565 public:
566
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000567 void VisitPointer(Object** p) { ScavengePointer(p); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568
569 void VisitPointers(Object** start, Object** end) {
570 // Copy all HeapObject pointers in [start, end)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000571 for (Object** p = start; p < end; p++) ScavengePointer(p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000572 }
573
574 private:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000575 void ScavengePointer(Object** p) {
576 Object* object = *p;
577 if (!Heap::InNewSpace(object)) return;
578 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
579 reinterpret_cast<HeapObject*>(object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000580 }
581};
582
583
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000584// A queue of pointers and maps of to-be-promoted objects during a
585// scavenge collection.
586class PromotionQueue {
587 public:
588 void Initialize(Address start_address) {
589 front_ = rear_ = reinterpret_cast<HeapObject**>(start_address);
590 }
591
592 bool is_empty() { return front_ <= rear_; }
593
594 void insert(HeapObject* object, Map* map) {
595 *(--rear_) = object;
596 *(--rear_) = map;
597 // Assert no overflow into live objects.
598 ASSERT(reinterpret_cast<Address>(rear_) >= Heap::new_space()->top());
599 }
600
601 void remove(HeapObject** object, Map** map) {
602 *object = *(--front_);
603 *map = Map::cast(*(--front_));
604 // Assert no underflow.
605 ASSERT(front_ >= rear_);
606 }
607
608 private:
609 // The front of the queue is higher in memory than the rear.
610 HeapObject** front_;
611 HeapObject** rear_;
612};
613
614
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000615// Shared state read by the scavenge collector and set by ScavengeObject.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000616static PromotionQueue promotion_queue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000617
618
619#ifdef DEBUG
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000620// Visitor class to verify pointers in code or data space do not point into
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000621// new space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000622class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 public:
624 void VisitPointers(Object** start, Object**end) {
625 for (Object** current = start; current < end; current++) {
626 if ((*current)->IsHeapObject()) {
627 ASSERT(!Heap::InNewSpace(HeapObject::cast(*current)));
628 }
629 }
630 }
631};
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000632
633
634static void VerifyNonPointerSpacePointers() {
635 // Verify that there are no pointers to new space in spaces where we
636 // do not expect them.
637 VerifyNonPointerSpacePointersVisitor v;
638 HeapObjectIterator code_it(Heap::code_space());
639 while (code_it.has_next()) {
640 HeapObject* object = code_it.next();
641 if (object->IsCode()) {
642 Code::cast(object)->ConvertICTargetsFromAddressToObject();
643 object->Iterate(&v);
644 Code::cast(object)->ConvertICTargetsFromObjectToAddress();
645 } else {
646 // If we find non-code objects in code space (e.g., free list
647 // nodes) we want to verify them as well.
648 object->Iterate(&v);
649 }
650 }
651
652 HeapObjectIterator data_it(Heap::old_data_space());
653 while (data_it.has_next()) data_it.next()->Iterate(&v);
654}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000655#endif
656
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000657
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000658void Heap::Scavenge() {
659#ifdef DEBUG
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000660 if (FLAG_enable_slow_asserts) VerifyNonPointerSpacePointers();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000661#endif
662
663 gc_state_ = SCAVENGE;
664
665 // Implements Cheney's copying algorithm
666 LOG(ResourceEvent("scavenge", "begin"));
667
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000668 // Clear descriptor cache.
669 DescriptorLookupCache::Clear();
670
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000671 // Used for updating survived_since_last_expansion_ at function end.
672 int survived_watermark = PromotedSpaceSize();
673
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000674 if (new_space_.Capacity() < new_space_.MaximumCapacity() &&
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000675 survived_since_last_expansion_ > new_space_.Capacity()) {
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000676 // Grow the size of new space if there is room to grow and enough
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000677 // data has survived scavenge since the last expansion.
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000678 new_space_.Grow();
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000679 survived_since_last_expansion_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000680 }
681
682 // Flip the semispaces. After flipping, to space is empty, from space has
683 // live objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000684 new_space_.Flip();
685 new_space_.ResetAllocationInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000686
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000687 // We need to sweep newly copied objects which can be either in the
688 // to space or promoted to the old generation. For to-space
689 // objects, we treat the bottom of the to space as a queue. Newly
690 // copied and unswept objects lie between a 'front' mark and the
691 // allocation pointer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000692 //
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000693 // Promoted objects can go into various old-generation spaces, and
694 // can be allocated internally in the spaces (from the free list).
695 // We treat the top of the to space as a queue of addresses of
696 // promoted objects. The addresses of newly promoted and unswept
697 // objects lie between a 'front' mark and a 'rear' mark that is
698 // updated as a side effect of promoting an object.
699 //
700 // There is guaranteed to be enough room at the top of the to space
701 // for the addresses of promoted objects: every object promoted
702 // frees up its size in bytes from the top of the new space, and
703 // objects are at least one pointer in size.
704 Address new_space_front = new_space_.ToSpaceLow();
705 promotion_queue.Initialize(new_space_.ToSpaceHigh());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000706
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000707 ScavengeVisitor scavenge_visitor;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000708 // Copy roots.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000709 IterateRoots(&scavenge_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000710
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000711 // Copy objects reachable from weak pointers.
712 GlobalHandles::IterateWeakRoots(&scavenge_visitor);
713
714 // Copy objects reachable from the old generation. By definition,
715 // there are no intergenerational pointers in code or data spaces.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000716 IterateRSet(old_pointer_space_, &ScavengePointer);
717 IterateRSet(map_space_, &ScavengePointer);
718 lo_space_->IterateRSet(&ScavengePointer);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000719
720 // Copy objects reachable from cells by scavenging cell values directly.
721 HeapObjectIterator cell_iterator(cell_space_);
722 while (cell_iterator.has_next()) {
723 HeapObject* cell = cell_iterator.next();
724 if (cell->IsJSGlobalPropertyCell()) {
725 Address value_address =
726 reinterpret_cast<Address>(cell) +
727 (JSGlobalPropertyCell::kValueOffset - kHeapObjectTag);
728 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address));
729 }
730 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000731
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000732 do {
733 ASSERT(new_space_front <= new_space_.top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000734
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000735 // The addresses new_space_front and new_space_.top() define a
736 // queue of unprocessed copied objects. Process them until the
737 // queue is empty.
738 while (new_space_front < new_space_.top()) {
739 HeapObject* object = HeapObject::FromAddress(new_space_front);
740 object->Iterate(&scavenge_visitor);
741 new_space_front += object->Size();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000742 }
743
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000744 // Promote and process all the to-be-promoted objects.
745 while (!promotion_queue.is_empty()) {
746 HeapObject* source;
747 Map* map;
748 promotion_queue.remove(&source, &map);
749 // Copy the from-space object to its new location (given by the
750 // forwarding address) and fix its map.
751 HeapObject* target = source->map_word().ToForwardingAddress();
752 CopyBlock(reinterpret_cast<Object**>(target->address()),
753 reinterpret_cast<Object**>(source->address()),
754 source->SizeFromMap(map));
755 target->set_map(map);
756
757#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
758 // Update NewSpace stats if necessary.
759 RecordCopiedObject(target);
760#endif
761 // Visit the newly copied object for pointers to new space.
762 target->Iterate(&scavenge_visitor);
763 UpdateRSet(target);
764 }
765
766 // Take another spin if there are now unswept objects in new space
767 // (there are currently no more unswept promoted objects).
768 } while (new_space_front < new_space_.top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769
770 // Set age mark.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000771 new_space_.set_age_mark(new_space_.top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000772
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000773 // Update how much has survived scavenge.
774 survived_since_last_expansion_ +=
775 (PromotedSpaceSize() - survived_watermark) + new_space_.Size();
776
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000777 LOG(ResourceEvent("scavenge", "end"));
778
779 gc_state_ = NOT_IN_GC;
780}
781
782
783void Heap::ClearRSetRange(Address start, int size_in_bytes) {
784 uint32_t start_bit;
785 Address start_word_address =
786 Page::ComputeRSetBitPosition(start, 0, &start_bit);
787 uint32_t end_bit;
788 Address end_word_address =
789 Page::ComputeRSetBitPosition(start + size_in_bytes - kIntSize,
790 0,
791 &end_bit);
792
793 // We want to clear the bits in the starting word starting with the
794 // first bit, and in the ending word up to and including the last
795 // bit. Build a pair of bitmasks to do that.
796 uint32_t start_bitmask = start_bit - 1;
797 uint32_t end_bitmask = ~((end_bit << 1) - 1);
798
799 // If the start address and end address are the same, we mask that
800 // word once, otherwise mask the starting and ending word
801 // separately and all the ones in between.
802 if (start_word_address == end_word_address) {
803 Memory::uint32_at(start_word_address) &= (start_bitmask | end_bitmask);
804 } else {
805 Memory::uint32_at(start_word_address) &= start_bitmask;
806 Memory::uint32_at(end_word_address) &= end_bitmask;
807 start_word_address += kIntSize;
808 memset(start_word_address, 0, end_word_address - start_word_address);
809 }
810}
811
812
813class UpdateRSetVisitor: public ObjectVisitor {
814 public:
815
816 void VisitPointer(Object** p) {
817 UpdateRSet(p);
818 }
819
820 void VisitPointers(Object** start, Object** end) {
821 // Update a store into slots [start, end), used (a) to update remembered
822 // set when promoting a young object to old space or (b) to rebuild
823 // remembered sets after a mark-compact collection.
824 for (Object** p = start; p < end; p++) UpdateRSet(p);
825 }
826 private:
827
828 void UpdateRSet(Object** p) {
829 // The remembered set should not be set. It should be clear for objects
830 // newly copied to old space, and it is cleared before rebuilding in the
831 // mark-compact collector.
832 ASSERT(!Page::IsRSetSet(reinterpret_cast<Address>(p), 0));
833 if (Heap::InNewSpace(*p)) {
834 Page::SetRSet(reinterpret_cast<Address>(p), 0);
835 }
836 }
837};
838
839
840int Heap::UpdateRSet(HeapObject* obj) {
841 ASSERT(!InNewSpace(obj));
842 // Special handling of fixed arrays to iterate the body based on the start
843 // address and offset. Just iterating the pointers as in UpdateRSetVisitor
844 // will not work because Page::SetRSet needs to have the start of the
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000845 // object for large object pages.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000846 if (obj->IsFixedArray()) {
847 FixedArray* array = FixedArray::cast(obj);
848 int length = array->length();
849 for (int i = 0; i < length; i++) {
850 int offset = FixedArray::kHeaderSize + i * kPointerSize;
851 ASSERT(!Page::IsRSetSet(obj->address(), offset));
852 if (Heap::InNewSpace(array->get(i))) {
853 Page::SetRSet(obj->address(), offset);
854 }
855 }
856 } else if (!obj->IsCode()) {
857 // Skip code object, we know it does not contain inter-generational
858 // pointers.
859 UpdateRSetVisitor v;
860 obj->Iterate(&v);
861 }
862 return obj->Size();
863}
864
865
866void Heap::RebuildRSets() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000867 // By definition, we do not care about remembered set bits in code,
868 // data, or cell spaces.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000869 map_space_->ClearRSet();
870 RebuildRSets(map_space_);
871
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000872 old_pointer_space_->ClearRSet();
873 RebuildRSets(old_pointer_space_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000874
875 Heap::lo_space_->ClearRSet();
876 RebuildRSets(lo_space_);
877}
878
879
880void Heap::RebuildRSets(PagedSpace* space) {
881 HeapObjectIterator it(space);
882 while (it.has_next()) Heap::UpdateRSet(it.next());
883}
884
885
886void Heap::RebuildRSets(LargeObjectSpace* space) {
887 LargeObjectIterator it(space);
888 while (it.has_next()) Heap::UpdateRSet(it.next());
889}
890
891
892#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
893void Heap::RecordCopiedObject(HeapObject* obj) {
894 bool should_record = false;
895#ifdef DEBUG
896 should_record = FLAG_heap_stats;
897#endif
898#ifdef ENABLE_LOGGING_AND_PROFILING
899 should_record = should_record || FLAG_log_gc;
900#endif
901 if (should_record) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000902 if (new_space_.Contains(obj)) {
903 new_space_.RecordAllocation(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000904 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000905 new_space_.RecordPromotion(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000906 }
907 }
908}
909#endif // defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
910
911
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000912
913HeapObject* Heap::MigrateObject(HeapObject* source,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000914 HeapObject* target,
915 int size) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000916 // Copy the content of source to target.
917 CopyBlock(reinterpret_cast<Object**>(target->address()),
918 reinterpret_cast<Object**>(source->address()),
919 size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000920
kasper.lund7276f142008-07-30 08:49:36 +0000921 // Set the forwarding address.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000922 source->set_map_word(MapWord::FromForwardingAddress(target));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000924#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000925 // Update NewSpace stats if necessary.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926 RecordCopiedObject(target);
927#endif
928
929 return target;
930}
931
932
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000933static inline bool IsShortcutCandidate(HeapObject* object, Map* map) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000934 STATIC_ASSERT(kNotStringTag != 0 && kSymbolTag != 0);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000935 ASSERT(object->map() == map);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000936 InstanceType type = map->instance_type();
937 if ((type & kShortcutTypeMask) != kShortcutTypeTag) return false;
938 ASSERT(object->IsString() && !object->IsSymbol());
939 return ConsString::cast(object)->unchecked_second() == Heap::empty_string();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000940}
941
942
943void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) {
944 ASSERT(InFromSpace(object));
945 MapWord first_word = object->map_word();
946 ASSERT(!first_word.IsForwardingAddress());
947
948 // Optimization: Bypass flattened ConsString objects.
949 if (IsShortcutCandidate(object, first_word.ToMap())) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000950 object = HeapObject::cast(ConsString::cast(object)->unchecked_first());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000951 *p = object;
952 // After patching *p we have to repeat the checks that object is in the
953 // active semispace of the young generation and not already copied.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000954 if (!InNewSpace(object)) return;
kasper.lund7276f142008-07-30 08:49:36 +0000955 first_word = object->map_word();
956 if (first_word.IsForwardingAddress()) {
957 *p = first_word.ToForwardingAddress();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000958 return;
959 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000960 }
961
kasper.lund7276f142008-07-30 08:49:36 +0000962 int object_size = object->SizeFromMap(first_word.ToMap());
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000963 // We rely on live objects in new space to be at least two pointers,
964 // so we can store the from-space address and map pointer of promoted
965 // objects in the to space.
966 ASSERT(object_size >= 2 * kPointerSize);
967
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000968 // If the object should be promoted, we try to copy it to old space.
969 if (ShouldBePromoted(object->address(), object_size)) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000970 Object* result;
971 if (object_size > MaxObjectSizeInPagedSpace()) {
972 result = lo_space_->AllocateRawFixedArray(object_size);
973 if (!result->IsFailure()) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000974 // Save the from-space object pointer and its map pointer at the
975 // top of the to space to be swept and copied later. Write the
976 // forwarding address over the map word of the from-space
977 // object.
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000978 HeapObject* target = HeapObject::cast(result);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000979 promotion_queue.insert(object, first_word.ToMap());
980 object->set_map_word(MapWord::FromForwardingAddress(target));
981
982 // Give the space allocated for the result a proper map by
983 // treating it as a free list node (not linked into the free
984 // list).
985 FreeListNode* node = FreeListNode::FromAddress(target->address());
986 node->set_size(object_size);
987
988 *p = target;
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000989 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000990 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000991 } else {
992 OldSpace* target_space = Heap::TargetSpace(object);
993 ASSERT(target_space == Heap::old_pointer_space_ ||
994 target_space == Heap::old_data_space_);
995 result = target_space->AllocateRaw(object_size);
996 if (!result->IsFailure()) {
997 HeapObject* target = HeapObject::cast(result);
998 if (target_space == Heap::old_pointer_space_) {
999 // Save the from-space object pointer and its map pointer at the
1000 // top of the to space to be swept and copied later. Write the
1001 // forwarding address over the map word of the from-space
1002 // object.
1003 promotion_queue.insert(object, first_word.ToMap());
1004 object->set_map_word(MapWord::FromForwardingAddress(target));
1005
1006 // Give the space allocated for the result a proper map by
1007 // treating it as a free list node (not linked into the free
1008 // list).
1009 FreeListNode* node = FreeListNode::FromAddress(target->address());
1010 node->set_size(object_size);
1011
1012 *p = target;
1013 } else {
1014 // Objects promoted to the data space can be copied immediately
1015 // and not revisited---we will never sweep that space for
1016 // pointers and the copied objects do not contain pointers to
1017 // new space objects.
1018 *p = MigrateObject(object, target, object_size);
1019#ifdef DEBUG
1020 VerifyNonPointerSpacePointersVisitor v;
1021 (*p)->Iterate(&v);
1022#endif
1023 }
1024 return;
1025 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001026 }
1027 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001028 // The object should remain in new space or the old space allocation failed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001029 Object* result = new_space_.AllocateRaw(object_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001030 // Failed allocation at this point is utterly unexpected.
1031 ASSERT(!result->IsFailure());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001032 *p = MigrateObject(object, HeapObject::cast(result), object_size);
1033}
1034
1035
1036void Heap::ScavengePointer(HeapObject** p) {
1037 ScavengeObject(p, *p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001038}
1039
1040
1041Object* Heap::AllocatePartialMap(InstanceType instance_type,
1042 int instance_size) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001043 Object* result = AllocateRawMap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001044 if (result->IsFailure()) return result;
1045
1046 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001047 reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048 reinterpret_cast<Map*>(result)->set_instance_type(instance_type);
1049 reinterpret_cast<Map*>(result)->set_instance_size(instance_size);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001050 reinterpret_cast<Map*>(result)->set_inobject_properties(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051 reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
1052 return result;
1053}
1054
1055
1056Object* Heap::AllocateMap(InstanceType instance_type, int instance_size) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001057 Object* result = AllocateRawMap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058 if (result->IsFailure()) return result;
1059
1060 Map* map = reinterpret_cast<Map*>(result);
1061 map->set_map(meta_map());
1062 map->set_instance_type(instance_type);
1063 map->set_prototype(null_value());
1064 map->set_constructor(null_value());
1065 map->set_instance_size(instance_size);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001066 map->set_inobject_properties(0);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001067 map->set_pre_allocated_property_fields(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001068 map->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069 map->set_code_cache(empty_fixed_array());
1070 map->set_unused_property_fields(0);
1071 map->set_bit_field(0);
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00001072 map->set_bit_field2(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073 return map;
1074}
1075
1076
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001077const Heap::StringTypeTable Heap::string_type_table[] = {
1078#define STRING_TYPE_ELEMENT(type, size, name, camel_name) \
1079 {type, size, k##camel_name##MapRootIndex},
1080 STRING_TYPE_LIST(STRING_TYPE_ELEMENT)
1081#undef STRING_TYPE_ELEMENT
1082};
1083
1084
1085const Heap::ConstantSymbolTable Heap::constant_symbol_table[] = {
1086#define CONSTANT_SYMBOL_ELEMENT(name, contents) \
1087 {contents, k##name##RootIndex},
1088 SYMBOL_LIST(CONSTANT_SYMBOL_ELEMENT)
1089#undef CONSTANT_SYMBOL_ELEMENT
1090};
1091
1092
1093const Heap::StructTable Heap::struct_table[] = {
1094#define STRUCT_TABLE_ELEMENT(NAME, Name, name) \
1095 { NAME##_TYPE, Name::kSize, k##Name##MapRootIndex },
1096 STRUCT_LIST(STRUCT_TABLE_ELEMENT)
1097#undef STRUCT_TABLE_ELEMENT
1098};
1099
1100
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001101bool Heap::CreateInitialMaps() {
1102 Object* obj = AllocatePartialMap(MAP_TYPE, Map::kSize);
1103 if (obj->IsFailure()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001104 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001105 Map* new_meta_map = reinterpret_cast<Map*>(obj);
1106 set_meta_map(new_meta_map);
1107 new_meta_map->set_map(new_meta_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001108
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001109 obj = AllocatePartialMap(FIXED_ARRAY_TYPE, FixedArray::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001110 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001111 set_fixed_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001112
1113 obj = AllocatePartialMap(ODDBALL_TYPE, Oddball::kSize);
1114 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001115 set_oddball_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001116
1117 // Allocate the empty array
1118 obj = AllocateEmptyFixedArray();
1119 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001120 set_empty_fixed_array(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001121
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001122 obj = Allocate(oddball_map(), OLD_DATA_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001123 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001124 set_null_value(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001125
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001126 // Allocate the empty descriptor array.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001127 obj = AllocateEmptyFixedArray();
1128 if (obj->IsFailure()) return false;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001129 set_empty_descriptor_array(DescriptorArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001130
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001131 // Fix the instance_descriptors for the existing maps.
1132 meta_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001133 meta_map()->set_code_cache(empty_fixed_array());
1134
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001135 fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001136 fixed_array_map()->set_code_cache(empty_fixed_array());
1137
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001138 oddball_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001139 oddball_map()->set_code_cache(empty_fixed_array());
1140
1141 // Fix prototype object for existing maps.
1142 meta_map()->set_prototype(null_value());
1143 meta_map()->set_constructor(null_value());
1144
1145 fixed_array_map()->set_prototype(null_value());
1146 fixed_array_map()->set_constructor(null_value());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001147
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148 oddball_map()->set_prototype(null_value());
1149 oddball_map()->set_constructor(null_value());
1150
1151 obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
1152 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001153 set_heap_number_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001154
1155 obj = AllocateMap(PROXY_TYPE, Proxy::kSize);
1156 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001157 set_proxy_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001158
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001159 for (unsigned i = 0; i < ARRAY_SIZE(string_type_table); i++) {
1160 const StringTypeTable& entry = string_type_table[i];
1161 obj = AllocateMap(entry.type, entry.size);
1162 if (obj->IsFailure()) return false;
1163 roots_[entry.index] = Map::cast(obj);
1164 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001166 obj = AllocateMap(SHORT_STRING_TYPE, SeqTwoByteString::kAlignedSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001167 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001168 set_undetectable_short_string_map(Map::cast(obj));
1169 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001170
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001171 obj = AllocateMap(MEDIUM_STRING_TYPE, SeqTwoByteString::kAlignedSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001173 set_undetectable_medium_string_map(Map::cast(obj));
1174 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001176 obj = AllocateMap(LONG_STRING_TYPE, SeqTwoByteString::kAlignedSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001177 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001178 set_undetectable_long_string_map(Map::cast(obj));
1179 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001180
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001181 obj = AllocateMap(SHORT_ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001182 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001183 set_undetectable_short_ascii_string_map(Map::cast(obj));
1184 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001186 obj = AllocateMap(MEDIUM_ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001187 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001188 set_undetectable_medium_ascii_string_map(Map::cast(obj));
1189 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001191 obj = AllocateMap(LONG_ASCII_STRING_TYPE, SeqAsciiString::kAlignedSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001192 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001193 set_undetectable_long_ascii_string_map(Map::cast(obj));
1194 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001195
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001196 obj = AllocateMap(BYTE_ARRAY_TYPE, ByteArray::kAlignedSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001198 set_byte_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001199
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001200 obj = AllocateMap(PIXEL_ARRAY_TYPE, PixelArray::kAlignedSize);
1201 if (obj->IsFailure()) return false;
1202 set_pixel_array_map(Map::cast(obj));
1203
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001204 obj = AllocateMap(CODE_TYPE, Code::kHeaderSize);
1205 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001206 set_code_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001207
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001208 obj = AllocateMap(JS_GLOBAL_PROPERTY_CELL_TYPE,
1209 JSGlobalPropertyCell::kSize);
1210 if (obj->IsFailure()) return false;
1211 set_global_property_cell_map(Map::cast(obj));
1212
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001213 obj = AllocateMap(FILLER_TYPE, kPointerSize);
1214 if (obj->IsFailure()) return false;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001215 set_one_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001216
1217 obj = AllocateMap(FILLER_TYPE, 2 * kPointerSize);
1218 if (obj->IsFailure()) return false;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001219 set_two_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001220
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001221 for (unsigned i = 0; i < ARRAY_SIZE(struct_table); i++) {
1222 const StructTable& entry = struct_table[i];
1223 obj = AllocateMap(entry.type, entry.size);
1224 if (obj->IsFailure()) return false;
1225 roots_[entry.index] = Map::cast(obj);
1226 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001227
ager@chromium.org236ad962008-09-25 09:45:57 +00001228 obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001229 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001230 set_hash_table_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001231
ager@chromium.org236ad962008-09-25 09:45:57 +00001232 obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001233 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001234 set_context_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001235
ager@chromium.org236ad962008-09-25 09:45:57 +00001236 obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001238 set_catch_context_map(Map::cast(obj));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001239
1240 obj = AllocateMap(FIXED_ARRAY_TYPE, HeapObject::kHeaderSize);
1241 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001242 set_global_context_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001243
1244 obj = AllocateMap(JS_FUNCTION_TYPE, JSFunction::kSize);
1245 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001246 set_boilerplate_function_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247
1248 obj = AllocateMap(SHARED_FUNCTION_INFO_TYPE, SharedFunctionInfo::kSize);
1249 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001250 set_shared_function_info_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001251
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001252 ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001253 return true;
1254}
1255
1256
1257Object* Heap::AllocateHeapNumber(double value, PretenureFlag pretenure) {
1258 // Statically ensure that it is safe to allocate heap numbers in paged
1259 // spaces.
1260 STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxHeapObjectSize);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001261 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001262 Object* result = AllocateRaw(HeapNumber::kSize, space, OLD_DATA_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001263 if (result->IsFailure()) return result;
1264
1265 HeapObject::cast(result)->set_map(heap_number_map());
1266 HeapNumber::cast(result)->set_value(value);
1267 return result;
1268}
1269
1270
1271Object* Heap::AllocateHeapNumber(double value) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001272 // Use general version, if we're forced to always allocate.
1273 if (always_allocate()) return AllocateHeapNumber(value, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274 // This version of AllocateHeapNumber is optimized for
1275 // allocation in new space.
1276 STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxHeapObjectSize);
1277 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001278 Object* result = new_space_.AllocateRaw(HeapNumber::kSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001279 if (result->IsFailure()) return result;
1280 HeapObject::cast(result)->set_map(heap_number_map());
1281 HeapNumber::cast(result)->set_value(value);
1282 return result;
1283}
1284
1285
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001286Object* Heap::AllocateJSGlobalPropertyCell(Object* value) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001287 Object* result = AllocateRawCell();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001288 if (result->IsFailure()) return result;
1289 HeapObject::cast(result)->set_map(global_property_cell_map());
1290 JSGlobalPropertyCell::cast(result)->set_value(value);
1291 return result;
1292}
1293
1294
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295Object* Heap::CreateOddball(Map* map,
1296 const char* to_string,
1297 Object* to_number) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001298 Object* result = Allocate(map, OLD_DATA_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001299 if (result->IsFailure()) return result;
1300 return Oddball::cast(result)->Initialize(to_string, to_number);
1301}
1302
1303
1304bool Heap::CreateApiObjects() {
1305 Object* obj;
1306
1307 obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
1308 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001309 set_neander_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001311 obj = Heap::AllocateJSObjectFromMap(neander_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312 if (obj->IsFailure()) return false;
1313 Object* elements = AllocateFixedArray(2);
1314 if (elements->IsFailure()) return false;
1315 FixedArray::cast(elements)->set(0, Smi::FromInt(0));
1316 JSObject::cast(obj)->set_elements(FixedArray::cast(elements));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001317 set_message_listeners(JSObject::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001318
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319 return true;
1320}
1321
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001322
1323void Heap::CreateCEntryStub() {
1324 CEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001325 set_c_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001326}
1327
1328
1329void Heap::CreateCEntryDebugBreakStub() {
1330 CEntryDebugBreakStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001331 set_c_entry_debug_break_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001332}
1333
1334
1335void Heap::CreateJSEntryStub() {
1336 JSEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001337 set_js_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001338}
1339
1340
1341void Heap::CreateJSConstructEntryStub() {
1342 JSConstructEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001343 set_js_construct_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001344}
1345
1346
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347void Heap::CreateFixedStubs() {
1348 // Here we create roots for fixed stubs. They are needed at GC
1349 // for cooking and uncooking (check out frames.cc).
1350 // The eliminates the need for doing dictionary lookup in the
1351 // stub cache for these stubs.
1352 HandleScope scope;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001353 // gcc-4.4 has problem generating correct code of following snippet:
1354 // { CEntryStub stub;
1355 // c_entry_code_ = *stub.GetCode();
1356 // }
1357 // { CEntryDebugBreakStub stub;
1358 // c_entry_debug_break_code_ = *stub.GetCode();
1359 // }
1360 // To workaround the problem, make separate functions without inlining.
1361 Heap::CreateCEntryStub();
1362 Heap::CreateCEntryDebugBreakStub();
1363 Heap::CreateJSEntryStub();
1364 Heap::CreateJSConstructEntryStub();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001365}
1366
1367
1368bool Heap::CreateInitialObjects() {
1369 Object* obj;
1370
1371 // The -0 value must be set before NumberFromDouble works.
1372 obj = AllocateHeapNumber(-0.0, TENURED);
1373 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001374 set_minus_zero_value(obj);
1375 ASSERT(signbit(minus_zero_value()->Number()) != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376
1377 obj = AllocateHeapNumber(OS::nan_value(), TENURED);
1378 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001379 set_nan_value(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001380
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001381 obj = Allocate(oddball_map(), OLD_DATA_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001382 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001383 set_undefined_value(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001384 ASSERT(!InNewSpace(undefined_value()));
1385
1386 // Allocate initial symbol table.
1387 obj = SymbolTable::Allocate(kInitialSymbolTableSize);
1388 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001389 // Don't use set_symbol_table() due to asserts.
1390 roots_[kSymbolTableRootIndex] = obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001391
1392 // Assign the print strings for oddballs after creating symboltable.
1393 Object* symbol = LookupAsciiSymbol("undefined");
1394 if (symbol->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001395 Oddball::cast(undefined_value())->set_to_string(String::cast(symbol));
1396 Oddball::cast(undefined_value())->set_to_number(nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001397
1398 // Assign the print strings for oddballs after creating symboltable.
1399 symbol = LookupAsciiSymbol("null");
1400 if (symbol->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001401 Oddball::cast(null_value())->set_to_string(String::cast(symbol));
1402 Oddball::cast(null_value())->set_to_number(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403
1404 // Allocate the null_value
1405 obj = Oddball::cast(null_value())->Initialize("null", Smi::FromInt(0));
1406 if (obj->IsFailure()) return false;
1407
1408 obj = CreateOddball(oddball_map(), "true", Smi::FromInt(1));
1409 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001410 set_true_value(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001411
1412 obj = CreateOddball(oddball_map(), "false", Smi::FromInt(0));
1413 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001414 set_false_value(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415
1416 obj = CreateOddball(oddball_map(), "hole", Smi::FromInt(-1));
1417 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001418 set_the_hole_value(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001420 obj = CreateOddball(
1421 oddball_map(), "no_interceptor_result_sentinel", Smi::FromInt(-2));
1422 if (obj->IsFailure()) return false;
1423 set_no_interceptor_result_sentinel(obj);
1424
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00001425 obj = CreateOddball(oddball_map(), "termination_exception", Smi::FromInt(-3));
1426 if (obj->IsFailure()) return false;
1427 set_termination_exception(obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001428
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001429 // Allocate the empty string.
1430 obj = AllocateRawAsciiString(0, TENURED);
1431 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001432 set_empty_string(String::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001433
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001434 for (unsigned i = 0; i < ARRAY_SIZE(constant_symbol_table); i++) {
1435 obj = LookupAsciiSymbol(constant_symbol_table[i].contents);
1436 if (obj->IsFailure()) return false;
1437 roots_[constant_symbol_table[i].index] = String::cast(obj);
1438 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001439
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001440 // Allocate the hidden symbol which is used to identify the hidden properties
1441 // in JSObjects. The hash code has a special value so that it will not match
1442 // the empty string when searching for the property. It cannot be part of the
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001443 // loop above because it needs to be allocated manually with the special
ager@chromium.org3b45ab52009-03-19 22:21:34 +00001444 // hash code in place. The hash code for the hidden_symbol is zero to ensure
1445 // that it will always be at the first entry in property descriptors.
1446 obj = AllocateSymbol(CStrVector(""), 0, String::kHashComputedMask);
1447 if (obj->IsFailure()) return false;
1448 hidden_symbol_ = String::cast(obj);
1449
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001450 // Allocate the proxy for __proto__.
1451 obj = AllocateProxy((Address) &Accessors::ObjectPrototype);
1452 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001453 set_prototype_accessors(Proxy::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001454
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001455 // Allocate the code_stubs dictionary. The initial size is set to avoid
1456 // expanding the dictionary during bootstrapping.
1457 obj = NumberDictionary::Allocate(128);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001459 set_code_stubs(NumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001461 // Allocate the non_monomorphic_cache used in stub-cache.cc. The initial size
1462 // is set to avoid expanding the dictionary during bootstrapping.
1463 obj = NumberDictionary::Allocate(64);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001464 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001465 set_non_monomorphic_cache(NumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466
1467 CreateFixedStubs();
1468
1469 // Allocate the number->string conversion cache
1470 obj = AllocateFixedArray(kNumberStringCacheSize * 2);
1471 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001472 set_number_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473
1474 // Allocate cache for single character strings.
1475 obj = AllocateFixedArray(String::kMaxAsciiCharCode+1);
1476 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001477 set_single_character_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001478
1479 // Allocate cache for external strings pointing to native source code.
1480 obj = AllocateFixedArray(Natives::GetBuiltinsCount());
1481 if (obj->IsFailure()) return false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001482 set_natives_source_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001483
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001484 // Handling of script id generation is in Factory::NewScript.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001485 set_last_script_id(undefined_value());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001486
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001487 // Initialize keyed lookup cache.
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001488 KeyedLookupCache::Clear();
1489
1490 // Initialize context slot cache.
1491 ContextSlotCache::Clear();
1492
1493 // Initialize descriptor cache.
1494 DescriptorLookupCache::Clear();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001495
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001496 // Initialize compilation cache.
1497 CompilationCache::Clear();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001498
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001499 return true;
1500}
1501
1502
1503static inline int double_get_hash(double d) {
1504 DoubleRepresentation rep(d);
1505 return ((static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32)) &
1506 (Heap::kNumberStringCacheSize - 1));
1507}
1508
1509
1510static inline int smi_get_hash(Smi* smi) {
1511 return (smi->value() & (Heap::kNumberStringCacheSize - 1));
1512}
1513
1514
1515
1516Object* Heap::GetNumberStringCache(Object* number) {
1517 int hash;
1518 if (number->IsSmi()) {
1519 hash = smi_get_hash(Smi::cast(number));
1520 } else {
1521 hash = double_get_hash(number->Number());
1522 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001523 Object* key = number_string_cache()->get(hash * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524 if (key == number) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001525 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001526 } else if (key->IsHeapNumber() &&
1527 number->IsHeapNumber() &&
1528 key->Number() == number->Number()) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001529 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001530 }
1531 return undefined_value();
1532}
1533
1534
1535void Heap::SetNumberStringCache(Object* number, String* string) {
1536 int hash;
1537 if (number->IsSmi()) {
1538 hash = smi_get_hash(Smi::cast(number));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001539 number_string_cache()->set(hash * 2, number, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540 } else {
1541 hash = double_get_hash(number->Number());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001542 number_string_cache()->set(hash * 2, number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001544 number_string_cache()->set(hash * 2 + 1, string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001545}
1546
1547
1548Object* Heap::SmiOrNumberFromDouble(double value,
1549 bool new_object,
1550 PretenureFlag pretenure) {
1551 // We need to distinguish the minus zero value and this cannot be
1552 // done after conversion to int. Doing this by comparing bit
1553 // patterns is faster than using fpclassify() et al.
1554 static const DoubleRepresentation plus_zero(0.0);
1555 static const DoubleRepresentation minus_zero(-0.0);
1556 static const DoubleRepresentation nan(OS::nan_value());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001557 ASSERT(minus_zero_value() != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001558 ASSERT(sizeof(plus_zero.value) == sizeof(plus_zero.bits));
1559
1560 DoubleRepresentation rep(value);
1561 if (rep.bits == plus_zero.bits) return Smi::FromInt(0); // not uncommon
1562 if (rep.bits == minus_zero.bits) {
1563 return new_object ? AllocateHeapNumber(-0.0, pretenure)
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001564 : minus_zero_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001565 }
1566 if (rep.bits == nan.bits) {
1567 return new_object
1568 ? AllocateHeapNumber(OS::nan_value(), pretenure)
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001569 : nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001570 }
1571
1572 // Try to represent the value as a tagged small integer.
1573 int int_value = FastD2I(value);
1574 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
1575 return Smi::FromInt(int_value);
1576 }
1577
1578 // Materialize the value in the heap.
1579 return AllocateHeapNumber(value, pretenure);
1580}
1581
1582
1583Object* Heap::NewNumberFromDouble(double value, PretenureFlag pretenure) {
1584 return SmiOrNumberFromDouble(value,
1585 true /* number object must be new */,
1586 pretenure);
1587}
1588
1589
1590Object* Heap::NumberFromDouble(double value, PretenureFlag pretenure) {
1591 return SmiOrNumberFromDouble(value,
1592 false /* use preallocated NaN, -0.0 */,
1593 pretenure);
1594}
1595
1596
1597Object* Heap::AllocateProxy(Address proxy, PretenureFlag pretenure) {
1598 // Statically ensure that it is safe to allocate proxies in paged spaces.
1599 STATIC_ASSERT(Proxy::kSize <= Page::kMaxHeapObjectSize);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001600 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601 Object* result = Allocate(proxy_map(), space);
1602 if (result->IsFailure()) return result;
1603
1604 Proxy::cast(result)->set_proxy(proxy);
1605 return result;
1606}
1607
1608
1609Object* Heap::AllocateSharedFunctionInfo(Object* name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001610 Object* result = Allocate(shared_function_info_map(), OLD_POINTER_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001611 if (result->IsFailure()) return result;
1612
1613 SharedFunctionInfo* share = SharedFunctionInfo::cast(result);
1614 share->set_name(name);
1615 Code* illegal = Builtins::builtin(Builtins::Illegal);
1616 share->set_code(illegal);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001617 Code* construct_stub = Builtins::builtin(Builtins::JSConstructStubGeneric);
1618 share->set_construct_stub(construct_stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001619 share->set_expected_nof_properties(0);
1620 share->set_length(0);
1621 share->set_formal_parameter_count(0);
1622 share->set_instance_class_name(Object_symbol());
1623 share->set_function_data(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001624 share->set_script(undefined_value());
1625 share->set_start_position_and_type(0);
1626 share->set_debug_info(undefined_value());
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00001627 share->set_inferred_name(empty_string());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001628 share->set_compiler_hints(0);
1629 share->set_this_property_assignments_count(0);
1630 share->set_this_property_assignments(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631 return result;
1632}
1633
1634
ager@chromium.org3e875802009-06-29 08:26:34 +00001635Object* Heap::AllocateConsString(String* first, String* second) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001636 int first_length = first->length();
ager@chromium.org3e875802009-06-29 08:26:34 +00001637 if (first_length == 0) return second;
1638
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001639 int second_length = second->length();
ager@chromium.org3e875802009-06-29 08:26:34 +00001640 if (second_length == 0) return first;
1641
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001642 int length = first_length + second_length;
ager@chromium.org5ec48922009-05-05 07:25:34 +00001643 bool is_ascii = first->IsAsciiRepresentation()
1644 && second->IsAsciiRepresentation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001645
ager@chromium.org3e875802009-06-29 08:26:34 +00001646 // Make sure that an out of memory exception is thrown if the length
1647 // of the new cons string is too large to fit in a Smi.
1648 if (length > Smi::kMaxValue || length < -0) {
1649 Top::context()->mark_out_of_memory();
1650 return Failure::OutOfMemoryException();
1651 }
1652
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001653 // If the resulting string is small make a flat string.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001654 if (length < String::kMinNonFlatLength) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001655 ASSERT(first->IsFlat());
1656 ASSERT(second->IsFlat());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001657 if (is_ascii) {
1658 Object* result = AllocateRawAsciiString(length);
1659 if (result->IsFailure()) return result;
1660 // Copy the characters into the new object.
1661 char* dest = SeqAsciiString::cast(result)->GetChars();
ager@chromium.org3e875802009-06-29 08:26:34 +00001662 // Copy first part.
1663 char* src = SeqAsciiString::cast(first)->GetChars();
1664 for (int i = 0; i < first_length; i++) *dest++ = src[i];
1665 // Copy second part.
1666 src = SeqAsciiString::cast(second)->GetChars();
1667 for (int i = 0; i < second_length; i++) *dest++ = src[i];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001668 return result;
1669 } else {
1670 Object* result = AllocateRawTwoByteString(length);
1671 if (result->IsFailure()) return result;
1672 // Copy the characters into the new object.
1673 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001674 String::WriteToFlat(first, dest, 0, first_length);
1675 String::WriteToFlat(second, dest + first_length, 0, second_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001676 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001677 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001678 }
1679
1680 Map* map;
1681 if (length <= String::kMaxShortStringSize) {
1682 map = is_ascii ? short_cons_ascii_string_map()
1683 : short_cons_string_map();
1684 } else if (length <= String::kMaxMediumStringSize) {
1685 map = is_ascii ? medium_cons_ascii_string_map()
1686 : medium_cons_string_map();
1687 } else {
1688 map = is_ascii ? long_cons_ascii_string_map()
1689 : long_cons_string_map();
1690 }
1691
1692 Object* result = Allocate(map, NEW_SPACE);
1693 if (result->IsFailure()) return result;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001694 ASSERT(InNewSpace(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001695 ConsString* cons_string = ConsString::cast(result);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001696 cons_string->set_first(first, SKIP_WRITE_BARRIER);
1697 cons_string->set_second(second, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001698 cons_string->set_length(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001699 return result;
1700}
1701
1702
ager@chromium.org870a0b62008-11-04 11:43:05 +00001703Object* Heap::AllocateSlicedString(String* buffer,
ager@chromium.org870a0b62008-11-04 11:43:05 +00001704 int start,
1705 int end) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001706 int length = end - start;
1707
1708 // If the resulting string is small make a sub string.
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +00001709 if (length <= String::kMinNonFlatLength) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001710 return Heap::AllocateSubString(buffer, start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001711 }
1712
1713 Map* map;
1714 if (length <= String::kMaxShortStringSize) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00001715 map = buffer->IsAsciiRepresentation() ?
ager@chromium.org870a0b62008-11-04 11:43:05 +00001716 short_sliced_ascii_string_map() :
1717 short_sliced_string_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001718 } else if (length <= String::kMaxMediumStringSize) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00001719 map = buffer->IsAsciiRepresentation() ?
ager@chromium.org870a0b62008-11-04 11:43:05 +00001720 medium_sliced_ascii_string_map() :
1721 medium_sliced_string_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001722 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00001723 map = buffer->IsAsciiRepresentation() ?
ager@chromium.org870a0b62008-11-04 11:43:05 +00001724 long_sliced_ascii_string_map() :
1725 long_sliced_string_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001726 }
1727
1728 Object* result = Allocate(map, NEW_SPACE);
1729 if (result->IsFailure()) return result;
1730
1731 SlicedString* sliced_string = SlicedString::cast(result);
1732 sliced_string->set_buffer(buffer);
1733 sliced_string->set_start(start);
1734 sliced_string->set_length(length);
1735
1736 return result;
1737}
1738
1739
ager@chromium.org870a0b62008-11-04 11:43:05 +00001740Object* Heap::AllocateSubString(String* buffer,
ager@chromium.org870a0b62008-11-04 11:43:05 +00001741 int start,
1742 int end) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001743 int length = end - start;
1744
ager@chromium.org7c537e22008-10-16 08:43:32 +00001745 if (length == 1) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001746 return Heap::LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001747 buffer->Get(start));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001748 }
1749
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001750 // Make an attempt to flatten the buffer to reduce access time.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001751 if (!buffer->IsFlat()) {
1752 buffer->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001753 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001754
ager@chromium.org5ec48922009-05-05 07:25:34 +00001755 Object* result = buffer->IsAsciiRepresentation()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001756 ? AllocateRawAsciiString(length)
1757 : AllocateRawTwoByteString(length);
1758 if (result->IsFailure()) return result;
1759
1760 // Copy the characters into the new object.
1761 String* string_result = String::cast(result);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001762 StringHasher hasher(length);
1763 int i = 0;
1764 for (; i < length && hasher.is_array_index(); i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001765 uc32 c = buffer->Get(start + i);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001766 hasher.AddCharacter(c);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001767 string_result->Set(i, c);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001768 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001769 for (; i < length; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001770 uc32 c = buffer->Get(start + i);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001771 hasher.AddCharacterNoIndex(c);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001772 string_result->Set(i, c);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001773 }
1774 string_result->set_length_field(hasher.GetHashField());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001775 return result;
1776}
1777
1778
1779Object* Heap::AllocateExternalStringFromAscii(
1780 ExternalAsciiString::Resource* resource) {
1781 Map* map;
1782 int length = resource->length();
1783 if (length <= String::kMaxShortStringSize) {
1784 map = short_external_ascii_string_map();
1785 } else if (length <= String::kMaxMediumStringSize) {
1786 map = medium_external_ascii_string_map();
1787 } else {
1788 map = long_external_ascii_string_map();
1789 }
1790
1791 Object* result = Allocate(map, NEW_SPACE);
1792 if (result->IsFailure()) return result;
1793
1794 ExternalAsciiString* external_string = ExternalAsciiString::cast(result);
1795 external_string->set_length(length);
1796 external_string->set_resource(resource);
1797
1798 return result;
1799}
1800
1801
1802Object* Heap::AllocateExternalStringFromTwoByte(
1803 ExternalTwoByteString::Resource* resource) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001804 int length = resource->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001805
ager@chromium.org6f10e412009-02-13 10:11:16 +00001806 Map* map = ExternalTwoByteString::StringMap(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001807 Object* result = Allocate(map, NEW_SPACE);
1808 if (result->IsFailure()) return result;
1809
1810 ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result);
1811 external_string->set_length(length);
1812 external_string->set_resource(resource);
1813
1814 return result;
1815}
1816
1817
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001818Object* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001819 if (code <= String::kMaxAsciiCharCode) {
1820 Object* value = Heap::single_character_string_cache()->get(code);
1821 if (value != Heap::undefined_value()) return value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001822
1823 char buffer[1];
1824 buffer[0] = static_cast<char>(code);
1825 Object* result = LookupSymbol(Vector<const char>(buffer, 1));
1826
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001827 if (result->IsFailure()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001828 Heap::single_character_string_cache()->set(code, result);
1829 return result;
1830 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001831
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001832 Object* result = Heap::AllocateRawTwoByteString(1);
1833 if (result->IsFailure()) return result;
ager@chromium.org870a0b62008-11-04 11:43:05 +00001834 String* answer = String::cast(result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001835 answer->Set(0, code);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001836 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001837}
1838
1839
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001840Object* Heap::AllocateByteArray(int length, PretenureFlag pretenure) {
1841 if (pretenure == NOT_TENURED) {
1842 return AllocateByteArray(length);
1843 }
1844 int size = ByteArray::SizeFor(length);
1845 AllocationSpace space =
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001846 size > MaxObjectSizeInPagedSpace() ? LO_SPACE : OLD_DATA_SPACE;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001847
1848 Object* result = AllocateRaw(size, space, OLD_DATA_SPACE);
1849
1850 if (result->IsFailure()) return result;
1851
1852 reinterpret_cast<Array*>(result)->set_map(byte_array_map());
1853 reinterpret_cast<Array*>(result)->set_length(length);
1854 return result;
1855}
1856
1857
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001858Object* Heap::AllocateByteArray(int length) {
1859 int size = ByteArray::SizeFor(length);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001860 AllocationSpace space =
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001861 size > MaxObjectSizeInPagedSpace() ? LO_SPACE : NEW_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001862
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001863 Object* result = AllocateRaw(size, space, OLD_DATA_SPACE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001864
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001865 if (result->IsFailure()) return result;
1866
1867 reinterpret_cast<Array*>(result)->set_map(byte_array_map());
1868 reinterpret_cast<Array*>(result)->set_length(length);
1869 return result;
1870}
1871
1872
ager@chromium.org6f10e412009-02-13 10:11:16 +00001873void Heap::CreateFillerObjectAt(Address addr, int size) {
1874 if (size == 0) return;
1875 HeapObject* filler = HeapObject::FromAddress(addr);
1876 if (size == kPointerSize) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001877 filler->set_map(Heap::one_pointer_filler_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +00001878 } else {
1879 filler->set_map(Heap::byte_array_map());
1880 ByteArray::cast(filler)->set_length(ByteArray::LengthFor(size));
1881 }
1882}
1883
1884
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001885Object* Heap::AllocatePixelArray(int length,
1886 uint8_t* external_pointer,
1887 PretenureFlag pretenure) {
1888 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
1889
1890 Object* result = AllocateRaw(PixelArray::kAlignedSize, space, OLD_DATA_SPACE);
1891
1892 if (result->IsFailure()) return result;
1893
1894 reinterpret_cast<PixelArray*>(result)->set_map(pixel_array_map());
1895 reinterpret_cast<PixelArray*>(result)->set_length(length);
1896 reinterpret_cast<PixelArray*>(result)->set_external_pointer(external_pointer);
1897
1898 return result;
1899}
1900
1901
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001902Object* Heap::CreateCode(const CodeDesc& desc,
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001903 ZoneScopeInfo* sinfo,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001904 Code::Flags flags,
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001905 Handle<Object> self_reference) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001906 // Compute size
1907 int body_size = RoundUp(desc.instr_size + desc.reloc_size, kObjectAlignment);
1908 int sinfo_size = 0;
1909 if (sinfo != NULL) sinfo_size = sinfo->Serialize(NULL);
1910 int obj_size = Code::SizeFor(body_size, sinfo_size);
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001911 ASSERT(IsAligned(obj_size, Code::kCodeAlignment));
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001912 Object* result;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001913 if (obj_size > MaxObjectSizeInPagedSpace()) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001914 result = lo_space_->AllocateRawCode(obj_size);
1915 } else {
1916 result = code_space_->AllocateRaw(obj_size);
1917 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001918
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001919 if (result->IsFailure()) return result;
1920
1921 // Initialize the object
1922 HeapObject::cast(result)->set_map(code_map());
1923 Code* code = Code::cast(result);
1924 code->set_instruction_size(desc.instr_size);
1925 code->set_relocation_size(desc.reloc_size);
1926 code->set_sinfo_size(sinfo_size);
1927 code->set_flags(flags);
1928 code->set_ic_flag(Code::IC_TARGET_IS_ADDRESS);
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001929 // Allow self references to created code object by patching the handle to
1930 // point to the newly allocated Code object.
1931 if (!self_reference.is_null()) {
1932 *(self_reference.location()) = code;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001933 }
1934 // Migrate generated code.
1935 // The generated code can contain Object** values (typically from handles)
1936 // that are dereferenced during the copy to point directly to the actual heap
1937 // objects. These pointers can include references to the code object itself,
1938 // through the self_reference parameter.
1939 code->CopyFrom(desc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001940 if (sinfo != NULL) sinfo->Serialize(code); // write scope info
1941
1942#ifdef DEBUG
1943 code->Verify();
1944#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001945 return code;
1946}
1947
1948
1949Object* Heap::CopyCode(Code* code) {
1950 // Allocate an object the same size as the code object.
1951 int obj_size = code->Size();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001952 Object* result;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001953 if (obj_size > MaxObjectSizeInPagedSpace()) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001954 result = lo_space_->AllocateRawCode(obj_size);
1955 } else {
1956 result = code_space_->AllocateRaw(obj_size);
1957 }
1958
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001959 if (result->IsFailure()) return result;
1960
1961 // Copy code object.
1962 Address old_addr = code->address();
1963 Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001964 CopyBlock(reinterpret_cast<Object**>(new_addr),
1965 reinterpret_cast<Object**>(old_addr),
1966 obj_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001967 // Relocate the copy.
1968 Code* new_code = Code::cast(result);
1969 new_code->Relocate(new_addr - old_addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001970 return new_code;
1971}
1972
1973
1974Object* Heap::Allocate(Map* map, AllocationSpace space) {
1975 ASSERT(gc_state_ == NOT_IN_GC);
1976 ASSERT(map->instance_type() != MAP_TYPE);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001977 Object* result = AllocateRaw(map->instance_size(),
1978 space,
1979 TargetSpaceId(map->instance_type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001980 if (result->IsFailure()) return result;
1981 HeapObject::cast(result)->set_map(map);
1982 return result;
1983}
1984
1985
1986Object* Heap::InitializeFunction(JSFunction* function,
1987 SharedFunctionInfo* shared,
1988 Object* prototype) {
1989 ASSERT(!prototype->IsMap());
1990 function->initialize_properties();
1991 function->initialize_elements();
1992 function->set_shared(shared);
1993 function->set_prototype_or_initial_map(prototype);
1994 function->set_context(undefined_value());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001995 function->set_literals(empty_fixed_array(), SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001996 return function;
1997}
1998
1999
2000Object* Heap::AllocateFunctionPrototype(JSFunction* function) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00002001 // Allocate the prototype. Make sure to use the object function
2002 // from the function's context, since the function can be from a
2003 // different context.
2004 JSFunction* object_function =
2005 function->context()->global_context()->object_function();
2006 Object* prototype = AllocateJSObject(object_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002007 if (prototype->IsFailure()) return prototype;
2008 // When creating the prototype for the function we must set its
2009 // constructor to the function.
2010 Object* result =
2011 JSObject::cast(prototype)->SetProperty(constructor_symbol(),
2012 function,
2013 DONT_ENUM);
2014 if (result->IsFailure()) return result;
2015 return prototype;
2016}
2017
2018
2019Object* Heap::AllocateFunction(Map* function_map,
2020 SharedFunctionInfo* shared,
2021 Object* prototype) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002022 Object* result = Allocate(function_map, OLD_POINTER_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002023 if (result->IsFailure()) return result;
2024 return InitializeFunction(JSFunction::cast(result), shared, prototype);
2025}
2026
2027
2028Object* Heap::AllocateArgumentsObject(Object* callee, int length) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002029 // To get fast allocation and map sharing for arguments objects we
2030 // allocate them based on an arguments boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002031
2032 // This calls Copy directly rather than using Heap::AllocateRaw so we
2033 // duplicate the check here.
2034 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
2035
2036 JSObject* boilerplate =
2037 Top::context()->global_context()->arguments_boilerplate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002038
2039 // Make the clone.
2040 Map* map = boilerplate->map();
2041 int object_size = map->instance_size();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002042 Object* result = AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002043 if (result->IsFailure()) return result;
2044
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002045 // Copy the content. The arguments boilerplate doesn't have any
2046 // fields that point to new space so it's safe to skip the write
2047 // barrier here.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002048 CopyBlock(reinterpret_cast<Object**>(HeapObject::cast(result)->address()),
2049 reinterpret_cast<Object**>(boilerplate->address()),
2050 object_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002052 // Set the two properties.
2053 JSObject::cast(result)->InObjectPropertyAtPut(arguments_callee_index,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002054 callee);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002055 JSObject::cast(result)->InObjectPropertyAtPut(arguments_length_index,
2056 Smi::FromInt(length),
2057 SKIP_WRITE_BARRIER);
2058
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002059 // Check the state of the object
2060 ASSERT(JSObject::cast(result)->HasFastProperties());
2061 ASSERT(JSObject::cast(result)->HasFastElements());
2062
2063 return result;
2064}
2065
2066
2067Object* Heap::AllocateInitialMap(JSFunction* fun) {
2068 ASSERT(!fun->has_initial_map());
2069
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002070 // First create a new map with the size and number of in-object properties
2071 // suggested by the function.
2072 int instance_size = fun->shared()->CalculateInstanceSize();
2073 int in_object_properties = fun->shared()->CalculateInObjectProperties();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002074 Object* map_obj = Heap::AllocateMap(JS_OBJECT_TYPE, instance_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002075 if (map_obj->IsFailure()) return map_obj;
2076
2077 // Fetch or allocate prototype.
2078 Object* prototype;
2079 if (fun->has_instance_prototype()) {
2080 prototype = fun->instance_prototype();
2081 } else {
2082 prototype = AllocateFunctionPrototype(fun);
2083 if (prototype->IsFailure()) return prototype;
2084 }
2085 Map* map = Map::cast(map_obj);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002086 map->set_inobject_properties(in_object_properties);
2087 map->set_unused_property_fields(in_object_properties);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002088 map->set_prototype(prototype);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002089
2090 // If the function has only simple this property assignments add field
2091 // descriptors for these to the initial map as the object cannot be
2092 // constructed without having these properties.
2093 ASSERT(in_object_properties <= Map::kMaxPreAllocatedPropertyFields);
2094 if (fun->shared()->has_only_this_property_assignments() &&
2095 fun->shared()->this_property_assignments_count() > 0) {
2096 int count = fun->shared()->this_property_assignments_count();
2097 if (count > in_object_properties) {
2098 count = in_object_properties;
2099 }
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00002100 Object* descriptors_obj = DescriptorArray::Allocate(count);
2101 if (descriptors_obj->IsFailure()) return descriptors_obj;
2102 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_obj);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002103 for (int i = 0; i < count; i++) {
2104 String* name = fun->shared()->GetThisPropertyAssignmentName(i);
2105 ASSERT(name->IsSymbol());
2106 FieldDescriptor field(name, i, NONE);
2107 descriptors->Set(i, &field);
2108 }
2109 descriptors->Sort();
2110 map->set_instance_descriptors(descriptors);
2111 map->set_pre_allocated_property_fields(count);
2112 map->set_unused_property_fields(in_object_properties - count);
2113 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002114 return map;
2115}
2116
2117
2118void Heap::InitializeJSObjectFromMap(JSObject* obj,
2119 FixedArray* properties,
2120 Map* map) {
2121 obj->set_properties(properties);
2122 obj->initialize_elements();
2123 // TODO(1240798): Initialize the object's body using valid initial values
2124 // according to the object's initial map. For example, if the map's
2125 // instance type is JS_ARRAY_TYPE, the length field should be initialized
2126 // to a number (eg, Smi::FromInt(0)) and the elements initialized to a
2127 // fixed array (eg, Heap::empty_fixed_array()). Currently, the object
2128 // verification code has to cope with (temporarily) invalid objects. See
2129 // for example, JSArray::JSArrayVerify).
2130 obj->InitializeBody(map->instance_size());
2131}
2132
2133
2134Object* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) {
2135 // JSFunctions should be allocated using AllocateFunction to be
2136 // properly initialized.
2137 ASSERT(map->instance_type() != JS_FUNCTION_TYPE);
2138
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002139 // Both types of globla objects should be allocated using
2140 // AllocateGloblaObject to be properly initialized.
2141 ASSERT(map->instance_type() != JS_GLOBAL_OBJECT_TYPE);
2142 ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE);
2143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002144 // Allocate the backing storage for the properties.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002145 int prop_size =
2146 map->pre_allocated_property_fields() +
2147 map->unused_property_fields() -
2148 map->inobject_properties();
2149 ASSERT(prop_size >= 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002150 Object* properties = AllocateFixedArray(prop_size, pretenure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002151 if (properties->IsFailure()) return properties;
2152
2153 // Allocate the JSObject.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002154 AllocationSpace space =
2155 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002156 if (map->instance_size() > MaxObjectSizeInPagedSpace()) space = LO_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002157 Object* obj = Allocate(map, space);
2158 if (obj->IsFailure()) return obj;
2159
2160 // Initialize the JSObject.
2161 InitializeJSObjectFromMap(JSObject::cast(obj),
2162 FixedArray::cast(properties),
2163 map);
2164 return obj;
2165}
2166
2167
2168Object* Heap::AllocateJSObject(JSFunction* constructor,
2169 PretenureFlag pretenure) {
2170 // Allocate the initial map if absent.
2171 if (!constructor->has_initial_map()) {
2172 Object* initial_map = AllocateInitialMap(constructor);
2173 if (initial_map->IsFailure()) return initial_map;
2174 constructor->set_initial_map(Map::cast(initial_map));
2175 Map::cast(initial_map)->set_constructor(constructor);
2176 }
2177 // Allocate the object based on the constructors initial map.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002178 Object* result =
2179 AllocateJSObjectFromMap(constructor->initial_map(), pretenure);
2180 // Make sure result is NOT a global object if valid.
2181 ASSERT(result->IsFailure() || !result->IsGlobalObject());
2182 return result;
2183}
2184
2185
2186Object* Heap::AllocateGlobalObject(JSFunction* constructor) {
2187 ASSERT(constructor->has_initial_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002188 Map* map = constructor->initial_map();
2189
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002190 // Make sure no field properties are described in the initial map.
2191 // This guarantees us that normalizing the properties does not
2192 // require us to change property values to JSGlobalPropertyCells.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002193 ASSERT(map->NextFreePropertyIndex() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002194
2195 // Make sure we don't have a ton of pre-allocated slots in the
2196 // global objects. They will be unused once we normalize the object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002197 ASSERT(map->unused_property_fields() == 0);
2198 ASSERT(map->inobject_properties() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002199
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002200 // Initial size of the backing store to avoid resize of the storage during
2201 // bootstrapping. The size differs between the JS global object ad the
2202 // builtins object.
2203 int initial_size = map->instance_type() == JS_GLOBAL_OBJECT_TYPE ? 64 : 512;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002204
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002205 // Allocate a dictionary object for backing storage.
2206 Object* obj =
2207 StringDictionary::Allocate(
2208 map->NumberOfDescribedProperties() * 2 + initial_size);
2209 if (obj->IsFailure()) return obj;
2210 StringDictionary* dictionary = StringDictionary::cast(obj);
2211
2212 // The global object might be created from an object template with accessors.
2213 // Fill these accessors into the dictionary.
2214 DescriptorArray* descs = map->instance_descriptors();
2215 for (int i = 0; i < descs->number_of_descriptors(); i++) {
2216 PropertyDetails details = descs->GetDetails(i);
2217 ASSERT(details.type() == CALLBACKS); // Only accessors are expected.
2218 PropertyDetails d =
2219 PropertyDetails(details.attributes(), CALLBACKS, details.index());
2220 Object* value = descs->GetCallbacksObject(i);
2221 value = Heap::AllocateJSGlobalPropertyCell(value);
2222 if (value->IsFailure()) return value;
2223
2224 Object* result = dictionary->Add(descs->GetKey(i), value, d);
2225 if (result->IsFailure()) return result;
2226 dictionary = StringDictionary::cast(result);
2227 }
2228
2229 // Allocate the global object and initialize it with the backing store.
2230 obj = Allocate(map, OLD_POINTER_SPACE);
2231 if (obj->IsFailure()) return obj;
2232 JSObject* global = JSObject::cast(obj);
2233 InitializeJSObjectFromMap(global, dictionary, map);
2234
2235 // Create a new map for the global object.
2236 obj = map->CopyDropDescriptors();
2237 if (obj->IsFailure()) return obj;
2238 Map* new_map = Map::cast(obj);
2239
2240 // Setup the global object as a normalized object.
2241 global->set_map(new_map);
2242 global->map()->set_instance_descriptors(Heap::empty_descriptor_array());
2243 global->set_properties(dictionary);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002244
2245 // Make sure result is a global object with properties in dictionary.
2246 ASSERT(global->IsGlobalObject());
2247 ASSERT(!global->HasFastProperties());
2248 return global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002249}
2250
2251
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002252Object* Heap::CopyJSObject(JSObject* source) {
2253 // Never used to copy functions. If functions need to be copied we
2254 // have to be careful to clear the literals array.
2255 ASSERT(!source->IsJSFunction());
2256
2257 // Make the clone.
2258 Map* map = source->map();
2259 int object_size = map->instance_size();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002260 Object* clone;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002261
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002262 // If we're forced to always allocate, we use the general allocation
2263 // functions which may leave us with an object in old space.
2264 if (always_allocate()) {
2265 clone = AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE);
2266 if (clone->IsFailure()) return clone;
2267 Address clone_address = HeapObject::cast(clone)->address();
2268 CopyBlock(reinterpret_cast<Object**>(clone_address),
2269 reinterpret_cast<Object**>(source->address()),
2270 object_size);
2271 // Update write barrier for all fields that lie beyond the header.
2272 for (int offset = JSObject::kHeaderSize;
2273 offset < object_size;
2274 offset += kPointerSize) {
2275 RecordWrite(clone_address, offset);
2276 }
2277 } else {
2278 clone = new_space_.AllocateRaw(object_size);
2279 if (clone->IsFailure()) return clone;
2280 ASSERT(Heap::InNewSpace(clone));
2281 // Since we know the clone is allocated in new space, we can copy
ager@chromium.org32912102009-01-16 10:38:43 +00002282 // the contents without worrying about updating the write barrier.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002283 CopyBlock(reinterpret_cast<Object**>(HeapObject::cast(clone)->address()),
2284 reinterpret_cast<Object**>(source->address()),
2285 object_size);
2286 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002287
2288 FixedArray* elements = FixedArray::cast(source->elements());
2289 FixedArray* properties = FixedArray::cast(source->properties());
2290 // Update elements if necessary.
2291 if (elements->length()> 0) {
2292 Object* elem = CopyFixedArray(elements);
2293 if (elem->IsFailure()) return elem;
2294 JSObject::cast(clone)->set_elements(FixedArray::cast(elem));
2295 }
2296 // Update properties if necessary.
2297 if (properties->length() > 0) {
2298 Object* prop = CopyFixedArray(properties);
2299 if (prop->IsFailure()) return prop;
2300 JSObject::cast(clone)->set_properties(FixedArray::cast(prop));
2301 }
2302 // Return the new clone.
2303 return clone;
2304}
2305
2306
2307Object* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor,
2308 JSGlobalProxy* object) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002309 // Allocate initial map if absent.
2310 if (!constructor->has_initial_map()) {
2311 Object* initial_map = AllocateInitialMap(constructor);
2312 if (initial_map->IsFailure()) return initial_map;
2313 constructor->set_initial_map(Map::cast(initial_map));
2314 Map::cast(initial_map)->set_constructor(constructor);
2315 }
2316
2317 Map* map = constructor->initial_map();
2318
2319 // Check that the already allocated object has the same size as
2320 // objects allocated using the constructor.
2321 ASSERT(map->instance_size() == object->map()->instance_size());
2322
2323 // Allocate the backing storage for the properties.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002324 int prop_size = map->unused_property_fields() - map->inobject_properties();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002325 Object* properties = AllocateFixedArray(prop_size, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002326 if (properties->IsFailure()) return properties;
2327
2328 // Reset the map for the object.
2329 object->set_map(constructor->initial_map());
2330
2331 // Reinitialize the object from the constructor map.
2332 InitializeJSObjectFromMap(object, FixedArray::cast(properties), map);
2333 return object;
2334}
2335
2336
2337Object* Heap::AllocateStringFromAscii(Vector<const char> string,
2338 PretenureFlag pretenure) {
2339 Object* result = AllocateRawAsciiString(string.length(), pretenure);
2340 if (result->IsFailure()) return result;
2341
2342 // Copy the characters into the new object.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002343 SeqAsciiString* string_result = SeqAsciiString::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002344 for (int i = 0; i < string.length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002345 string_result->SeqAsciiStringSet(i, string[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002346 }
2347 return result;
2348}
2349
2350
2351Object* Heap::AllocateStringFromUtf8(Vector<const char> string,
2352 PretenureFlag pretenure) {
2353 // Count the number of characters in the UTF-8 string and check if
2354 // it is an ASCII string.
2355 Access<Scanner::Utf8Decoder> decoder(Scanner::utf8_decoder());
2356 decoder->Reset(string.start(), string.length());
2357 int chars = 0;
2358 bool is_ascii = true;
2359 while (decoder->has_more()) {
2360 uc32 r = decoder->GetNext();
2361 if (r > String::kMaxAsciiCharCode) is_ascii = false;
2362 chars++;
2363 }
2364
2365 // If the string is ascii, we do not need to convert the characters
2366 // since UTF8 is backwards compatible with ascii.
2367 if (is_ascii) return AllocateStringFromAscii(string, pretenure);
2368
2369 Object* result = AllocateRawTwoByteString(chars, pretenure);
2370 if (result->IsFailure()) return result;
2371
2372 // Convert and copy the characters into the new object.
2373 String* string_result = String::cast(result);
2374 decoder->Reset(string.start(), string.length());
2375 for (int i = 0; i < chars; i++) {
2376 uc32 r = decoder->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002377 string_result->Set(i, r);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002378 }
2379 return result;
2380}
2381
2382
2383Object* Heap::AllocateStringFromTwoByte(Vector<const uc16> string,
2384 PretenureFlag pretenure) {
2385 // Check if the string is an ASCII string.
2386 int i = 0;
2387 while (i < string.length() && string[i] <= String::kMaxAsciiCharCode) i++;
2388
2389 Object* result;
2390 if (i == string.length()) { // It's an ASCII string.
2391 result = AllocateRawAsciiString(string.length(), pretenure);
2392 } else { // It's not an ASCII string.
2393 result = AllocateRawTwoByteString(string.length(), pretenure);
2394 }
2395 if (result->IsFailure()) return result;
2396
2397 // Copy the characters into the new object, which may be either ASCII or
2398 // UTF-16.
2399 String* string_result = String::cast(result);
2400 for (int i = 0; i < string.length(); i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002401 string_result->Set(i, string[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002402 }
2403 return result;
2404}
2405
2406
2407Map* Heap::SymbolMapForString(String* string) {
2408 // If the string is in new space it cannot be used as a symbol.
2409 if (InNewSpace(string)) return NULL;
2410
2411 // Find the corresponding symbol map for strings.
2412 Map* map = string->map();
2413
2414 if (map == short_ascii_string_map()) return short_ascii_symbol_map();
2415 if (map == medium_ascii_string_map()) return medium_ascii_symbol_map();
2416 if (map == long_ascii_string_map()) return long_ascii_symbol_map();
2417
2418 if (map == short_string_map()) return short_symbol_map();
2419 if (map == medium_string_map()) return medium_symbol_map();
2420 if (map == long_string_map()) return long_symbol_map();
2421
2422 if (map == short_cons_string_map()) return short_cons_symbol_map();
2423 if (map == medium_cons_string_map()) return medium_cons_symbol_map();
2424 if (map == long_cons_string_map()) return long_cons_symbol_map();
2425
2426 if (map == short_cons_ascii_string_map()) {
2427 return short_cons_ascii_symbol_map();
2428 }
2429 if (map == medium_cons_ascii_string_map()) {
2430 return medium_cons_ascii_symbol_map();
2431 }
2432 if (map == long_cons_ascii_string_map()) {
2433 return long_cons_ascii_symbol_map();
2434 }
2435
2436 if (map == short_sliced_string_map()) return short_sliced_symbol_map();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002437 if (map == medium_sliced_string_map()) return medium_sliced_symbol_map();
2438 if (map == long_sliced_string_map()) return long_sliced_symbol_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002439
2440 if (map == short_sliced_ascii_string_map()) {
2441 return short_sliced_ascii_symbol_map();
2442 }
2443 if (map == medium_sliced_ascii_string_map()) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002444 return medium_sliced_ascii_symbol_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002445 }
2446 if (map == long_sliced_ascii_string_map()) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002447 return long_sliced_ascii_symbol_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002448 }
2449
ager@chromium.org6f10e412009-02-13 10:11:16 +00002450 if (map == short_external_string_map()) {
2451 return short_external_symbol_map();
2452 }
2453 if (map == medium_external_string_map()) {
2454 return medium_external_symbol_map();
2455 }
2456 if (map == long_external_string_map()) {
2457 return long_external_symbol_map();
2458 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002459
2460 if (map == short_external_ascii_string_map()) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00002461 return short_external_ascii_symbol_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002462 }
2463 if (map == medium_external_ascii_string_map()) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00002464 return medium_external_ascii_symbol_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002465 }
2466 if (map == long_external_ascii_string_map()) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00002467 return long_external_ascii_symbol_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002468 }
2469
2470 // No match found.
2471 return NULL;
2472}
2473
2474
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002475Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
2476 int chars,
2477 uint32_t length_field) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002478 // Ensure the chars matches the number of characters in the buffer.
2479 ASSERT(static_cast<unsigned>(chars) == buffer->Length());
2480 // Determine whether the string is ascii.
2481 bool is_ascii = true;
ager@chromium.org6f10e412009-02-13 10:11:16 +00002482 while (buffer->has_more() && is_ascii) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002483 if (buffer->GetNext() > unibrow::Utf8::kMaxOneByteChar) is_ascii = false;
2484 }
2485 buffer->Rewind();
2486
2487 // Compute map and object size.
2488 int size;
2489 Map* map;
2490
2491 if (is_ascii) {
2492 if (chars <= String::kMaxShortStringSize) {
2493 map = short_ascii_symbol_map();
2494 } else if (chars <= String::kMaxMediumStringSize) {
2495 map = medium_ascii_symbol_map();
2496 } else {
2497 map = long_ascii_symbol_map();
2498 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002499 size = SeqAsciiString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002500 } else {
2501 if (chars <= String::kMaxShortStringSize) {
2502 map = short_symbol_map();
2503 } else if (chars <= String::kMaxMediumStringSize) {
2504 map = medium_symbol_map();
2505 } else {
2506 map = long_symbol_map();
2507 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002508 size = SeqTwoByteString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002509 }
2510
2511 // Allocate string.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002512 AllocationSpace space =
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002513 (size > MaxObjectSizeInPagedSpace()) ? LO_SPACE : OLD_DATA_SPACE;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002514 Object* result = AllocateRaw(size, space, OLD_DATA_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002515 if (result->IsFailure()) return result;
2516
2517 reinterpret_cast<HeapObject*>(result)->set_map(map);
2518 // The hash value contains the length of the string.
ager@chromium.org870a0b62008-11-04 11:43:05 +00002519 String* answer = String::cast(result);
ager@chromium.org870a0b62008-11-04 11:43:05 +00002520 answer->set_length_field(length_field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002521
ager@chromium.org870a0b62008-11-04 11:43:05 +00002522 ASSERT_EQ(size, answer->Size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002523
2524 // Fill in the characters.
2525 for (int i = 0; i < chars; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002526 answer->Set(i, buffer->GetNext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002527 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00002528 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002529}
2530
2531
2532Object* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002533 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002534 int size = SeqAsciiString::SizeFor(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002535
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002536 Object* result = Failure::OutOfMemoryException();
2537 if (space == NEW_SPACE) {
2538 result = size <= kMaxObjectSizeInNewSpace
2539 ? new_space_.AllocateRaw(size)
2540 : lo_space_->AllocateRawFixedArray(size);
2541 } else {
2542 if (size > MaxObjectSizeInPagedSpace()) space = LO_SPACE;
2543 result = AllocateRaw(size, space, OLD_DATA_SPACE);
2544 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002545 if (result->IsFailure()) return result;
2546
2547 // Determine the map based on the string's length.
2548 Map* map;
2549 if (length <= String::kMaxShortStringSize) {
2550 map = short_ascii_string_map();
2551 } else if (length <= String::kMaxMediumStringSize) {
2552 map = medium_ascii_string_map();
2553 } else {
2554 map = long_ascii_string_map();
2555 }
2556
2557 // Partially initialize the object.
2558 HeapObject::cast(result)->set_map(map);
2559 String::cast(result)->set_length(length);
2560 ASSERT_EQ(size, HeapObject::cast(result)->Size());
2561 return result;
2562}
2563
2564
2565Object* Heap::AllocateRawTwoByteString(int length, PretenureFlag pretenure) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002566 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002567 int size = SeqTwoByteString::SizeFor(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002568
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002569 Object* result = Failure::OutOfMemoryException();
2570 if (space == NEW_SPACE) {
2571 result = size <= kMaxObjectSizeInNewSpace
2572 ? new_space_.AllocateRaw(size)
2573 : lo_space_->AllocateRawFixedArray(size);
2574 } else {
2575 if (size > MaxObjectSizeInPagedSpace()) space = LO_SPACE;
2576 result = AllocateRaw(size, space, OLD_DATA_SPACE);
2577 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002578 if (result->IsFailure()) return result;
2579
2580 // Determine the map based on the string's length.
2581 Map* map;
2582 if (length <= String::kMaxShortStringSize) {
2583 map = short_string_map();
2584 } else if (length <= String::kMaxMediumStringSize) {
2585 map = medium_string_map();
2586 } else {
2587 map = long_string_map();
2588 }
2589
2590 // Partially initialize the object.
2591 HeapObject::cast(result)->set_map(map);
2592 String::cast(result)->set_length(length);
2593 ASSERT_EQ(size, HeapObject::cast(result)->Size());
2594 return result;
2595}
2596
2597
2598Object* Heap::AllocateEmptyFixedArray() {
2599 int size = FixedArray::SizeFor(0);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002600 Object* result = AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002601 if (result->IsFailure()) return result;
2602 // Initialize the object.
2603 reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
2604 reinterpret_cast<Array*>(result)->set_length(0);
2605 return result;
2606}
2607
2608
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002609Object* Heap::AllocateRawFixedArray(int length) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002610 // Use the general function if we're forced to always allocate.
2611 if (always_allocate()) return AllocateFixedArray(length, NOT_TENURED);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002612 // Allocate the raw data for a fixed array.
2613 int size = FixedArray::SizeFor(length);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002614 return size <= kMaxObjectSizeInNewSpace
2615 ? new_space_.AllocateRaw(size)
2616 : lo_space_->AllocateRawFixedArray(size);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002617}
2618
2619
2620Object* Heap::CopyFixedArray(FixedArray* src) {
2621 int len = src->length();
2622 Object* obj = AllocateRawFixedArray(len);
2623 if (obj->IsFailure()) return obj;
2624 if (Heap::InNewSpace(obj)) {
2625 HeapObject* dst = HeapObject::cast(obj);
2626 CopyBlock(reinterpret_cast<Object**>(dst->address()),
2627 reinterpret_cast<Object**>(src->address()),
2628 FixedArray::SizeFor(len));
2629 return obj;
2630 }
2631 HeapObject::cast(obj)->set_map(src->map());
2632 FixedArray* result = FixedArray::cast(obj);
2633 result->set_length(len);
2634 // Copy the content
2635 WriteBarrierMode mode = result->GetWriteBarrierMode();
2636 for (int i = 0; i < len; i++) result->set(i, src->get(i), mode);
2637 return result;
2638}
2639
2640
2641Object* Heap::AllocateFixedArray(int length) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002642 ASSERT(length >= 0);
ager@chromium.org32912102009-01-16 10:38:43 +00002643 if (length == 0) return empty_fixed_array();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002644 Object* result = AllocateRawFixedArray(length);
2645 if (!result->IsFailure()) {
2646 // Initialize header.
2647 reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
2648 FixedArray* array = FixedArray::cast(result);
2649 array->set_length(length);
2650 Object* value = undefined_value();
2651 // Initialize body.
2652 for (int index = 0; index < length; index++) {
2653 array->set(index, value, SKIP_WRITE_BARRIER);
2654 }
2655 }
2656 return result;
2657}
2658
2659
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002660Object* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) {
2661 ASSERT(empty_fixed_array()->IsFixedArray());
2662 if (length == 0) return empty_fixed_array();
2663
2664 int size = FixedArray::SizeFor(length);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002665 Object* result = Failure::OutOfMemoryException();
2666 if (pretenure != TENURED) {
2667 result = size <= kMaxObjectSizeInNewSpace
2668 ? new_space_.AllocateRaw(size)
2669 : lo_space_->AllocateRawFixedArray(size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002670 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002671 if (result->IsFailure()) {
2672 if (size > MaxObjectSizeInPagedSpace()) {
2673 result = lo_space_->AllocateRawFixedArray(size);
2674 } else {
2675 AllocationSpace space =
2676 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
2677 result = AllocateRaw(size, space, OLD_POINTER_SPACE);
2678 }
2679 if (result->IsFailure()) return result;
2680 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002681 // Initialize the object.
2682 reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
2683 FixedArray* array = FixedArray::cast(result);
2684 array->set_length(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002685 Object* value = undefined_value();
2686 for (int index = 0; index < length; index++) {
2687 array->set(index, value, SKIP_WRITE_BARRIER);
2688 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002689 return array;
2690}
2691
2692
2693Object* Heap::AllocateFixedArrayWithHoles(int length) {
2694 if (length == 0) return empty_fixed_array();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002695 Object* result = AllocateRawFixedArray(length);
2696 if (!result->IsFailure()) {
2697 // Initialize header.
2698 reinterpret_cast<Array*>(result)->set_map(fixed_array_map());
2699 FixedArray* array = FixedArray::cast(result);
2700 array->set_length(length);
2701 // Initialize body.
2702 Object* value = the_hole_value();
2703 for (int index = 0; index < length; index++) {
2704 array->set(index, value, SKIP_WRITE_BARRIER);
2705 }
2706 }
2707 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002708}
2709
2710
2711Object* Heap::AllocateHashTable(int length) {
2712 Object* result = Heap::AllocateFixedArray(length);
2713 if (result->IsFailure()) return result;
2714 reinterpret_cast<Array*>(result)->set_map(hash_table_map());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002715 ASSERT(result->IsHashTable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002716 return result;
2717}
2718
2719
2720Object* Heap::AllocateGlobalContext() {
2721 Object* result = Heap::AllocateFixedArray(Context::GLOBAL_CONTEXT_SLOTS);
2722 if (result->IsFailure()) return result;
2723 Context* context = reinterpret_cast<Context*>(result);
2724 context->set_map(global_context_map());
2725 ASSERT(context->IsGlobalContext());
2726 ASSERT(result->IsContext());
2727 return result;
2728}
2729
2730
2731Object* Heap::AllocateFunctionContext(int length, JSFunction* function) {
2732 ASSERT(length >= Context::MIN_CONTEXT_SLOTS);
2733 Object* result = Heap::AllocateFixedArray(length);
2734 if (result->IsFailure()) return result;
2735 Context* context = reinterpret_cast<Context*>(result);
2736 context->set_map(context_map());
2737 context->set_closure(function);
2738 context->set_fcontext(context);
2739 context->set_previous(NULL);
2740 context->set_extension(NULL);
2741 context->set_global(function->context()->global());
2742 ASSERT(!context->IsGlobalContext());
2743 ASSERT(context->is_function_context());
2744 ASSERT(result->IsContext());
2745 return result;
2746}
2747
2748
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002749Object* Heap::AllocateWithContext(Context* previous,
2750 JSObject* extension,
2751 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002752 Object* result = Heap::AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
2753 if (result->IsFailure()) return result;
2754 Context* context = reinterpret_cast<Context*>(result);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002755 context->set_map(is_catch_context ? catch_context_map() : context_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002756 context->set_closure(previous->closure());
2757 context->set_fcontext(previous->fcontext());
2758 context->set_previous(previous);
2759 context->set_extension(extension);
2760 context->set_global(previous->global());
2761 ASSERT(!context->IsGlobalContext());
2762 ASSERT(!context->is_function_context());
2763 ASSERT(result->IsContext());
2764 return result;
2765}
2766
2767
2768Object* Heap::AllocateStruct(InstanceType type) {
2769 Map* map;
2770 switch (type) {
2771#define MAKE_CASE(NAME, Name, name) case NAME##_TYPE: map = name##_map(); break;
2772STRUCT_LIST(MAKE_CASE)
2773#undef MAKE_CASE
2774 default:
2775 UNREACHABLE();
2776 return Failure::InternalError();
2777 }
2778 int size = map->instance_size();
2779 AllocationSpace space =
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002780 (size > MaxObjectSizeInPagedSpace()) ? LO_SPACE : OLD_POINTER_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002781 Object* result = Heap::Allocate(map, space);
2782 if (result->IsFailure()) return result;
2783 Struct::cast(result)->InitializeBody(size);
2784 return result;
2785}
2786
2787
ager@chromium.org96c75b52009-08-26 09:13:16 +00002788bool Heap::IdleNotification() {
2789 static const int kIdlesBeforeCollection = 7;
2790 static int number_idle_notifications = 0;
2791 static int last_gc_count = gc_count_;
2792
2793 bool finished = false;
2794
2795 if (last_gc_count == gc_count_) {
2796 number_idle_notifications++;
2797 } else {
2798 number_idle_notifications = 0;
2799 last_gc_count = gc_count_;
2800 }
2801
2802 if (number_idle_notifications >= kIdlesBeforeCollection) {
2803 // The first time through we collect without forcing compaction.
2804 // The second time through we force compaction and quit.
2805 bool force_compaction =
2806 number_idle_notifications > kIdlesBeforeCollection;
2807 CollectAllGarbage(force_compaction);
2808 last_gc_count = gc_count_;
2809 if (force_compaction) {
2810 number_idle_notifications = 0;
2811 finished = true;
2812 }
2813 }
2814
2815 // Uncommit unused memory in new space.
2816 Heap::UncommitFromSpace();
2817 return finished;
2818}
2819
2820
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002821#ifdef DEBUG
2822
2823void Heap::Print() {
2824 if (!HasBeenSetup()) return;
2825 Top::PrintStack();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002826 AllSpaces spaces;
2827 while (Space* space = spaces.next()) space->Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002828}
2829
2830
2831void Heap::ReportCodeStatistics(const char* title) {
2832 PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title);
2833 PagedSpace::ResetCodeStatistics();
2834 // We do not look for code in new space, map space, or old space. If code
2835 // somehow ends up in those spaces, we would miss it here.
2836 code_space_->CollectCodeStatistics();
2837 lo_space_->CollectCodeStatistics();
2838 PagedSpace::ReportCodeStatistics();
2839}
2840
2841
2842// This function expects that NewSpace's allocated objects histogram is
2843// populated (via a call to CollectStatistics or else as a side effect of a
2844// just-completed scavenge collection).
2845void Heap::ReportHeapStatistics(const char* title) {
2846 USE(title);
2847 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n",
2848 title, gc_count_);
2849 PrintF("mark-compact GC : %d\n", mc_count_);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002850 PrintF("old_gen_promotion_limit_ %d\n", old_gen_promotion_limit_);
2851 PrintF("old_gen_allocation_limit_ %d\n", old_gen_allocation_limit_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002852
2853 PrintF("\n");
2854 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles());
2855 GlobalHandles::PrintStats();
2856 PrintF("\n");
2857
2858 PrintF("Heap statistics : ");
2859 MemoryAllocator::ReportStatistics();
2860 PrintF("To space : ");
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002861 new_space_.ReportStatistics();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002862 PrintF("Old pointer space : ");
2863 old_pointer_space_->ReportStatistics();
2864 PrintF("Old data space : ");
2865 old_data_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002866 PrintF("Code space : ");
2867 code_space_->ReportStatistics();
2868 PrintF("Map space : ");
2869 map_space_->ReportStatistics();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002870 PrintF("Cell space : ");
2871 cell_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002872 PrintF("Large object space : ");
2873 lo_space_->ReportStatistics();
2874 PrintF(">>>>>> ========================================= >>>>>>\n");
2875}
2876
2877#endif // DEBUG
2878
2879bool Heap::Contains(HeapObject* value) {
2880 return Contains(value->address());
2881}
2882
2883
2884bool Heap::Contains(Address addr) {
2885 if (OS::IsOutsideAllocatedSpace(addr)) return false;
2886 return HasBeenSetup() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002887 (new_space_.ToSpaceContains(addr) ||
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002888 old_pointer_space_->Contains(addr) ||
2889 old_data_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002890 code_space_->Contains(addr) ||
2891 map_space_->Contains(addr) ||
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002892 cell_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002893 lo_space_->SlowContains(addr));
2894}
2895
2896
2897bool Heap::InSpace(HeapObject* value, AllocationSpace space) {
2898 return InSpace(value->address(), space);
2899}
2900
2901
2902bool Heap::InSpace(Address addr, AllocationSpace space) {
2903 if (OS::IsOutsideAllocatedSpace(addr)) return false;
2904 if (!HasBeenSetup()) return false;
2905
2906 switch (space) {
2907 case NEW_SPACE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002908 return new_space_.ToSpaceContains(addr);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002909 case OLD_POINTER_SPACE:
2910 return old_pointer_space_->Contains(addr);
2911 case OLD_DATA_SPACE:
2912 return old_data_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002913 case CODE_SPACE:
2914 return code_space_->Contains(addr);
2915 case MAP_SPACE:
2916 return map_space_->Contains(addr);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002917 case CELL_SPACE:
2918 return cell_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002919 case LO_SPACE:
2920 return lo_space_->SlowContains(addr);
2921 }
2922
2923 return false;
2924}
2925
2926
2927#ifdef DEBUG
2928void Heap::Verify() {
2929 ASSERT(HasBeenSetup());
2930
2931 VerifyPointersVisitor visitor;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002932 IterateRoots(&visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002933
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002934 new_space_.Verify();
2935
2936 VerifyPointersAndRSetVisitor rset_visitor;
2937 old_pointer_space_->Verify(&rset_visitor);
2938 map_space_->Verify(&rset_visitor);
2939
2940 VerifyPointersVisitor no_rset_visitor;
2941 old_data_space_->Verify(&no_rset_visitor);
2942 code_space_->Verify(&no_rset_visitor);
2943 cell_space_->Verify(&no_rset_visitor);
2944
2945 lo_space_->Verify();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002946}
2947#endif // DEBUG
2948
2949
2950Object* Heap::LookupSymbol(Vector<const char> string) {
2951 Object* symbol = NULL;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002952 Object* new_table = symbol_table()->LookupSymbol(string, &symbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002953 if (new_table->IsFailure()) return new_table;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002954 // Can't use set_symbol_table because SymbolTable::cast knows that
2955 // SymbolTable is a singleton and checks for identity.
2956 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002957 ASSERT(symbol != NULL);
2958 return symbol;
2959}
2960
2961
2962Object* Heap::LookupSymbol(String* string) {
2963 if (string->IsSymbol()) return string;
2964 Object* symbol = NULL;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002965 Object* new_table = symbol_table()->LookupString(string, &symbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002966 if (new_table->IsFailure()) return new_table;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002967 // Can't use set_symbol_table because SymbolTable::cast knows that
2968 // SymbolTable is a singleton and checks for identity.
2969 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002970 ASSERT(symbol != NULL);
2971 return symbol;
2972}
2973
2974
ager@chromium.org7c537e22008-10-16 08:43:32 +00002975bool Heap::LookupSymbolIfExists(String* string, String** symbol) {
2976 if (string->IsSymbol()) {
2977 *symbol = string;
2978 return true;
2979 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002980 return symbol_table()->LookupSymbolIfExists(string, symbol);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002981}
2982
2983
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002984#ifdef DEBUG
2985void Heap::ZapFromSpace() {
2986 ASSERT(HAS_HEAP_OBJECT_TAG(kFromSpaceZapValue));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002987 for (Address a = new_space_.FromSpaceLow();
2988 a < new_space_.FromSpaceHigh();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002989 a += kPointerSize) {
2990 Memory::Address_at(a) = kFromSpaceZapValue;
2991 }
2992}
2993#endif // DEBUG
2994
2995
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002996int Heap::IterateRSetRange(Address object_start,
2997 Address object_end,
2998 Address rset_start,
2999 ObjectSlotCallback copy_object_func) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003000 Address object_address = object_start;
3001 Address rset_address = rset_start;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003002 int set_bits_count = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003003
3004 // Loop over all the pointers in [object_start, object_end).
3005 while (object_address < object_end) {
3006 uint32_t rset_word = Memory::uint32_at(rset_address);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003007 if (rset_word != 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003008 uint32_t result_rset = rset_word;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003009 for (uint32_t bitmask = 1; bitmask != 0; bitmask = bitmask << 1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003010 // Do not dereference pointers at or past object_end.
3011 if ((rset_word & bitmask) != 0 && object_address < object_end) {
3012 Object** object_p = reinterpret_cast<Object**>(object_address);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003013 if (Heap::InNewSpace(*object_p)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003014 copy_object_func(reinterpret_cast<HeapObject**>(object_p));
3015 }
3016 // If this pointer does not need to be remembered anymore, clear
3017 // the remembered set bit.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003018 if (!Heap::InNewSpace(*object_p)) result_rset &= ~bitmask;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003019 set_bits_count++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003020 }
3021 object_address += kPointerSize;
3022 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003023 // Update the remembered set if it has changed.
3024 if (result_rset != rset_word) {
3025 Memory::uint32_at(rset_address) = result_rset;
3026 }
3027 } else {
3028 // No bits in the word were set. This is the common case.
3029 object_address += kPointerSize * kBitsPerInt;
3030 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003031 rset_address += kIntSize;
3032 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003033 return set_bits_count;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003034}
3035
3036
3037void Heap::IterateRSet(PagedSpace* space, ObjectSlotCallback copy_object_func) {
3038 ASSERT(Page::is_rset_in_use());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003039 ASSERT(space == old_pointer_space_ || space == map_space_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003040
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003041 static void* paged_rset_histogram = StatsTable::CreateHistogram(
3042 "V8.RSetPaged",
3043 0,
3044 Page::kObjectAreaSize / kPointerSize,
3045 30);
3046
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003047 PageIterator it(space, PageIterator::PAGES_IN_USE);
3048 while (it.has_next()) {
3049 Page* page = it.next();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003050 int count = IterateRSetRange(page->ObjectAreaStart(), page->AllocationTop(),
3051 page->RSetStart(), copy_object_func);
3052 if (paged_rset_histogram != NULL) {
3053 StatsTable::AddHistogramSample(paged_rset_histogram, count);
3054 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003055 }
3056}
3057
3058
3059#ifdef DEBUG
3060#define SYNCHRONIZE_TAG(tag) v->Synchronize(tag)
3061#else
3062#define SYNCHRONIZE_TAG(tag)
3063#endif
3064
3065void Heap::IterateRoots(ObjectVisitor* v) {
3066 IterateStrongRoots(v);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003067 v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003068 SYNCHRONIZE_TAG("symbol_table");
3069}
3070
3071
3072void Heap::IterateStrongRoots(ObjectVisitor* v) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003073 v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003074 SYNCHRONIZE_TAG("strong_root_list");
3075
ager@chromium.org3b45ab52009-03-19 22:21:34 +00003076 v->VisitPointer(bit_cast<Object**, String**>(&hidden_symbol_));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003077 SYNCHRONIZE_TAG("symbol");
3078
3079 Bootstrapper::Iterate(v);
3080 SYNCHRONIZE_TAG("bootstrapper");
3081 Top::Iterate(v);
3082 SYNCHRONIZE_TAG("top");
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003083
3084#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003085 Debug::Iterate(v);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003086#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003087 SYNCHRONIZE_TAG("debug");
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003088 CompilationCache::Iterate(v);
3089 SYNCHRONIZE_TAG("compilationcache");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003090
3091 // Iterate over local handles in handle scopes.
3092 HandleScopeImplementer::Iterate(v);
3093 SYNCHRONIZE_TAG("handlescope");
3094
3095 // Iterate over the builtin code objects and code stubs in the heap. Note
3096 // that it is not strictly necessary to iterate over code objects on
3097 // scavenge collections. We still do it here because this same function
3098 // is used by the mark-sweep collector and the deserializer.
3099 Builtins::IterateBuiltins(v);
3100 SYNCHRONIZE_TAG("builtins");
3101
3102 // Iterate over global handles.
3103 GlobalHandles::IterateRoots(v);
3104 SYNCHRONIZE_TAG("globalhandles");
3105
3106 // Iterate over pointers being held by inactive threads.
3107 ThreadManager::Iterate(v);
3108 SYNCHRONIZE_TAG("threadmanager");
3109}
3110#undef SYNCHRONIZE_TAG
3111
3112
3113// Flag is set when the heap has been configured. The heap can be repeatedly
3114// configured through the API until it is setup.
3115static bool heap_configured = false;
3116
3117// TODO(1236194): Since the heap size is configurable on the command line
3118// and through the API, we should gracefully handle the case that the heap
3119// size is not big enough to fit all the initial objects.
3120bool Heap::ConfigureHeap(int semispace_size, int old_gen_size) {
3121 if (HasBeenSetup()) return false;
3122
3123 if (semispace_size > 0) semispace_size_ = semispace_size;
3124 if (old_gen_size > 0) old_generation_size_ = old_gen_size;
3125
3126 // The new space size must be a power of two to support single-bit testing
3127 // for containment.
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00003128 semispace_size_ = RoundUpToPowerOf2(semispace_size_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003129 initial_semispace_size_ = Min(initial_semispace_size_, semispace_size_);
3130 young_generation_size_ = 2 * semispace_size_;
kasperl@chromium.orge959c182009-07-27 08:59:04 +00003131 external_allocation_limit_ = 10 * semispace_size_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003132
3133 // The old generation is paged.
3134 old_generation_size_ = RoundUp(old_generation_size_, Page::kPageSize);
3135
3136 heap_configured = true;
3137 return true;
3138}
3139
3140
kasper.lund7276f142008-07-30 08:49:36 +00003141bool Heap::ConfigureHeapDefault() {
3142 return ConfigureHeap(FLAG_new_space_size, FLAG_old_space_size);
3143}
3144
3145
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003146int Heap::PromotedSpaceSize() {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003147 return old_pointer_space_->Size()
3148 + old_data_space_->Size()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003149 + code_space_->Size()
3150 + map_space_->Size()
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003151 + cell_space_->Size()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003152 + lo_space_->Size();
3153}
3154
3155
kasper.lund7276f142008-07-30 08:49:36 +00003156int Heap::PromotedExternalMemorySize() {
3157 if (amount_of_external_allocated_memory_
3158 <= amount_of_external_allocated_memory_at_last_global_gc_) return 0;
3159 return amount_of_external_allocated_memory_
3160 - amount_of_external_allocated_memory_at_last_global_gc_;
3161}
3162
3163
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003164bool Heap::Setup(bool create_heap_objects) {
3165 // Initialize heap spaces and initial maps and objects. Whenever something
3166 // goes wrong, just return false. The caller should check the results and
3167 // call Heap::TearDown() to release allocated memory.
3168 //
3169 // If the heap is not yet configured (eg, through the API), configure it.
3170 // Configuration is based on the flags new-space-size (really the semispace
3171 // size) and old-space-size if set or the initial values of semispace_size_
3172 // and old_generation_size_ otherwise.
3173 if (!heap_configured) {
kasper.lund7276f142008-07-30 08:49:36 +00003174 if (!ConfigureHeapDefault()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003175 }
3176
3177 // Setup memory allocator and allocate an initial chunk of memory. The
3178 // initial chunk is double the size of the new space to ensure that we can
3179 // find a pair of semispaces that are contiguous and aligned to their size.
3180 if (!MemoryAllocator::Setup(MaxCapacity())) return false;
3181 void* chunk
3182 = MemoryAllocator::ReserveInitialChunk(2 * young_generation_size_);
3183 if (chunk == NULL) return false;
3184
3185 // Put the initial chunk of the old space at the start of the initial
3186 // chunk, then the two new space semispaces, then the initial chunk of
3187 // code space. Align the pair of semispaces to their size, which must be
3188 // a power of 2.
3189 ASSERT(IsPowerOf2(young_generation_size_));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003190 Address code_space_start = reinterpret_cast<Address>(chunk);
3191 Address new_space_start = RoundUp(code_space_start, young_generation_size_);
3192 Address old_space_start = new_space_start + young_generation_size_;
3193 int code_space_size = new_space_start - code_space_start;
3194 int old_space_size = young_generation_size_ - code_space_size;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003195
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003196 // Initialize new space.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003197 if (!new_space_.Setup(new_space_start, young_generation_size_)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003198
3199 // Initialize old space, set the maximum capacity to the old generation
kasper.lund7276f142008-07-30 08:49:36 +00003200 // size. It will not contain code.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003201 old_pointer_space_ =
3202 new OldSpace(old_generation_size_, OLD_POINTER_SPACE, NOT_EXECUTABLE);
3203 if (old_pointer_space_ == NULL) return false;
3204 if (!old_pointer_space_->Setup(old_space_start, old_space_size >> 1)) {
3205 return false;
3206 }
3207 old_data_space_ =
3208 new OldSpace(old_generation_size_, OLD_DATA_SPACE, NOT_EXECUTABLE);
3209 if (old_data_space_ == NULL) return false;
3210 if (!old_data_space_->Setup(old_space_start + (old_space_size >> 1),
3211 old_space_size >> 1)) {
3212 return false;
3213 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003214
3215 // Initialize the code space, set its maximum capacity to the old
kasper.lund7276f142008-07-30 08:49:36 +00003216 // generation size. It needs executable memory.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003217 code_space_ =
3218 new OldSpace(old_generation_size_, CODE_SPACE, EXECUTABLE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003219 if (code_space_ == NULL) return false;
3220 if (!code_space_->Setup(code_space_start, code_space_size)) return false;
3221
3222 // Initialize map space.
kasper.lund7276f142008-07-30 08:49:36 +00003223 map_space_ = new MapSpace(kMaxMapSpaceSize, MAP_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003224 if (map_space_ == NULL) return false;
3225 // Setting up a paged space without giving it a virtual memory range big
3226 // enough to hold at least a page will cause it to allocate.
3227 if (!map_space_->Setup(NULL, 0)) return false;
3228
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003229 // Initialize global property cell space.
3230 cell_space_ = new CellSpace(old_generation_size_, CELL_SPACE);
3231 if (cell_space_ == NULL) return false;
3232 // Setting up a paged space without giving it a virtual memory range big
3233 // enough to hold at least a page will cause it to allocate.
3234 if (!cell_space_->Setup(NULL, 0)) return false;
3235
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003236 // The large object code space may contain code or data. We set the memory
3237 // to be non-executable here for safety, but this means we need to enable it
3238 // explicitly when allocating large code objects.
3239 lo_space_ = new LargeObjectSpace(LO_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003240 if (lo_space_ == NULL) return false;
3241 if (!lo_space_->Setup()) return false;
3242
3243 if (create_heap_objects) {
3244 // Create initial maps.
3245 if (!CreateInitialMaps()) return false;
3246 if (!CreateApiObjects()) return false;
3247
3248 // Create initial objects
3249 if (!CreateInitialObjects()) return false;
3250 }
3251
3252 LOG(IntEvent("heap-capacity", Capacity()));
3253 LOG(IntEvent("heap-available", Available()));
3254
3255 return true;
3256}
3257
3258
3259void Heap::TearDown() {
3260 GlobalHandles::TearDown();
3261
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003262 new_space_.TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003263
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003264 if (old_pointer_space_ != NULL) {
3265 old_pointer_space_->TearDown();
3266 delete old_pointer_space_;
3267 old_pointer_space_ = NULL;
3268 }
3269
3270 if (old_data_space_ != NULL) {
3271 old_data_space_->TearDown();
3272 delete old_data_space_;
3273 old_data_space_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003274 }
3275
3276 if (code_space_ != NULL) {
3277 code_space_->TearDown();
3278 delete code_space_;
3279 code_space_ = NULL;
3280 }
3281
3282 if (map_space_ != NULL) {
3283 map_space_->TearDown();
3284 delete map_space_;
3285 map_space_ = NULL;
3286 }
3287
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003288 if (cell_space_ != NULL) {
3289 cell_space_->TearDown();
3290 delete cell_space_;
3291 cell_space_ = NULL;
3292 }
3293
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003294 if (lo_space_ != NULL) {
3295 lo_space_->TearDown();
3296 delete lo_space_;
3297 lo_space_ = NULL;
3298 }
3299
3300 MemoryAllocator::TearDown();
3301}
3302
3303
3304void Heap::Shrink() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003305 // Try to shrink all paged spaces.
3306 PagedSpaces spaces;
3307 while (PagedSpace* space = spaces.next()) space->Shrink();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003308}
3309
3310
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +00003311#ifdef ENABLE_HEAP_PROTECTION
3312
3313void Heap::Protect() {
ager@chromium.org71daaf62009-04-01 07:22:49 +00003314 if (HasBeenSetup()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003315 AllSpaces spaces;
3316 while (Space* space = spaces.next()) space->Protect();
ager@chromium.org71daaf62009-04-01 07:22:49 +00003317 }
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +00003318}
3319
3320
3321void Heap::Unprotect() {
ager@chromium.org71daaf62009-04-01 07:22:49 +00003322 if (HasBeenSetup()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003323 AllSpaces spaces;
3324 while (Space* space = spaces.next()) space->Unprotect();
ager@chromium.org71daaf62009-04-01 07:22:49 +00003325 }
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +00003326}
3327
3328#endif
3329
3330
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003331#ifdef DEBUG
3332
3333class PrintHandleVisitor: public ObjectVisitor {
3334 public:
3335 void VisitPointers(Object** start, Object** end) {
3336 for (Object** p = start; p < end; p++)
3337 PrintF(" handle %p to %p\n", p, *p);
3338 }
3339};
3340
3341void Heap::PrintHandles() {
3342 PrintF("Handles:\n");
3343 PrintHandleVisitor v;
3344 HandleScopeImplementer::Iterate(&v);
3345}
3346
3347#endif
3348
3349
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003350Space* AllSpaces::next() {
3351 switch (counter_++) {
3352 case NEW_SPACE:
3353 return Heap::new_space();
3354 case OLD_POINTER_SPACE:
3355 return Heap::old_pointer_space();
3356 case OLD_DATA_SPACE:
3357 return Heap::old_data_space();
3358 case CODE_SPACE:
3359 return Heap::code_space();
3360 case MAP_SPACE:
3361 return Heap::map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003362 case CELL_SPACE:
3363 return Heap::cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003364 case LO_SPACE:
3365 return Heap::lo_space();
3366 default:
3367 return NULL;
3368 }
3369}
3370
3371
3372PagedSpace* PagedSpaces::next() {
3373 switch (counter_++) {
3374 case OLD_POINTER_SPACE:
3375 return Heap::old_pointer_space();
3376 case OLD_DATA_SPACE:
3377 return Heap::old_data_space();
3378 case CODE_SPACE:
3379 return Heap::code_space();
3380 case MAP_SPACE:
3381 return Heap::map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003382 case CELL_SPACE:
3383 return Heap::cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003384 default:
3385 return NULL;
3386 }
3387}
3388
3389
3390
3391OldSpace* OldSpaces::next() {
3392 switch (counter_++) {
3393 case OLD_POINTER_SPACE:
3394 return Heap::old_pointer_space();
3395 case OLD_DATA_SPACE:
3396 return Heap::old_data_space();
3397 case CODE_SPACE:
3398 return Heap::code_space();
3399 default:
3400 return NULL;
3401 }
3402}
3403
3404
kasper.lund7276f142008-07-30 08:49:36 +00003405SpaceIterator::SpaceIterator() : current_space_(FIRST_SPACE), iterator_(NULL) {
3406}
3407
3408
3409SpaceIterator::~SpaceIterator() {
3410 // Delete active iterator if any.
3411 delete iterator_;
3412}
3413
3414
3415bool SpaceIterator::has_next() {
3416 // Iterate until no more spaces.
3417 return current_space_ != LAST_SPACE;
3418}
3419
3420
3421ObjectIterator* SpaceIterator::next() {
3422 if (iterator_ != NULL) {
3423 delete iterator_;
3424 iterator_ = NULL;
3425 // Move to the next space
3426 current_space_++;
3427 if (current_space_ > LAST_SPACE) {
3428 return NULL;
3429 }
3430 }
3431
3432 // Return iterator for the new current space.
3433 return CreateIterator();
3434}
3435
3436
3437// Create an iterator for the space to iterate.
3438ObjectIterator* SpaceIterator::CreateIterator() {
3439 ASSERT(iterator_ == NULL);
3440
3441 switch (current_space_) {
3442 case NEW_SPACE:
3443 iterator_ = new SemiSpaceIterator(Heap::new_space());
3444 break;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003445 case OLD_POINTER_SPACE:
3446 iterator_ = new HeapObjectIterator(Heap::old_pointer_space());
3447 break;
3448 case OLD_DATA_SPACE:
3449 iterator_ = new HeapObjectIterator(Heap::old_data_space());
kasper.lund7276f142008-07-30 08:49:36 +00003450 break;
3451 case CODE_SPACE:
3452 iterator_ = new HeapObjectIterator(Heap::code_space());
3453 break;
3454 case MAP_SPACE:
3455 iterator_ = new HeapObjectIterator(Heap::map_space());
3456 break;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003457 case CELL_SPACE:
3458 iterator_ = new HeapObjectIterator(Heap::cell_space());
3459 break;
kasper.lund7276f142008-07-30 08:49:36 +00003460 case LO_SPACE:
3461 iterator_ = new LargeObjectIterator(Heap::lo_space());
3462 break;
3463 }
3464
3465 // Return the newly allocated iterator;
3466 ASSERT(iterator_ != NULL);
3467 return iterator_;
3468}
3469
3470
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003471HeapIterator::HeapIterator() {
3472 Init();
3473}
3474
3475
3476HeapIterator::~HeapIterator() {
3477 Shutdown();
3478}
3479
3480
3481void HeapIterator::Init() {
3482 // Start the iteration.
3483 space_iterator_ = new SpaceIterator();
3484 object_iterator_ = space_iterator_->next();
3485}
3486
3487
3488void HeapIterator::Shutdown() {
3489 // Make sure the last iterator is deallocated.
3490 delete space_iterator_;
3491 space_iterator_ = NULL;
3492 object_iterator_ = NULL;
3493}
3494
3495
3496bool HeapIterator::has_next() {
3497 // No iterator means we are done.
3498 if (object_iterator_ == NULL) return false;
3499
3500 if (object_iterator_->has_next_object()) {
3501 // If the current iterator has more objects we are fine.
3502 return true;
3503 } else {
3504 // Go though the spaces looking for one that has objects.
3505 while (space_iterator_->has_next()) {
3506 object_iterator_ = space_iterator_->next();
3507 if (object_iterator_->has_next_object()) {
3508 return true;
3509 }
3510 }
3511 }
3512 // Done with the last space.
3513 object_iterator_ = NULL;
3514 return false;
3515}
3516
3517
3518HeapObject* HeapIterator::next() {
3519 if (has_next()) {
3520 return object_iterator_->next_object();
3521 } else {
3522 return NULL;
3523 }
3524}
3525
3526
3527void HeapIterator::reset() {
3528 // Restart the iterator.
3529 Shutdown();
3530 Init();
3531}
3532
3533
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003534#ifdef ENABLE_LOGGING_AND_PROFILING
3535namespace {
3536
3537// JSConstructorProfile is responsible for gathering and logging
3538// "constructor profile" of JS object allocated on heap.
3539// It is run during garbage collection cycle, thus it doesn't need
3540// to use handles.
3541class JSConstructorProfile BASE_EMBEDDED {
3542 public:
3543 JSConstructorProfile() : zscope_(DELETE_ON_EXIT) {}
3544 void CollectStats(JSObject* obj);
3545 void PrintStats();
3546 // Used by ZoneSplayTree::ForEach.
3547 void Call(String* name, const NumberAndSizeInfo& number_and_size);
3548 private:
3549 struct TreeConfig {
3550 typedef String* Key;
3551 typedef NumberAndSizeInfo Value;
3552 static const Key kNoKey;
3553 static const Value kNoValue;
3554 // Strings are unique, so it is sufficient to compare their pointers.
3555 static int Compare(const Key& a, const Key& b) {
3556 return a == b ? 0 : (a < b ? -1 : 1);
3557 }
3558 };
3559
3560 typedef ZoneSplayTree<TreeConfig> JSObjectsInfoTree;
3561 static int CalculateJSObjectNetworkSize(JSObject* obj);
3562
3563 ZoneScope zscope_;
3564 JSObjectsInfoTree js_objects_info_tree_;
3565};
3566
3567const JSConstructorProfile::TreeConfig::Key
3568 JSConstructorProfile::TreeConfig::kNoKey = NULL;
3569const JSConstructorProfile::TreeConfig::Value
3570 JSConstructorProfile::TreeConfig::kNoValue;
3571
3572
3573int JSConstructorProfile::CalculateJSObjectNetworkSize(JSObject* obj) {
3574 int size = obj->Size();
3575 // If 'properties' and 'elements' are non-empty (thus, non-shared),
3576 // take their size into account.
3577 if (FixedArray::cast(obj->properties())->length() != 0) {
3578 size += obj->properties()->Size();
3579 }
3580 if (FixedArray::cast(obj->elements())->length() != 0) {
3581 size += obj->elements()->Size();
3582 }
3583 return size;
3584}
3585
3586
3587void JSConstructorProfile::Call(String* name,
3588 const NumberAndSizeInfo& number_and_size) {
3589 SmartPointer<char> s_name;
3590 if (name != NULL) {
3591 s_name = name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
3592 }
3593 LOG(HeapSampleJSConstructorEvent(*s_name,
3594 number_and_size.number(),
3595 number_and_size.bytes()));
3596}
3597
3598
3599void JSConstructorProfile::CollectStats(JSObject* obj) {
3600 String* constructor_func = NULL;
3601 if (obj->map()->constructor()->IsJSFunction()) {
3602 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
3603 SharedFunctionInfo* sfi = constructor->shared();
3604 String* name = String::cast(sfi->name());
3605 constructor_func = name->length() > 0 ? name : sfi->inferred_name();
3606 } else if (obj->IsJSFunction()) {
3607 constructor_func = Heap::function_class_symbol();
3608 }
3609 JSObjectsInfoTree::Locator loc;
3610 if (!js_objects_info_tree_.Find(constructor_func, &loc)) {
3611 js_objects_info_tree_.Insert(constructor_func, &loc);
3612 }
3613 NumberAndSizeInfo number_and_size = loc.value();
3614 number_and_size.increment_number(1);
3615 number_and_size.increment_bytes(CalculateJSObjectNetworkSize(obj));
3616 loc.set_value(number_and_size);
3617}
3618
3619
3620void JSConstructorProfile::PrintStats() {
3621 js_objects_info_tree_.ForEach(this);
3622}
3623
3624} // namespace
3625#endif
3626
3627
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003628//
3629// HeapProfiler class implementation.
3630//
3631#ifdef ENABLE_LOGGING_AND_PROFILING
3632void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) {
3633 InstanceType type = obj->map()->instance_type();
3634 ASSERT(0 <= type && type <= LAST_TYPE);
3635 info[type].increment_number(1);
3636 info[type].increment_bytes(obj->Size());
3637}
3638#endif
3639
3640
3641#ifdef ENABLE_LOGGING_AND_PROFILING
3642void HeapProfiler::WriteSample() {
3643 LOG(HeapSampleBeginEvent("Heap", "allocated"));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00003644 LOG(HeapSampleStats(
3645 "Heap", "allocated", Heap::Capacity(), Heap::SizeOfObjects()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003646
3647 HistogramInfo info[LAST_TYPE+1];
3648#define DEF_TYPE_NAME(name) info[name].set_name(#name);
3649 INSTANCE_TYPE_LIST(DEF_TYPE_NAME)
3650#undef DEF_TYPE_NAME
3651
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003652 JSConstructorProfile js_cons_profile;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003653 HeapIterator iterator;
3654 while (iterator.has_next()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003655 HeapObject* obj = iterator.next();
3656 CollectStats(obj, info);
3657 if (obj->IsJSObject()) {
3658 js_cons_profile.CollectStats(JSObject::cast(obj));
3659 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003660 }
3661
3662 // Lump all the string types together.
3663 int string_number = 0;
3664 int string_bytes = 0;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003665#define INCREMENT_SIZE(type, size, name, camel_name) \
3666 string_number += info[type].number(); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003667 string_bytes += info[type].bytes();
3668 STRING_TYPE_LIST(INCREMENT_SIZE)
3669#undef INCREMENT_SIZE
3670 if (string_bytes > 0) {
3671 LOG(HeapSampleItemEvent("STRING_TYPE", string_number, string_bytes));
3672 }
3673
3674 for (int i = FIRST_NONSTRING_TYPE; i <= LAST_TYPE; ++i) {
3675 if (info[i].bytes() > 0) {
3676 LOG(HeapSampleItemEvent(info[i].name(), info[i].number(),
3677 info[i].bytes()));
3678 }
3679 }
3680
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003681 js_cons_profile.PrintStats();
3682
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003683 LOG(HeapSampleEndEvent("Heap", "allocated"));
3684}
3685
3686
3687#endif
3688
3689
3690
3691#ifdef DEBUG
3692
3693static bool search_for_any_global;
3694static Object* search_target;
3695static bool found_target;
3696static List<Object*> object_stack(20);
3697
3698
3699// Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject.
3700static const int kMarkTag = 2;
3701
3702static void MarkObjectRecursively(Object** p);
3703class MarkObjectVisitor : public ObjectVisitor {
3704 public:
3705 void VisitPointers(Object** start, Object** end) {
3706 // Copy all HeapObject pointers in [start, end)
3707 for (Object** p = start; p < end; p++) {
3708 if ((*p)->IsHeapObject())
3709 MarkObjectRecursively(p);
3710 }
3711 }
3712};
3713
3714static MarkObjectVisitor mark_visitor;
3715
3716static void MarkObjectRecursively(Object** p) {
3717 if (!(*p)->IsHeapObject()) return;
3718
3719 HeapObject* obj = HeapObject::cast(*p);
3720
3721 Object* map = obj->map();
3722
3723 if (!map->IsHeapObject()) return; // visited before
3724
3725 if (found_target) return; // stop if target found
3726 object_stack.Add(obj);
3727 if ((search_for_any_global && obj->IsJSGlobalObject()) ||
3728 (!search_for_any_global && (obj == search_target))) {
3729 found_target = true;
3730 return;
3731 }
3732
3733 if (obj->IsCode()) {
3734 Code::cast(obj)->ConvertICTargetsFromAddressToObject();
3735 }
3736
3737 // not visited yet
3738 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
3739
3740 Address map_addr = map_p->address();
3741
3742 obj->set_map(reinterpret_cast<Map*>(map_addr + kMarkTag));
3743
3744 MarkObjectRecursively(&map);
3745
3746 obj->IterateBody(map_p->instance_type(), obj->SizeFromMap(map_p),
3747 &mark_visitor);
3748
3749 if (!found_target) // don't pop if found the target
3750 object_stack.RemoveLast();
3751}
3752
3753
3754static void UnmarkObjectRecursively(Object** p);
3755class UnmarkObjectVisitor : public ObjectVisitor {
3756 public:
3757 void VisitPointers(Object** start, Object** end) {
3758 // Copy all HeapObject pointers in [start, end)
3759 for (Object** p = start; p < end; p++) {
3760 if ((*p)->IsHeapObject())
3761 UnmarkObjectRecursively(p);
3762 }
3763 }
3764};
3765
3766static UnmarkObjectVisitor unmark_visitor;
3767
3768static void UnmarkObjectRecursively(Object** p) {
3769 if (!(*p)->IsHeapObject()) return;
3770
3771 HeapObject* obj = HeapObject::cast(*p);
3772
3773 Object* map = obj->map();
3774
3775 if (map->IsHeapObject()) return; // unmarked already
3776
3777 Address map_addr = reinterpret_cast<Address>(map);
3778
3779 map_addr -= kMarkTag;
3780
3781 ASSERT_TAG_ALIGNED(map_addr);
3782
3783 HeapObject* map_p = HeapObject::FromAddress(map_addr);
3784
3785 obj->set_map(reinterpret_cast<Map*>(map_p));
3786
3787 UnmarkObjectRecursively(reinterpret_cast<Object**>(&map_p));
3788
3789 obj->IterateBody(Map::cast(map_p)->instance_type(),
3790 obj->SizeFromMap(Map::cast(map_p)),
3791 &unmark_visitor);
3792
3793 if (obj->IsCode()) {
3794 Code::cast(obj)->ConvertICTargetsFromObjectToAddress();
3795 }
3796}
3797
3798
3799static void MarkRootObjectRecursively(Object** root) {
3800 if (search_for_any_global) {
3801 ASSERT(search_target == NULL);
3802 } else {
3803 ASSERT(search_target->IsHeapObject());
3804 }
3805 found_target = false;
3806 object_stack.Clear();
3807
3808 MarkObjectRecursively(root);
3809 UnmarkObjectRecursively(root);
3810
3811 if (found_target) {
3812 PrintF("=====================================\n");
3813 PrintF("==== Path to object ====\n");
3814 PrintF("=====================================\n\n");
3815
3816 ASSERT(!object_stack.is_empty());
3817 for (int i = 0; i < object_stack.length(); i++) {
3818 if (i > 0) PrintF("\n |\n |\n V\n\n");
3819 Object* obj = object_stack[i];
3820 obj->Print();
3821 }
3822 PrintF("=====================================\n");
3823 }
3824}
3825
3826
3827// Helper class for visiting HeapObjects recursively.
3828class MarkRootVisitor: public ObjectVisitor {
3829 public:
3830 void VisitPointers(Object** start, Object** end) {
3831 // Visit all HeapObject pointers in [start, end)
3832 for (Object** p = start; p < end; p++) {
3833 if ((*p)->IsHeapObject())
3834 MarkRootObjectRecursively(p);
3835 }
3836 }
3837};
3838
3839
3840// Triggers a depth-first traversal of reachable objects from roots
3841// and finds a path to a specific heap object and prints it.
3842void Heap::TracePathToObject() {
3843 search_target = NULL;
3844 search_for_any_global = false;
3845
3846 MarkRootVisitor root_visitor;
3847 IterateRoots(&root_visitor);
3848}
3849
3850
3851// Triggers a depth-first traversal of reachable objects from roots
3852// and finds a path to any global object and prints it. Useful for
3853// determining the source for leaks of global objects.
3854void Heap::TracePathToGlobal() {
3855 search_target = NULL;
3856 search_for_any_global = true;
3857
3858 MarkRootVisitor root_visitor;
3859 IterateRoots(&root_visitor);
3860}
3861#endif
3862
3863
kasper.lund7276f142008-07-30 08:49:36 +00003864GCTracer::GCTracer()
3865 : start_time_(0.0),
3866 start_size_(0.0),
3867 gc_count_(0),
3868 full_gc_count_(0),
3869 is_compacting_(false),
3870 marked_count_(0) {
3871 // These two fields reflect the state of the previous full collection.
3872 // Set them before they are changed by the collector.
3873 previous_has_compacted_ = MarkCompactCollector::HasCompacted();
3874 previous_marked_count_ = MarkCompactCollector::previous_marked_count();
3875 if (!FLAG_trace_gc) return;
3876 start_time_ = OS::TimeCurrentMillis();
3877 start_size_ = SizeOfHeapObjects();
3878}
3879
3880
3881GCTracer::~GCTracer() {
3882 if (!FLAG_trace_gc) return;
3883 // Printf ONE line iff flag is set.
3884 PrintF("%s %.1f -> %.1f MB, %d ms.\n",
3885 CollectorString(),
3886 start_size_, SizeOfHeapObjects(),
3887 static_cast<int>(OS::TimeCurrentMillis() - start_time_));
kasperl@chromium.orge959c182009-07-27 08:59:04 +00003888
3889#if defined(ENABLE_LOGGING_AND_PROFILING)
3890 Heap::PrintShortHeapStatistics();
3891#endif
kasper.lund7276f142008-07-30 08:49:36 +00003892}
3893
3894
3895const char* GCTracer::CollectorString() {
3896 switch (collector_) {
3897 case SCAVENGER:
3898 return "Scavenge";
3899 case MARK_COMPACTOR:
3900 return MarkCompactCollector::HasCompacted() ? "Mark-compact"
3901 : "Mark-sweep";
3902 }
3903 return "Unknown GC";
3904}
3905
3906
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003907int KeyedLookupCache::Hash(Map* map, String* name) {
3908 // Uses only lower 32 bits if pointers are larger.
3909 uintptr_t addr_hash =
3910 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> 2;
3911 return (addr_hash ^ name->Hash()) % kLength;
3912}
3913
3914
3915int KeyedLookupCache::Lookup(Map* map, String* name) {
3916 int index = Hash(map, name);
3917 Key& key = keys_[index];
3918 if ((key.map == map) && key.name->Equals(name)) {
3919 return field_offsets_[index];
3920 }
3921 return -1;
3922}
3923
3924
3925void KeyedLookupCache::Update(Map* map, String* name, int field_offset) {
3926 String* symbol;
3927 if (Heap::LookupSymbolIfExists(name, &symbol)) {
3928 int index = Hash(map, symbol);
3929 Key& key = keys_[index];
3930 key.map = map;
3931 key.name = symbol;
3932 field_offsets_[index] = field_offset;
3933 }
3934}
3935
3936
3937void KeyedLookupCache::Clear() {
3938 for (int index = 0; index < kLength; index++) keys_[index].map = NULL;
3939}
3940
3941
3942KeyedLookupCache::Key KeyedLookupCache::keys_[KeyedLookupCache::kLength];
3943
3944
3945int KeyedLookupCache::field_offsets_[KeyedLookupCache::kLength];
3946
3947
3948void DescriptorLookupCache::Clear() {
3949 for (int index = 0; index < kLength; index++) keys_[index].array = NULL;
3950}
3951
3952
3953DescriptorLookupCache::Key
3954DescriptorLookupCache::keys_[DescriptorLookupCache::kLength];
3955
3956int DescriptorLookupCache::results_[DescriptorLookupCache::kLength];
3957
3958
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003959#ifdef DEBUG
3960bool Heap::GarbageCollectionGreedyCheck() {
3961 ASSERT(FLAG_gc_greedy);
3962 if (Bootstrapper::IsActive()) return true;
3963 if (disallow_allocation_failure()) return true;
3964 return CollectGarbage(0, NEW_SPACE);
3965}
3966#endif
3967
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003968} } // namespace v8::internal