blob: b85f1bcb4d8e3594d2918cdbe495d86e5d090a98 [file] [log] [blame]
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001// Copyright 2012 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"
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000033#include "codegen.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"
ricow@chromium.org4f693d62011-07-04 14:01:31 +000036#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "global-handles.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000038#include "heap-profiler.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000039#include "incremental-marking.h"
ager@chromium.org0ee099b2011-01-25 14:06:47 +000040#include "liveobjectlist-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "mark-compact.h"
42#include "natives.h"
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000043#include "objects-visiting.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000044#include "objects-visiting-inl.h"
fschneider@chromium.org7d10be52012-04-10 12:30:14 +000045#include "once.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000046#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047#include "scopeinfo.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000048#include "snapshot.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000049#include "store-buffer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050#include "v8threads.h"
ulan@chromium.org56c14af2012-09-20 12:51:09 +000051#include "v8utils.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000052#include "vm-state-inl.h"
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000053#if V8_TARGET_ARCH_ARM && !V8_INTERPRETED_REGEXP
ager@chromium.org18ad94b2009-09-02 08:22:29 +000054#include "regexp-macro-assembler.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000055#include "arm/regexp-macro-assembler-arm.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000056#endif
lrn@chromium.org7516f052011-03-30 08:52:27 +000057#if V8_TARGET_ARCH_MIPS && !V8_INTERPRETED_REGEXP
58#include "regexp-macro-assembler.h"
59#include "mips/regexp-macro-assembler-mips.h"
60#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
kasper.lund7276f142008-07-30 08:49:36 +000065
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000066Heap::Heap()
67 : isolate_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068// semispace_size_ should be a power of 2 and old_generation_size_ should be
69// a multiple of Page::kPageSize.
mmassi@chromium.org7028c052012-06-13 11:51:58 +000070#if defined(V8_TARGET_ARCH_X64)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000071#define LUMP_OF_MEMORY (2 * MB)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000072 code_range_size_(512*MB),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000073#else
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000074#define LUMP_OF_MEMORY MB
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000075 code_range_size_(0),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000076#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +000077#if defined(ANDROID)
78 reserved_semispace_size_(4 * Max(LUMP_OF_MEMORY, Page::kPageSize)),
79 max_semispace_size_(4 * Max(LUMP_OF_MEMORY, Page::kPageSize)),
80 initial_semispace_size_(Page::kPageSize),
81 max_old_generation_size_(192*MB),
82 max_executable_size_(max_old_generation_size_),
83#else
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000084 reserved_semispace_size_(8 * Max(LUMP_OF_MEMORY, Page::kPageSize)),
85 max_semispace_size_(8 * Max(LUMP_OF_MEMORY, Page::kPageSize)),
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000086 initial_semispace_size_(Page::kPageSize),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000087 max_old_generation_size_(700ul * LUMP_OF_MEMORY),
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000088 max_executable_size_(256l * LUMP_OF_MEMORY),
mmassi@chromium.org7028c052012-06-13 11:51:58 +000089#endif
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000090
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091// Variables set based on semispace_size_ and old_generation_size_ in
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000092// ConfigureHeap (survived_since_last_expansion_, external_allocation_limit_)
ager@chromium.org3811b432009-10-28 14:53:37 +000093// Will be 4 * reserved_semispace_size_ to ensure that young
94// generation can be aligned to its size.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000095 survived_since_last_expansion_(0),
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +000096 sweep_generation_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000097 always_allocate_scope_depth_(0),
98 linear_allocation_scope_depth_(0),
99 contexts_disposed_(0),
danno@chromium.org88aa0582012-03-23 15:11:57 +0000100 global_ic_age_(0),
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000101 flush_monomorphic_ics_(false),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000102 scan_on_scavenge_pages_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000103 new_space_(this),
104 old_pointer_space_(NULL),
105 old_data_space_(NULL),
106 code_space_(NULL),
107 map_space_(NULL),
108 cell_space_(NULL),
109 lo_space_(NULL),
110 gc_state_(NOT_IN_GC),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000111 gc_post_processing_depth_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000112 ms_count_(0),
113 gc_count_(0),
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000114 remembered_unmapped_pages_index_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000115 unflattened_strings_length_(0),
kasper.lund7276f142008-07-30 08:49:36 +0000116#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000117 allocation_allowed_(true),
118 allocation_timeout_(0),
119 disallow_allocation_failure_(false),
120 debug_utils_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121#endif // DEBUG
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000122 new_space_high_promotion_mode_active_(false),
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000123 old_gen_promotion_limit_(kMinimumPromotionLimit),
124 old_gen_allocation_limit_(kMinimumAllocationLimit),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000125 old_gen_limit_factor_(1),
126 size_of_old_gen_at_last_old_space_gc_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000127 external_allocation_limit_(0),
128 amount_of_external_allocated_memory_(0),
129 amount_of_external_allocated_memory_at_last_global_gc_(0),
130 old_gen_exhausted_(false),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000131 store_buffer_rebuilder_(store_buffer()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000132 hidden_symbol_(NULL),
133 global_gc_prologue_callback_(NULL),
134 global_gc_epilogue_callback_(NULL),
135 gc_safe_size_of_old_object_(NULL),
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000136 total_regexp_code_generated_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 tracer_(NULL),
138 young_survivors_after_last_gc_(0),
139 high_survival_rate_period_length_(0),
140 survival_rate_(0),
141 previous_survival_rate_trend_(Heap::STABLE),
142 survival_rate_trend_(Heap::STABLE),
143 max_gc_pause_(0),
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000144 total_gc_time_ms_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145 max_alive_after_gc_(0),
146 min_in_mutator_(kMaxInt),
147 alive_after_last_gc_(0),
148 last_gc_end_timestamp_(0.0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000149 store_buffer_(this),
150 marking_(this),
151 incremental_marking_(this),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000152 number_idle_notifications_(0),
153 last_idle_notification_gc_count_(0),
154 last_idle_notification_gc_count_init_(false),
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +0000155 mark_sweeps_since_idle_round_started_(0),
156 ms_count_at_last_idle_notification_(0),
157 gc_count_at_last_idle_gc_(0),
158 scavenges_since_last_idle_round_(kIdleScavengeThreshold),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000159 promotion_queue_(this),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 configured_(false),
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000161 chunks_queued_for_free_(NULL),
162 relocation_mutex_(NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000163 // Allow build-time customization of the max semispace size. Building
164 // V8 with snapshots and a non-default max semispace size is much
165 // easier if you can define it as part of the build environment.
166#if defined(V8_MAX_SEMISPACE_SIZE)
167 max_semispace_size_ = reserved_semispace_size_ = V8_MAX_SEMISPACE_SIZE;
168#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000169
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000170 intptr_t max_virtual = OS::MaxVirtualMemory();
171
172 if (max_virtual > 0) {
173 if (code_range_size_ > 0) {
174 // Reserve no more than 1/8 of the memory for the code range.
175 code_range_size_ = Min(code_range_size_, max_virtual >> 3);
176 }
177 }
178
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000179 memset(roots_, 0, sizeof(roots_[0]) * kRootListLength);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000180 native_contexts_list_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000181 mark_compact_collector_.heap_ = this;
182 external_string_table_.heap_ = this;
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000183 // Put a dummy entry in the remembered pages so we can find the list the
184 // minidump even if there are no real unmapped pages.
185 RememberUnmappedPage(NULL, false);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000186
187 ClearObjectStats(true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000188}
189
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000190
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000191intptr_t Heap::Capacity() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000192 if (!HasBeenSetUp()) return 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000193
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000194 return new_space_.Capacity() +
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000195 old_pointer_space_->Capacity() +
196 old_data_space_->Capacity() +
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000197 code_space_->Capacity() +
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000198 map_space_->Capacity() +
199 cell_space_->Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000200}
201
202
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000203intptr_t Heap::CommittedMemory() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000204 if (!HasBeenSetUp()) return 0;
ager@chromium.org3811b432009-10-28 14:53:37 +0000205
206 return new_space_.CommittedMemory() +
207 old_pointer_space_->CommittedMemory() +
208 old_data_space_->CommittedMemory() +
209 code_space_->CommittedMemory() +
210 map_space_->CommittedMemory() +
211 cell_space_->CommittedMemory() +
212 lo_space_->Size();
213}
214
danno@chromium.org72204d52012-10-31 10:02:10 +0000215
216size_t Heap::CommittedPhysicalMemory() {
217 if (!HasBeenSetUp()) return 0;
218
219 return new_space_.CommittedPhysicalMemory() +
220 old_pointer_space_->CommittedPhysicalMemory() +
221 old_data_space_->CommittedPhysicalMemory() +
222 code_space_->CommittedPhysicalMemory() +
223 map_space_->CommittedPhysicalMemory() +
224 cell_space_->CommittedPhysicalMemory() +
225 lo_space_->CommittedPhysicalMemory();
226}
227
228
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000229intptr_t Heap::CommittedMemoryExecutable() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000230 if (!HasBeenSetUp()) return 0;
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000231
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000232 return isolate()->memory_allocator()->SizeExecutable();
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000233}
234
ager@chromium.org3811b432009-10-28 14:53:37 +0000235
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000236intptr_t Heap::Available() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000237 if (!HasBeenSetUp()) return 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000239 return new_space_.Available() +
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000240 old_pointer_space_->Available() +
241 old_data_space_->Available() +
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000242 code_space_->Available() +
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000243 map_space_->Available() +
244 cell_space_->Available();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000245}
246
247
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000248bool Heap::HasBeenSetUp() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000249 return old_pointer_space_ != NULL &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000250 old_data_space_ != NULL &&
251 code_space_ != NULL &&
252 map_space_ != NULL &&
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000253 cell_space_ != NULL &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000254 lo_space_ != NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000255}
256
257
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000258int Heap::GcSafeSizeOfOldObject(HeapObject* object) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000259 if (IntrusiveMarking::IsMarked(object)) {
260 return IntrusiveMarking::SizeOfMarkedObject(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000261 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000262 return object->SizeFromMap(object->map());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000263}
264
265
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000266GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space,
267 const char** reason) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000268 // Is global GC requested?
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000269 if (space != NEW_SPACE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000270 isolate_->counters()->gc_compactor_caused_by_request()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000271 *reason = "GC in old space requested";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000272 return MARK_COMPACTOR;
273 }
274
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000275 if (FLAG_gc_global || (FLAG_stress_compaction && (gc_count_ & 1) != 0)) {
276 *reason = "GC in old space forced by flags";
277 return MARK_COMPACTOR;
278 }
279
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000280 // Is enough data promoted to justify a global GC?
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000281 if (OldGenerationPromotionLimitReached()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000282 isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000283 *reason = "promotion limit reached";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000284 return MARK_COMPACTOR;
285 }
286
287 // Have allocation in OLD and LO failed?
288 if (old_gen_exhausted_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000289 isolate_->counters()->
290 gc_compactor_caused_by_oldspace_exhaustion()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000291 *reason = "old generations exhausted";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000292 return MARK_COMPACTOR;
293 }
294
295 // Is there enough space left in OLD to guarantee that a scavenge can
296 // succeed?
297 //
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000298 // Note that MemoryAllocator->MaxAvailable() undercounts the memory available
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000299 // for object promotion. It counts only the bytes that the memory
300 // allocator has not yet allocated from the OS and assigned to any space,
301 // and does not count available bytes already in the old space or code
302 // space. Undercounting is safe---we may get an unrequested full GC when
303 // a scavenge would have succeeded.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 if (isolate_->memory_allocator()->MaxAvailable() <= new_space_.Size()) {
305 isolate_->counters()->
306 gc_compactor_caused_by_oldspace_exhaustion()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000307 *reason = "scavenge might not succeed";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000308 return MARK_COMPACTOR;
309 }
310
311 // Default
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000312 *reason = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000313 return SCAVENGER;
314}
315
316
317// TODO(1238405): Combine the infrastructure for --heap-stats and
318// --log-gc to avoid the complicated preprocessor and flag testing.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000319void Heap::ReportStatisticsBeforeGC() {
320 // Heap::ReportHeapStatistics will also log NewSpace statistics when
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000321 // compiled --log-gc is set. The following logic is used to avoid
322 // double logging.
323#ifdef DEBUG
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000324 if (FLAG_heap_stats || FLAG_log_gc) new_space_.CollectStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325 if (FLAG_heap_stats) {
326 ReportHeapStatistics("Before GC");
327 } else if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000328 new_space_.ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000329 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000330 if (FLAG_heap_stats || FLAG_log_gc) new_space_.ClearHistograms();
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000331#else
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000332 if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000333 new_space_.CollectStatistics();
334 new_space_.ReportStatistics();
335 new_space_.ClearHistograms();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000336 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000337#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338}
339
340
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000341void Heap::PrintShortHeapStatistics() {
342 if (!FLAG_trace_gc_verbose) return;
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000343 PrintPID("Memory allocator, used: %6" V8_PTR_PREFIX "d KB"
344 ", available: %6" V8_PTR_PREFIX "d KB\n",
345 isolate_->memory_allocator()->Size() / KB,
346 isolate_->memory_allocator()->Available() / KB);
347 PrintPID("New space, used: %6" V8_PTR_PREFIX "d KB"
348 ", available: %6" V8_PTR_PREFIX "d KB"
349 ", committed: %6" V8_PTR_PREFIX "d KB\n",
350 new_space_.Size() / KB,
351 new_space_.Available() / KB,
352 new_space_.CommittedMemory() / KB);
353 PrintPID("Old pointers, used: %6" V8_PTR_PREFIX "d KB"
354 ", available: %6" V8_PTR_PREFIX "d KB"
355 ", committed: %6" V8_PTR_PREFIX "d KB\n",
356 old_pointer_space_->SizeOfObjects() / KB,
357 old_pointer_space_->Available() / KB,
358 old_pointer_space_->CommittedMemory() / KB);
359 PrintPID("Old data space, used: %6" V8_PTR_PREFIX "d KB"
360 ", available: %6" V8_PTR_PREFIX "d KB"
361 ", committed: %6" V8_PTR_PREFIX "d KB\n",
362 old_data_space_->SizeOfObjects() / KB,
363 old_data_space_->Available() / KB,
364 old_data_space_->CommittedMemory() / KB);
365 PrintPID("Code space, used: %6" V8_PTR_PREFIX "d KB"
366 ", available: %6" V8_PTR_PREFIX "d KB"
367 ", committed: %6" V8_PTR_PREFIX "d KB\n",
368 code_space_->SizeOfObjects() / KB,
369 code_space_->Available() / KB,
370 code_space_->CommittedMemory() / KB);
371 PrintPID("Map space, used: %6" V8_PTR_PREFIX "d KB"
372 ", available: %6" V8_PTR_PREFIX "d KB"
373 ", committed: %6" V8_PTR_PREFIX "d KB\n",
374 map_space_->SizeOfObjects() / KB,
375 map_space_->Available() / KB,
376 map_space_->CommittedMemory() / KB);
377 PrintPID("Cell space, used: %6" V8_PTR_PREFIX "d KB"
378 ", available: %6" V8_PTR_PREFIX "d KB"
379 ", committed: %6" V8_PTR_PREFIX "d KB\n",
380 cell_space_->SizeOfObjects() / KB,
381 cell_space_->Available() / KB,
382 cell_space_->CommittedMemory() / KB);
383 PrintPID("Large object space, used: %6" V8_PTR_PREFIX "d KB"
384 ", available: %6" V8_PTR_PREFIX "d KB"
385 ", committed: %6" V8_PTR_PREFIX "d KB\n",
386 lo_space_->SizeOfObjects() / KB,
387 lo_space_->Available() / KB,
388 lo_space_->CommittedMemory() / KB);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000389 PrintPID("All spaces, used: %6" V8_PTR_PREFIX "d KB"
390 ", available: %6" V8_PTR_PREFIX "d KB"
391 ", committed: %6" V8_PTR_PREFIX "d KB\n",
392 this->SizeOfObjects() / KB,
393 this->Available() / KB,
394 this->CommittedMemory() / KB);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000395 PrintPID("Total time spent in GC : %d ms\n", total_gc_time_ms_);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000396}
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000397
398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399// TODO(1238405): Combine the infrastructure for --heap-stats and
400// --log-gc to avoid the complicated preprocessor and flag testing.
401void Heap::ReportStatisticsAfterGC() {
402 // Similar to the before GC, we use some complicated logic to ensure that
403 // NewSpace statistics are logged exactly once when --log-gc is turned on.
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000404#if defined(DEBUG)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000405 if (FLAG_heap_stats) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000406 new_space_.CollectStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000407 ReportHeapStatistics("After GC");
408 } else if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000409 new_space_.ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000411#else
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000412 if (FLAG_log_gc) new_space_.ReportStatistics();
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000413#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000415
416
417void Heap::GarbageCollectionPrologue() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 isolate_->transcendental_cache()->Clear();
ager@chromium.orgac091b72010-05-05 07:34:42 +0000419 ClearJSFunctionResultCaches();
kasper.lund7276f142008-07-30 08:49:36 +0000420 gc_count_++;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000421 unflattened_strings_length_ = 0;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000422
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000423 if (FLAG_flush_code && FLAG_flush_code_incrementally) {
424 mark_compact_collector()->EnableCodeFlushing(true);
425 }
426
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000427#ifdef VERIFY_HEAP
428 if (FLAG_verify_heap) {
429 Verify();
430 }
431#endif
432
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000433#ifdef DEBUG
434 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
435 allow_allocation(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000436
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437 if (FLAG_gc_verbose) Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000439 ReportStatisticsBeforeGC();
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000440#endif // DEBUG
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000441
442 LiveObjectList::GCPrologue();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000443 store_buffer()->GCPrologue();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444}
445
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000446
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000447intptr_t Heap::SizeOfObjects() {
448 intptr_t total = 0;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000449 AllSpaces spaces;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000450 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000451 total += space->SizeOfObjects();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000452 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000453 return total;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000454}
455
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000456
457void Heap::RepairFreeListsAfterBoot() {
458 PagedSpaces spaces;
459 for (PagedSpace* space = spaces.next();
460 space != NULL;
461 space = spaces.next()) {
462 space->RepairFreeListsAfterBoot();
463 }
464}
465
466
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000467void Heap::GarbageCollectionEpilogue() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000468 store_buffer()->GCEpilogue();
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000469 LiveObjectList::GCEpilogue();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000470
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000471 // In release mode, we only zap the from space under heap verification.
472 if (Heap::ShouldZapGarbage()) {
473 ZapFromSpace();
474 }
475
476#ifdef VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000477 if (FLAG_verify_heap) {
478 Verify();
479 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000480#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000481
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000482#ifdef DEBUG
483 allow_allocation(true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000484 if (FLAG_print_global_handles) isolate_->global_handles()->Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485 if (FLAG_print_handles) PrintHandles();
486 if (FLAG_gc_verbose) Print();
487 if (FLAG_code_stats) ReportCodeStatistics("After GC");
488#endif
489
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000490 isolate_->counters()->alive_after_last_gc()->Set(
491 static_cast<int>(SizeOfObjects()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000492
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000493 isolate_->counters()->symbol_table_capacity()->Set(
494 symbol_table()->Capacity());
495 isolate_->counters()->number_of_symbols()->Set(
496 symbol_table()->NumberOfElements());
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000497
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000498 if (CommittedMemory() > 0) {
499 isolate_->counters()->external_fragmentation_total()->AddSample(
500 static_cast<int>(100 - (SizeOfObjects() * 100.0) / CommittedMemory()));
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000501
502 isolate_->counters()->heap_fraction_map_space()->AddSample(
503 static_cast<int>(
504 (map_space()->CommittedMemory() * 100.0) / CommittedMemory()));
505 isolate_->counters()->heap_fraction_cell_space()->AddSample(
506 static_cast<int>(
507 (cell_space()->CommittedMemory() * 100.0) / CommittedMemory()));
508
509 isolate_->counters()->heap_sample_total_committed()->AddSample(
510 static_cast<int>(CommittedMemory() / KB));
511 isolate_->counters()->heap_sample_total_used()->AddSample(
512 static_cast<int>(SizeOfObjects() / KB));
513 isolate_->counters()->heap_sample_map_space_committed()->AddSample(
514 static_cast<int>(map_space()->CommittedMemory() / KB));
515 isolate_->counters()->heap_sample_cell_space_committed()->AddSample(
516 static_cast<int>(cell_space()->CommittedMemory() / KB));
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000517 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000518
519#define UPDATE_COUNTERS_FOR_SPACE(space) \
520 isolate_->counters()->space##_bytes_available()->Set( \
521 static_cast<int>(space()->Available())); \
522 isolate_->counters()->space##_bytes_committed()->Set( \
523 static_cast<int>(space()->CommittedMemory())); \
524 isolate_->counters()->space##_bytes_used()->Set( \
525 static_cast<int>(space()->SizeOfObjects()));
526#define UPDATE_FRAGMENTATION_FOR_SPACE(space) \
527 if (space()->CommittedMemory() > 0) { \
528 isolate_->counters()->external_fragmentation_##space()->AddSample( \
529 static_cast<int>(100 - \
530 (space()->SizeOfObjects() * 100.0) / space()->CommittedMemory())); \
531 }
532#define UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(space) \
533 UPDATE_COUNTERS_FOR_SPACE(space) \
534 UPDATE_FRAGMENTATION_FOR_SPACE(space)
535
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000536 UPDATE_COUNTERS_FOR_SPACE(new_space)
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000537 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(old_pointer_space)
538 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(old_data_space)
539 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(code_space)
540 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(map_space)
541 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(cell_space)
542 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(lo_space)
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000543#undef UPDATE_COUNTERS_FOR_SPACE
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000544#undef UPDATE_FRAGMENTATION_FOR_SPACE
545#undef UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000546
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000547#if defined(DEBUG)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548 ReportStatisticsAfterGC();
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000549#endif // DEBUG
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000550#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 isolate_->debug()->AfterGarbageCollection();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000552#endif // ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000553}
554
555
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000556void Heap::CollectAllGarbage(int flags, const char* gc_reason) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000557 // Since we are ignoring the return value, the exact choice of space does
558 // not matter, so long as we do not specify NEW_SPACE, which would not
559 // cause a full GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000560 mark_compact_collector_.SetFlags(flags);
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000561 CollectGarbage(OLD_POINTER_SPACE, gc_reason);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000562 mark_compact_collector_.SetFlags(kNoGCFlags);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000563}
564
565
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000566void Heap::CollectAllAvailableGarbage(const char* gc_reason) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000567 // Since we are ignoring the return value, the exact choice of space does
568 // not matter, so long as we do not specify NEW_SPACE, which would not
569 // cause a full GC.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000570 // Major GC would invoke weak handle callbacks on weakly reachable
571 // handles, but won't collect weakly reachable objects until next
572 // major GC. Therefore if we collect aggressively and weak handle callback
573 // has been invoked, we rerun major GC to release objects which become
574 // garbage.
575 // Note: as weak callbacks can execute arbitrary code, we cannot
576 // hope that eventually there will be no weak callbacks invocations.
577 // Therefore stop recollecting after several attempts.
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000578 mark_compact_collector()->SetFlags(kMakeHeapIterableMask |
579 kReduceMemoryFootprintMask);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000580 isolate_->compilation_cache()->Clear();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000581 const int kMaxNumberOfAttempts = 7;
582 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000583 if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR, gc_reason, NULL)) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000584 break;
585 }
586 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000587 mark_compact_collector()->SetFlags(kNoGCFlags);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000588 new_space_.Shrink();
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000589 UncommitFromSpace();
590 Shrink();
danno@chromium.orgc612e022011-11-10 11:38:15 +0000591 incremental_marking()->UncommitMarkingDeque();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000592}
593
594
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000595bool Heap::CollectGarbage(AllocationSpace space,
596 GarbageCollector collector,
597 const char* gc_reason,
598 const char* collector_reason) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599 // The VM is in the GC state until exiting this function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 VMState state(isolate_, GC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000601
602#ifdef DEBUG
603 // Reset the allocation timeout to the GC interval, but make sure to
604 // allow at least a few allocations after a collection. The reason
605 // for this is that we have a lot of allocation sequences and we
606 // assume that a garbage collection will allow the subsequent
607 // allocation attempts to go through.
608 allocation_timeout_ = Max(6, FLAG_gc_interval);
609#endif
610
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000611 if (collector == SCAVENGER && !incremental_marking()->IsStopped()) {
612 if (FLAG_trace_incremental_marking) {
613 PrintF("[IncrementalMarking] Scavenge during marking.\n");
614 }
615 }
616
617 if (collector == MARK_COMPACTOR &&
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000618 !mark_compact_collector()->abort_incremental_marking_ &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000619 !incremental_marking()->IsStopped() &&
620 !incremental_marking()->should_hurry() &&
621 FLAG_incremental_marking_steps) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000622 // Make progress in incremental marking.
623 const intptr_t kStepSizeWhenDelayedByScavenge = 1 * MB;
624 incremental_marking()->Step(kStepSizeWhenDelayedByScavenge,
625 IncrementalMarking::NO_GC_VIA_STACK_GUARD);
626 if (!incremental_marking()->IsComplete()) {
627 if (FLAG_trace_incremental_marking) {
628 PrintF("[IncrementalMarking] Delaying MarkSweep.\n");
629 }
630 collector = SCAVENGER;
631 collector_reason = "incremental marking delaying mark-sweep";
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000632 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000633 }
634
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000635 bool next_gc_likely_to_collect_more = false;
636
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000637 { GCTracer tracer(this, gc_reason, collector_reason);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000638 GarbageCollectionPrologue();
kasper.lund7276f142008-07-30 08:49:36 +0000639 // The GC count was incremented in the prologue. Tell the tracer about
640 // it.
641 tracer.set_gc_count(gc_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000642
kasper.lund7276f142008-07-30 08:49:36 +0000643 // Tell the tracer which collector we've selected.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000644 tracer.set_collector(collector);
645
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000646 HistogramTimer* rate = (collector == SCAVENGER)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 ? isolate_->counters()->gc_scavenger()
648 : isolate_->counters()->gc_compactor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 rate->Start();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000650 next_gc_likely_to_collect_more =
651 PerformGarbageCollection(collector, &tracer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000652 rate->Stop();
653
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000654 ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped());
655
656 // This can do debug callbacks and restart incremental marking.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000657 GarbageCollectionEpilogue();
658 }
659
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000660 if (incremental_marking()->IsStopped()) {
661 if (incremental_marking()->WorthActivating() && NextGCIsLikelyToBeFull()) {
662 incremental_marking()->Start();
663 }
664 }
665
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000666 return next_gc_likely_to_collect_more;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000667}
668
669
kasper.lund7276f142008-07-30 08:49:36 +0000670void Heap::PerformScavenge() {
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000671 GCTracer tracer(this, NULL, NULL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000672 if (incremental_marking()->IsStopped()) {
673 PerformGarbageCollection(SCAVENGER, &tracer);
674 } else {
675 PerformGarbageCollection(MARK_COMPACTOR, &tracer);
676 }
kasper.lund7276f142008-07-30 08:49:36 +0000677}
678
679
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000680#ifdef VERIFY_HEAP
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000681// Helper class for verifying the symbol table.
682class SymbolTableVerifier : public ObjectVisitor {
683 public:
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000684 void VisitPointers(Object** start, Object** end) {
685 // Visit all HeapObject pointers in [start, end).
686 for (Object** p = start; p < end; p++) {
687 if ((*p)->IsHeapObject()) {
688 // Check that the symbol is actually a symbol.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000689 CHECK((*p)->IsTheHole() || (*p)->IsUndefined() || (*p)->IsSymbol());
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000690 }
691 }
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000692 }
693};
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000694
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000695
696static void VerifySymbolTable() {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000697 SymbolTableVerifier verifier;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000698 HEAP->symbol_table()->IterateElements(&verifier);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000699}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000700#endif // VERIFY_HEAP
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000701
702
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000703static bool AbortIncrementalMarkingAndCollectGarbage(
704 Heap* heap,
705 AllocationSpace space,
706 const char* gc_reason = NULL) {
707 heap->mark_compact_collector()->SetFlags(Heap::kAbortIncrementalMarkingMask);
708 bool result = heap->CollectGarbage(space, gc_reason);
709 heap->mark_compact_collector()->SetFlags(Heap::kNoGCFlags);
710 return result;
711}
712
713
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000714void Heap::ReserveSpace(
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000715 int *sizes,
716 Address *locations_out) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000717 bool gc_performed = true;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000718 int counter = 0;
719 static const int kThreshold = 20;
720 while (gc_performed && counter++ < kThreshold) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000721 gc_performed = false;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000722 ASSERT(NEW_SPACE == FIRST_PAGED_SPACE - 1);
723 for (int space = NEW_SPACE; space <= LAST_PAGED_SPACE; space++) {
724 if (sizes[space] != 0) {
725 MaybeObject* allocation;
726 if (space == NEW_SPACE) {
727 allocation = new_space()->AllocateRaw(sizes[space]);
728 } else {
729 allocation = paged_space(space)->AllocateRaw(sizes[space]);
730 }
731 FreeListNode* node;
732 if (!allocation->To<FreeListNode>(&node)) {
733 if (space == NEW_SPACE) {
734 Heap::CollectGarbage(NEW_SPACE,
735 "failed to reserve space in the new space");
736 } else {
737 AbortIncrementalMarkingAndCollectGarbage(
738 this,
739 static_cast<AllocationSpace>(space),
740 "failed to reserve space in paged space");
741 }
742 gc_performed = true;
743 break;
744 } else {
745 // Mark with a free list node, in case we have a GC before
746 // deserializing.
747 node->set_size(this, sizes[space]);
748 locations_out[space] = node->address();
749 }
750 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000751 }
752 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000753
754 if (gc_performed) {
755 // Failed to reserve the space after several attempts.
756 V8::FatalProcessOutOfMemory("Heap::ReserveSpace");
757 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000758}
759
760
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000761void Heap::EnsureFromSpaceIsCommitted() {
762 if (new_space_.CommitFromSpaceIfNeeded()) return;
763
764 // Committing memory to from space failed.
765 // Try shrinking and try again.
766 Shrink();
767 if (new_space_.CommitFromSpaceIfNeeded()) return;
768
769 // Committing memory to from space failed again.
770 // Memory is exhausted and we will die.
771 V8::FatalProcessOutOfMemory("Committing semi space failed.");
772}
773
774
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000775void Heap::ClearJSFunctionResultCaches() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000776 if (isolate_->bootstrapper()->IsActive()) return;
ager@chromium.orgac091b72010-05-05 07:34:42 +0000777
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000778 Object* context = native_contexts_list_;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000779 while (!context->IsUndefined()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000780 // Get the caches for this context. GC can happen when the context
781 // is not fully initialized, so the caches can be undefined.
782 Object* caches_or_undefined =
783 Context::cast(context)->get(Context::JSFUNCTION_RESULT_CACHES_INDEX);
784 if (!caches_or_undefined->IsUndefined()) {
785 FixedArray* caches = FixedArray::cast(caches_or_undefined);
786 // Clear the caches:
787 int length = caches->length();
788 for (int i = 0; i < length; i++) {
789 JSFunctionResultCache::cast(caches->get(i))->Clear();
790 }
ager@chromium.orgac091b72010-05-05 07:34:42 +0000791 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000792 // Get the next context:
793 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000794 }
ager@chromium.orgac091b72010-05-05 07:34:42 +0000795}
796
797
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000798
ricow@chromium.org65fae842010-08-25 15:26:24 +0000799void Heap::ClearNormalizedMapCaches() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000800 if (isolate_->bootstrapper()->IsActive() &&
801 !incremental_marking()->IsMarking()) {
802 return;
803 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000804
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000805 Object* context = native_contexts_list_;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000806 while (!context->IsUndefined()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000807 // GC can happen when the context is not fully initialized,
808 // so the cache can be undefined.
809 Object* cache =
810 Context::cast(context)->get(Context::NORMALIZED_MAP_CACHE_INDEX);
811 if (!cache->IsUndefined()) {
812 NormalizedMapCache::cast(cache)->Clear();
813 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000814 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
815 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000816}
817
818
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000819void Heap::UpdateSurvivalRateTrend(int start_new_space_size) {
820 double survival_rate =
821 (static_cast<double>(young_survivors_after_last_gc_) * 100) /
822 start_new_space_size;
823
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000824 if (survival_rate > kYoungSurvivalRateHighThreshold) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000825 high_survival_rate_period_length_++;
826 } else {
827 high_survival_rate_period_length_ = 0;
828 }
829
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000830 if (survival_rate < kYoungSurvivalRateLowThreshold) {
831 low_survival_rate_period_length_++;
832 } else {
833 low_survival_rate_period_length_ = 0;
834 }
835
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000836 double survival_rate_diff = survival_rate_ - survival_rate;
837
838 if (survival_rate_diff > kYoungSurvivalRateAllowedDeviation) {
839 set_survival_rate_trend(DECREASING);
840 } else if (survival_rate_diff < -kYoungSurvivalRateAllowedDeviation) {
841 set_survival_rate_trend(INCREASING);
842 } else {
843 set_survival_rate_trend(STABLE);
844 }
845
846 survival_rate_ = survival_rate;
847}
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000848
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000849bool Heap::PerformGarbageCollection(GarbageCollector collector,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000850 GCTracer* tracer) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000851 bool next_gc_likely_to_collect_more = false;
852
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000853 if (collector != SCAVENGER) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000854 PROFILE(isolate_, CodeMovingGCEvent());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000855 }
856
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000857#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000858 if (FLAG_verify_heap) {
859 VerifySymbolTable();
860 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000861#endif
862
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863 if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) {
864 ASSERT(!allocation_allowed_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000865 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000866 global_gc_prologue_callback_();
867 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000868
869 GCType gc_type =
870 collector == MARK_COMPACTOR ? kGCTypeMarkSweepCompact : kGCTypeScavenge;
871
872 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
873 if (gc_type & gc_prologue_callbacks_[i].gc_type) {
874 gc_prologue_callbacks_[i].callback(gc_type, kNoGCCallbackFlags);
875 }
876 }
877
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000878 EnsureFromSpaceIsCommitted();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000879
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000880 int start_new_space_size = Heap::new_space()->SizeAsInt();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000881
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000882 if (IsHighSurvivalRate()) {
883 // We speed up the incremental marker if it is running so that it
884 // does not fall behind the rate of promotion, which would cause a
885 // constantly growing old space.
886 incremental_marking()->NotifyOfHighPromotionRate();
887 }
888
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889 if (collector == MARK_COMPACTOR) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000890 // Perform mark-sweep with optional compaction.
kasper.lund7276f142008-07-30 08:49:36 +0000891 MarkCompact(tracer);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000892 sweep_generation_++;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000893 bool high_survival_rate_during_scavenges = IsHighSurvivalRate() &&
894 IsStableOrIncreasingSurvivalTrend();
895
896 UpdateSurvivalRateTrend(start_new_space_size);
897
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000898 size_of_old_gen_at_last_old_space_gc_ = PromotedSpaceSizeOfObjects();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000899
lrn@chromium.org303ada72010-10-27 09:33:13 +0000900 if (high_survival_rate_during_scavenges &&
901 IsStableOrIncreasingSurvivalTrend()) {
902 // Stable high survival rates of young objects both during partial and
903 // full collection indicate that mutator is either building or modifying
904 // a structure with a long lifetime.
905 // In this case we aggressively raise old generation memory limits to
906 // postpone subsequent mark-sweep collection and thus trade memory
907 // space for the mutation speed.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000908 old_gen_limit_factor_ = 2;
909 } else {
910 old_gen_limit_factor_ = 1;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000911 }
912
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000913 old_gen_promotion_limit_ =
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000914 OldGenPromotionLimit(size_of_old_gen_at_last_old_space_gc_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000915 old_gen_allocation_limit_ =
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000916 OldGenAllocationLimit(size_of_old_gen_at_last_old_space_gc_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000917
lrn@chromium.org303ada72010-10-27 09:33:13 +0000918 old_gen_exhausted_ = false;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000919 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000920 tracer_ = tracer;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000921 Scavenge();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000922 tracer_ = NULL;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000923
924 UpdateSurvivalRateTrend(start_new_space_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000925 }
ager@chromium.org439e85a2009-08-26 13:15:29 +0000926
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000927 if (!new_space_high_promotion_mode_active_ &&
928 new_space_.Capacity() == new_space_.MaximumCapacity() &&
929 IsStableOrIncreasingSurvivalTrend() &&
930 IsHighSurvivalRate()) {
931 // Stable high survival rates even though young generation is at
932 // maximum capacity indicates that most objects will be promoted.
933 // To decrease scavenger pauses and final mark-sweep pauses, we
934 // have to limit maximal capacity of the young generation.
935 new_space_high_promotion_mode_active_ = true;
936 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000937 PrintPID("Limited new space size due to high promotion rate: %d MB\n",
938 new_space_.InitialCapacity() / MB);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000939 }
940 } else if (new_space_high_promotion_mode_active_ &&
941 IsStableOrDecreasingSurvivalTrend() &&
942 IsLowSurvivalRate()) {
943 // Decreasing low survival rates might indicate that the above high
944 // promotion mode is over and we should allow the young generation
945 // to grow again.
946 new_space_high_promotion_mode_active_ = false;
947 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000948 PrintPID("Unlimited new space size due to low promotion rate: %d MB\n",
949 new_space_.MaximumCapacity() / MB);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000950 }
951 }
952
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000953 if (new_space_high_promotion_mode_active_ &&
954 new_space_.Capacity() > new_space_.InitialCapacity()) {
955 new_space_.Shrink();
956 }
957
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000958 isolate_->counters()->objs_since_last_young()->Set(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000959
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000960 gc_post_processing_depth_++;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000961 { DisableAssertNoAllocation allow_allocation;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000962 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000963 next_gc_likely_to_collect_more =
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000964 isolate_->global_handles()->PostGarbageCollectionProcessing(collector);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000965 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000966 gc_post_processing_depth_--;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000967
ager@chromium.org3811b432009-10-28 14:53:37 +0000968 // Update relocatables.
969 Relocatable::PostGarbageCollectionProcessing();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000970
kasper.lund7276f142008-07-30 08:49:36 +0000971 if (collector == MARK_COMPACTOR) {
972 // Register the amount of external allocated memory.
973 amount_of_external_allocated_memory_at_last_global_gc_ =
974 amount_of_external_allocated_memory_;
975 }
976
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000977 GCCallbackFlags callback_flags = kNoGCCallbackFlags;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000978 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
979 if (gc_type & gc_epilogue_callbacks_[i].gc_type) {
980 gc_epilogue_callbacks_[i].callback(gc_type, callback_flags);
981 }
982 }
983
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984 if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) {
985 ASSERT(!allocation_allowed_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000986 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000987 global_gc_epilogue_callback_();
988 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000989
990#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000991 if (FLAG_verify_heap) {
992 VerifySymbolTable();
993 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000994#endif
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000995
996 return next_gc_likely_to_collect_more;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997}
998
999
kasper.lund7276f142008-07-30 08:49:36 +00001000void Heap::MarkCompact(GCTracer* tracer) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001001 gc_state_ = MARK_COMPACT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001002 LOG(isolate_, ResourceEvent("markcompact", "begin"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001004 mark_compact_collector_.Prepare(tracer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001005
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001006 ms_count_++;
1007 tracer->set_full_gc_count(ms_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001008
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001009 MarkCompactPrologue();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001010
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001011 mark_compact_collector_.CollectGarbage();
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001012
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001013 LOG(isolate_, ResourceEvent("markcompact", "end"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014
1015 gc_state_ = NOT_IN_GC;
1016
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001017 isolate_->counters()->objs_since_last_full()->Set(0);
kasperl@chromium.org8b2bb262010-03-01 09:46:28 +00001018
1019 contexts_disposed_ = 0;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001020
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001021 flush_monomorphic_ics_ = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001022}
1023
1024
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001025void Heap::MarkCompactPrologue() {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001026 // At any old GC clear the keyed lookup cache to enable collection of unused
1027 // maps.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001028 isolate_->keyed_lookup_cache()->Clear();
1029 isolate_->context_slot_cache()->Clear();
1030 isolate_->descriptor_lookup_cache()->Clear();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001031 RegExpResultsCache::Clear(string_split_cache());
1032 RegExpResultsCache::Clear(regexp_multiple_cache());
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001033
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001034 isolate_->compilation_cache()->MarkCompactPrologue();
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001035
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001036 CompletelyClearInstanceofCache();
1037
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001038 FlushNumberStringCache();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001039 if (FLAG_cleanup_code_caches_at_gc) {
1040 polymorphic_code_cache()->set_cache(undefined_value());
1041 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001042
1043 ClearNormalizedMapCaches();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001044}
1045
1046
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001047Object* Heap::FindCodeObject(Address a) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001048 return isolate()->inner_pointer_to_code_cache()->
1049 GcSafeFindCodeForInnerPointer(a);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001050}
1051
1052
1053// Helper class for copying HeapObjects
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001054class ScavengeVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001055 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001056 explicit ScavengeVisitor(Heap* heap) : heap_(heap) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001058 void VisitPointer(Object** p) { ScavengePointer(p); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001059
1060 void VisitPointers(Object** start, Object** end) {
1061 // Copy all HeapObject pointers in [start, end)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001062 for (Object** p = start; p < end; p++) ScavengePointer(p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001063 }
1064
1065 private:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001066 void ScavengePointer(Object** p) {
1067 Object* object = *p;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001068 if (!heap_->InNewSpace(object)) return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001069 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
1070 reinterpret_cast<HeapObject*>(object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001071 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001072
1073 Heap* heap_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001074};
1075
1076
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001077#ifdef VERIFY_HEAP
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001078// Visitor class to verify pointers in code or data space do not point into
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001079// new space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001080class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001081 public:
1082 void VisitPointers(Object** start, Object**end) {
1083 for (Object** current = start; current < end; current++) {
1084 if ((*current)->IsHeapObject()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001085 CHECK(!HEAP->InNewSpace(HeapObject::cast(*current)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001086 }
1087 }
1088 }
1089};
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001090
1091
1092static void VerifyNonPointerSpacePointers() {
1093 // Verify that there are no pointers to new space in spaces where we
1094 // do not expect them.
1095 VerifyNonPointerSpacePointersVisitor v;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001096 HeapObjectIterator code_it(HEAP->code_space());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001097 for (HeapObject* object = code_it.Next();
1098 object != NULL; object = code_it.Next())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001099 object->Iterate(&v);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001100
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001101 // The old data space was normally swept conservatively so that the iterator
1102 // doesn't work, so we normally skip the next bit.
1103 if (!HEAP->old_data_space()->was_swept_conservatively()) {
1104 HeapObjectIterator data_it(HEAP->old_data_space());
1105 for (HeapObject* object = data_it.Next();
1106 object != NULL; object = data_it.Next())
1107 object->Iterate(&v);
1108 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001109}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001110#endif // VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001112
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001113void Heap::CheckNewSpaceExpansionCriteria() {
1114 if (new_space_.Capacity() < new_space_.MaximumCapacity() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001115 survived_since_last_expansion_ > new_space_.Capacity() &&
1116 !new_space_high_promotion_mode_active_) {
1117 // Grow the size of new space if there is room to grow, enough data
1118 // has survived scavenge since the last expansion and we are not in
1119 // high promotion mode.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001120 new_space_.Grow();
1121 survived_since_last_expansion_ = 0;
1122 }
1123}
1124
1125
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001126static bool IsUnscavengedHeapObject(Heap* heap, Object** p) {
1127 return heap->InNewSpace(*p) &&
1128 !HeapObject::cast(*p)->map_word().IsForwardingAddress();
1129}
1130
1131
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001132void Heap::ScavengeStoreBufferCallback(
1133 Heap* heap,
1134 MemoryChunk* page,
1135 StoreBufferEvent event) {
1136 heap->store_buffer_rebuilder_.Callback(page, event);
1137}
1138
1139
1140void StoreBufferRebuilder::Callback(MemoryChunk* page, StoreBufferEvent event) {
1141 if (event == kStoreBufferStartScanningPagesEvent) {
1142 start_of_current_page_ = NULL;
1143 current_page_ = NULL;
1144 } else if (event == kStoreBufferScanningPageEvent) {
1145 if (current_page_ != NULL) {
1146 // If this page already overflowed the store buffer during this iteration.
1147 if (current_page_->scan_on_scavenge()) {
1148 // Then we should wipe out the entries that have been added for it.
1149 store_buffer_->SetTop(start_of_current_page_);
1150 } else if (store_buffer_->Top() - start_of_current_page_ >=
1151 (store_buffer_->Limit() - store_buffer_->Top()) >> 2) {
1152 // Did we find too many pointers in the previous page? The heuristic is
1153 // that no page can take more then 1/5 the remaining slots in the store
1154 // buffer.
1155 current_page_->set_scan_on_scavenge(true);
1156 store_buffer_->SetTop(start_of_current_page_);
1157 } else {
1158 // In this case the page we scanned took a reasonable number of slots in
1159 // the store buffer. It has now been rehabilitated and is no longer
1160 // marked scan_on_scavenge.
1161 ASSERT(!current_page_->scan_on_scavenge());
1162 }
1163 }
1164 start_of_current_page_ = store_buffer_->Top();
1165 current_page_ = page;
1166 } else if (event == kStoreBufferFullEvent) {
1167 // The current page overflowed the store buffer again. Wipe out its entries
1168 // in the store buffer and mark it scan-on-scavenge again. This may happen
1169 // several times while scanning.
1170 if (current_page_ == NULL) {
1171 // Store Buffer overflowed while scanning promoted objects. These are not
1172 // in any particular page, though they are likely to be clustered by the
1173 // allocation routines.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001174 store_buffer_->EnsureSpace(StoreBuffer::kStoreBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001175 } else {
1176 // Store Buffer overflowed while scanning a particular old space page for
1177 // pointers to new space.
1178 ASSERT(current_page_ == page);
1179 ASSERT(page != NULL);
1180 current_page_->set_scan_on_scavenge(true);
1181 ASSERT(start_of_current_page_ != store_buffer_->Top());
1182 store_buffer_->SetTop(start_of_current_page_);
1183 }
1184 } else {
1185 UNREACHABLE();
1186 }
1187}
1188
1189
danno@chromium.orgc612e022011-11-10 11:38:15 +00001190void PromotionQueue::Initialize() {
1191 // Assumes that a NewSpacePage exactly fits a number of promotion queue
1192 // entries (where each is a pair of intptr_t). This allows us to simplify
1193 // the test fpr when to switch pages.
1194 ASSERT((Page::kPageSize - MemoryChunk::kBodyOffset) % (2 * kPointerSize)
1195 == 0);
1196 limit_ = reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceStart());
1197 front_ = rear_ =
1198 reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceEnd());
1199 emergency_stack_ = NULL;
1200 guard_ = false;
1201}
1202
1203
1204void PromotionQueue::RelocateQueueHead() {
1205 ASSERT(emergency_stack_ == NULL);
1206
1207 Page* p = Page::FromAllocationTop(reinterpret_cast<Address>(rear_));
1208 intptr_t* head_start = rear_;
1209 intptr_t* head_end =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001210 Min(front_, reinterpret_cast<intptr_t*>(p->area_end()));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001211
1212 int entries_count =
1213 static_cast<int>(head_end - head_start) / kEntrySizeInWords;
1214
1215 emergency_stack_ = new List<Entry>(2 * entries_count);
1216
1217 while (head_start != head_end) {
1218 int size = static_cast<int>(*(head_start++));
1219 HeapObject* obj = reinterpret_cast<HeapObject*>(*(head_start++));
1220 emergency_stack_->Add(Entry(obj, size));
1221 }
1222 rear_ = head_end;
1223}
1224
1225
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001226class ScavengeWeakObjectRetainer : public WeakObjectRetainer {
1227 public:
1228 explicit ScavengeWeakObjectRetainer(Heap* heap) : heap_(heap) { }
1229
1230 virtual Object* RetainAs(Object* object) {
1231 if (!heap_->InFromSpace(object)) {
1232 return object;
1233 }
1234
1235 MapWord map_word = HeapObject::cast(object)->map_word();
1236 if (map_word.IsForwardingAddress()) {
1237 return map_word.ToForwardingAddress();
1238 }
1239 return NULL;
1240 }
1241
1242 private:
1243 Heap* heap_;
1244};
1245
1246
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247void Heap::Scavenge() {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001248 RelocationLock relocation_lock(this);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001249
1250#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001251 if (FLAG_verify_heap) VerifyNonPointerSpacePointers();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001252#endif
1253
1254 gc_state_ = SCAVENGE;
1255
1256 // Implements Cheney's copying algorithm
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001257 LOG(isolate_, ResourceEvent("scavenge", "begin"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001259 // Clear descriptor cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001260 isolate_->descriptor_lookup_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001261
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001262 // Used for updating survived_since_last_expansion_ at function end.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001263 intptr_t survived_watermark = PromotedSpaceSizeOfObjects();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001264
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001265 CheckNewSpaceExpansionCriteria();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001267 SelectScavengingVisitorsTable();
1268
1269 incremental_marking()->PrepareForScavenge();
1270
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001271 AdvanceSweepers(static_cast<int>(new_space_.Size()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001272
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001273 // Flip the semispaces. After flipping, to space is empty, from space has
1274 // live objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001275 new_space_.Flip();
1276 new_space_.ResetAllocationInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001278 // We need to sweep newly copied objects which can be either in the
1279 // to space or promoted to the old generation. For to-space
1280 // objects, we treat the bottom of the to space as a queue. Newly
1281 // copied and unswept objects lie between a 'front' mark and the
1282 // allocation pointer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283 //
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001284 // Promoted objects can go into various old-generation spaces, and
1285 // can be allocated internally in the spaces (from the free list).
1286 // We treat the top of the to space as a queue of addresses of
1287 // promoted objects. The addresses of newly promoted and unswept
1288 // objects lie between a 'front' mark and a 'rear' mark that is
1289 // updated as a side effect of promoting an object.
1290 //
1291 // There is guaranteed to be enough room at the top of the to space
1292 // for the addresses of promoted objects: every object promoted
1293 // frees up its size in bytes from the top of the new space, and
1294 // objects are at least one pointer in size.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001295 Address new_space_front = new_space_.ToSpaceStart();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001296 promotion_queue_.Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001297
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001298#ifdef DEBUG
1299 store_buffer()->Clean();
1300#endif
1301
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 ScavengeVisitor scavenge_visitor(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303 // Copy roots.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001304 IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001305
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001306 // Copy objects reachable from the old generation.
1307 {
1308 StoreBufferRebuildScope scope(this,
1309 store_buffer(),
1310 &ScavengeStoreBufferCallback);
1311 store_buffer()->IteratePointersToNewSpace(&ScavengeObject);
1312 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001313
1314 // Copy objects reachable from cells by scavenging cell values directly.
1315 HeapObjectIterator cell_iterator(cell_space_);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001316 for (HeapObject* heap_object = cell_iterator.Next();
1317 heap_object != NULL;
1318 heap_object = cell_iterator.Next()) {
1319 if (heap_object->IsJSGlobalPropertyCell()) {
1320 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(heap_object);
1321 Address value_address = cell->ValueAddress();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001322 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address));
1323 }
1324 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001326 // Copy objects reachable from the code flushing candidates list.
1327 MarkCompactCollector* collector = mark_compact_collector();
1328 if (collector->is_code_flushing_enabled()) {
1329 collector->code_flusher()->IteratePointersToFromSpace(&scavenge_visitor);
1330 }
1331
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001332 // Scavenge object reachable from the native contexts list directly.
1333 scavenge_visitor.VisitPointer(BitCast<Object**>(&native_contexts_list_));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001334
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001335 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001336
1337 while (IterateObjectGroups(&scavenge_visitor)) {
1338 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
1339 }
1340 isolate()->global_handles()->RemoveObjectGroups();
1341
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001342 isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles(
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001343 &IsUnscavengedHeapObject);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001344 isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots(
1345 &scavenge_visitor);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001346 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
1347
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001348 UpdateNewSpaceReferencesInExternalStringTable(
1349 &UpdateNewSpaceReferenceInExternalStringTableEntry);
1350
danno@chromium.orgc612e022011-11-10 11:38:15 +00001351 promotion_queue_.Destroy();
1352
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001353 LiveObjectList::UpdateReferencesForScavengeGC();
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001354 if (!FLAG_watch_ic_patching) {
1355 isolate()->runtime_profiler()->UpdateSamplesAfterScavenge();
1356 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001357 incremental_marking()->UpdateMarkingDequeAfterScavenge();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001358
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001359 ScavengeWeakObjectRetainer weak_object_retainer(this);
1360 ProcessWeakReferences(&weak_object_retainer);
1361
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001362 ASSERT(new_space_front == new_space_.top());
1363
1364 // Set age mark.
1365 new_space_.set_age_mark(new_space_.top());
1366
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001367 new_space_.LowerInlineAllocationLimit(
1368 new_space_.inline_allocation_limit_step());
1369
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001370 // Update how much has survived scavenge.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001371 IncrementYoungSurvivorsCounter(static_cast<int>(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001372 (PromotedSpaceSizeOfObjects() - survived_watermark) + new_space_.Size()));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001373
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 LOG(isolate_, ResourceEvent("scavenge", "end"));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001375
1376 gc_state_ = NOT_IN_GC;
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001377
1378 scavenges_since_last_idle_round_++;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001379}
1380
1381
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001382// TODO(mstarzinger): Unify this method with
1383// MarkCompactCollector::MarkObjectGroups().
1384bool Heap::IterateObjectGroups(ObjectVisitor* scavenge_visitor) {
1385 List<ObjectGroup*>* object_groups =
1386 isolate()->global_handles()->object_groups();
1387
1388 int last = 0;
1389 bool changed = false;
1390 for (int i = 0; i < object_groups->length(); i++) {
1391 ObjectGroup* entry = object_groups->at(i);
1392 ASSERT(entry != NULL);
1393
1394 Object*** objects = entry->objects_;
1395 bool group_marked = false;
1396 for (size_t j = 0; j < entry->length_; j++) {
1397 Object* object = *objects[j];
1398 if (object->IsHeapObject()) {
1399 if (!IsUnscavengedHeapObject(this, &object)) {
1400 group_marked = true;
1401 break;
1402 }
1403 }
1404 }
1405
1406 if (!group_marked) {
1407 (*object_groups)[last++] = entry;
1408 continue;
1409 }
1410
1411 for (size_t j = 0; j < entry->length_; ++j) {
1412 Object* object = *objects[j];
1413 if (object->IsHeapObject()) {
1414 scavenge_visitor->VisitPointer(&object);
1415 changed = true;
1416 }
1417 }
1418
1419 entry->Dispose();
1420 object_groups->at(i) = NULL;
1421 }
1422 object_groups->Rewind(last);
1423 return changed;
1424}
1425
1426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001427String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
1428 Object** p) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001429 MapWord first_word = HeapObject::cast(*p)->map_word();
1430
1431 if (!first_word.IsForwardingAddress()) {
1432 // Unreachable external string can be finalized.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001433 heap->FinalizeExternalString(String::cast(*p));
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001434 return NULL;
1435 }
1436
1437 // String is still reachable.
1438 return String::cast(first_word.ToForwardingAddress());
1439}
1440
1441
1442void Heap::UpdateNewSpaceReferencesInExternalStringTable(
1443 ExternalStringTableUpdaterCallback updater_func) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001444#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001445 if (FLAG_verify_heap) {
1446 external_string_table_.Verify();
1447 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001448#endif
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001449
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001450 if (external_string_table_.new_space_strings_.is_empty()) return;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001451
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001452 Object** start = &external_string_table_.new_space_strings_[0];
1453 Object** end = start + external_string_table_.new_space_strings_.length();
1454 Object** last = start;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001455
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001456 for (Object** p = start; p < end; ++p) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 ASSERT(InFromSpace(*p));
1458 String* target = updater_func(this, p);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001459
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001460 if (target == NULL) continue;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001461
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001462 ASSERT(target->IsExternalString());
1463
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001464 if (InNewSpace(target)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001465 // String is still in new space. Update the table entry.
1466 *last = target;
1467 ++last;
1468 } else {
1469 // String got promoted. Move it to the old string list.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001470 external_string_table_.AddOldString(target);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001471 }
1472 }
1473
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001474 ASSERT(last <= end);
1475 external_string_table_.ShrinkNewStrings(static_cast<int>(last - start));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001476}
1477
1478
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001479void Heap::UpdateReferencesInExternalStringTable(
1480 ExternalStringTableUpdaterCallback updater_func) {
1481
1482 // Update old space string references.
1483 if (external_string_table_.old_space_strings_.length() > 0) {
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001484 Object** start = &external_string_table_.old_space_strings_[0];
1485 Object** end = start + external_string_table_.old_space_strings_.length();
1486 for (Object** p = start; p < end; ++p) *p = updater_func(this, p);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001487 }
1488
1489 UpdateNewSpaceReferencesInExternalStringTable(updater_func);
1490}
1491
1492
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001493static Object* ProcessFunctionWeakReferences(Heap* heap,
1494 Object* function,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001495 WeakObjectRetainer* retainer,
1496 bool record_slots) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001497 Object* undefined = heap->undefined_value();
1498 Object* head = undefined;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001499 JSFunction* tail = NULL;
1500 Object* candidate = function;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 while (candidate != undefined) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001502 // Check whether to keep the candidate in the list.
1503 JSFunction* candidate_function = reinterpret_cast<JSFunction*>(candidate);
1504 Object* retain = retainer->RetainAs(candidate);
1505 if (retain != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001506 if (head == undefined) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001507 // First element in the list.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001508 head = retain;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001509 } else {
1510 // Subsequent elements in the list.
1511 ASSERT(tail != NULL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001512 tail->set_next_function_link(retain);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001513 if (record_slots) {
1514 Object** next_function =
1515 HeapObject::RawField(tail, JSFunction::kNextFunctionLinkOffset);
1516 heap->mark_compact_collector()->RecordSlot(
1517 next_function, next_function, retain);
1518 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001519 }
1520 // Retained function is new tail.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001521 candidate_function = reinterpret_cast<JSFunction*>(retain);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001522 tail = candidate_function;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001523
1524 ASSERT(retain->IsUndefined() || retain->IsJSFunction());
1525
1526 if (retain == undefined) break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001527 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001528
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001529 // Move to next element in the list.
1530 candidate = candidate_function->next_function_link();
1531 }
1532
1533 // Terminate the list if there is one or more elements.
1534 if (tail != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001535 tail->set_next_function_link(undefined);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001536 }
1537
1538 return head;
1539}
1540
1541
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001542void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001543 Object* undefined = undefined_value();
1544 Object* head = undefined;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001545 Context* tail = NULL;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001546 Object* candidate = native_contexts_list_;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001547
1548 // We don't record weak slots during marking or scavenges.
1549 // Instead we do it once when we complete mark-compact cycle.
1550 // Note that write barrier has no effect if we are already in the middle of
1551 // compacting mark-sweep cycle and we have to record slots manually.
1552 bool record_slots =
1553 gc_state() == MARK_COMPACT &&
1554 mark_compact_collector()->is_compacting();
1555
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001556 while (candidate != undefined) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001557 // Check whether to keep the candidate in the list.
1558 Context* candidate_context = reinterpret_cast<Context*>(candidate);
1559 Object* retain = retainer->RetainAs(candidate);
1560 if (retain != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001561 if (head == undefined) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001562 // First element in the list.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001563 head = retain;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001564 } else {
1565 // Subsequent elements in the list.
1566 ASSERT(tail != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001567 tail->set_unchecked(this,
1568 Context::NEXT_CONTEXT_LINK,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001569 retain,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001570 UPDATE_WRITE_BARRIER);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001571
1572 if (record_slots) {
1573 Object** next_context =
1574 HeapObject::RawField(
1575 tail, FixedArray::SizeFor(Context::NEXT_CONTEXT_LINK));
1576 mark_compact_collector()->RecordSlot(
1577 next_context, next_context, retain);
1578 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001579 }
1580 // Retained context is new tail.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001581 candidate_context = reinterpret_cast<Context*>(retain);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001582 tail = candidate_context;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001583
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001584 if (retain == undefined) break;
1585
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001586 // Process the weak list of optimized functions for the context.
1587 Object* function_list_head =
1588 ProcessFunctionWeakReferences(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001589 this,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001590 candidate_context->get(Context::OPTIMIZED_FUNCTIONS_LIST),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001591 retainer,
1592 record_slots);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001593 candidate_context->set_unchecked(this,
1594 Context::OPTIMIZED_FUNCTIONS_LIST,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001595 function_list_head,
1596 UPDATE_WRITE_BARRIER);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001597 if (record_slots) {
1598 Object** optimized_functions =
1599 HeapObject::RawField(
1600 tail, FixedArray::SizeFor(Context::OPTIMIZED_FUNCTIONS_LIST));
1601 mark_compact_collector()->RecordSlot(
1602 optimized_functions, optimized_functions, function_list_head);
1603 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001604 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001605
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001606 // Move to next element in the list.
1607 candidate = candidate_context->get(Context::NEXT_CONTEXT_LINK);
1608 }
1609
1610 // Terminate the list if there is one or more elements.
1611 if (tail != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001612 tail->set_unchecked(this,
1613 Context::NEXT_CONTEXT_LINK,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001614 Heap::undefined_value(),
1615 UPDATE_WRITE_BARRIER);
1616 }
1617
1618 // Update the head of the list of contexts.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001619 native_contexts_list_ = head;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001620}
1621
1622
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001623void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) {
1624 AssertNoAllocation no_allocation;
1625
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001626 // Both the external string table and the symbol table may contain
1627 // external strings, but neither lists them exhaustively, nor is the
1628 // intersection set empty. Therefore we iterate over the external string
1629 // table first, ignoring symbols, and then over the symbol table.
1630
1631 class ExternalStringTableVisitorAdapter : public ObjectVisitor {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001632 public:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001633 explicit ExternalStringTableVisitorAdapter(
1634 v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001635 virtual void VisitPointers(Object** start, Object** end) {
1636 for (Object** p = start; p < end; p++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001637 // Visit non-symbol external strings,
1638 // since symbols are listed in the symbol table.
1639 if (!(*p)->IsSymbol()) {
1640 ASSERT((*p)->IsExternalString());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001641 visitor_->VisitExternalString(Utils::ToLocal(
1642 Handle<String>(String::cast(*p))));
1643 }
1644 }
1645 }
1646 private:
1647 v8::ExternalResourceVisitor* visitor_;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001648 } external_string_table_visitor(visitor);
1649
1650 external_string_table_.Iterate(&external_string_table_visitor);
1651
1652 class SymbolTableVisitorAdapter : public ObjectVisitor {
1653 public:
1654 explicit SymbolTableVisitorAdapter(
1655 v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
1656 virtual void VisitPointers(Object** start, Object** end) {
1657 for (Object** p = start; p < end; p++) {
1658 if ((*p)->IsExternalString()) {
1659 ASSERT((*p)->IsSymbol());
1660 visitor_->VisitExternalString(Utils::ToLocal(
1661 Handle<String>(String::cast(*p))));
1662 }
1663 }
1664 }
1665 private:
1666 v8::ExternalResourceVisitor* visitor_;
1667 } symbol_table_visitor(visitor);
1668
1669 symbol_table()->IterateElements(&symbol_table_visitor);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001670}
1671
1672
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001673class NewSpaceScavenger : public StaticNewSpaceVisitor<NewSpaceScavenger> {
1674 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001675 static inline void VisitPointer(Heap* heap, Object** p) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001676 Object* object = *p;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001677 if (!heap->InNewSpace(object)) return;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001678 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
1679 reinterpret_cast<HeapObject*>(object));
1680 }
1681};
1682
1683
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001684Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
1685 Address new_space_front) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001686 do {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001687 SemiSpace::AssertValidRange(new_space_front, new_space_.top());
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001688 // The addresses new_space_front and new_space_.top() define a
1689 // queue of unprocessed copied objects. Process them until the
1690 // queue is empty.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001691 while (new_space_front != new_space_.top()) {
1692 if (!NewSpacePage::IsAtEnd(new_space_front)) {
1693 HeapObject* object = HeapObject::FromAddress(new_space_front);
1694 new_space_front +=
1695 NewSpaceScavenger::IterateBody(object->map(), object);
1696 } else {
1697 new_space_front =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001698 NewSpacePage::FromLimit(new_space_front)->next_page()->area_start();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001699 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001700 }
1701
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001702 // Promote and process all the to-be-promoted objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001703 {
1704 StoreBufferRebuildScope scope(this,
1705 store_buffer(),
1706 &ScavengeStoreBufferCallback);
1707 while (!promotion_queue()->is_empty()) {
1708 HeapObject* target;
1709 int size;
1710 promotion_queue()->remove(&target, &size);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001711
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001712 // Promoted object might be already partially visited
1713 // during old space pointer iteration. Thus we search specificly
1714 // for pointers to from semispace instead of looking for pointers
1715 // to new space.
1716 ASSERT(!target->IsMap());
1717 IterateAndMarkPointersToFromSpace(target->address(),
1718 target->address() + size,
1719 &ScavengeObject);
1720 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001721 }
1722
1723 // Take another spin if there are now unswept objects in new space
1724 // (there are currently no more unswept promoted objects).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001725 } while (new_space_front != new_space_.top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001726
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001727 return new_space_front;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001728}
1729
1730
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001731STATIC_ASSERT((FixedDoubleArray::kHeaderSize & kDoubleAlignmentMask) == 0);
1732
1733
1734INLINE(static HeapObject* EnsureDoubleAligned(Heap* heap,
1735 HeapObject* object,
1736 int size));
1737
1738static HeapObject* EnsureDoubleAligned(Heap* heap,
1739 HeapObject* object,
1740 int size) {
1741 if ((OffsetFrom(object->address()) & kDoubleAlignmentMask) != 0) {
1742 heap->CreateFillerObjectAt(object->address(), kPointerSize);
1743 return HeapObject::FromAddress(object->address() + kPointerSize);
1744 } else {
1745 heap->CreateFillerObjectAt(object->address() + size - kPointerSize,
1746 kPointerSize);
1747 return object;
1748 }
1749}
1750
1751
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001752enum LoggingAndProfiling {
1753 LOGGING_AND_PROFILING_ENABLED,
1754 LOGGING_AND_PROFILING_DISABLED
1755};
1756
1757
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001758enum MarksHandling { TRANSFER_MARKS, IGNORE_MARKS };
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001759
1760
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001761template<MarksHandling marks_handling,
1762 LoggingAndProfiling logging_and_profiling_mode>
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001763class ScavengingVisitor : public StaticVisitorBase {
1764 public:
1765 static void Initialize() {
1766 table_.Register(kVisitSeqAsciiString, &EvacuateSeqAsciiString);
1767 table_.Register(kVisitSeqTwoByteString, &EvacuateSeqTwoByteString);
1768 table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate);
1769 table_.Register(kVisitByteArray, &EvacuateByteArray);
1770 table_.Register(kVisitFixedArray, &EvacuateFixedArray);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001771 table_.Register(kVisitFixedDoubleArray, &EvacuateFixedDoubleArray);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001772
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001773 table_.Register(kVisitNativeContext,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001774 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001775 template VisitSpecialized<Context::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001776
1777 table_.Register(kVisitConsString,
1778 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001779 template VisitSpecialized<ConsString::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001780
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001781 table_.Register(kVisitSlicedString,
1782 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1783 template VisitSpecialized<SlicedString::kSize>);
1784
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001785 table_.Register(kVisitSharedFunctionInfo,
1786 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001787 template VisitSpecialized<SharedFunctionInfo::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001788
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001789 table_.Register(kVisitJSWeakMap,
1790 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1791 Visit);
1792
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001793 table_.Register(kVisitJSRegExp,
1794 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1795 Visit);
1796
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001797 if (marks_handling == IGNORE_MARKS) {
1798 table_.Register(kVisitJSFunction,
1799 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1800 template VisitSpecialized<JSFunction::kSize>);
1801 } else {
1802 table_.Register(kVisitJSFunction, &EvacuateJSFunction);
1803 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001804
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001805 table_.RegisterSpecializations<ObjectEvacuationStrategy<DATA_OBJECT>,
1806 kVisitDataObject,
1807 kVisitDataObjectGeneric>();
1808
1809 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>,
1810 kVisitJSObject,
1811 kVisitJSObjectGeneric>();
1812
1813 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>,
1814 kVisitStruct,
1815 kVisitStructGeneric>();
1816 }
1817
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001818 static VisitorDispatchTable<ScavengingCallback>* GetTable() {
1819 return &table_;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001820 }
1821
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001822 private:
1823 enum ObjectContents { DATA_OBJECT, POINTER_OBJECT };
1824 enum SizeRestriction { SMALL, UNKNOWN_SIZE };
1825
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826 static void RecordCopiedObject(Heap* heap, HeapObject* obj) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001827 bool should_record = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001828#ifdef DEBUG
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001829 should_record = FLAG_heap_stats;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001830#endif
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001831 should_record = should_record || FLAG_log_gc;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001832 if (should_record) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001833 if (heap->new_space()->Contains(obj)) {
1834 heap->new_space()->RecordAllocation(obj);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001835 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836 heap->new_space()->RecordPromotion(obj);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001837 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001838 }
1839 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001840
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001841 // Helper function used by CopyObject to copy a source object to an
1842 // allocated target object and update the forwarding pointer in the source
1843 // object. Returns the target object.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001844 INLINE(static void MigrateObject(Heap* heap,
1845 HeapObject* source,
1846 HeapObject* target,
1847 int size)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001848 // Copy the content of source to target.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001849 heap->CopyBlock(target->address(), source->address(), size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001850
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001851 // Set the forwarding address.
1852 source->set_map_word(MapWord::FromForwardingAddress(target));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001854 if (logging_and_profiling_mode == LOGGING_AND_PROFILING_ENABLED) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001855 // Update NewSpace stats if necessary.
1856 RecordCopiedObject(heap, target);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001857 HEAP_PROFILE(heap, ObjectMoveEvent(source->address(), target->address()));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001858 Isolate* isolate = heap->isolate();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001859 if (isolate->logger()->is_logging_code_events() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001860 CpuProfiler::is_profiling(isolate)) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001861 if (target->IsSharedFunctionInfo()) {
1862 PROFILE(isolate, SharedFunctionInfoMoveEvent(
1863 source->address(), target->address()));
1864 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001865 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001866 }
1867
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001868 if (marks_handling == TRANSFER_MARKS) {
1869 if (Marking::TransferColor(source, target)) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001870 MemoryChunk::IncrementLiveBytesFromGC(target->address(), size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001871 }
1872 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001873 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001874
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001875
1876 template<ObjectContents object_contents,
1877 SizeRestriction size_restriction,
1878 int alignment>
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001879 static inline void EvacuateObject(Map* map,
1880 HeapObject** slot,
1881 HeapObject* object,
1882 int object_size) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001883 SLOW_ASSERT((size_restriction != SMALL) ||
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001884 (object_size <= Page::kMaxNonCodeHeapObjectSize));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001885 SLOW_ASSERT(object->Size() == object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001886
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001887 int allocation_size = object_size;
1888 if (alignment != kObjectAlignment) {
1889 ASSERT(alignment == kDoubleAlignment);
1890 allocation_size += kPointerSize;
1891 }
1892
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001893 Heap* heap = map->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001894 if (heap->ShouldBePromoted(object->address(), object_size)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001895 MaybeObject* maybe_result;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001896
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001897 if ((size_restriction != SMALL) &&
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001898 (allocation_size > Page::kMaxNonCodeHeapObjectSize)) {
1899 maybe_result = heap->lo_space()->AllocateRaw(allocation_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001900 NOT_EXECUTABLE);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001901 } else {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001902 if (object_contents == DATA_OBJECT) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001903 maybe_result = heap->old_data_space()->AllocateRaw(allocation_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001904 } else {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001905 maybe_result =
1906 heap->old_pointer_space()->AllocateRaw(allocation_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001907 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001908 }
1909
lrn@chromium.org303ada72010-10-27 09:33:13 +00001910 Object* result = NULL; // Initialization to please compiler.
1911 if (maybe_result->ToObject(&result)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001912 HeapObject* target = HeapObject::cast(result);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001913
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001914 if (alignment != kObjectAlignment) {
1915 target = EnsureDoubleAligned(heap, target, allocation_size);
1916 }
1917
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001918 // Order is important: slot might be inside of the target if target
1919 // was allocated over a dead object and slot comes from the store
1920 // buffer.
1921 *slot = target;
1922 MigrateObject(heap, object, target, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001923
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001924 if (object_contents == POINTER_OBJECT) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001925 if (map->instance_type() == JS_FUNCTION_TYPE) {
1926 heap->promotion_queue()->insert(
1927 target, JSFunction::kNonWeakFieldsEndOffset);
1928 } else {
1929 heap->promotion_queue()->insert(target, object_size);
1930 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001931 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001932
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001933 heap->tracer()->increment_promoted_objects_size(object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001934 return;
1935 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001936 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001937 MaybeObject* allocation = heap->new_space()->AllocateRaw(allocation_size);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001938 heap->promotion_queue()->SetNewLimit(heap->new_space()->top());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001939 Object* result = allocation->ToObjectUnchecked();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001940 HeapObject* target = HeapObject::cast(result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001941
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001942 if (alignment != kObjectAlignment) {
1943 target = EnsureDoubleAligned(heap, target, allocation_size);
1944 }
1945
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001946 // Order is important: slot might be inside of the target if target
1947 // was allocated over a dead object and slot comes from the store
1948 // buffer.
1949 *slot = target;
1950 MigrateObject(heap, object, target, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001951 return;
1952 }
1953
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001954
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001955 static inline void EvacuateJSFunction(Map* map,
1956 HeapObject** slot,
1957 HeapObject* object) {
1958 ObjectEvacuationStrategy<POINTER_OBJECT>::
1959 template VisitSpecialized<JSFunction::kSize>(map, slot, object);
1960
1961 HeapObject* target = *slot;
1962 MarkBit mark_bit = Marking::MarkBitFrom(target);
1963 if (Marking::IsBlack(mark_bit)) {
1964 // This object is black and it might not be rescanned by marker.
1965 // We should explicitly record code entry slot for compaction because
1966 // promotion queue processing (IterateAndMarkPointersToFromSpace) will
1967 // miss it as it is not HeapObject-tagged.
1968 Address code_entry_slot =
1969 target->address() + JSFunction::kCodeEntryOffset;
1970 Code* code = Code::cast(Code::GetObjectFromEntryAddress(code_entry_slot));
1971 map->GetHeap()->mark_compact_collector()->
1972 RecordCodeEntrySlot(code_entry_slot, code);
1973 }
1974 }
1975
1976
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001977 static inline void EvacuateFixedArray(Map* map,
1978 HeapObject** slot,
1979 HeapObject* object) {
1980 int object_size = FixedArray::BodyDescriptor::SizeOf(map, object);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001981 EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(map,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001982 slot,
1983 object,
1984 object_size);
1985 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001986
1987
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001988 static inline void EvacuateFixedDoubleArray(Map* map,
1989 HeapObject** slot,
1990 HeapObject* object) {
1991 int length = reinterpret_cast<FixedDoubleArray*>(object)->length();
1992 int object_size = FixedDoubleArray::SizeFor(length);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001993 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kDoubleAlignment>(
1994 map,
1995 slot,
1996 object,
1997 object_size);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001998 }
1999
2000
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002001 static inline void EvacuateByteArray(Map* map,
2002 HeapObject** slot,
2003 HeapObject* object) {
2004 int object_size = reinterpret_cast<ByteArray*>(object)->ByteArraySize();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002005 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
2006 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002007 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002008
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002009
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002010 static inline void EvacuateSeqAsciiString(Map* map,
2011 HeapObject** slot,
2012 HeapObject* object) {
2013 int object_size = SeqAsciiString::cast(object)->
2014 SeqAsciiStringSize(map->instance_type());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002015 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
2016 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002017 }
2018
2019
2020 static inline void EvacuateSeqTwoByteString(Map* map,
2021 HeapObject** slot,
2022 HeapObject* object) {
2023 int object_size = SeqTwoByteString::cast(object)->
2024 SeqTwoByteStringSize(map->instance_type());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002025 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
2026 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002027 }
2028
2029
2030 static inline bool IsShortcutCandidate(int type) {
2031 return ((type & kShortcutTypeMask) == kShortcutTypeTag);
2032 }
2033
2034 static inline void EvacuateShortcutCandidate(Map* map,
2035 HeapObject** slot,
2036 HeapObject* object) {
2037 ASSERT(IsShortcutCandidate(map->instance_type()));
2038
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002039 Heap* heap = map->GetHeap();
2040
2041 if (marks_handling == IGNORE_MARKS &&
2042 ConsString::cast(object)->unchecked_second() ==
2043 heap->empty_string()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002044 HeapObject* first =
2045 HeapObject::cast(ConsString::cast(object)->unchecked_first());
2046
2047 *slot = first;
2048
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002049 if (!heap->InNewSpace(first)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002050 object->set_map_word(MapWord::FromForwardingAddress(first));
2051 return;
2052 }
2053
2054 MapWord first_word = first->map_word();
2055 if (first_word.IsForwardingAddress()) {
2056 HeapObject* target = first_word.ToForwardingAddress();
2057
2058 *slot = target;
2059 object->set_map_word(MapWord::FromForwardingAddress(target));
2060 return;
2061 }
2062
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002063 heap->DoScavengeObject(first->map(), slot, first);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002064 object->set_map_word(MapWord::FromForwardingAddress(*slot));
2065 return;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002066 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002067
2068 int object_size = ConsString::kSize;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002069 EvacuateObject<POINTER_OBJECT, SMALL, kObjectAlignment>(
2070 map, slot, object, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002071 }
2072
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002073 template<ObjectContents object_contents>
2074 class ObjectEvacuationStrategy {
2075 public:
2076 template<int object_size>
2077 static inline void VisitSpecialized(Map* map,
2078 HeapObject** slot,
2079 HeapObject* object) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002080 EvacuateObject<object_contents, SMALL, kObjectAlignment>(
2081 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002082 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002083
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002084 static inline void Visit(Map* map,
2085 HeapObject** slot,
2086 HeapObject* object) {
2087 int object_size = map->instance_size();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002088 EvacuateObject<object_contents, SMALL, kObjectAlignment>(
2089 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002090 }
2091 };
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002093 static VisitorDispatchTable<ScavengingCallback> table_;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002094};
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002095
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002096
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002097template<MarksHandling marks_handling,
2098 LoggingAndProfiling logging_and_profiling_mode>
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002099VisitorDispatchTable<ScavengingCallback>
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002100 ScavengingVisitor<marks_handling, logging_and_profiling_mode>::table_;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002101
2102
2103static void InitializeScavengingVisitorsTables() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002104 ScavengingVisitor<TRANSFER_MARKS,
2105 LOGGING_AND_PROFILING_DISABLED>::Initialize();
2106 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_DISABLED>::Initialize();
2107 ScavengingVisitor<TRANSFER_MARKS,
2108 LOGGING_AND_PROFILING_ENABLED>::Initialize();
2109 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_ENABLED>::Initialize();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002110}
2111
2112
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002113void Heap::SelectScavengingVisitorsTable() {
2114 bool logging_and_profiling =
2115 isolate()->logger()->is_logging() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002116 CpuProfiler::is_profiling(isolate()) ||
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002117 (isolate()->heap_profiler() != NULL &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002118 isolate()->heap_profiler()->is_profiling());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002119
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002120 if (!incremental_marking()->IsMarking()) {
2121 if (!logging_and_profiling) {
2122 scavenging_visitors_table_.CopyFrom(
2123 ScavengingVisitor<IGNORE_MARKS,
2124 LOGGING_AND_PROFILING_DISABLED>::GetTable());
2125 } else {
2126 scavenging_visitors_table_.CopyFrom(
2127 ScavengingVisitor<IGNORE_MARKS,
2128 LOGGING_AND_PROFILING_ENABLED>::GetTable());
2129 }
2130 } else {
2131 if (!logging_and_profiling) {
2132 scavenging_visitors_table_.CopyFrom(
2133 ScavengingVisitor<TRANSFER_MARKS,
2134 LOGGING_AND_PROFILING_DISABLED>::GetTable());
2135 } else {
2136 scavenging_visitors_table_.CopyFrom(
2137 ScavengingVisitor<TRANSFER_MARKS,
2138 LOGGING_AND_PROFILING_ENABLED>::GetTable());
2139 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002140
2141 if (incremental_marking()->IsCompacting()) {
2142 // When compacting forbid short-circuiting of cons-strings.
2143 // Scavenging code relies on the fact that new space object
2144 // can't be evacuated into evacuation candidate but
2145 // short-circuiting violates this assumption.
2146 scavenging_visitors_table_.Register(
2147 StaticVisitorBase::kVisitShortcutCandidate,
2148 scavenging_visitors_table_.GetVisitorById(
2149 StaticVisitorBase::kVisitConsString));
2150 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002151 }
2152}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002153
2154
2155void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002156 SLOW_ASSERT(HEAP->InFromSpace(object));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002157 MapWord first_word = object->map_word();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002158 SLOW_ASSERT(!first_word.IsForwardingAddress());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002159 Map* map = first_word.ToMap();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002160 map->GetHeap()->DoScavengeObject(map, p, object);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002161}
2162
2163
lrn@chromium.org303ada72010-10-27 09:33:13 +00002164MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type,
2165 int instance_size) {
2166 Object* result;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002167 MaybeObject* maybe_result = AllocateRawMap();
2168 if (!maybe_result->ToObject(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002169
2170 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002171 reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002172 reinterpret_cast<Map*>(result)->set_instance_type(instance_type);
2173 reinterpret_cast<Map*>(result)->set_instance_size(instance_size);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002174 reinterpret_cast<Map*>(result)->set_visitor_id(
2175 StaticVisitorBase::GetVisitorId(instance_type, instance_size));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002176 reinterpret_cast<Map*>(result)->set_inobject_properties(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002177 reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002178 reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002179 reinterpret_cast<Map*>(result)->set_bit_field(0);
2180 reinterpret_cast<Map*>(result)->set_bit_field2(0);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002181 int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) |
2182 Map::OwnsDescriptors::encode(true);
2183 reinterpret_cast<Map*>(result)->set_bit_field3(bit_field3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002184 return result;
2185}
2186
2187
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002188MaybeObject* Heap::AllocateMap(InstanceType instance_type,
2189 int instance_size,
2190 ElementsKind elements_kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002191 Object* result;
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002192 MaybeObject* maybe_result = AllocateRawMap();
2193 if (!maybe_result->To(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002194
2195 Map* map = reinterpret_cast<Map*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002196 map->set_map_no_write_barrier(meta_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002197 map->set_instance_type(instance_type);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002198 map->set_visitor_id(
2199 StaticVisitorBase::GetVisitorId(instance_type, instance_size));
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002200 map->set_prototype(null_value(), SKIP_WRITE_BARRIER);
2201 map->set_constructor(null_value(), SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002202 map->set_instance_size(instance_size);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002203 map->set_inobject_properties(0);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002204 map->set_pre_allocated_property_fields(0);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002205 map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002206 map->init_back_pointer(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002207 map->set_unused_property_fields(0);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002208 map->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002209 map->set_bit_field(0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002210 map->set_bit_field2(1 << Map::kIsExtensible);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002211 int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) |
2212 Map::OwnsDescriptors::encode(true);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002213 map->set_bit_field3(bit_field3);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002214 map->set_elements_kind(elements_kind);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002215
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002216 return map;
2217}
2218
2219
lrn@chromium.org303ada72010-10-27 09:33:13 +00002220MaybeObject* Heap::AllocateCodeCache() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002221 CodeCache* code_cache;
2222 { MaybeObject* maybe_code_cache = AllocateStruct(CODE_CACHE_TYPE);
2223 if (!maybe_code_cache->To(&code_cache)) return maybe_code_cache;
lrn@chromium.org303ada72010-10-27 09:33:13 +00002224 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002225 code_cache->set_default_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
2226 code_cache->set_normal_type_cache(undefined_value(), SKIP_WRITE_BARRIER);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002227 return code_cache;
2228}
2229
2230
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002231MaybeObject* Heap::AllocatePolymorphicCodeCache() {
2232 return AllocateStruct(POLYMORPHIC_CODE_CACHE_TYPE);
2233}
2234
2235
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002236MaybeObject* Heap::AllocateAccessorPair() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002237 AccessorPair* accessors;
2238 { MaybeObject* maybe_accessors = AllocateStruct(ACCESSOR_PAIR_TYPE);
2239 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002240 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002241 accessors->set_getter(the_hole_value(), SKIP_WRITE_BARRIER);
2242 accessors->set_setter(the_hole_value(), SKIP_WRITE_BARRIER);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002243 return accessors;
2244}
2245
2246
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002247MaybeObject* Heap::AllocateTypeFeedbackInfo() {
2248 TypeFeedbackInfo* info;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002249 { MaybeObject* maybe_info = AllocateStruct(TYPE_FEEDBACK_INFO_TYPE);
2250 if (!maybe_info->To(&info)) return maybe_info;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002251 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002252 info->initialize_storage();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002253 info->set_type_feedback_cells(TypeFeedbackCells::cast(empty_fixed_array()),
2254 SKIP_WRITE_BARRIER);
2255 return info;
2256}
2257
2258
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002259MaybeObject* Heap::AllocateAliasedArgumentsEntry(int aliased_context_slot) {
2260 AliasedArgumentsEntry* entry;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002261 { MaybeObject* maybe_entry = AllocateStruct(ALIASED_ARGUMENTS_ENTRY_TYPE);
2262 if (!maybe_entry->To(&entry)) return maybe_entry;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002263 }
2264 entry->set_aliased_context_slot(aliased_context_slot);
2265 return entry;
2266}
2267
2268
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002269const Heap::StringTypeTable Heap::string_type_table[] = {
2270#define STRING_TYPE_ELEMENT(type, size, name, camel_name) \
2271 {type, size, k##camel_name##MapRootIndex},
2272 STRING_TYPE_LIST(STRING_TYPE_ELEMENT)
2273#undef STRING_TYPE_ELEMENT
2274};
2275
2276
2277const Heap::ConstantSymbolTable Heap::constant_symbol_table[] = {
2278#define CONSTANT_SYMBOL_ELEMENT(name, contents) \
2279 {contents, k##name##RootIndex},
2280 SYMBOL_LIST(CONSTANT_SYMBOL_ELEMENT)
2281#undef CONSTANT_SYMBOL_ELEMENT
2282};
2283
2284
2285const Heap::StructTable Heap::struct_table[] = {
2286#define STRUCT_TABLE_ELEMENT(NAME, Name, name) \
2287 { NAME##_TYPE, Name::kSize, k##Name##MapRootIndex },
2288 STRUCT_LIST(STRUCT_TABLE_ELEMENT)
2289#undef STRUCT_TABLE_ELEMENT
2290};
2291
2292
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002293bool Heap::CreateInitialMaps() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002294 Object* obj;
2295 { MaybeObject* maybe_obj = AllocatePartialMap(MAP_TYPE, Map::kSize);
2296 if (!maybe_obj->ToObject(&obj)) return false;
2297 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002298 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002299 Map* new_meta_map = reinterpret_cast<Map*>(obj);
2300 set_meta_map(new_meta_map);
2301 new_meta_map->set_map(new_meta_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002302
lrn@chromium.org303ada72010-10-27 09:33:13 +00002303 { MaybeObject* maybe_obj =
2304 AllocatePartialMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2305 if (!maybe_obj->ToObject(&obj)) return false;
2306 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002307 set_fixed_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002308
lrn@chromium.org303ada72010-10-27 09:33:13 +00002309 { MaybeObject* maybe_obj = AllocatePartialMap(ODDBALL_TYPE, Oddball::kSize);
2310 if (!maybe_obj->ToObject(&obj)) return false;
2311 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002312 set_oddball_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002313
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002314 // Allocate the empty array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002315 { MaybeObject* maybe_obj = AllocateEmptyFixedArray();
2316 if (!maybe_obj->ToObject(&obj)) return false;
2317 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002318 set_empty_fixed_array(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002319
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002320 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002321 if (!maybe_obj->ToObject(&obj)) return false;
2322 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002323 set_null_value(Oddball::cast(obj));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002324 Oddball::cast(obj)->set_kind(Oddball::kNull);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002325
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002326 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE);
2327 if (!maybe_obj->ToObject(&obj)) return false;
2328 }
2329 set_undefined_value(Oddball::cast(obj));
2330 Oddball::cast(obj)->set_kind(Oddball::kUndefined);
2331 ASSERT(!InNewSpace(undefined_value()));
2332
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002333 // Allocate the empty descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002334 { MaybeObject* maybe_obj = AllocateEmptyFixedArray();
2335 if (!maybe_obj->ToObject(&obj)) return false;
2336 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002337 set_empty_descriptor_array(DescriptorArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002338
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002339 // Fix the instance_descriptors for the existing maps.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002340 meta_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002341 meta_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002342 meta_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002343
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002344 fixed_array_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002345 fixed_array_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002346 fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002347
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002348 oddball_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002349 oddball_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002350 oddball_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002351
2352 // Fix prototype object for existing maps.
2353 meta_map()->set_prototype(null_value());
2354 meta_map()->set_constructor(null_value());
2355
2356 fixed_array_map()->set_prototype(null_value());
2357 fixed_array_map()->set_constructor(null_value());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002358
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002359 oddball_map()->set_prototype(null_value());
2360 oddball_map()->set_constructor(null_value());
2361
lrn@chromium.org303ada72010-10-27 09:33:13 +00002362 { MaybeObject* maybe_obj =
2363 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2364 if (!maybe_obj->ToObject(&obj)) return false;
2365 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002366 set_fixed_cow_array_map(Map::cast(obj));
2367 ASSERT(fixed_array_map() != fixed_cow_array_map());
2368
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002369 { MaybeObject* maybe_obj =
2370 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2371 if (!maybe_obj->ToObject(&obj)) return false;
2372 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002373 set_scope_info_map(Map::cast(obj));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002374
lrn@chromium.org303ada72010-10-27 09:33:13 +00002375 { MaybeObject* maybe_obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
2376 if (!maybe_obj->ToObject(&obj)) return false;
2377 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002378 set_heap_number_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002379
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002380 { MaybeObject* maybe_obj = AllocateMap(FOREIGN_TYPE, Foreign::kSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002381 if (!maybe_obj->ToObject(&obj)) return false;
2382 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002383 set_foreign_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002384
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002385 for (unsigned i = 0; i < ARRAY_SIZE(string_type_table); i++) {
2386 const StringTypeTable& entry = string_type_table[i];
lrn@chromium.org303ada72010-10-27 09:33:13 +00002387 { MaybeObject* maybe_obj = AllocateMap(entry.type, entry.size);
2388 if (!maybe_obj->ToObject(&obj)) return false;
2389 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002390 roots_[entry.index] = Map::cast(obj);
2391 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002392
lrn@chromium.org303ada72010-10-27 09:33:13 +00002393 { MaybeObject* maybe_obj = AllocateMap(STRING_TYPE, kVariableSizeSentinel);
2394 if (!maybe_obj->ToObject(&obj)) return false;
2395 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002396 set_undetectable_string_map(Map::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002397 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002398
lrn@chromium.org303ada72010-10-27 09:33:13 +00002399 { MaybeObject* maybe_obj =
2400 AllocateMap(ASCII_STRING_TYPE, kVariableSizeSentinel);
2401 if (!maybe_obj->ToObject(&obj)) return false;
2402 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002403 set_undetectable_ascii_string_map(Map::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002404 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002405
lrn@chromium.org303ada72010-10-27 09:33:13 +00002406 { MaybeObject* maybe_obj =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002407 AllocateMap(FIXED_DOUBLE_ARRAY_TYPE, kVariableSizeSentinel);
2408 if (!maybe_obj->ToObject(&obj)) return false;
2409 }
2410 set_fixed_double_array_map(Map::cast(obj));
2411
2412 { MaybeObject* maybe_obj =
lrn@chromium.org303ada72010-10-27 09:33:13 +00002413 AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel);
2414 if (!maybe_obj->ToObject(&obj)) return false;
2415 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002416 set_byte_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002417
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002418 { MaybeObject* maybe_obj =
2419 AllocateMap(FREE_SPACE_TYPE, kVariableSizeSentinel);
2420 if (!maybe_obj->ToObject(&obj)) return false;
2421 }
2422 set_free_space_map(Map::cast(obj));
2423
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002424 { MaybeObject* maybe_obj = AllocateByteArray(0, TENURED);
2425 if (!maybe_obj->ToObject(&obj)) return false;
2426 }
2427 set_empty_byte_array(ByteArray::cast(obj));
2428
lrn@chromium.org303ada72010-10-27 09:33:13 +00002429 { MaybeObject* maybe_obj =
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002430 AllocateMap(EXTERNAL_PIXEL_ARRAY_TYPE, ExternalArray::kAlignedSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002431 if (!maybe_obj->ToObject(&obj)) return false;
2432 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002433 set_external_pixel_array_map(Map::cast(obj));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002434
lrn@chromium.org303ada72010-10-27 09:33:13 +00002435 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_BYTE_ARRAY_TYPE,
2436 ExternalArray::kAlignedSize);
2437 if (!maybe_obj->ToObject(&obj)) return false;
2438 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002439 set_external_byte_array_map(Map::cast(obj));
2440
lrn@chromium.org303ada72010-10-27 09:33:13 +00002441 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE,
2442 ExternalArray::kAlignedSize);
2443 if (!maybe_obj->ToObject(&obj)) return false;
2444 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002445 set_external_unsigned_byte_array_map(Map::cast(obj));
2446
lrn@chromium.org303ada72010-10-27 09:33:13 +00002447 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_SHORT_ARRAY_TYPE,
2448 ExternalArray::kAlignedSize);
2449 if (!maybe_obj->ToObject(&obj)) return false;
2450 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002451 set_external_short_array_map(Map::cast(obj));
2452
lrn@chromium.org303ada72010-10-27 09:33:13 +00002453 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE,
2454 ExternalArray::kAlignedSize);
2455 if (!maybe_obj->ToObject(&obj)) return false;
2456 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002457 set_external_unsigned_short_array_map(Map::cast(obj));
2458
lrn@chromium.org303ada72010-10-27 09:33:13 +00002459 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_INT_ARRAY_TYPE,
2460 ExternalArray::kAlignedSize);
2461 if (!maybe_obj->ToObject(&obj)) return false;
2462 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002463 set_external_int_array_map(Map::cast(obj));
2464
lrn@chromium.org303ada72010-10-27 09:33:13 +00002465 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE,
2466 ExternalArray::kAlignedSize);
2467 if (!maybe_obj->ToObject(&obj)) return false;
2468 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002469 set_external_unsigned_int_array_map(Map::cast(obj));
2470
lrn@chromium.org303ada72010-10-27 09:33:13 +00002471 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_FLOAT_ARRAY_TYPE,
2472 ExternalArray::kAlignedSize);
2473 if (!maybe_obj->ToObject(&obj)) return false;
2474 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002475 set_external_float_array_map(Map::cast(obj));
2476
whesse@chromium.org7b260152011-06-20 15:33:18 +00002477 { MaybeObject* maybe_obj =
2478 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2479 if (!maybe_obj->ToObject(&obj)) return false;
2480 }
2481 set_non_strict_arguments_elements_map(Map::cast(obj));
2482
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002483 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_DOUBLE_ARRAY_TYPE,
2484 ExternalArray::kAlignedSize);
2485 if (!maybe_obj->ToObject(&obj)) return false;
2486 }
2487 set_external_double_array_map(Map::cast(obj));
2488
lrn@chromium.org303ada72010-10-27 09:33:13 +00002489 { MaybeObject* maybe_obj = AllocateMap(CODE_TYPE, kVariableSizeSentinel);
2490 if (!maybe_obj->ToObject(&obj)) return false;
2491 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002492 set_code_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002493
lrn@chromium.org303ada72010-10-27 09:33:13 +00002494 { MaybeObject* maybe_obj = AllocateMap(JS_GLOBAL_PROPERTY_CELL_TYPE,
2495 JSGlobalPropertyCell::kSize);
2496 if (!maybe_obj->ToObject(&obj)) return false;
2497 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002498 set_global_property_cell_map(Map::cast(obj));
2499
lrn@chromium.org303ada72010-10-27 09:33:13 +00002500 { MaybeObject* maybe_obj = AllocateMap(FILLER_TYPE, kPointerSize);
2501 if (!maybe_obj->ToObject(&obj)) return false;
2502 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002503 set_one_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002504
lrn@chromium.org303ada72010-10-27 09:33:13 +00002505 { MaybeObject* maybe_obj = AllocateMap(FILLER_TYPE, 2 * kPointerSize);
2506 if (!maybe_obj->ToObject(&obj)) return false;
2507 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002508 set_two_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002509
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002510 for (unsigned i = 0; i < ARRAY_SIZE(struct_table); i++) {
2511 const StructTable& entry = struct_table[i];
lrn@chromium.org303ada72010-10-27 09:33:13 +00002512 { MaybeObject* maybe_obj = AllocateMap(entry.type, entry.size);
2513 if (!maybe_obj->ToObject(&obj)) return false;
2514 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002515 roots_[entry.index] = Map::cast(obj);
2516 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002517
lrn@chromium.org303ada72010-10-27 09:33:13 +00002518 { MaybeObject* maybe_obj =
2519 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2520 if (!maybe_obj->ToObject(&obj)) return false;
2521 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002522 set_hash_table_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002523
lrn@chromium.org303ada72010-10-27 09:33:13 +00002524 { MaybeObject* maybe_obj =
2525 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2526 if (!maybe_obj->ToObject(&obj)) return false;
2527 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002528 set_function_context_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002529
lrn@chromium.org303ada72010-10-27 09:33:13 +00002530 { MaybeObject* maybe_obj =
2531 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2532 if (!maybe_obj->ToObject(&obj)) return false;
2533 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002534 set_catch_context_map(Map::cast(obj));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002535
lrn@chromium.org303ada72010-10-27 09:33:13 +00002536 { MaybeObject* maybe_obj =
2537 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2538 if (!maybe_obj->ToObject(&obj)) return false;
2539 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002540 set_with_context_map(Map::cast(obj));
2541
2542 { MaybeObject* maybe_obj =
2543 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2544 if (!maybe_obj->ToObject(&obj)) return false;
2545 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002546 set_block_context_map(Map::cast(obj));
2547
2548 { MaybeObject* maybe_obj =
2549 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2550 if (!maybe_obj->ToObject(&obj)) return false;
2551 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002552 set_module_context_map(Map::cast(obj));
2553
2554 { MaybeObject* maybe_obj =
2555 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2556 if (!maybe_obj->ToObject(&obj)) return false;
2557 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002558 set_global_context_map(Map::cast(obj));
2559
2560 { MaybeObject* maybe_obj =
2561 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2562 if (!maybe_obj->ToObject(&obj)) return false;
2563 }
2564 Map* native_context_map = Map::cast(obj);
2565 native_context_map->set_dictionary_map(true);
2566 native_context_map->set_visitor_id(StaticVisitorBase::kVisitNativeContext);
2567 set_native_context_map(native_context_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002568
lrn@chromium.org303ada72010-10-27 09:33:13 +00002569 { MaybeObject* maybe_obj = AllocateMap(SHARED_FUNCTION_INFO_TYPE,
2570 SharedFunctionInfo::kAlignedSize);
2571 if (!maybe_obj->ToObject(&obj)) return false;
2572 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002573 set_shared_function_info_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002574
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002575 { MaybeObject* maybe_obj = AllocateMap(JS_MESSAGE_OBJECT_TYPE,
2576 JSMessageObject::kSize);
2577 if (!maybe_obj->ToObject(&obj)) return false;
2578 }
2579 set_message_object_map(Map::cast(obj));
2580
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002581 ASSERT(!InNewSpace(empty_fixed_array()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002582 return true;
2583}
2584
2585
lrn@chromium.org303ada72010-10-27 09:33:13 +00002586MaybeObject* Heap::AllocateHeapNumber(double value, PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002587 // Statically ensure that it is safe to allocate heap numbers in paged
2588 // spaces.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002589 STATIC_ASSERT(HeapNumber::kSize <= Page::kNonCodeObjectAreaSize);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002590 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002591
lrn@chromium.org303ada72010-10-27 09:33:13 +00002592 Object* result;
2593 { MaybeObject* maybe_result =
2594 AllocateRaw(HeapNumber::kSize, space, OLD_DATA_SPACE);
2595 if (!maybe_result->ToObject(&result)) return maybe_result;
2596 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002597
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002598 HeapObject::cast(result)->set_map_no_write_barrier(heap_number_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002599 HeapNumber::cast(result)->set_value(value);
2600 return result;
2601}
2602
2603
lrn@chromium.org303ada72010-10-27 09:33:13 +00002604MaybeObject* Heap::AllocateHeapNumber(double value) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002605 // Use general version, if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002606 if (always_allocate()) return AllocateHeapNumber(value, TENURED);
2607
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002608 // This version of AllocateHeapNumber is optimized for
2609 // allocation in new space.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002610 STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxNonCodeHeapObjectSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002611 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002612 Object* result;
2613 { MaybeObject* maybe_result = new_space_.AllocateRaw(HeapNumber::kSize);
2614 if (!maybe_result->ToObject(&result)) return maybe_result;
2615 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002616 HeapObject::cast(result)->set_map_no_write_barrier(heap_number_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002617 HeapNumber::cast(result)->set_value(value);
2618 return result;
2619}
2620
2621
lrn@chromium.org303ada72010-10-27 09:33:13 +00002622MaybeObject* Heap::AllocateJSGlobalPropertyCell(Object* value) {
2623 Object* result;
2624 { MaybeObject* maybe_result = AllocateRawCell();
2625 if (!maybe_result->ToObject(&result)) return maybe_result;
2626 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002627 HeapObject::cast(result)->set_map_no_write_barrier(
2628 global_property_cell_map());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002629 JSGlobalPropertyCell::cast(result)->set_value(value);
2630 return result;
2631}
2632
2633
lrn@chromium.org303ada72010-10-27 09:33:13 +00002634MaybeObject* Heap::CreateOddball(const char* to_string,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002635 Object* to_number,
2636 byte kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002637 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002638 { MaybeObject* maybe_result = Allocate(oddball_map(), OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002639 if (!maybe_result->ToObject(&result)) return maybe_result;
2640 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002641 return Oddball::cast(result)->Initialize(to_string, to_number, kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002642}
2643
2644
2645bool Heap::CreateApiObjects() {
2646 Object* obj;
2647
lrn@chromium.org303ada72010-10-27 09:33:13 +00002648 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
2649 if (!maybe_obj->ToObject(&obj)) return false;
2650 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002651 // Don't use Smi-only elements optimizations for objects with the neander
2652 // map. There are too many cases where element values are set directly with a
2653 // bottleneck to trap the Smi-only -> fast elements transition, and there
2654 // appears to be no benefit for optimize this case.
2655 Map* new_neander_map = Map::cast(obj);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002656 new_neander_map->set_elements_kind(TERMINAL_FAST_ELEMENTS_KIND);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002657 set_neander_map(new_neander_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002658
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002659 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(neander_map());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002660 if (!maybe_obj->ToObject(&obj)) return false;
2661 }
2662 Object* elements;
2663 { MaybeObject* maybe_elements = AllocateFixedArray(2);
2664 if (!maybe_elements->ToObject(&elements)) return false;
2665 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002666 FixedArray::cast(elements)->set(0, Smi::FromInt(0));
2667 JSObject::cast(obj)->set_elements(FixedArray::cast(elements));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002668 set_message_listeners(JSObject::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002669
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002670 return true;
2671}
2672
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002673
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002674void Heap::CreateJSEntryStub() {
2675 JSEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002676 set_js_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002677}
2678
2679
2680void Heap::CreateJSConstructEntryStub() {
2681 JSConstructEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002682 set_js_construct_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002683}
2684
2685
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002686void Heap::CreateFixedStubs() {
2687 // Here we create roots for fixed stubs. They are needed at GC
2688 // for cooking and uncooking (check out frames.cc).
2689 // The eliminates the need for doing dictionary lookup in the
2690 // stub cache for these stubs.
2691 HandleScope scope;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002692 // gcc-4.4 has problem generating correct code of following snippet:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002693 // { JSEntryStub stub;
2694 // js_entry_code_ = *stub.GetCode();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002695 // }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002696 // { JSConstructEntryStub stub;
2697 // js_construct_entry_code_ = *stub.GetCode();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002698 // }
2699 // To workaround the problem, make separate functions without inlining.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002700 Heap::CreateJSEntryStub();
2701 Heap::CreateJSConstructEntryStub();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002702
2703 // Create stubs that should be there, so we don't unexpectedly have to
2704 // create them if we need them during the creation of another stub.
2705 // Stub creation mixes raw pointers and handles in an unsafe manner so
2706 // we cannot create stubs while we are creating stubs.
2707 CodeStub::GenerateStubsAheadOfTime();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002708}
2709
2710
2711bool Heap::CreateInitialObjects() {
2712 Object* obj;
2713
2714 // The -0 value must be set before NumberFromDouble works.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002715 { MaybeObject* maybe_obj = AllocateHeapNumber(-0.0, TENURED);
2716 if (!maybe_obj->ToObject(&obj)) return false;
2717 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002718 set_minus_zero_value(HeapNumber::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002719 ASSERT(signbit(minus_zero_value()->Number()) != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002720
lrn@chromium.org303ada72010-10-27 09:33:13 +00002721 { MaybeObject* maybe_obj = AllocateHeapNumber(OS::nan_value(), TENURED);
2722 if (!maybe_obj->ToObject(&obj)) return false;
2723 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002724 set_nan_value(HeapNumber::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002725
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002726 { MaybeObject* maybe_obj = AllocateHeapNumber(V8_INFINITY, TENURED);
2727 if (!maybe_obj->ToObject(&obj)) return false;
2728 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002729 set_infinity_value(HeapNumber::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002730
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00002731 // The hole has not been created yet, but we want to put something
2732 // predictable in the gaps in the symbol table, so lets make that Smi zero.
2733 set_the_hole_value(reinterpret_cast<Oddball*>(Smi::FromInt(0)));
2734
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002735 // Allocate initial symbol table.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002736 { MaybeObject* maybe_obj = SymbolTable::Allocate(kInitialSymbolTableSize);
2737 if (!maybe_obj->ToObject(&obj)) return false;
2738 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002739 // Don't use set_symbol_table() due to asserts.
2740 roots_[kSymbolTableRootIndex] = obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002741
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002742 // Finish initializing oddballs after creating symboltable.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002743 { MaybeObject* maybe_obj =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002744 undefined_value()->Initialize("undefined",
2745 nan_value(),
2746 Oddball::kUndefined);
2747 if (!maybe_obj->ToObject(&obj)) return false;
2748 }
2749
2750 // Initialize the null_value.
2751 { MaybeObject* maybe_obj =
2752 null_value()->Initialize("null", Smi::FromInt(0), Oddball::kNull);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002753 if (!maybe_obj->ToObject(&obj)) return false;
2754 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002755
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002756 { MaybeObject* maybe_obj = CreateOddball("true",
2757 Smi::FromInt(1),
2758 Oddball::kTrue);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002759 if (!maybe_obj->ToObject(&obj)) return false;
2760 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002761 set_true_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002762
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002763 { MaybeObject* maybe_obj = CreateOddball("false",
2764 Smi::FromInt(0),
2765 Oddball::kFalse);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002766 if (!maybe_obj->ToObject(&obj)) return false;
2767 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002768 set_false_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002769
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002770 { MaybeObject* maybe_obj = CreateOddball("hole",
2771 Smi::FromInt(-1),
2772 Oddball::kTheHole);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002773 if (!maybe_obj->ToObject(&obj)) return false;
2774 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002775 set_the_hole_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002776
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002777 { MaybeObject* maybe_obj = CreateOddball("arguments_marker",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002778 Smi::FromInt(-4),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002779 Oddball::kArgumentMarker);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002780 if (!maybe_obj->ToObject(&obj)) return false;
2781 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002782 set_arguments_marker(Oddball::cast(obj));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002783
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002784 { MaybeObject* maybe_obj = CreateOddball("no_interceptor_result_sentinel",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002785 Smi::FromInt(-2),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002786 Oddball::kOther);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002787 if (!maybe_obj->ToObject(&obj)) return false;
2788 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002789 set_no_interceptor_result_sentinel(obj);
2790
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002791 { MaybeObject* maybe_obj = CreateOddball("termination_exception",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002792 Smi::FromInt(-3),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002793 Oddball::kOther);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002794 if (!maybe_obj->ToObject(&obj)) return false;
2795 }
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00002796 set_termination_exception(obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002797
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002798 // Allocate the empty string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002799 { MaybeObject* maybe_obj = AllocateRawAsciiString(0, TENURED);
2800 if (!maybe_obj->ToObject(&obj)) return false;
2801 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002802 set_empty_string(String::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002803
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002804 for (unsigned i = 0; i < ARRAY_SIZE(constant_symbol_table); i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002805 { MaybeObject* maybe_obj =
2806 LookupAsciiSymbol(constant_symbol_table[i].contents);
2807 if (!maybe_obj->ToObject(&obj)) return false;
2808 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002809 roots_[constant_symbol_table[i].index] = String::cast(obj);
2810 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002811
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002812 // Allocate the hidden symbol which is used to identify the hidden properties
2813 // in JSObjects. The hash code has a special value so that it will not match
2814 // the empty string when searching for the property. It cannot be part of the
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002815 // loop above because it needs to be allocated manually with the special
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002816 // hash code in place. The hash code for the hidden_symbol is zero to ensure
2817 // that it will always be at the first entry in property descriptors.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002818 { MaybeObject* maybe_obj =
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002819 AllocateSymbol(CStrVector(""), 0, String::kEmptyStringHash);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002820 if (!maybe_obj->ToObject(&obj)) return false;
2821 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002822 hidden_symbol_ = String::cast(obj);
2823
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002824 // Allocate the foreign for __proto__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002825 { MaybeObject* maybe_obj =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002826 AllocateForeign((Address) &Accessors::ObjectPrototype);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002827 if (!maybe_obj->ToObject(&obj)) return false;
2828 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002829 set_prototype_accessors(Foreign::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002830
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002831 // Allocate the code_stubs dictionary. The initial size is set to avoid
2832 // expanding the dictionary during bootstrapping.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002833 { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(128);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002834 if (!maybe_obj->ToObject(&obj)) return false;
2835 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002836 set_code_stubs(UnseededNumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002837
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002838
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002839 // Allocate the non_monomorphic_cache used in stub-cache.cc. The initial size
2840 // is set to avoid expanding the dictionary during bootstrapping.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002841 { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(64);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002842 if (!maybe_obj->ToObject(&obj)) return false;
2843 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002844 set_non_monomorphic_cache(UnseededNumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002845
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002846 { MaybeObject* maybe_obj = AllocatePolymorphicCodeCache();
2847 if (!maybe_obj->ToObject(&obj)) return false;
2848 }
2849 set_polymorphic_code_cache(PolymorphicCodeCache::cast(obj));
2850
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002851 set_instanceof_cache_function(Smi::FromInt(0));
2852 set_instanceof_cache_map(Smi::FromInt(0));
2853 set_instanceof_cache_answer(Smi::FromInt(0));
2854
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002855 CreateFixedStubs();
2856
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002857 // Allocate the dictionary of intrinsic function names.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002858 { MaybeObject* maybe_obj = StringDictionary::Allocate(Runtime::kNumFunctions);
2859 if (!maybe_obj->ToObject(&obj)) return false;
2860 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002861 { MaybeObject* maybe_obj = Runtime::InitializeIntrinsicFunctionNames(this,
2862 obj);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002863 if (!maybe_obj->ToObject(&obj)) return false;
2864 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002865 set_intrinsic_function_names(StringDictionary::cast(obj));
2866
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002867 { MaybeObject* maybe_obj = AllocateInitialNumberStringCache();
2868 if (!maybe_obj->ToObject(&obj)) return false;
2869 }
2870 set_number_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002871
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002872 // Allocate cache for single character ASCII strings.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002873 { MaybeObject* maybe_obj =
2874 AllocateFixedArray(String::kMaxAsciiCharCode + 1, TENURED);
2875 if (!maybe_obj->ToObject(&obj)) return false;
2876 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002877 set_single_character_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002878
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002879 // Allocate cache for string split.
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002880 { MaybeObject* maybe_obj = AllocateFixedArray(
2881 RegExpResultsCache::kRegExpResultsCacheSize, TENURED);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002882 if (!maybe_obj->ToObject(&obj)) return false;
2883 }
2884 set_string_split_cache(FixedArray::cast(obj));
2885
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002886 { MaybeObject* maybe_obj = AllocateFixedArray(
2887 RegExpResultsCache::kRegExpResultsCacheSize, TENURED);
2888 if (!maybe_obj->ToObject(&obj)) return false;
2889 }
2890 set_regexp_multiple_cache(FixedArray::cast(obj));
2891
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002892 // Allocate cache for external strings pointing to native source code.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002893 { MaybeObject* maybe_obj = AllocateFixedArray(Natives::GetBuiltinsCount());
2894 if (!maybe_obj->ToObject(&obj)) return false;
2895 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002896 set_natives_source_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002897
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002898 // Allocate object to hold object observation state.
2899 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
2900 if (!maybe_obj->ToObject(&obj)) return false;
2901 }
2902 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(Map::cast(obj));
2903 if (!maybe_obj->ToObject(&obj)) return false;
2904 }
2905 set_observation_state(JSObject::cast(obj));
2906
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002907 // Handling of script id generation is in FACTORY->NewScript.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002908 set_last_script_id(undefined_value());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002909
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002910 // Initialize keyed lookup cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002911 isolate_->keyed_lookup_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002912
2913 // Initialize context slot cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002914 isolate_->context_slot_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002915
2916 // Initialize descriptor cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002917 isolate_->descriptor_lookup_cache()->Clear();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002918
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002919 // Initialize compilation cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002920 isolate_->compilation_cache()->Clear();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002921
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002922 return true;
2923}
2924
2925
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002926bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) {
2927 RootListIndex writable_roots[] = {
2928 kStoreBufferTopRootIndex,
2929 kStackLimitRootIndex,
2930 kInstanceofCacheFunctionRootIndex,
2931 kInstanceofCacheMapRootIndex,
2932 kInstanceofCacheAnswerRootIndex,
2933 kCodeStubsRootIndex,
2934 kNonMonomorphicCacheRootIndex,
2935 kPolymorphicCodeCacheRootIndex,
2936 kLastScriptIdRootIndex,
2937 kEmptyScriptRootIndex,
2938 kRealStackLimitRootIndex,
2939 kArgumentsAdaptorDeoptPCOffsetRootIndex,
2940 kConstructStubDeoptPCOffsetRootIndex,
2941 kGetterStubDeoptPCOffsetRootIndex,
2942 kSetterStubDeoptPCOffsetRootIndex,
2943 kSymbolTableRootIndex,
2944 };
2945
2946 for (unsigned int i = 0; i < ARRAY_SIZE(writable_roots); i++) {
2947 if (root_index == writable_roots[i])
2948 return true;
2949 }
2950 return false;
2951}
2952
2953
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002954Object* RegExpResultsCache::Lookup(Heap* heap,
2955 String* key_string,
2956 Object* key_pattern,
2957 ResultsCacheType type) {
2958 FixedArray* cache;
2959 if (!key_string->IsSymbol()) return Smi::FromInt(0);
2960 if (type == STRING_SPLIT_SUBSTRINGS) {
2961 ASSERT(key_pattern->IsString());
2962 if (!key_pattern->IsSymbol()) return Smi::FromInt(0);
2963 cache = heap->string_split_cache();
2964 } else {
2965 ASSERT(type == REGEXP_MULTIPLE_INDICES);
2966 ASSERT(key_pattern->IsFixedArray());
2967 cache = heap->regexp_multiple_cache();
2968 }
2969
2970 uint32_t hash = key_string->Hash();
2971 uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) &
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002972 ~(kArrayEntriesPerCacheEntry - 1));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002973 if (cache->get(index + kStringOffset) == key_string &&
2974 cache->get(index + kPatternOffset) == key_pattern) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002975 return cache->get(index + kArrayOffset);
2976 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002977 index =
2978 ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1));
2979 if (cache->get(index + kStringOffset) == key_string &&
2980 cache->get(index + kPatternOffset) == key_pattern) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002981 return cache->get(index + kArrayOffset);
2982 }
2983 return Smi::FromInt(0);
2984}
2985
2986
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002987void RegExpResultsCache::Enter(Heap* heap,
2988 String* key_string,
2989 Object* key_pattern,
2990 FixedArray* value_array,
2991 ResultsCacheType type) {
2992 FixedArray* cache;
2993 if (!key_string->IsSymbol()) return;
2994 if (type == STRING_SPLIT_SUBSTRINGS) {
2995 ASSERT(key_pattern->IsString());
2996 if (!key_pattern->IsSymbol()) return;
2997 cache = heap->string_split_cache();
2998 } else {
2999 ASSERT(type == REGEXP_MULTIPLE_INDICES);
3000 ASSERT(key_pattern->IsFixedArray());
3001 cache = heap->regexp_multiple_cache();
3002 }
3003
3004 uint32_t hash = key_string->Hash();
3005 uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) &
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003006 ~(kArrayEntriesPerCacheEntry - 1));
3007 if (cache->get(index + kStringOffset) == Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003008 cache->set(index + kStringOffset, key_string);
3009 cache->set(index + kPatternOffset, key_pattern);
3010 cache->set(index + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003011 } else {
3012 uint32_t index2 =
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003013 ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1));
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003014 if (cache->get(index2 + kStringOffset) == Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003015 cache->set(index2 + kStringOffset, key_string);
3016 cache->set(index2 + kPatternOffset, key_pattern);
3017 cache->set(index2 + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003018 } else {
3019 cache->set(index2 + kStringOffset, Smi::FromInt(0));
3020 cache->set(index2 + kPatternOffset, Smi::FromInt(0));
3021 cache->set(index2 + kArrayOffset, Smi::FromInt(0));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003022 cache->set(index + kStringOffset, key_string);
3023 cache->set(index + kPatternOffset, key_pattern);
3024 cache->set(index + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003025 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003026 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003027 // If the array is a reasonably short list of substrings, convert it into a
3028 // list of symbols.
3029 if (type == STRING_SPLIT_SUBSTRINGS && value_array->length() < 100) {
3030 for (int i = 0; i < value_array->length(); i++) {
3031 String* str = String::cast(value_array->get(i));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003032 Object* symbol;
3033 MaybeObject* maybe_symbol = heap->LookupSymbol(str);
3034 if (maybe_symbol->ToObject(&symbol)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003035 value_array->set(i, symbol);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003036 }
3037 }
3038 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003039 // Convert backing store to a copy-on-write array.
3040 value_array->set_map_no_write_barrier(heap->fixed_cow_array_map());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003041}
3042
3043
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003044void RegExpResultsCache::Clear(FixedArray* cache) {
3045 for (int i = 0; i < kRegExpResultsCacheSize; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003046 cache->set(i, Smi::FromInt(0));
3047 }
3048}
3049
3050
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003051MaybeObject* Heap::AllocateInitialNumberStringCache() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003052 MaybeObject* maybe_obj =
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003053 AllocateFixedArray(kInitialNumberStringCacheSize * 2, TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003054 return maybe_obj;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003055}
3056
3057
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003058int Heap::FullSizeNumberStringCacheLength() {
3059 // Compute the size of the number string cache based on the max newspace size.
3060 // The number string cache has a minimum size based on twice the initial cache
3061 // size to ensure that it is bigger after being made 'full size'.
3062 int number_string_cache_size = max_semispace_size_ / 512;
3063 number_string_cache_size = Max(kInitialNumberStringCacheSize * 2,
3064 Min(0x4000, number_string_cache_size));
3065 // There is a string and a number per entry so the length is twice the number
3066 // of entries.
3067 return number_string_cache_size * 2;
3068}
3069
3070
3071void Heap::AllocateFullSizeNumberStringCache() {
3072 // The idea is to have a small number string cache in the snapshot to keep
3073 // boot-time memory usage down. If we expand the number string cache already
3074 // while creating the snapshot then that didn't work out.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003075 ASSERT(!Serializer::enabled() || FLAG_extra_code != NULL);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003076 MaybeObject* maybe_obj =
3077 AllocateFixedArray(FullSizeNumberStringCacheLength(), TENURED);
3078 Object* new_cache;
3079 if (maybe_obj->ToObject(&new_cache)) {
3080 // We don't bother to repopulate the cache with entries from the old cache.
3081 // It will be repopulated soon enough with new strings.
3082 set_number_string_cache(FixedArray::cast(new_cache));
3083 }
3084 // If allocation fails then we just return without doing anything. It is only
3085 // a cache, so best effort is OK here.
3086}
3087
3088
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003089void Heap::FlushNumberStringCache() {
3090 // Flush the number to string cache.
3091 int len = number_string_cache()->length();
3092 for (int i = 0; i < len; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003093 number_string_cache()->set_undefined(this, i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003094 }
3095}
3096
3097
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003098static inline int double_get_hash(double d) {
3099 DoubleRepresentation rep(d);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003100 return static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003101}
3102
3103
3104static inline int smi_get_hash(Smi* smi) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003105 return smi->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003106}
3107
3108
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003109Object* Heap::GetNumberStringCache(Object* number) {
3110 int hash;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003111 int mask = (number_string_cache()->length() >> 1) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003112 if (number->IsSmi()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003113 hash = smi_get_hash(Smi::cast(number)) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003114 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003115 hash = double_get_hash(number->Number()) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003116 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003117 Object* key = number_string_cache()->get(hash * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003118 if (key == number) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003119 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003120 } else if (key->IsHeapNumber() &&
3121 number->IsHeapNumber() &&
3122 key->Number() == number->Number()) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003123 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003124 }
3125 return undefined_value();
3126}
3127
3128
3129void Heap::SetNumberStringCache(Object* number, String* string) {
3130 int hash;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003131 int mask = (number_string_cache()->length() >> 1) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003132 if (number->IsSmi()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003133 hash = smi_get_hash(Smi::cast(number)) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003134 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003135 hash = double_get_hash(number->Number()) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003136 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003137 if (number_string_cache()->get(hash * 2) != undefined_value() &&
3138 number_string_cache()->length() != FullSizeNumberStringCacheLength()) {
3139 // The first time we have a hash collision, we move to the full sized
3140 // number string cache.
3141 AllocateFullSizeNumberStringCache();
3142 return;
3143 }
3144 number_string_cache()->set(hash * 2, number);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003145 number_string_cache()->set(hash * 2 + 1, string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003146}
3147
3148
lrn@chromium.org303ada72010-10-27 09:33:13 +00003149MaybeObject* Heap::NumberToString(Object* number,
3150 bool check_number_string_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003151 isolate_->counters()->number_to_string_runtime()->Increment();
ager@chromium.org357bf652010-04-12 11:30:10 +00003152 if (check_number_string_cache) {
3153 Object* cached = GetNumberStringCache(number);
3154 if (cached != undefined_value()) {
3155 return cached;
3156 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003157 }
3158
3159 char arr[100];
3160 Vector<char> buffer(arr, ARRAY_SIZE(arr));
3161 const char* str;
3162 if (number->IsSmi()) {
3163 int num = Smi::cast(number)->value();
3164 str = IntToCString(num, buffer);
3165 } else {
3166 double num = HeapNumber::cast(number)->value();
3167 str = DoubleToCString(num, buffer);
3168 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003169
lrn@chromium.org303ada72010-10-27 09:33:13 +00003170 Object* js_string;
3171 MaybeObject* maybe_js_string = AllocateStringFromAscii(CStrVector(str));
3172 if (maybe_js_string->ToObject(&js_string)) {
3173 SetNumberStringCache(number, String::cast(js_string));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003174 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00003175 return maybe_js_string;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003176}
3177
3178
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003179MaybeObject* Heap::Uint32ToString(uint32_t value,
3180 bool check_number_string_cache) {
3181 Object* number;
3182 MaybeObject* maybe = NumberFromUint32(value);
3183 if (!maybe->To<Object>(&number)) return maybe;
3184 return NumberToString(number, check_number_string_cache);
3185}
3186
3187
ager@chromium.org3811b432009-10-28 14:53:37 +00003188Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) {
3189 return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]);
3190}
3191
3192
3193Heap::RootListIndex Heap::RootIndexForExternalArrayType(
3194 ExternalArrayType array_type) {
3195 switch (array_type) {
3196 case kExternalByteArray:
3197 return kExternalByteArrayMapRootIndex;
3198 case kExternalUnsignedByteArray:
3199 return kExternalUnsignedByteArrayMapRootIndex;
3200 case kExternalShortArray:
3201 return kExternalShortArrayMapRootIndex;
3202 case kExternalUnsignedShortArray:
3203 return kExternalUnsignedShortArrayMapRootIndex;
3204 case kExternalIntArray:
3205 return kExternalIntArrayMapRootIndex;
3206 case kExternalUnsignedIntArray:
3207 return kExternalUnsignedIntArrayMapRootIndex;
3208 case kExternalFloatArray:
3209 return kExternalFloatArrayMapRootIndex;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003210 case kExternalDoubleArray:
3211 return kExternalDoubleArrayMapRootIndex;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003212 case kExternalPixelArray:
3213 return kExternalPixelArrayMapRootIndex;
ager@chromium.org3811b432009-10-28 14:53:37 +00003214 default:
3215 UNREACHABLE();
3216 return kUndefinedValueRootIndex;
3217 }
3218}
3219
3220
lrn@chromium.org303ada72010-10-27 09:33:13 +00003221MaybeObject* Heap::NumberFromDouble(double value, PretenureFlag pretenure) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003222 // We need to distinguish the minus zero value and this cannot be
3223 // done after conversion to int. Doing this by comparing bit
3224 // patterns is faster than using fpclassify() et al.
3225 static const DoubleRepresentation minus_zero(-0.0);
3226
3227 DoubleRepresentation rep(value);
3228 if (rep.bits == minus_zero.bits) {
3229 return AllocateHeapNumber(-0.0, pretenure);
3230 }
3231
3232 int int_value = FastD2I(value);
3233 if (value == int_value && Smi::IsValid(int_value)) {
3234 return Smi::FromInt(int_value);
3235 }
3236
3237 // Materialize the value in the heap.
3238 return AllocateHeapNumber(value, pretenure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003239}
3240
3241
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003242MaybeObject* Heap::AllocateForeign(Address address, PretenureFlag pretenure) {
3243 // Statically ensure that it is safe to allocate foreigns in paged spaces.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003244 STATIC_ASSERT(Foreign::kSize <= Page::kMaxNonCodeHeapObjectSize);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003245 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003246 Foreign* result;
3247 MaybeObject* maybe_result = Allocate(foreign_map(), space);
3248 if (!maybe_result->To(&result)) return maybe_result;
3249 result->set_foreign_address(address);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003250 return result;
3251}
3252
3253
lrn@chromium.org303ada72010-10-27 09:33:13 +00003254MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003255 SharedFunctionInfo* share;
3256 MaybeObject* maybe = Allocate(shared_function_info_map(), OLD_POINTER_SPACE);
3257 if (!maybe->To<SharedFunctionInfo>(&share)) return maybe;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003258
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003259 // Set pointer fields.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003260 share->set_name(name);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003261 Code* illegal = isolate_->builtins()->builtin(Builtins::kIllegal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003262 share->set_code(illegal);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003263 share->ClearOptimizedCodeMap();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003264 share->set_scope_info(ScopeInfo::Empty());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003265 Code* construct_stub =
3266 isolate_->builtins()->builtin(Builtins::kJSConstructStubGeneric);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003267 share->set_construct_stub(construct_stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003268 share->set_instance_class_name(Object_symbol());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003269 share->set_function_data(undefined_value(), SKIP_WRITE_BARRIER);
3270 share->set_script(undefined_value(), SKIP_WRITE_BARRIER);
3271 share->set_debug_info(undefined_value(), SKIP_WRITE_BARRIER);
3272 share->set_inferred_name(empty_string(), SKIP_WRITE_BARRIER);
3273 share->set_initial_map(undefined_value(), SKIP_WRITE_BARRIER);
3274 share->set_this_property_assignments(undefined_value(), SKIP_WRITE_BARRIER);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003275 share->set_ast_node_count(0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003276 share->set_stress_deopt_counter(FLAG_deopt_every_n_times);
3277 share->set_counters(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003278
3279 // Set integer fields (smi or int, depending on the architecture).
3280 share->set_length(0);
3281 share->set_formal_parameter_count(0);
3282 share->set_expected_nof_properties(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003283 share->set_num_literals(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003284 share->set_start_position_and_type(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003285 share->set_end_position(0);
3286 share->set_function_token_position(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003287 // All compiler hints default to false or 0.
3288 share->set_compiler_hints(0);
3289 share->set_this_property_assignments_count(0);
3290 share->set_opt_count(0);
3291
3292 return share;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003293}
3294
3295
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003296MaybeObject* Heap::AllocateJSMessageObject(String* type,
3297 JSArray* arguments,
3298 int start_position,
3299 int end_position,
3300 Object* script,
3301 Object* stack_trace,
3302 Object* stack_frames) {
3303 Object* result;
3304 { MaybeObject* maybe_result = Allocate(message_object_map(), NEW_SPACE);
3305 if (!maybe_result->ToObject(&result)) return maybe_result;
3306 }
3307 JSMessageObject* message = JSMessageObject::cast(result);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003308 message->set_properties(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003309 message->initialize_elements();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003310 message->set_elements(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003311 message->set_type(type);
3312 message->set_arguments(arguments);
3313 message->set_start_position(start_position);
3314 message->set_end_position(end_position);
3315 message->set_script(script);
3316 message->set_stack_trace(stack_trace);
3317 message->set_stack_frames(stack_frames);
3318 return result;
3319}
3320
3321
3322
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003323// Returns true for a character in a range. Both limits are inclusive.
3324static inline bool Between(uint32_t character, uint32_t from, uint32_t to) {
3325 // This makes uses of the the unsigned wraparound.
3326 return character - from <= to - from;
3327}
3328
3329
lrn@chromium.org303ada72010-10-27 09:33:13 +00003330MUST_USE_RESULT static inline MaybeObject* MakeOrFindTwoCharacterString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003331 Heap* heap,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003332 uint32_t c1,
3333 uint32_t c2) {
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003334 String* symbol;
3335 // Numeric strings have a different hash algorithm not known by
3336 // LookupTwoCharsSymbolIfExists, so we skip this step for such strings.
3337 if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003338 heap->symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) {
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003339 return symbol;
3340 // Now we know the length is 2, we might as well make use of that fact
3341 // when building the new string.
3342 } else if ((c1 | c2) <= String::kMaxAsciiCharCodeU) { // We can do this
3343 ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1)); // because of this.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003344 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003345 { MaybeObject* maybe_result = heap->AllocateRawAsciiString(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003346 if (!maybe_result->ToObject(&result)) return maybe_result;
3347 }
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003348 char* dest = SeqAsciiString::cast(result)->GetChars();
3349 dest[0] = c1;
3350 dest[1] = c2;
3351 return result;
3352 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003353 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003354 { MaybeObject* maybe_result = heap->AllocateRawTwoByteString(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003355 if (!maybe_result->ToObject(&result)) return maybe_result;
3356 }
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003357 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
3358 dest[0] = c1;
3359 dest[1] = c2;
3360 return result;
3361 }
3362}
3363
3364
lrn@chromium.org303ada72010-10-27 09:33:13 +00003365MaybeObject* Heap::AllocateConsString(String* first, String* second) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003366 int first_length = first->length();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003367 if (first_length == 0) {
3368 return second;
3369 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003370
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003371 int second_length = second->length();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003372 if (second_length == 0) {
3373 return first;
3374 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003375
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003376 int length = first_length + second_length;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003377
3378 // Optimization for 2-byte strings often used as keys in a decompression
3379 // dictionary. Check whether we already have the string in the symbol
3380 // table to prevent creation of many unneccesary strings.
3381 if (length == 2) {
3382 unsigned c1 = first->Get(0);
3383 unsigned c2 = second->Get(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003384 return MakeOrFindTwoCharacterString(this, c1, c2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003385 }
3386
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003387 bool first_is_ascii = first->IsAsciiRepresentation();
3388 bool second_is_ascii = second->IsAsciiRepresentation();
3389 bool is_ascii = first_is_ascii && second_is_ascii;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003390
ager@chromium.org3e875802009-06-29 08:26:34 +00003391 // Make sure that an out of memory exception is thrown if the length
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003392 // of the new cons string is too large.
3393 if (length > String::kMaxLength || length < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003394 isolate()->context()->mark_out_of_memory();
ager@chromium.org3e875802009-06-29 08:26:34 +00003395 return Failure::OutOfMemoryException();
3396 }
3397
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003398 bool is_ascii_data_in_two_byte_string = false;
3399 if (!is_ascii) {
3400 // At least one of the strings uses two-byte representation so we
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003401 // can't use the fast case code for short ASCII strings below, but
3402 // we can try to save memory if all chars actually fit in ASCII.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003403 is_ascii_data_in_two_byte_string =
3404 first->HasOnlyAsciiChars() && second->HasOnlyAsciiChars();
3405 if (is_ascii_data_in_two_byte_string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003406 isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003407 }
3408 }
3409
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003410 // If the resulting string is small make a flat string.
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003411 if (length < ConsString::kMinLength) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003412 // Note that neither of the two inputs can be a slice because:
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003413 STATIC_ASSERT(ConsString::kMinLength <= SlicedString::kMinLength);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003414 ASSERT(first->IsFlat());
3415 ASSERT(second->IsFlat());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003416 if (is_ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003417 Object* result;
3418 { MaybeObject* maybe_result = AllocateRawAsciiString(length);
3419 if (!maybe_result->ToObject(&result)) return maybe_result;
3420 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003421 // Copy the characters into the new object.
3422 char* dest = SeqAsciiString::cast(result)->GetChars();
ager@chromium.org3e875802009-06-29 08:26:34 +00003423 // Copy first part.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003424 const char* src;
3425 if (first->IsExternalString()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003426 src = ExternalAsciiString::cast(first)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003427 } else {
3428 src = SeqAsciiString::cast(first)->GetChars();
3429 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003430 for (int i = 0; i < first_length; i++) *dest++ = src[i];
3431 // Copy second part.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003432 if (second->IsExternalString()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003433 src = ExternalAsciiString::cast(second)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003434 } else {
3435 src = SeqAsciiString::cast(second)->GetChars();
3436 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003437 for (int i = 0; i < second_length; i++) *dest++ = src[i];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003438 return result;
3439 } else {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003440 if (is_ascii_data_in_two_byte_string) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003441 Object* result;
3442 { MaybeObject* maybe_result = AllocateRawAsciiString(length);
3443 if (!maybe_result->ToObject(&result)) return maybe_result;
3444 }
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003445 // Copy the characters into the new object.
3446 char* dest = SeqAsciiString::cast(result)->GetChars();
3447 String::WriteToFlat(first, dest, 0, first_length);
3448 String::WriteToFlat(second, dest + first_length, 0, second_length);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003449 isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003450 return result;
3451 }
3452
lrn@chromium.org303ada72010-10-27 09:33:13 +00003453 Object* result;
3454 { MaybeObject* maybe_result = AllocateRawTwoByteString(length);
3455 if (!maybe_result->ToObject(&result)) return maybe_result;
3456 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003457 // Copy the characters into the new object.
3458 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003459 String::WriteToFlat(first, dest, 0, first_length);
3460 String::WriteToFlat(second, dest + first_length, 0, second_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003461 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003462 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003463 }
3464
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003465 Map* map = (is_ascii || is_ascii_data_in_two_byte_string) ?
3466 cons_ascii_string_map() : cons_string_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003467
lrn@chromium.org303ada72010-10-27 09:33:13 +00003468 Object* result;
3469 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3470 if (!maybe_result->ToObject(&result)) return maybe_result;
3471 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003472
3473 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003474 ConsString* cons_string = ConsString::cast(result);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003475 WriteBarrierMode mode = cons_string->GetWriteBarrierMode(no_gc);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003476 cons_string->set_length(length);
3477 cons_string->set_hash_field(String::kEmptyHashField);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003478 cons_string->set_first(first, mode);
3479 cons_string->set_second(second, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003480 return result;
3481}
3482
3483
lrn@chromium.org303ada72010-10-27 09:33:13 +00003484MaybeObject* Heap::AllocateSubString(String* buffer,
ager@chromium.org04921a82011-06-27 13:21:41 +00003485 int start,
3486 int end,
3487 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003488 int length = end - start;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003489 if (length <= 0) {
ager@chromium.org04921a82011-06-27 13:21:41 +00003490 return empty_string();
3491 } else if (length == 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003492 return LookupSingleCharacterStringFromCode(buffer->Get(start));
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003493 } else if (length == 2) {
3494 // Optimization for 2-byte strings often used as keys in a decompression
3495 // dictionary. Check whether we already have the string in the symbol
3496 // table to prevent creation of many unneccesary strings.
3497 unsigned c1 = buffer->Get(start);
3498 unsigned c2 = buffer->Get(start + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003499 return MakeOrFindTwoCharacterString(this, c1, c2);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003500 }
3501
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003502 // Make an attempt to flatten the buffer to reduce access time.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003503 buffer = buffer->TryFlattenGetString();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003504
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003505 if (!FLAG_string_slices ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003506 !buffer->IsFlat() ||
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003507 length < SlicedString::kMinLength ||
3508 pretenure == TENURED) {
3509 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003510 // WriteToFlat takes care of the case when an indirect string has a
3511 // different encoding from its underlying string. These encodings may
3512 // differ because of externalization.
3513 bool is_ascii = buffer->IsAsciiRepresentation();
3514 { MaybeObject* maybe_result = is_ascii
3515 ? AllocateRawAsciiString(length, pretenure)
3516 : AllocateRawTwoByteString(length, pretenure);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003517 if (!maybe_result->ToObject(&result)) return maybe_result;
3518 }
3519 String* string_result = String::cast(result);
3520 // Copy the characters into the new object.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003521 if (is_ascii) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003522 ASSERT(string_result->IsAsciiRepresentation());
3523 char* dest = SeqAsciiString::cast(string_result)->GetChars();
3524 String::WriteToFlat(buffer, dest, start, end);
3525 } else {
3526 ASSERT(string_result->IsTwoByteRepresentation());
3527 uc16* dest = SeqTwoByteString::cast(string_result)->GetChars();
3528 String::WriteToFlat(buffer, dest, start, end);
3529 }
3530 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003531 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003532
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003533 ASSERT(buffer->IsFlat());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003534#if VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003535 if (FLAG_verify_heap) {
3536 buffer->StringVerify();
3537 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003538#endif
3539
3540 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003541 // When slicing an indirect string we use its encoding for a newly created
3542 // slice and don't check the encoding of the underlying string. This is safe
3543 // even if the encodings are different because of externalization. If an
3544 // indirect ASCII string is pointing to a two-byte string, the two-byte char
3545 // codes of the underlying string must still fit into ASCII (because
3546 // externalization must not change char codes).
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003547 { Map* map = buffer->IsAsciiRepresentation()
3548 ? sliced_ascii_string_map()
3549 : sliced_string_map();
3550 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3551 if (!maybe_result->ToObject(&result)) return maybe_result;
3552 }
3553
3554 AssertNoAllocation no_gc;
3555 SlicedString* sliced_string = SlicedString::cast(result);
3556 sliced_string->set_length(length);
3557 sliced_string->set_hash_field(String::kEmptyHashField);
3558 if (buffer->IsConsString()) {
3559 ConsString* cons = ConsString::cast(buffer);
3560 ASSERT(cons->second()->length() == 0);
3561 sliced_string->set_parent(cons->first());
3562 sliced_string->set_offset(start);
3563 } else if (buffer->IsSlicedString()) {
3564 // Prevent nesting sliced strings.
3565 SlicedString* parent_slice = SlicedString::cast(buffer);
3566 sliced_string->set_parent(parent_slice->parent());
3567 sliced_string->set_offset(start + parent_slice->offset());
3568 } else {
3569 sliced_string->set_parent(buffer);
3570 sliced_string->set_offset(start);
3571 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003572 ASSERT(sliced_string->parent()->IsSeqString() ||
3573 sliced_string->parent()->IsExternalString());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003574 return result;
3575}
3576
3577
lrn@chromium.org303ada72010-10-27 09:33:13 +00003578MaybeObject* Heap::AllocateExternalStringFromAscii(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003579 const ExternalAsciiString::Resource* resource) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003580 size_t length = resource->length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003581 if (length > static_cast<size_t>(String::kMaxLength)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003582 isolate()->context()->mark_out_of_memory();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003583 return Failure::OutOfMemoryException();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003584 }
3585
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00003586 ASSERT(String::IsAscii(resource->data(), static_cast<int>(length)));
3587
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003588 Map* map = external_ascii_string_map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003589 Object* result;
3590 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3591 if (!maybe_result->ToObject(&result)) return maybe_result;
3592 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003593
3594 ExternalAsciiString* external_string = ExternalAsciiString::cast(result);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003595 external_string->set_length(static_cast<int>(length));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003596 external_string->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003597 external_string->set_resource(resource);
3598
3599 return result;
3600}
3601
3602
lrn@chromium.org303ada72010-10-27 09:33:13 +00003603MaybeObject* Heap::AllocateExternalStringFromTwoByte(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003604 const ExternalTwoByteString::Resource* resource) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003605 size_t length = resource->length();
3606 if (length > static_cast<size_t>(String::kMaxLength)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003607 isolate()->context()->mark_out_of_memory();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003608 return Failure::OutOfMemoryException();
3609 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003610
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003611 // For small strings we check whether the resource contains only
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003612 // ASCII characters. If yes, we use a different string map.
3613 static const size_t kAsciiCheckLengthLimit = 32;
3614 bool is_ascii = length <= kAsciiCheckLengthLimit &&
3615 String::IsAscii(resource->data(), static_cast<int>(length));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003616 Map* map = is_ascii ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003617 external_string_with_ascii_data_map() : external_string_map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003618 Object* result;
3619 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3620 if (!maybe_result->ToObject(&result)) return maybe_result;
3621 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622
3623 ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003624 external_string->set_length(static_cast<int>(length));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003625 external_string->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003626 external_string->set_resource(resource);
3627
3628 return result;
3629}
3630
3631
lrn@chromium.org303ada72010-10-27 09:33:13 +00003632MaybeObject* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003633 if (code <= String::kMaxAsciiCharCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003634 Object* value = single_character_string_cache()->get(code);
3635 if (value != undefined_value()) return value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003636
3637 char buffer[1];
3638 buffer[0] = static_cast<char>(code);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003639 Object* result;
3640 MaybeObject* maybe_result = LookupSymbol(Vector<const char>(buffer, 1));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003641
lrn@chromium.org303ada72010-10-27 09:33:13 +00003642 if (!maybe_result->ToObject(&result)) return maybe_result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003643 single_character_string_cache()->set(code, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003644 return result;
3645 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003646
lrn@chromium.org303ada72010-10-27 09:33:13 +00003647 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003648 { MaybeObject* maybe_result = AllocateRawTwoByteString(1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003649 if (!maybe_result->ToObject(&result)) return maybe_result;
3650 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00003651 String* answer = String::cast(result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003652 answer->Set(0, code);
ager@chromium.org870a0b62008-11-04 11:43:05 +00003653 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003654}
3655
3656
lrn@chromium.org303ada72010-10-27 09:33:13 +00003657MaybeObject* Heap::AllocateByteArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003658 if (length < 0 || length > ByteArray::kMaxLength) {
3659 return Failure::OutOfMemoryException();
3660 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003661 if (pretenure == NOT_TENURED) {
3662 return AllocateByteArray(length);
3663 }
3664 int size = ByteArray::SizeFor(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003665 Object* result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003666 { MaybeObject* maybe_result = (size <= Page::kMaxNonCodeHeapObjectSize)
lrn@chromium.org303ada72010-10-27 09:33:13 +00003667 ? old_data_space_->AllocateRaw(size)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003668 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003669 if (!maybe_result->ToObject(&result)) return maybe_result;
3670 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003671
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003672 reinterpret_cast<ByteArray*>(result)->set_map_no_write_barrier(
3673 byte_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003674 reinterpret_cast<ByteArray*>(result)->set_length(length);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003675 return result;
3676}
3677
3678
lrn@chromium.org303ada72010-10-27 09:33:13 +00003679MaybeObject* Heap::AllocateByteArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003680 if (length < 0 || length > ByteArray::kMaxLength) {
3681 return Failure::OutOfMemoryException();
3682 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003683 int size = ByteArray::SizeFor(length);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003684 AllocationSpace space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003685 (size > Page::kMaxNonCodeHeapObjectSize) ? LO_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003686 Object* result;
3687 { MaybeObject* maybe_result = AllocateRaw(size, space, OLD_DATA_SPACE);
3688 if (!maybe_result->ToObject(&result)) return maybe_result;
3689 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003690
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003691 reinterpret_cast<ByteArray*>(result)->set_map_no_write_barrier(
3692 byte_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003693 reinterpret_cast<ByteArray*>(result)->set_length(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003694 return result;
3695}
3696
3697
ager@chromium.org6f10e412009-02-13 10:11:16 +00003698void Heap::CreateFillerObjectAt(Address addr, int size) {
3699 if (size == 0) return;
3700 HeapObject* filler = HeapObject::FromAddress(addr);
3701 if (size == kPointerSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003702 filler->set_map_no_write_barrier(one_pointer_filler_map());
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00003703 } else if (size == 2 * kPointerSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003704 filler->set_map_no_write_barrier(two_pointer_filler_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +00003705 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003706 filler->set_map_no_write_barrier(free_space_map());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003707 FreeSpace::cast(filler)->set_size(size);
ager@chromium.org6f10e412009-02-13 10:11:16 +00003708 }
3709}
3710
3711
lrn@chromium.org303ada72010-10-27 09:33:13 +00003712MaybeObject* Heap::AllocateExternalArray(int length,
3713 ExternalArrayType array_type,
3714 void* external_pointer,
3715 PretenureFlag pretenure) {
ager@chromium.org3811b432009-10-28 14:53:37 +00003716 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003717 Object* result;
3718 { MaybeObject* maybe_result = AllocateRaw(ExternalArray::kAlignedSize,
3719 space,
3720 OLD_DATA_SPACE);
3721 if (!maybe_result->ToObject(&result)) return maybe_result;
3722 }
ager@chromium.org3811b432009-10-28 14:53:37 +00003723
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003724 reinterpret_cast<ExternalArray*>(result)->set_map_no_write_barrier(
ager@chromium.org3811b432009-10-28 14:53:37 +00003725 MapForExternalArrayType(array_type));
3726 reinterpret_cast<ExternalArray*>(result)->set_length(length);
3727 reinterpret_cast<ExternalArray*>(result)->set_external_pointer(
3728 external_pointer);
3729
3730 return result;
3731}
3732
3733
lrn@chromium.org303ada72010-10-27 09:33:13 +00003734MaybeObject* Heap::CreateCode(const CodeDesc& desc,
3735 Code::Flags flags,
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003736 Handle<Object> self_reference,
3737 bool immovable) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003738 // Allocate ByteArray before the Code object, so that we do not risk
3739 // leaving uninitialized Code object (and breaking the heap).
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003740 ByteArray* reloc_info;
3741 MaybeObject* maybe_reloc_info = AllocateByteArray(desc.reloc_size, TENURED);
3742 if (!maybe_reloc_info->To(&reloc_info)) return maybe_reloc_info;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003743
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003744 // Compute size.
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003745 int body_size = RoundUp(desc.instr_size, kObjectAlignment);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003746 int obj_size = Code::SizeFor(body_size);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003747 ASSERT(IsAligned(static_cast<intptr_t>(obj_size), kCodeAlignment));
lrn@chromium.org303ada72010-10-27 09:33:13 +00003748 MaybeObject* maybe_result;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003749 // Large code objects and code objects which should stay at a fixed address
3750 // are allocated in large object space.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003751 HeapObject* result;
3752 bool force_lo_space = obj_size > code_space()->AreaSize();
3753 if (force_lo_space) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003754 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003755 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003756 maybe_result = code_space_->AllocateRaw(obj_size);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003757 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003758 if (!maybe_result->To<HeapObject>(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003759
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003760 if (immovable && !force_lo_space &&
3761 // Objects on the first page of each space are never moved.
3762 !code_space_->FirstPage()->Contains(result->address())) {
3763 // Discard the first code allocation, which was on a page where it could be
3764 // moved.
3765 CreateFillerObjectAt(result->address(), obj_size);
3766 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
3767 if (!maybe_result->To<HeapObject>(&result)) return maybe_result;
3768 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003769
3770 // Initialize the object
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003771 result->set_map_no_write_barrier(code_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003772 Code* code = Code::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003773 ASSERT(!isolate_->code_range()->exists() ||
3774 isolate_->code_range()->contains(code->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003775 code->set_instruction_size(desc.instr_size);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003776 code->set_relocation_info(reloc_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003777 code->set_flags(flags);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003778 if (code->is_call_stub() || code->is_keyed_call_stub()) {
3779 code->set_check_type(RECEIVER_MAP_CHECK);
3780 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003781 code->set_deoptimization_data(empty_fixed_array(), SKIP_WRITE_BARRIER);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003782 code->set_type_feedback_info(undefined_value(), SKIP_WRITE_BARRIER);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003783 code->set_handler_table(empty_fixed_array(), SKIP_WRITE_BARRIER);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00003784 code->set_gc_metadata(Smi::FromInt(0));
danno@chromium.org88aa0582012-03-23 15:11:57 +00003785 code->set_ic_age(global_ic_age_);
kasperl@chromium.org061ef742009-02-27 12:16:20 +00003786 // Allow self references to created code object by patching the handle to
3787 // point to the newly allocated Code object.
3788 if (!self_reference.is_null()) {
3789 *(self_reference.location()) = code;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003790 }
3791 // Migrate generated code.
3792 // The generated code can contain Object** values (typically from handles)
3793 // that are dereferenced during the copy to point directly to the actual heap
3794 // objects. These pointers can include references to the code object itself,
3795 // through the self_reference parameter.
3796 code->CopyFrom(desc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003797
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003798#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003799 if (FLAG_verify_heap) {
3800 code->Verify();
3801 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003802#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003803 return code;
3804}
3805
3806
lrn@chromium.org303ada72010-10-27 09:33:13 +00003807MaybeObject* Heap::CopyCode(Code* code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003808 // Allocate an object the same size as the code object.
3809 int obj_size = code->Size();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003810 MaybeObject* maybe_result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003811 if (obj_size > code_space()->AreaSize()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003812 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003813 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003814 maybe_result = code_space_->AllocateRaw(obj_size);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003815 }
3816
lrn@chromium.org303ada72010-10-27 09:33:13 +00003817 Object* result;
3818 if (!maybe_result->ToObject(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003819
3820 // Copy code object.
3821 Address old_addr = code->address();
3822 Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003823 CopyBlock(new_addr, old_addr, obj_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003824 // Relocate the copy.
3825 Code* new_code = Code::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003826 ASSERT(!isolate_->code_range()->exists() ||
3827 isolate_->code_range()->contains(code->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003828 new_code->Relocate(new_addr - old_addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003829 return new_code;
3830}
3831
3832
lrn@chromium.org303ada72010-10-27 09:33:13 +00003833MaybeObject* Heap::CopyCode(Code* code, Vector<byte> reloc_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003834 // Allocate ByteArray before the Code object, so that we do not risk
3835 // leaving uninitialized Code object (and breaking the heap).
lrn@chromium.org303ada72010-10-27 09:33:13 +00003836 Object* reloc_info_array;
3837 { MaybeObject* maybe_reloc_info_array =
3838 AllocateByteArray(reloc_info.length(), TENURED);
3839 if (!maybe_reloc_info_array->ToObject(&reloc_info_array)) {
3840 return maybe_reloc_info_array;
3841 }
3842 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003843
3844 int new_body_size = RoundUp(code->instruction_size(), kObjectAlignment);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003845
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003846 int new_obj_size = Code::SizeFor(new_body_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003847
3848 Address old_addr = code->address();
3849
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00003850 size_t relocation_offset =
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003851 static_cast<size_t>(code->instruction_end() - old_addr);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003852
lrn@chromium.org303ada72010-10-27 09:33:13 +00003853 MaybeObject* maybe_result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003854 if (new_obj_size > code_space()->AreaSize()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003855 maybe_result = lo_space_->AllocateRaw(new_obj_size, EXECUTABLE);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003856 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003857 maybe_result = code_space_->AllocateRaw(new_obj_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003858 }
3859
lrn@chromium.org303ada72010-10-27 09:33:13 +00003860 Object* result;
3861 if (!maybe_result->ToObject(&result)) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003862
3863 // Copy code object.
3864 Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
3865
3866 // Copy header and instructions.
3867 memcpy(new_addr, old_addr, relocation_offset);
3868
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003869 Code* new_code = Code::cast(result);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003870 new_code->set_relocation_info(ByteArray::cast(reloc_info_array));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003871
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003872 // Copy patched rinfo.
3873 memcpy(new_code->relocation_start(), reloc_info.start(), reloc_info.length());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003874
3875 // Relocate the copy.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003876 ASSERT(!isolate_->code_range()->exists() ||
3877 isolate_->code_range()->contains(code->address()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003878 new_code->Relocate(new_addr - old_addr);
3879
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003880#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003881 if (FLAG_verify_heap) {
3882 code->Verify();
3883 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003884#endif
3885 return new_code;
3886}
3887
3888
lrn@chromium.org303ada72010-10-27 09:33:13 +00003889MaybeObject* Heap::Allocate(Map* map, AllocationSpace space) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003890 ASSERT(gc_state_ == NOT_IN_GC);
3891 ASSERT(map->instance_type() != MAP_TYPE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003892 // If allocation failures are disallowed, we may allocate in a different
3893 // space when new space is full and the object is not a large object.
3894 AllocationSpace retry_space =
3895 (space != NEW_SPACE) ? space : TargetSpaceId(map->instance_type());
lrn@chromium.org303ada72010-10-27 09:33:13 +00003896 Object* result;
3897 { MaybeObject* maybe_result =
3898 AllocateRaw(map->instance_size(), space, retry_space);
3899 if (!maybe_result->ToObject(&result)) return maybe_result;
3900 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003901 // No need for write barrier since object is white and map is in old space.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003902 HeapObject::cast(result)->set_map_no_write_barrier(map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003903 return result;
3904}
3905
3906
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003907void Heap::InitializeFunction(JSFunction* function,
3908 SharedFunctionInfo* shared,
3909 Object* prototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003910 ASSERT(!prototype->IsMap());
3911 function->initialize_properties();
3912 function->initialize_elements();
3913 function->set_shared(shared);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00003914 function->set_code(shared->code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003915 function->set_prototype_or_initial_map(prototype);
3916 function->set_context(undefined_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003917 function->set_literals_or_bindings(empty_fixed_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003918 function->set_next_function_link(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003919}
3920
3921
lrn@chromium.org303ada72010-10-27 09:33:13 +00003922MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00003923 // Allocate the prototype. Make sure to use the object function
3924 // from the function's context, since the function can be from a
3925 // different context.
3926 JSFunction* object_function =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003927 function->context()->native_context()->object_function();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003928
3929 // Each function prototype gets a copy of the object function map.
3930 // This avoid unwanted sharing of maps between prototypes of different
3931 // constructors.
3932 Map* new_map;
3933 ASSERT(object_function->has_initial_map());
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003934 MaybeObject* maybe_map = object_function->initial_map()->Copy();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003935 if (!maybe_map->To(&new_map)) return maybe_map;
3936
lrn@chromium.org303ada72010-10-27 09:33:13 +00003937 Object* prototype;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003938 MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map);
3939 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
3940
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003941 // When creating the prototype for the function we must set its
3942 // constructor to the function.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003943 MaybeObject* maybe_failure =
3944 JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
3945 constructor_symbol(), function, DONT_ENUM);
3946 if (maybe_failure->IsFailure()) return maybe_failure;
3947
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003948 return prototype;
3949}
3950
3951
lrn@chromium.org303ada72010-10-27 09:33:13 +00003952MaybeObject* Heap::AllocateFunction(Map* function_map,
3953 SharedFunctionInfo* shared,
3954 Object* prototype,
3955 PretenureFlag pretenure) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003956 AllocationSpace space =
3957 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003958 Object* result;
3959 { MaybeObject* maybe_result = Allocate(function_map, space);
3960 if (!maybe_result->ToObject(&result)) return maybe_result;
3961 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003962 InitializeFunction(JSFunction::cast(result), shared, prototype);
3963 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003964}
3965
3966
lrn@chromium.org303ada72010-10-27 09:33:13 +00003967MaybeObject* Heap::AllocateArgumentsObject(Object* callee, int length) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003968 // To get fast allocation and map sharing for arguments objects we
3969 // allocate them based on an arguments boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003970
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003971 JSObject* boilerplate;
3972 int arguments_object_size;
3973 bool strict_mode_callee = callee->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003974 !JSFunction::cast(callee)->shared()->is_classic_mode();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003975 if (strict_mode_callee) {
3976 boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003977 isolate()->context()->native_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003978 strict_mode_arguments_boilerplate();
3979 arguments_object_size = kArgumentsObjectSizeStrict;
3980 } else {
3981 boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003982 isolate()->context()->native_context()->arguments_boilerplate();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003983 arguments_object_size = kArgumentsObjectSize;
3984 }
3985
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003986 // This calls Copy directly rather than using Heap::AllocateRaw so we
3987 // duplicate the check here.
3988 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
3989
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003990 // Check that the size of the boilerplate matches our
3991 // expectations. The ArgumentsAccessStub::GenerateNewObject relies
3992 // on the size being a known constant.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003993 ASSERT(arguments_object_size == boilerplate->map()->instance_size());
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003994
3995 // Do the allocation.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003996 Object* result;
3997 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003998 AllocateRaw(arguments_object_size, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003999 if (!maybe_result->ToObject(&result)) return maybe_result;
4000 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004001
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004002 // Copy the content. The arguments boilerplate doesn't have any
4003 // fields that point to new space so it's safe to skip the write
4004 // barrier here.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004005 CopyBlock(HeapObject::cast(result)->address(),
4006 boilerplate->address(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004007 JSObject::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004008
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004009 // Set the length property.
4010 JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsLengthIndex,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004011 Smi::FromInt(length),
4012 SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004013 // Set the callee property for non-strict mode arguments object only.
4014 if (!strict_mode_callee) {
4015 JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsCalleeIndex,
4016 callee);
4017 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004018
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 // Check the state of the object
4020 ASSERT(JSObject::cast(result)->HasFastProperties());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004021 ASSERT(JSObject::cast(result)->HasFastObjectElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004022
4023 return result;
4024}
4025
4026
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004027static bool HasDuplicates(DescriptorArray* descriptors) {
4028 int count = descriptors->number_of_descriptors();
4029 if (count > 1) {
4030 String* prev_key = descriptors->GetKey(0);
4031 for (int i = 1; i != count; i++) {
4032 String* current_key = descriptors->GetKey(i);
4033 if (prev_key == current_key) return true;
4034 prev_key = current_key;
4035 }
4036 }
4037 return false;
4038}
4039
4040
lrn@chromium.org303ada72010-10-27 09:33:13 +00004041MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004042 ASSERT(!fun->has_initial_map());
4043
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004044 // First create a new map with the size and number of in-object properties
4045 // suggested by the function.
4046 int instance_size = fun->shared()->CalculateInstanceSize();
4047 int in_object_properties = fun->shared()->CalculateInObjectProperties();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004048 Map* map;
4049 MaybeObject* maybe_map = AllocateMap(JS_OBJECT_TYPE, instance_size);
4050 if (!maybe_map->To(&map)) return maybe_map;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004051
4052 // Fetch or allocate prototype.
4053 Object* prototype;
4054 if (fun->has_instance_prototype()) {
4055 prototype = fun->instance_prototype();
4056 } else {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004057 MaybeObject* maybe_prototype = AllocateFunctionPrototype(fun);
4058 if (!maybe_prototype->To(&prototype)) return maybe_prototype;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004059 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004060 map->set_inobject_properties(in_object_properties);
4061 map->set_unused_property_fields(in_object_properties);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004062 map->set_prototype(prototype);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004063 ASSERT(map->has_fast_object_elements());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004064
ager@chromium.org5c838252010-02-19 08:53:10 +00004065 // If the function has only simple this property assignments add
4066 // field descriptors for these to the initial map as the object
4067 // cannot be constructed without having these properties. Guard by
4068 // the inline_new flag so we only change the map if we generate a
4069 // specialized construct stub.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004070 ASSERT(in_object_properties <= Map::kMaxPreAllocatedPropertyFields);
ager@chromium.org5c838252010-02-19 08:53:10 +00004071 if (fun->shared()->CanGenerateInlineConstructor(prototype)) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004072 int count = fun->shared()->this_property_assignments_count();
4073 if (count > in_object_properties) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004074 // Inline constructor can only handle inobject properties.
4075 fun->shared()->ForbidInlineConstructor();
4076 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004077 DescriptorArray* descriptors;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00004078 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(count);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004079 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
4080
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004081 DescriptorArray::WhitenessWitness witness(descriptors);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004082 for (int i = 0; i < count; i++) {
4083 String* name = fun->shared()->GetThisPropertyAssignmentName(i);
4084 ASSERT(name->IsSymbol());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004085 FieldDescriptor field(name, i, NONE, i + 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004086 descriptors->Set(i, &field, witness);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004087 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004088 descriptors->Sort();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004089
4090 // The descriptors may contain duplicates because the compiler does not
4091 // guarantee the uniqueness of property names (it would have required
4092 // quadratic time). Once the descriptors are sorted we can check for
4093 // duplicates in linear time.
4094 if (HasDuplicates(descriptors)) {
4095 fun->shared()->ForbidInlineConstructor();
4096 } else {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004097 map->InitializeDescriptors(descriptors);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004098 map->set_pre_allocated_property_fields(count);
4099 map->set_unused_property_fields(in_object_properties - count);
4100 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004101 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004102 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004103
4104 fun->shared()->StartInobjectSlackTracking(map);
4105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106 return map;
4107}
4108
4109
4110void Heap::InitializeJSObjectFromMap(JSObject* obj,
4111 FixedArray* properties,
4112 Map* map) {
4113 obj->set_properties(properties);
4114 obj->initialize_elements();
4115 // TODO(1240798): Initialize the object's body using valid initial values
4116 // according to the object's initial map. For example, if the map's
4117 // instance type is JS_ARRAY_TYPE, the length field should be initialized
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004118 // to a number (e.g. Smi::FromInt(0)) and the elements initialized to a
4119 // fixed array (e.g. Heap::empty_fixed_array()). Currently, the object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004120 // verification code has to cope with (temporarily) invalid objects. See
4121 // for example, JSArray::JSArrayVerify).
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004122 Object* filler;
4123 // We cannot always fill with one_pointer_filler_map because objects
4124 // created from API functions expect their internal fields to be initialized
4125 // with undefined_value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004126 // Pre-allocated fields need to be initialized with undefined_value as well
4127 // so that object accesses before the constructor completes (e.g. in the
4128 // debugger) will not cause a crash.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004129 if (map->constructor()->IsJSFunction() &&
4130 JSFunction::cast(map->constructor())->shared()->
4131 IsInobjectSlackTrackingInProgress()) {
4132 // We might want to shrink the object later.
4133 ASSERT(obj->GetInternalFieldCount() == 0);
4134 filler = Heap::one_pointer_filler_map();
4135 } else {
4136 filler = Heap::undefined_value();
4137 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004138 obj->InitializeBody(map, Heap::undefined_value(), filler);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004139}
4140
4141
lrn@chromium.org303ada72010-10-27 09:33:13 +00004142MaybeObject* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143 // JSFunctions should be allocated using AllocateFunction to be
4144 // properly initialized.
4145 ASSERT(map->instance_type() != JS_FUNCTION_TYPE);
4146
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00004147 // Both types of global objects should be allocated using
4148 // AllocateGlobalObject to be properly initialized.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004149 ASSERT(map->instance_type() != JS_GLOBAL_OBJECT_TYPE);
4150 ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE);
4151
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004152 // Allocate the backing storage for the properties.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004153 int prop_size =
4154 map->pre_allocated_property_fields() +
4155 map->unused_property_fields() -
4156 map->inobject_properties();
4157 ASSERT(prop_size >= 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004158 Object* properties;
4159 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, pretenure);
4160 if (!maybe_properties->ToObject(&properties)) return maybe_properties;
4161 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004162
4163 // Allocate the JSObject.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004164 AllocationSpace space =
4165 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004166 if (map->instance_size() > Page::kMaxNonCodeHeapObjectSize) space = LO_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004167 Object* obj;
4168 { MaybeObject* maybe_obj = Allocate(map, space);
4169 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4170 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004171
4172 // Initialize the JSObject.
4173 InitializeJSObjectFromMap(JSObject::cast(obj),
4174 FixedArray::cast(properties),
4175 map);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004176 ASSERT(JSObject::cast(obj)->HasFastSmiOrObjectElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004177 return obj;
4178}
4179
4180
lrn@chromium.org303ada72010-10-27 09:33:13 +00004181MaybeObject* Heap::AllocateJSObject(JSFunction* constructor,
4182 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004183 // Allocate the initial map if absent.
4184 if (!constructor->has_initial_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004185 Object* initial_map;
4186 { MaybeObject* maybe_initial_map = AllocateInitialMap(constructor);
4187 if (!maybe_initial_map->ToObject(&initial_map)) return maybe_initial_map;
4188 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004189 constructor->set_initial_map(Map::cast(initial_map));
4190 Map::cast(initial_map)->set_constructor(constructor);
4191 }
4192 // Allocate the object based on the constructors initial map.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004193 MaybeObject* result = AllocateJSObjectFromMap(
4194 constructor->initial_map(), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004195#ifdef DEBUG
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004196 // Make sure result is NOT a global object if valid.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004197 Object* non_failure;
4198 ASSERT(!result->ToObject(&non_failure) || !non_failure->IsGlobalObject());
4199#endif
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004200 return result;
4201}
4202
4203
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004204MaybeObject* Heap::AllocateJSModule(Context* context, ScopeInfo* scope_info) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004205 // Allocate a fresh map. Modules do not have a prototype.
4206 Map* map;
4207 MaybeObject* maybe_map = AllocateMap(JS_MODULE_TYPE, JSModule::kSize);
4208 if (!maybe_map->To(&map)) return maybe_map;
4209 // Allocate the object based on the map.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004210 JSModule* module;
4211 MaybeObject* maybe_module = AllocateJSObjectFromMap(map, TENURED);
4212 if (!maybe_module->To(&module)) return maybe_module;
4213 module->set_context(context);
4214 module->set_scope_info(scope_info);
4215 return module;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004216}
4217
4218
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004219MaybeObject* Heap::AllocateJSArrayAndStorage(
4220 ElementsKind elements_kind,
4221 int length,
4222 int capacity,
4223 ArrayStorageAllocationMode mode,
4224 PretenureFlag pretenure) {
4225 ASSERT(capacity >= length);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004226 if (length != 0 && mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE) {
4227 elements_kind = GetHoleyElementsKind(elements_kind);
4228 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004229 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
4230 JSArray* array;
4231 if (!maybe_array->To(&array)) return maybe_array;
4232
4233 if (capacity == 0) {
4234 array->set_length(Smi::FromInt(0));
4235 array->set_elements(empty_fixed_array());
4236 return array;
4237 }
4238
4239 FixedArrayBase* elms;
4240 MaybeObject* maybe_elms = NULL;
4241 if (elements_kind == FAST_DOUBLE_ELEMENTS) {
4242 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
4243 maybe_elms = AllocateUninitializedFixedDoubleArray(capacity);
4244 } else {
4245 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
4246 maybe_elms = AllocateFixedDoubleArrayWithHoles(capacity);
4247 }
4248 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004249 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004250 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
4251 maybe_elms = AllocateUninitializedFixedArray(capacity);
4252 } else {
4253 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
4254 maybe_elms = AllocateFixedArrayWithHoles(capacity);
4255 }
4256 }
4257 if (!maybe_elms->To(&elms)) return maybe_elms;
4258
4259 array->set_elements(elms);
4260 array->set_length(Smi::FromInt(length));
4261 return array;
4262}
4263
4264
4265MaybeObject* Heap::AllocateJSArrayWithElements(
4266 FixedArrayBase* elements,
4267 ElementsKind elements_kind,
4268 PretenureFlag pretenure) {
4269 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
4270 JSArray* array;
4271 if (!maybe_array->To(&array)) return maybe_array;
4272
4273 array->set_elements(elements);
4274 array->set_length(Smi::FromInt(elements->length()));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004275 array->ValidateElements();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004276 return array;
4277}
4278
4279
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004280MaybeObject* Heap::AllocateJSProxy(Object* handler, Object* prototype) {
4281 // Allocate map.
4282 // TODO(rossberg): Once we optimize proxies, think about a scheme to share
4283 // maps. Will probably depend on the identity of the handler object, too.
danno@chromium.org40cb8782011-05-25 07:58:50 +00004284 Map* map;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004285 MaybeObject* maybe_map_obj = AllocateMap(JS_PROXY_TYPE, JSProxy::kSize);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004286 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004287 map->set_prototype(prototype);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004288
4289 // Allocate the proxy object.
lrn@chromium.org34e60782011-09-15 07:25:40 +00004290 JSProxy* result;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004291 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004292 if (!maybe_result->To<JSProxy>(&result)) return maybe_result;
4293 result->InitializeBody(map->instance_size(), Smi::FromInt(0));
4294 result->set_handler(handler);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004295 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004296 return result;
4297}
4298
4299
4300MaybeObject* Heap::AllocateJSFunctionProxy(Object* handler,
4301 Object* call_trap,
4302 Object* construct_trap,
4303 Object* prototype) {
4304 // Allocate map.
4305 // TODO(rossberg): Once we optimize proxies, think about a scheme to share
4306 // maps. Will probably depend on the identity of the handler object, too.
4307 Map* map;
4308 MaybeObject* maybe_map_obj =
4309 AllocateMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize);
4310 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
4311 map->set_prototype(prototype);
4312
4313 // Allocate the proxy object.
4314 JSFunctionProxy* result;
4315 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
4316 if (!maybe_result->To<JSFunctionProxy>(&result)) return maybe_result;
4317 result->InitializeBody(map->instance_size(), Smi::FromInt(0));
4318 result->set_handler(handler);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004319 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004320 result->set_call_trap(call_trap);
4321 result->set_construct_trap(construct_trap);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004322 return result;
4323}
4324
4325
lrn@chromium.org303ada72010-10-27 09:33:13 +00004326MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004327 ASSERT(constructor->has_initial_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004328 Map* map = constructor->initial_map();
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004329 ASSERT(map->is_dictionary_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004330
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004331 // Make sure no field properties are described in the initial map.
4332 // This guarantees us that normalizing the properties does not
4333 // require us to change property values to JSGlobalPropertyCells.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004334 ASSERT(map->NextFreePropertyIndex() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004335
4336 // Make sure we don't have a ton of pre-allocated slots in the
4337 // global objects. They will be unused once we normalize the object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004338 ASSERT(map->unused_property_fields() == 0);
4339 ASSERT(map->inobject_properties() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004340
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004341 // Initial size of the backing store to avoid resize of the storage during
4342 // bootstrapping. The size differs between the JS global object ad the
4343 // builtins object.
4344 int initial_size = map->instance_type() == JS_GLOBAL_OBJECT_TYPE ? 64 : 512;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004345
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004346 // Allocate a dictionary object for backing storage.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004347 StringDictionary* dictionary;
4348 MaybeObject* maybe_dictionary =
4349 StringDictionary::Allocate(
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004350 map->NumberOfOwnDescriptors() * 2 + initial_size);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004351 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004352
4353 // The global object might be created from an object template with accessors.
4354 // Fill these accessors into the dictionary.
4355 DescriptorArray* descs = map->instance_descriptors();
4356 for (int i = 0; i < descs->number_of_descriptors(); i++) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004357 PropertyDetails details = descs->GetDetails(i);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004358 ASSERT(details.type() == CALLBACKS); // Only accessors are expected.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004359 PropertyDetails d = PropertyDetails(details.attributes(),
4360 CALLBACKS,
4361 details.descriptor_index());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004362 Object* value = descs->GetCallbacksObject(i);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004363 MaybeObject* maybe_value = AllocateJSGlobalPropertyCell(value);
4364 if (!maybe_value->ToObject(&value)) return maybe_value;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004365
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004366 MaybeObject* maybe_added = dictionary->Add(descs->GetKey(i), value, d);
4367 if (!maybe_added->To(&dictionary)) return maybe_added;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004368 }
4369
4370 // Allocate the global object and initialize it with the backing store.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004371 JSObject* global;
4372 MaybeObject* maybe_global = Allocate(map, OLD_POINTER_SPACE);
4373 if (!maybe_global->To(&global)) return maybe_global;
4374
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004375 InitializeJSObjectFromMap(global, dictionary, map);
4376
4377 // Create a new map for the global object.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004378 Map* new_map;
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004379 MaybeObject* maybe_map = map->CopyDropDescriptors();
4380 if (!maybe_map->To(&new_map)) return maybe_map;
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004381 new_map->set_dictionary_map(true);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004382
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004383 // Set up the global object as a normalized object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004384 global->set_map(new_map);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004385 global->set_properties(dictionary);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004386
4387 // Make sure result is a global object with properties in dictionary.
4388 ASSERT(global->IsGlobalObject());
4389 ASSERT(!global->HasFastProperties());
4390 return global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004391}
4392
4393
lrn@chromium.org303ada72010-10-27 09:33:13 +00004394MaybeObject* Heap::CopyJSObject(JSObject* source) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004395 // Never used to copy functions. If functions need to be copied we
4396 // have to be careful to clear the literals array.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004397 SLOW_ASSERT(!source->IsJSFunction());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004398
4399 // Make the clone.
4400 Map* map = source->map();
4401 int object_size = map->instance_size();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004402 Object* clone;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004403
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004404 WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER;
4405
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004406 // If we're forced to always allocate, we use the general allocation
4407 // functions which may leave us with an object in old space.
4408 if (always_allocate()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004409 { MaybeObject* maybe_clone =
4410 AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE);
4411 if (!maybe_clone->ToObject(&clone)) return maybe_clone;
4412 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004413 Address clone_address = HeapObject::cast(clone)->address();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004414 CopyBlock(clone_address,
4415 source->address(),
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004416 object_size);
4417 // Update write barrier for all fields that lie beyond the header.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004418 RecordWrites(clone_address,
4419 JSObject::kHeaderSize,
antonm@chromium.org8e5e3382010-03-24 09:56:30 +00004420 (object_size - JSObject::kHeaderSize) / kPointerSize);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004421 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004422 wb_mode = SKIP_WRITE_BARRIER;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004423 { MaybeObject* maybe_clone = new_space_.AllocateRaw(object_size);
4424 if (!maybe_clone->ToObject(&clone)) return maybe_clone;
4425 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004426 SLOW_ASSERT(InNewSpace(clone));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004427 // Since we know the clone is allocated in new space, we can copy
ager@chromium.org32912102009-01-16 10:38:43 +00004428 // the contents without worrying about updating the write barrier.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004429 CopyBlock(HeapObject::cast(clone)->address(),
4430 source->address(),
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004431 object_size);
4432 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004433
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004434 SLOW_ASSERT(
4435 JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004436 FixedArrayBase* elements = FixedArrayBase::cast(source->elements());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004437 FixedArray* properties = FixedArray::cast(source->properties());
4438 // Update elements if necessary.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00004439 if (elements->length() > 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004440 Object* elem;
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004441 { MaybeObject* maybe_elem;
4442 if (elements->map() == fixed_cow_array_map()) {
4443 maybe_elem = FixedArray::cast(elements);
4444 } else if (source->HasFastDoubleElements()) {
4445 maybe_elem = CopyFixedDoubleArray(FixedDoubleArray::cast(elements));
4446 } else {
4447 maybe_elem = CopyFixedArray(FixedArray::cast(elements));
4448 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004449 if (!maybe_elem->ToObject(&elem)) return maybe_elem;
4450 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004451 JSObject::cast(clone)->set_elements(FixedArrayBase::cast(elem), wb_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004452 }
4453 // Update properties if necessary.
4454 if (properties->length() > 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004455 Object* prop;
4456 { MaybeObject* maybe_prop = CopyFixedArray(properties);
4457 if (!maybe_prop->ToObject(&prop)) return maybe_prop;
4458 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004459 JSObject::cast(clone)->set_properties(FixedArray::cast(prop), wb_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004460 }
4461 // Return the new clone.
4462 return clone;
4463}
4464
4465
lrn@chromium.org34e60782011-09-15 07:25:40 +00004466MaybeObject* Heap::ReinitializeJSReceiver(
4467 JSReceiver* object, InstanceType type, int size) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004468 ASSERT(type >= FIRST_JS_OBJECT_TYPE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004469
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004470 // Allocate fresh map.
4471 // TODO(rossberg): Once we optimize proxies, cache these maps.
4472 Map* map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004473 MaybeObject* maybe = AllocateMap(type, size);
4474 if (!maybe->To<Map>(&map)) return maybe;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004475
lrn@chromium.org34e60782011-09-15 07:25:40 +00004476 // Check that the receiver has at least the size of the fresh object.
4477 int size_difference = object->map()->instance_size() - map->instance_size();
4478 ASSERT(size_difference >= 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004479
4480 map->set_prototype(object->map()->prototype());
4481
4482 // Allocate the backing storage for the properties.
4483 int prop_size = map->unused_property_fields() - map->inobject_properties();
4484 Object* properties;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004485 maybe = AllocateFixedArray(prop_size, TENURED);
4486 if (!maybe->ToObject(&properties)) return maybe;
4487
4488 // Functions require some allocation, which might fail here.
4489 SharedFunctionInfo* shared = NULL;
4490 if (type == JS_FUNCTION_TYPE) {
4491 String* name;
4492 maybe = LookupAsciiSymbol("<freezing call trap>");
4493 if (!maybe->To<String>(&name)) return maybe;
4494 maybe = AllocateSharedFunctionInfo(name);
4495 if (!maybe->To<SharedFunctionInfo>(&shared)) return maybe;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004496 }
4497
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004498 // Because of possible retries of this function after failure,
4499 // we must NOT fail after this point, where we have changed the type!
4500
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004501 // Reset the map for the object.
4502 object->set_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004503 JSObject* jsobj = JSObject::cast(object);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004504
4505 // Reinitialize the object from the constructor map.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004506 InitializeJSObjectFromMap(jsobj, FixedArray::cast(properties), map);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004507
4508 // Functions require some minimal initialization.
4509 if (type == JS_FUNCTION_TYPE) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004510 map->set_function_with_prototype(true);
4511 InitializeFunction(JSFunction::cast(object), shared, the_hole_value());
4512 JSFunction::cast(object)->set_context(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004513 isolate()->context()->native_context());
lrn@chromium.org34e60782011-09-15 07:25:40 +00004514 }
4515
4516 // Put in filler if the new object is smaller than the old.
4517 if (size_difference > 0) {
4518 CreateFillerObjectAt(
4519 object->address() + map->instance_size(), size_difference);
4520 }
4521
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004522 return object;
4523}
4524
4525
lrn@chromium.org303ada72010-10-27 09:33:13 +00004526MaybeObject* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor,
4527 JSGlobalProxy* object) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004528 ASSERT(constructor->has_initial_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004529 Map* map = constructor->initial_map();
4530
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004531 // Check that the already allocated object has the same size and type as
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004532 // objects allocated using the constructor.
4533 ASSERT(map->instance_size() == object->map()->instance_size());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004534 ASSERT(map->instance_type() == object->map()->instance_type());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004535
4536 // Allocate the backing storage for the properties.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004537 int prop_size = map->unused_property_fields() - map->inobject_properties();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004538 Object* properties;
4539 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, TENURED);
4540 if (!maybe_properties->ToObject(&properties)) return maybe_properties;
4541 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004542
4543 // Reset the map for the object.
4544 object->set_map(constructor->initial_map());
4545
4546 // Reinitialize the object from the constructor map.
4547 InitializeJSObjectFromMap(object, FixedArray::cast(properties), map);
4548 return object;
4549}
4550
4551
lrn@chromium.org303ada72010-10-27 09:33:13 +00004552MaybeObject* Heap::AllocateStringFromAscii(Vector<const char> string,
4553 PretenureFlag pretenure) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004554 int length = string.length();
4555 if (length == 1) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004556 return Heap::LookupSingleCharacterStringFromCode(string[0]);
4557 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004558 Object* result;
4559 { MaybeObject* maybe_result =
4560 AllocateRawAsciiString(string.length(), pretenure);
4561 if (!maybe_result->ToObject(&result)) return maybe_result;
4562 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004563
4564 // Copy the characters into the new object.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004565 CopyChars(SeqAsciiString::cast(result)->GetChars(), string.start(), length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004566 return result;
4567}
4568
4569
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004570MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector<const char> string,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004571 int non_ascii_start,
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004572 PretenureFlag pretenure) {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004573 // Continue counting the number of characters in the UTF-8 string, starting
4574 // from the first non-ascii character or word.
4575 int chars = non_ascii_start;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004576 Access<UnicodeCache::Utf8Decoder>
4577 decoder(isolate_->unicode_cache()->utf8_decoder());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004578 decoder->Reset(string.start() + non_ascii_start, string.length() - chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004579 while (decoder->has_more()) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004580 uint32_t r = decoder->GetNext();
4581 if (r <= unibrow::Utf16::kMaxNonSurrogateCharCode) {
4582 chars++;
4583 } else {
4584 chars += 2;
4585 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004586 }
4587
lrn@chromium.org303ada72010-10-27 09:33:13 +00004588 Object* result;
4589 { MaybeObject* maybe_result = AllocateRawTwoByteString(chars, pretenure);
4590 if (!maybe_result->ToObject(&result)) return maybe_result;
4591 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004592
4593 // Convert and copy the characters into the new object.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004594 SeqTwoByteString* twobyte = SeqTwoByteString::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004595 decoder->Reset(string.start(), string.length());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004596 int i = 0;
4597 while (i < chars) {
4598 uint32_t r = decoder->GetNext();
4599 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004600 twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::LeadSurrogate(r));
4601 twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::TrailSurrogate(r));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004602 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004603 twobyte->SeqTwoByteStringSet(i++, r);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004604 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004605 }
4606 return result;
4607}
4608
4609
lrn@chromium.org303ada72010-10-27 09:33:13 +00004610MaybeObject* Heap::AllocateStringFromTwoByte(Vector<const uc16> string,
4611 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004612 // Check if the string is an ASCII string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004613 Object* result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004614 int length = string.length();
4615 const uc16* start = string.start();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004616
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004617 if (String::IsAscii(start, length)) {
4618 MaybeObject* maybe_result = AllocateRawAsciiString(length, pretenure);
4619 if (!maybe_result->ToObject(&result)) return maybe_result;
4620 CopyChars(SeqAsciiString::cast(result)->GetChars(), start, length);
4621 } else { // It's not an ASCII string.
4622 MaybeObject* maybe_result = AllocateRawTwoByteString(length, pretenure);
4623 if (!maybe_result->ToObject(&result)) return maybe_result;
4624 CopyChars(SeqTwoByteString::cast(result)->GetChars(), start, length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004625 }
4626 return result;
4627}
4628
4629
4630Map* Heap::SymbolMapForString(String* string) {
4631 // If the string is in new space it cannot be used as a symbol.
4632 if (InNewSpace(string)) return NULL;
4633
4634 // Find the corresponding symbol map for strings.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004635 switch (string->map()->instance_type()) {
4636 case STRING_TYPE: return symbol_map();
4637 case ASCII_STRING_TYPE: return ascii_symbol_map();
4638 case CONS_STRING_TYPE: return cons_symbol_map();
4639 case CONS_ASCII_STRING_TYPE: return cons_ascii_symbol_map();
4640 case EXTERNAL_STRING_TYPE: return external_symbol_map();
4641 case EXTERNAL_ASCII_STRING_TYPE: return external_ascii_symbol_map();
4642 case EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
4643 return external_symbol_with_ascii_data_map();
4644 case SHORT_EXTERNAL_STRING_TYPE: return short_external_symbol_map();
4645 case SHORT_EXTERNAL_ASCII_STRING_TYPE:
4646 return short_external_ascii_symbol_map();
4647 case SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
4648 return short_external_symbol_with_ascii_data_map();
4649 default: return NULL; // No match found.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004650 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004651}
4652
4653
lrn@chromium.org303ada72010-10-27 09:33:13 +00004654MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
4655 int chars,
4656 uint32_t hash_field) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004657 ASSERT(chars >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004658 // Ensure the chars matches the number of characters in the buffer.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004659 ASSERT(static_cast<unsigned>(chars) == buffer->Utf16Length());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004660 // Determine whether the string is ASCII.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004661 bool is_ascii = true;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004662 while (buffer->has_more()) {
4663 if (buffer->GetNext() > unibrow::Utf8::kMaxOneByteChar) {
4664 is_ascii = false;
4665 break;
4666 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004667 }
4668 buffer->Rewind();
4669
4670 // Compute map and object size.
4671 int size;
4672 Map* map;
4673
4674 if (is_ascii) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004675 if (chars > SeqAsciiString::kMaxLength) {
4676 return Failure::OutOfMemoryException();
4677 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004678 map = ascii_symbol_map();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004679 size = SeqAsciiString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004680 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004681 if (chars > SeqTwoByteString::kMaxLength) {
4682 return Failure::OutOfMemoryException();
4683 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004684 map = symbol_map();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004685 size = SeqTwoByteString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004686 }
4687
4688 // Allocate string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004689 Object* result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004690 { MaybeObject* maybe_result = (size > Page::kMaxNonCodeHeapObjectSize)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004691 ? lo_space_->AllocateRaw(size, NOT_EXECUTABLE)
lrn@chromium.org303ada72010-10-27 09:33:13 +00004692 : old_data_space_->AllocateRaw(size);
4693 if (!maybe_result->ToObject(&result)) return maybe_result;
4694 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004695
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004696 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(map);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004697 // Set length and hash fields of the allocated string.
ager@chromium.org870a0b62008-11-04 11:43:05 +00004698 String* answer = String::cast(result);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004699 answer->set_length(chars);
4700 answer->set_hash_field(hash_field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004701
ager@chromium.org870a0b62008-11-04 11:43:05 +00004702 ASSERT_EQ(size, answer->Size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004703
4704 // Fill in the characters.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004705 int i = 0;
4706 while (i < chars) {
4707 uint32_t character = buffer->GetNext();
4708 if (character > unibrow::Utf16::kMaxNonSurrogateCharCode) {
4709 answer->Set(i++, unibrow::Utf16::LeadSurrogate(character));
4710 answer->Set(i++, unibrow::Utf16::TrailSurrogate(character));
4711 } else {
4712 answer->Set(i++, character);
4713 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004714 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00004715 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004716}
4717
4718
lrn@chromium.org303ada72010-10-27 09:33:13 +00004719MaybeObject* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004720 if (length < 0 || length > SeqAsciiString::kMaxLength) {
4721 return Failure::OutOfMemoryException();
4722 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004723
ager@chromium.org7c537e22008-10-16 08:43:32 +00004724 int size = SeqAsciiString::SizeFor(length);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004725 ASSERT(size <= SeqAsciiString::kMaxSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004726
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004727 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
4728 AllocationSpace retry_space = OLD_DATA_SPACE;
4729
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004730 if (space == NEW_SPACE) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004731 if (size > kMaxObjectSizeInNewSpace) {
4732 // Allocate in large object space, retry space will be ignored.
4733 space = LO_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004734 } else if (size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004735 // Allocate in new space, retry in large object space.
4736 retry_space = LO_SPACE;
4737 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004738 } else if (space == OLD_DATA_SPACE &&
4739 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004740 space = LO_SPACE;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004741 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004742 Object* result;
4743 { MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
4744 if (!maybe_result->ToObject(&result)) return maybe_result;
4745 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004746
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004747 // Partially initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004748 HeapObject::cast(result)->set_map_no_write_barrier(ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004749 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004750 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004751 ASSERT_EQ(size, HeapObject::cast(result)->Size());
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004752
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004753#ifdef VERIFY_HEAP
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004754 if (FLAG_verify_heap) {
4755 // Initialize string's content to ensure ASCII-ness (character range 0-127)
4756 // as required when verifying the heap.
4757 char* dest = SeqAsciiString::cast(result)->GetChars();
4758 memset(dest, 0x0F, length * kCharSize);
4759 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004760#endif
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004761
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004762 return result;
4763}
4764
4765
lrn@chromium.org303ada72010-10-27 09:33:13 +00004766MaybeObject* Heap::AllocateRawTwoByteString(int length,
4767 PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004768 if (length < 0 || length > SeqTwoByteString::kMaxLength) {
4769 return Failure::OutOfMemoryException();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004770 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004771 int size = SeqTwoByteString::SizeFor(length);
4772 ASSERT(size <= SeqTwoByteString::kMaxSize);
4773 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
4774 AllocationSpace retry_space = OLD_DATA_SPACE;
4775
4776 if (space == NEW_SPACE) {
4777 if (size > kMaxObjectSizeInNewSpace) {
4778 // Allocate in large object space, retry space will be ignored.
4779 space = LO_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004780 } else if (size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004781 // Allocate in new space, retry in large object space.
4782 retry_space = LO_SPACE;
4783 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004784 } else if (space == OLD_DATA_SPACE &&
4785 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004786 space = LO_SPACE;
4787 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004788 Object* result;
4789 { MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
4790 if (!maybe_result->ToObject(&result)) return maybe_result;
4791 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004792
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004793 // Partially initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004794 HeapObject::cast(result)->set_map_no_write_barrier(string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004795 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004796 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004797 ASSERT_EQ(size, HeapObject::cast(result)->Size());
4798 return result;
4799}
4800
4801
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004802MaybeObject* Heap::AllocateJSArray(
4803 ElementsKind elements_kind,
4804 PretenureFlag pretenure) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004805 Context* native_context = isolate()->context()->native_context();
4806 JSFunction* array_function = native_context->array_function();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004807 Map* map = array_function->initial_map();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004808 Object* maybe_map_array = native_context->js_array_maps();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004809 if (!maybe_map_array->IsUndefined()) {
4810 Object* maybe_transitioned_map =
4811 FixedArray::cast(maybe_map_array)->get(elements_kind);
4812 if (!maybe_transitioned_map->IsUndefined()) {
4813 map = Map::cast(maybe_transitioned_map);
4814 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004815 }
4816
4817 return AllocateJSObjectFromMap(map, pretenure);
4818}
4819
4820
lrn@chromium.org303ada72010-10-27 09:33:13 +00004821MaybeObject* Heap::AllocateEmptyFixedArray() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004822 int size = FixedArray::SizeFor(0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004823 Object* result;
4824 { MaybeObject* maybe_result =
4825 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
4826 if (!maybe_result->ToObject(&result)) return maybe_result;
4827 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004828 // Initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004829 reinterpret_cast<FixedArray*>(result)->set_map_no_write_barrier(
4830 fixed_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004831 reinterpret_cast<FixedArray*>(result)->set_length(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004832 return result;
4833}
4834
4835
lrn@chromium.org303ada72010-10-27 09:33:13 +00004836MaybeObject* Heap::AllocateRawFixedArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004837 if (length < 0 || length > FixedArray::kMaxLength) {
4838 return Failure::OutOfMemoryException();
4839 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004840 ASSERT(length > 0);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004841 // Use the general function if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004842 if (always_allocate()) return AllocateFixedArray(length, TENURED);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004843 // Allocate the raw data for a fixed array.
4844 int size = FixedArray::SizeFor(length);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004845 return size <= kMaxObjectSizeInNewSpace
4846 ? new_space_.AllocateRaw(size)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004847 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004848}
4849
4850
lrn@chromium.org303ada72010-10-27 09:33:13 +00004851MaybeObject* Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004852 int len = src->length();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004853 Object* obj;
4854 { MaybeObject* maybe_obj = AllocateRawFixedArray(len);
4855 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4856 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004857 if (InNewSpace(obj)) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004858 HeapObject* dst = HeapObject::cast(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004859 dst->set_map_no_write_barrier(map);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004860 CopyBlock(dst->address() + kPointerSize,
4861 src->address() + kPointerSize,
4862 FixedArray::SizeFor(len) - kPointerSize);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004863 return obj;
4864 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004865 HeapObject::cast(obj)->set_map_no_write_barrier(map);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004866 FixedArray* result = FixedArray::cast(obj);
4867 result->set_length(len);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004868
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004869 // Copy the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004870 AssertNoAllocation no_gc;
4871 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004872 for (int i = 0; i < len; i++) result->set(i, src->get(i), mode);
4873 return result;
4874}
4875
4876
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004877MaybeObject* Heap::CopyFixedDoubleArrayWithMap(FixedDoubleArray* src,
4878 Map* map) {
4879 int len = src->length();
4880 Object* obj;
4881 { MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(len, NOT_TENURED);
4882 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4883 }
4884 HeapObject* dst = HeapObject::cast(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004885 dst->set_map_no_write_barrier(map);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004886 CopyBlock(
4887 dst->address() + FixedDoubleArray::kLengthOffset,
4888 src->address() + FixedDoubleArray::kLengthOffset,
4889 FixedDoubleArray::SizeFor(len) - FixedDoubleArray::kLengthOffset);
4890 return obj;
4891}
4892
4893
lrn@chromium.org303ada72010-10-27 09:33:13 +00004894MaybeObject* Heap::AllocateFixedArray(int length) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004895 ASSERT(length >= 0);
ager@chromium.org32912102009-01-16 10:38:43 +00004896 if (length == 0) return empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004897 Object* result;
4898 { MaybeObject* maybe_result = AllocateRawFixedArray(length);
4899 if (!maybe_result->ToObject(&result)) return maybe_result;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004900 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004901 // Initialize header.
4902 FixedArray* array = reinterpret_cast<FixedArray*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004903 array->set_map_no_write_barrier(fixed_array_map());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004904 array->set_length(length);
4905 // Initialize body.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004906 ASSERT(!InNewSpace(undefined_value()));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004907 MemsetPointer(array->data_start(), undefined_value(), length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004908 return result;
4909}
4910
4911
lrn@chromium.org303ada72010-10-27 09:33:13 +00004912MaybeObject* Heap::AllocateRawFixedArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004913 if (length < 0 || length > FixedArray::kMaxLength) {
4914 return Failure::OutOfMemoryException();
4915 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004916
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004917 AllocationSpace space =
4918 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004919 int size = FixedArray::SizeFor(length);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004920 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
4921 // Too big for new space.
4922 space = LO_SPACE;
4923 } else if (space == OLD_POINTER_SPACE &&
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004924 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004925 // Too big for old pointer space.
4926 space = LO_SPACE;
4927 }
4928
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004929 AllocationSpace retry_space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004930 (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_POINTER_SPACE : LO_SPACE;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004931
4932 return AllocateRaw(size, space, retry_space);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004933}
4934
4935
lrn@chromium.org303ada72010-10-27 09:33:13 +00004936MUST_USE_RESULT static MaybeObject* AllocateFixedArrayWithFiller(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004937 Heap* heap,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004938 int length,
4939 PretenureFlag pretenure,
4940 Object* filler) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004941 ASSERT(length >= 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004942 ASSERT(heap->empty_fixed_array()->IsFixedArray());
4943 if (length == 0) return heap->empty_fixed_array();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004944
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004945 ASSERT(!heap->InNewSpace(filler));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004946 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004947 { MaybeObject* maybe_result = heap->AllocateRawFixedArray(length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004948 if (!maybe_result->ToObject(&result)) return maybe_result;
4949 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004950
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004951 HeapObject::cast(result)->set_map_no_write_barrier(heap->fixed_array_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004952 FixedArray* array = FixedArray::cast(result);
4953 array->set_length(length);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004954 MemsetPointer(array->data_start(), filler, length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004955 return array;
4956}
4957
4958
lrn@chromium.org303ada72010-10-27 09:33:13 +00004959MaybeObject* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004960 return AllocateFixedArrayWithFiller(this,
4961 length,
4962 pretenure,
4963 undefined_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004964}
4965
4966
lrn@chromium.org303ada72010-10-27 09:33:13 +00004967MaybeObject* Heap::AllocateFixedArrayWithHoles(int length,
4968 PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004969 return AllocateFixedArrayWithFiller(this,
4970 length,
4971 pretenure,
4972 the_hole_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004973}
4974
4975
lrn@chromium.org303ada72010-10-27 09:33:13 +00004976MaybeObject* Heap::AllocateUninitializedFixedArray(int length) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004977 if (length == 0) return empty_fixed_array();
4978
lrn@chromium.org303ada72010-10-27 09:33:13 +00004979 Object* obj;
4980 { MaybeObject* maybe_obj = AllocateRawFixedArray(length);
4981 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4982 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004983
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004984 reinterpret_cast<FixedArray*>(obj)->set_map_no_write_barrier(
4985 fixed_array_map());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004986 FixedArray::cast(obj)->set_length(length);
4987 return obj;
4988}
4989
4990
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004991MaybeObject* Heap::AllocateEmptyFixedDoubleArray() {
4992 int size = FixedDoubleArray::SizeFor(0);
4993 Object* result;
4994 { MaybeObject* maybe_result =
4995 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
4996 if (!maybe_result->ToObject(&result)) return maybe_result;
4997 }
4998 // Initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004999 reinterpret_cast<FixedDoubleArray*>(result)->set_map_no_write_barrier(
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005000 fixed_double_array_map());
5001 reinterpret_cast<FixedDoubleArray*>(result)->set_length(0);
5002 return result;
5003}
5004
5005
5006MaybeObject* Heap::AllocateUninitializedFixedDoubleArray(
5007 int length,
5008 PretenureFlag pretenure) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005009 if (length == 0) return empty_fixed_array();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005010
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005011 Object* elements_object;
5012 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
5013 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj;
5014 FixedDoubleArray* elements =
5015 reinterpret_cast<FixedDoubleArray*>(elements_object);
5016
5017 elements->set_map_no_write_barrier(fixed_double_array_map());
5018 elements->set_length(length);
5019 return elements;
5020}
5021
5022
5023MaybeObject* Heap::AllocateFixedDoubleArrayWithHoles(
5024 int length,
5025 PretenureFlag pretenure) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005026 if (length == 0) return empty_fixed_array();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005027
5028 Object* elements_object;
5029 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
5030 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj;
5031 FixedDoubleArray* elements =
5032 reinterpret_cast<FixedDoubleArray*>(elements_object);
5033
5034 for (int i = 0; i < length; ++i) {
5035 elements->set_the_hole(i);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005036 }
5037
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005038 elements->set_map_no_write_barrier(fixed_double_array_map());
5039 elements->set_length(length);
5040 return elements;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005041}
5042
5043
5044MaybeObject* Heap::AllocateRawFixedDoubleArray(int length,
5045 PretenureFlag pretenure) {
5046 if (length < 0 || length > FixedDoubleArray::kMaxLength) {
5047 return Failure::OutOfMemoryException();
5048 }
5049
5050 AllocationSpace space =
5051 (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
5052 int size = FixedDoubleArray::SizeFor(length);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005053
5054#ifndef V8_HOST_ARCH_64_BIT
5055 size += kPointerSize;
5056#endif
5057
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005058 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
5059 // Too big for new space.
5060 space = LO_SPACE;
5061 } else if (space == OLD_DATA_SPACE &&
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005062 size > Page::kMaxNonCodeHeapObjectSize) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005063 // Too big for old data space.
5064 space = LO_SPACE;
5065 }
5066
5067 AllocationSpace retry_space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005068 (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_DATA_SPACE : LO_SPACE;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005069
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005070 HeapObject* object;
5071 { MaybeObject* maybe_object = AllocateRaw(size, space, retry_space);
5072 if (!maybe_object->To<HeapObject>(&object)) return maybe_object;
5073 }
5074
5075 return EnsureDoubleAligned(this, object, size);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005076}
5077
5078
lrn@chromium.org303ada72010-10-27 09:33:13 +00005079MaybeObject* Heap::AllocateHashTable(int length, PretenureFlag pretenure) {
5080 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005081 { MaybeObject* maybe_result = AllocateFixedArray(length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005082 if (!maybe_result->ToObject(&result)) return maybe_result;
5083 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005084 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(
5085 hash_table_map());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005086 ASSERT(result->IsHashTable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005087 return result;
5088}
5089
5090
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005091MaybeObject* Heap::AllocateNativeContext() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005092 Object* result;
5093 { MaybeObject* maybe_result =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005094 AllocateFixedArray(Context::NATIVE_CONTEXT_SLOTS);
5095 if (!maybe_result->ToObject(&result)) return maybe_result;
5096 }
5097 Context* context = reinterpret_cast<Context*>(result);
5098 context->set_map_no_write_barrier(native_context_map());
5099 context->set_js_array_maps(undefined_value());
5100 ASSERT(context->IsNativeContext());
5101 ASSERT(result->IsContext());
5102 return result;
5103}
5104
5105
5106MaybeObject* Heap::AllocateGlobalContext(JSFunction* function,
5107 ScopeInfo* scope_info) {
5108 Object* result;
5109 { MaybeObject* maybe_result =
5110 AllocateFixedArray(scope_info->ContextLength(), TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005111 if (!maybe_result->ToObject(&result)) return maybe_result;
5112 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005113 Context* context = reinterpret_cast<Context*>(result);
danno@chromium.orgeb831462012-08-24 11:57:08 +00005114 context->set_map_no_write_barrier(global_context_map());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005115 context->set_closure(function);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005116 context->set_previous(function->context());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005117 context->set_extension(scope_info);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005118 context->set_global_object(function->context()->global_object());
danno@chromium.orgeb831462012-08-24 11:57:08 +00005119 ASSERT(context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005120 ASSERT(result->IsContext());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005121 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005122}
5123
5124
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005125MaybeObject* Heap::AllocateModuleContext(ScopeInfo* scope_info) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005126 Object* result;
5127 { MaybeObject* maybe_result =
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005128 AllocateFixedArray(scope_info->ContextLength(), TENURED);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005129 if (!maybe_result->ToObject(&result)) return maybe_result;
5130 }
5131 Context* context = reinterpret_cast<Context*>(result);
5132 context->set_map_no_write_barrier(module_context_map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005133 // Context links will be set later.
5134 context->set_extension(Smi::FromInt(0));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005135 return context;
5136}
5137
5138
lrn@chromium.org303ada72010-10-27 09:33:13 +00005139MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005140 ASSERT(length >= Context::MIN_CONTEXT_SLOTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005141 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005142 { MaybeObject* maybe_result = AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005143 if (!maybe_result->ToObject(&result)) return maybe_result;
5144 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005145 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005146 context->set_map_no_write_barrier(function_context_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005147 context->set_closure(function);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005148 context->set_previous(function->context());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005149 context->set_extension(Smi::FromInt(0));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005150 context->set_global_object(function->context()->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005151 return context;
5152}
5153
5154
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005155MaybeObject* Heap::AllocateCatchContext(JSFunction* function,
5156 Context* previous,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005157 String* name,
5158 Object* thrown_object) {
5159 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == Context::THROWN_OBJECT_INDEX);
5160 Object* result;
5161 { MaybeObject* maybe_result =
5162 AllocateFixedArray(Context::MIN_CONTEXT_SLOTS + 1);
5163 if (!maybe_result->ToObject(&result)) return maybe_result;
5164 }
5165 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005166 context->set_map_no_write_barrier(catch_context_map());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005167 context->set_closure(function);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005168 context->set_previous(previous);
5169 context->set_extension(name);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005170 context->set_global_object(previous->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005171 context->set(Context::THROWN_OBJECT_INDEX, thrown_object);
5172 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005173}
5174
5175
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005176MaybeObject* Heap::AllocateWithContext(JSFunction* function,
5177 Context* previous,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005178 JSObject* extension) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005179 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005180 { MaybeObject* maybe_result = AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005181 if (!maybe_result->ToObject(&result)) return maybe_result;
5182 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005183 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005184 context->set_map_no_write_barrier(with_context_map());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005185 context->set_closure(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005186 context->set_previous(previous);
5187 context->set_extension(extension);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005188 context->set_global_object(previous->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005189 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005190}
5191
5192
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005193MaybeObject* Heap::AllocateBlockContext(JSFunction* function,
5194 Context* previous,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005195 ScopeInfo* scope_info) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005196 Object* result;
5197 { MaybeObject* maybe_result =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005198 AllocateFixedArrayWithHoles(scope_info->ContextLength());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005199 if (!maybe_result->ToObject(&result)) return maybe_result;
5200 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005201 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005202 context->set_map_no_write_barrier(block_context_map());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005203 context->set_closure(function);
5204 context->set_previous(previous);
5205 context->set_extension(scope_info);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005206 context->set_global_object(previous->global_object());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005207 return context;
5208}
5209
5210
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005211MaybeObject* Heap::AllocateScopeInfo(int length) {
5212 FixedArray* scope_info;
5213 MaybeObject* maybe_scope_info = AllocateFixedArray(length, TENURED);
5214 if (!maybe_scope_info->To(&scope_info)) return maybe_scope_info;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005215 scope_info->set_map_no_write_barrier(scope_info_map());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005216 return scope_info;
5217}
5218
5219
lrn@chromium.org303ada72010-10-27 09:33:13 +00005220MaybeObject* Heap::AllocateStruct(InstanceType type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005221 Map* map;
5222 switch (type) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005223#define MAKE_CASE(NAME, Name, name) \
5224 case NAME##_TYPE: map = name##_map(); break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005225STRUCT_LIST(MAKE_CASE)
5226#undef MAKE_CASE
5227 default:
5228 UNREACHABLE();
5229 return Failure::InternalError();
5230 }
5231 int size = map->instance_size();
5232 AllocationSpace space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005233 (size > Page::kMaxNonCodeHeapObjectSize) ? LO_SPACE : OLD_POINTER_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005234 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005235 { MaybeObject* maybe_result = Allocate(map, space);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005236 if (!maybe_result->ToObject(&result)) return maybe_result;
5237 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005238 Struct::cast(result)->InitializeBody(size);
5239 return result;
5240}
5241
5242
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005243bool Heap::IsHeapIterable() {
5244 return (!old_pointer_space()->was_swept_conservatively() &&
5245 !old_data_space()->was_swept_conservatively());
5246}
5247
5248
5249void Heap::EnsureHeapIsIterable() {
5250 ASSERT(IsAllocationAllowed());
5251 if (!IsHeapIterable()) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005252 CollectAllGarbage(kMakeHeapIterableMask, "Heap::EnsureHeapIsIterable");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005253 }
5254 ASSERT(IsHeapIterable());
5255}
5256
5257
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005258void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005259 incremental_marking()->Step(step_size,
5260 IncrementalMarking::NO_GC_VIA_STACK_GUARD);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005261
5262 if (incremental_marking()->IsComplete()) {
5263 bool uncommit = false;
5264 if (gc_count_at_last_idle_gc_ == gc_count_) {
5265 // No GC since the last full GC, the mutator is probably not active.
5266 isolate_->compilation_cache()->Clear();
5267 uncommit = true;
5268 }
5269 CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental");
5270 gc_count_at_last_idle_gc_ = gc_count_;
5271 if (uncommit) {
5272 new_space_.Shrink();
5273 UncommitFromSpace();
5274 }
5275 }
5276}
5277
5278
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005279bool Heap::IdleNotification(int hint) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005280 // Hints greater than this value indicate that
5281 // the embedder is requesting a lot of GC work.
danno@chromium.org88aa0582012-03-23 15:11:57 +00005282 const int kMaxHint = 1000;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005283 // Minimal hint that allows to do full GC.
5284 const int kMinHintForFullGC = 100;
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005285 intptr_t size_factor = Min(Max(hint, 20), kMaxHint) / 4;
5286 // The size factor is in range [5..250]. The numbers here are chosen from
5287 // experiments. If you changes them, make sure to test with
5288 // chrome/performance_ui_tests --gtest_filter="GeneralMixMemoryTest.*
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00005289 intptr_t step_size =
5290 size_factor * IncrementalMarking::kAllocatedThreshold;
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005291
5292 if (contexts_disposed_ > 0) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005293 if (hint >= kMaxHint) {
5294 // The embedder is requesting a lot of GC work after context disposal,
5295 // we age inline caches so that they don't keep objects from
5296 // the old context alive.
5297 AgeInlineCaches();
5298 }
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005299 int mark_sweep_time = Min(TimeMarkSweepWouldTakeInMs(), 1000);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005300 if (hint >= mark_sweep_time && !FLAG_expose_gc &&
5301 incremental_marking()->IsStopped()) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005302 HistogramTimerScope scope(isolate_->counters()->gc_context());
5303 CollectAllGarbage(kReduceMemoryFootprintMask,
5304 "idle notification: contexts disposed");
5305 } else {
5306 AdvanceIdleIncrementalMarking(step_size);
5307 contexts_disposed_ = 0;
5308 }
5309 // Make sure that we have no pending context disposals.
5310 // Take into account that we might have decided to delay full collection
5311 // because incremental marking is in progress.
5312 ASSERT((contexts_disposed_ == 0) || !incremental_marking()->IsStopped());
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005313 // After context disposal there is likely a lot of garbage remaining, reset
5314 // the idle notification counters in order to trigger more incremental GCs
5315 // on subsequent idle notifications.
5316 StartIdleRound();
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005317 return false;
5318 }
5319
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005320 if (!FLAG_incremental_marking || FLAG_expose_gc || Serializer::enabled()) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005321 return IdleGlobalGC();
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005322 }
5323
5324 // By doing small chunks of GC work in each IdleNotification,
5325 // perform a round of incremental GCs and after that wait until
5326 // the mutator creates enough garbage to justify a new round.
5327 // An incremental GC progresses as follows:
5328 // 1. many incremental marking steps,
5329 // 2. one old space mark-sweep-compact,
5330 // 3. many lazy sweep steps.
5331 // Use mark-sweep-compact events to count incremental GCs in a round.
5332
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005333
5334 if (incremental_marking()->IsStopped()) {
5335 if (!IsSweepingComplete() &&
5336 !AdvanceSweepers(static_cast<int>(step_size))) {
5337 return false;
5338 }
5339 }
5340
5341 if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) {
5342 if (EnoughGarbageSinceLastIdleRound()) {
5343 StartIdleRound();
5344 } else {
5345 return true;
5346 }
5347 }
5348
5349 int new_mark_sweeps = ms_count_ - ms_count_at_last_idle_notification_;
5350 mark_sweeps_since_idle_round_started_ += new_mark_sweeps;
5351 ms_count_at_last_idle_notification_ = ms_count_;
5352
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005353 int remaining_mark_sweeps = kMaxMarkSweepsInIdleRound -
5354 mark_sweeps_since_idle_round_started_;
5355
5356 if (remaining_mark_sweeps <= 0) {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005357 FinishIdleRound();
5358 return true;
5359 }
5360
5361 if (incremental_marking()->IsStopped()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005362 // If there are no more than two GCs left in this idle round and we are
5363 // allowed to do a full GC, then make those GCs full in order to compact
5364 // the code space.
5365 // TODO(ulan): Once we enable code compaction for incremental marking,
5366 // we can get rid of this special case and always start incremental marking.
5367 if (remaining_mark_sweeps <= 2 && hint >= kMinHintForFullGC) {
5368 CollectAllGarbage(kReduceMemoryFootprintMask,
5369 "idle notification: finalize idle round");
5370 } else {
5371 incremental_marking()->Start();
5372 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005373 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005374 if (!incremental_marking()->IsStopped()) {
5375 AdvanceIdleIncrementalMarking(step_size);
5376 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005377 return false;
5378}
5379
5380
5381bool Heap::IdleGlobalGC() {
ager@chromium.orga1645e22009-09-09 19:27:10 +00005382 static const int kIdlesBeforeScavenge = 4;
5383 static const int kIdlesBeforeMarkSweep = 7;
5384 static const int kIdlesBeforeMarkCompact = 8;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005385 static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005386 static const unsigned int kGCsBetweenCleanup = 4;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005387
5388 if (!last_idle_notification_gc_count_init_) {
5389 last_idle_notification_gc_count_ = gc_count_;
5390 last_idle_notification_gc_count_init_ = true;
5391 }
ager@chromium.org96c75b52009-08-26 09:13:16 +00005392
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005393 bool uncommit = true;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005394 bool finished = false;
5395
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005396 // Reset the number of idle notifications received when a number of
5397 // GCs have taken place. This allows another round of cleanup based
5398 // on idle notifications if enough work has been carried out to
5399 // provoke a number of garbage collections.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005400 if (gc_count_ - last_idle_notification_gc_count_ < kGCsBetweenCleanup) {
5401 number_idle_notifications_ =
5402 Min(number_idle_notifications_ + 1, kMaxIdleCount);
ager@chromium.org96c75b52009-08-26 09:13:16 +00005403 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005404 number_idle_notifications_ = 0;
5405 last_idle_notification_gc_count_ = gc_count_;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005406 }
5407
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005408 if (number_idle_notifications_ == kIdlesBeforeScavenge) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005409 CollectGarbage(NEW_SPACE, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005410 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005411 last_idle_notification_gc_count_ = gc_count_;
5412 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005413 // Before doing the mark-sweep collections we clear the
5414 // compilation cache to avoid hanging on to source code and
5415 // generated code for cached functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005416 isolate_->compilation_cache()->Clear();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005417
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005418 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005419 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005420 last_idle_notification_gc_count_ = gc_count_;
ager@chromium.orga1645e22009-09-09 19:27:10 +00005421
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005422 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005423 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005424 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005425 last_idle_notification_gc_count_ = gc_count_;
5426 number_idle_notifications_ = 0;
ager@chromium.orga1645e22009-09-09 19:27:10 +00005427 finished = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005428 } else if (number_idle_notifications_ > kIdlesBeforeMarkCompact) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005429 // If we have received more than kIdlesBeforeMarkCompact idle
5430 // notifications we do not perform any cleanup because we don't
5431 // expect to gain much by doing so.
5432 finished = true;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005433 }
5434
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005435 if (uncommit) UncommitFromSpace();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005436
ager@chromium.org96c75b52009-08-26 09:13:16 +00005437 return finished;
5438}
5439
5440
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005441#ifdef DEBUG
5442
5443void Heap::Print() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005444 if (!HasBeenSetUp()) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005445 isolate()->PrintStack();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005446 AllSpaces spaces;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005447 for (Space* space = spaces.next(); space != NULL; space = spaces.next())
5448 space->Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005449}
5450
5451
5452void Heap::ReportCodeStatistics(const char* title) {
5453 PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title);
5454 PagedSpace::ResetCodeStatistics();
5455 // We do not look for code in new space, map space, or old space. If code
5456 // somehow ends up in those spaces, we would miss it here.
5457 code_space_->CollectCodeStatistics();
5458 lo_space_->CollectCodeStatistics();
5459 PagedSpace::ReportCodeStatistics();
5460}
5461
5462
5463// This function expects that NewSpace's allocated objects histogram is
5464// populated (via a call to CollectStatistics or else as a side effect of a
5465// just-completed scavenge collection).
5466void Heap::ReportHeapStatistics(const char* title) {
5467 USE(title);
5468 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n",
5469 title, gc_count_);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005470 PrintF("old_gen_promotion_limit_ %" V8_PTR_PREFIX "d\n",
5471 old_gen_promotion_limit_);
5472 PrintF("old_gen_allocation_limit_ %" V8_PTR_PREFIX "d\n",
5473 old_gen_allocation_limit_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005474 PrintF("old_gen_limit_factor_ %d\n", old_gen_limit_factor_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005475
5476 PrintF("\n");
5477 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005478 isolate_->global_handles()->PrintStats();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479 PrintF("\n");
5480
5481 PrintF("Heap statistics : ");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005482 isolate_->memory_allocator()->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005483 PrintF("To space : ");
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005484 new_space_.ReportStatistics();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005485 PrintF("Old pointer space : ");
5486 old_pointer_space_->ReportStatistics();
5487 PrintF("Old data space : ");
5488 old_data_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005489 PrintF("Code space : ");
5490 code_space_->ReportStatistics();
5491 PrintF("Map space : ");
5492 map_space_->ReportStatistics();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005493 PrintF("Cell space : ");
5494 cell_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005495 PrintF("Large object space : ");
5496 lo_space_->ReportStatistics();
5497 PrintF(">>>>>> ========================================= >>>>>>\n");
5498}
5499
5500#endif // DEBUG
5501
5502bool Heap::Contains(HeapObject* value) {
5503 return Contains(value->address());
5504}
5505
5506
5507bool Heap::Contains(Address addr) {
5508 if (OS::IsOutsideAllocatedSpace(addr)) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005509 return HasBeenSetUp() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005510 (new_space_.ToSpaceContains(addr) ||
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005511 old_pointer_space_->Contains(addr) ||
5512 old_data_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005513 code_space_->Contains(addr) ||
5514 map_space_->Contains(addr) ||
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005515 cell_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005516 lo_space_->SlowContains(addr));
5517}
5518
5519
5520bool Heap::InSpace(HeapObject* value, AllocationSpace space) {
5521 return InSpace(value->address(), space);
5522}
5523
5524
5525bool Heap::InSpace(Address addr, AllocationSpace space) {
5526 if (OS::IsOutsideAllocatedSpace(addr)) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005527 if (!HasBeenSetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005528
5529 switch (space) {
5530 case NEW_SPACE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005531 return new_space_.ToSpaceContains(addr);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005532 case OLD_POINTER_SPACE:
5533 return old_pointer_space_->Contains(addr);
5534 case OLD_DATA_SPACE:
5535 return old_data_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005536 case CODE_SPACE:
5537 return code_space_->Contains(addr);
5538 case MAP_SPACE:
5539 return map_space_->Contains(addr);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005540 case CELL_SPACE:
5541 return cell_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005542 case LO_SPACE:
5543 return lo_space_->SlowContains(addr);
5544 }
5545
5546 return false;
5547}
5548
5549
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005550#ifdef VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005551void Heap::Verify() {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005552 CHECK(HasBeenSetUp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005553
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005554 store_buffer()->Verify();
5555
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005556 VerifyPointersVisitor visitor;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005557 IterateRoots(&visitor, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005558
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005559 new_space_.Verify();
5560
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005561 old_pointer_space_->Verify(&visitor);
5562 map_space_->Verify(&visitor);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005563
5564 VerifyPointersVisitor no_dirty_regions_visitor;
5565 old_data_space_->Verify(&no_dirty_regions_visitor);
5566 code_space_->Verify(&no_dirty_regions_visitor);
5567 cell_space_->Verify(&no_dirty_regions_visitor);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005568
5569 lo_space_->Verify();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005570}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005571#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005572
5573
lrn@chromium.org303ada72010-10-27 09:33:13 +00005574MaybeObject* Heap::LookupSymbol(Vector<const char> string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005575 Object* symbol = NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005576 Object* new_table;
5577 { MaybeObject* maybe_new_table =
5578 symbol_table()->LookupSymbol(string, &symbol);
5579 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5580 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005581 // Can't use set_symbol_table because SymbolTable::cast knows that
5582 // SymbolTable is a singleton and checks for identity.
5583 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005584 ASSERT(symbol != NULL);
5585 return symbol;
5586}
5587
5588
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005589MaybeObject* Heap::LookupAsciiSymbol(Vector<const char> string) {
5590 Object* symbol = NULL;
5591 Object* new_table;
5592 { MaybeObject* maybe_new_table =
5593 symbol_table()->LookupAsciiSymbol(string, &symbol);
5594 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5595 }
5596 // Can't use set_symbol_table because SymbolTable::cast knows that
5597 // SymbolTable is a singleton and checks for identity.
5598 roots_[kSymbolTableRootIndex] = new_table;
5599 ASSERT(symbol != NULL);
5600 return symbol;
5601}
5602
5603
danno@chromium.org40cb8782011-05-25 07:58:50 +00005604MaybeObject* Heap::LookupAsciiSymbol(Handle<SeqAsciiString> string,
5605 int from,
5606 int length) {
5607 Object* symbol = NULL;
5608 Object* new_table;
5609 { MaybeObject* maybe_new_table =
5610 symbol_table()->LookupSubStringAsciiSymbol(string,
5611 from,
5612 length,
5613 &symbol);
5614 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5615 }
5616 // Can't use set_symbol_table because SymbolTable::cast knows that
5617 // SymbolTable is a singleton and checks for identity.
5618 roots_[kSymbolTableRootIndex] = new_table;
5619 ASSERT(symbol != NULL);
5620 return symbol;
5621}
5622
5623
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005624MaybeObject* Heap::LookupTwoByteSymbol(Vector<const uc16> string) {
5625 Object* symbol = NULL;
5626 Object* new_table;
5627 { MaybeObject* maybe_new_table =
5628 symbol_table()->LookupTwoByteSymbol(string, &symbol);
5629 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5630 }
5631 // Can't use set_symbol_table because SymbolTable::cast knows that
5632 // SymbolTable is a singleton and checks for identity.
5633 roots_[kSymbolTableRootIndex] = new_table;
5634 ASSERT(symbol != NULL);
5635 return symbol;
5636}
5637
5638
lrn@chromium.org303ada72010-10-27 09:33:13 +00005639MaybeObject* Heap::LookupSymbol(String* string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005640 if (string->IsSymbol()) return string;
5641 Object* symbol = NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005642 Object* new_table;
5643 { MaybeObject* maybe_new_table =
5644 symbol_table()->LookupString(string, &symbol);
5645 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5646 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005647 // Can't use set_symbol_table because SymbolTable::cast knows that
5648 // SymbolTable is a singleton and checks for identity.
5649 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005650 ASSERT(symbol != NULL);
5651 return symbol;
5652}
5653
5654
ager@chromium.org7c537e22008-10-16 08:43:32 +00005655bool Heap::LookupSymbolIfExists(String* string, String** symbol) {
5656 if (string->IsSymbol()) {
5657 *symbol = string;
5658 return true;
5659 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005660 return symbol_table()->LookupSymbolIfExists(string, symbol);
ager@chromium.org7c537e22008-10-16 08:43:32 +00005661}
5662
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005663
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005664void Heap::ZapFromSpace() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005665 NewSpacePageIterator it(new_space_.FromSpaceStart(),
5666 new_space_.FromSpaceEnd());
5667 while (it.has_next()) {
5668 NewSpacePage* page = it.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005669 for (Address cursor = page->area_start(), limit = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005670 cursor < limit;
5671 cursor += kPointerSize) {
5672 Memory::Address_at(cursor) = kFromSpaceZapValue;
5673 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005674 }
5675}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005676
5677
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005678void Heap::IterateAndMarkPointersToFromSpace(Address start,
5679 Address end,
5680 ObjectSlotCallback callback) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005681 Address slot_address = start;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005682
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005683 // We are not collecting slots on new space objects during mutation
5684 // thus we have to scan for pointers to evacuation candidates when we
5685 // promote objects. But we should not record any slots in non-black
5686 // objects. Grey object's slots would be rescanned.
5687 // White object might not survive until the end of collection
5688 // it would be a violation of the invariant to record it's slots.
5689 bool record_slots = false;
5690 if (incremental_marking()->IsCompacting()) {
5691 MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::FromAddress(start));
5692 record_slots = Marking::IsBlack(mark_bit);
5693 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005694
5695 while (slot_address < end) {
5696 Object** slot = reinterpret_cast<Object**>(slot_address);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005697 Object* object = *slot;
5698 // If the store buffer becomes overfull we mark pages as being exempt from
5699 // the store buffer. These pages are scanned to find pointers that point
5700 // to the new space. In that case we may hit newly promoted objects and
5701 // fix the pointers before the promotion queue gets to them. Thus the 'if'.
5702 if (object->IsHeapObject()) {
5703 if (Heap::InFromSpace(object)) {
5704 callback(reinterpret_cast<HeapObject**>(slot),
5705 HeapObject::cast(object));
5706 Object* new_object = *slot;
5707 if (InNewSpace(new_object)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005708 SLOW_ASSERT(Heap::InToSpace(new_object));
5709 SLOW_ASSERT(new_object->IsHeapObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005710 store_buffer_.EnterDirectlyIntoStoreBuffer(
5711 reinterpret_cast<Address>(slot));
5712 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005713 SLOW_ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_object));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005714 } else if (record_slots &&
5715 MarkCompactCollector::IsOnEvacuationCandidate(object)) {
5716 mark_compact_collector()->RecordSlot(slot, slot, object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005717 }
5718 }
5719 slot_address += kPointerSize;
5720 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005721}
5722
5723
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005724#ifdef DEBUG
5725typedef bool (*CheckStoreBufferFilter)(Object** addr);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005726
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005727
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005728bool IsAMapPointerAddress(Object** addr) {
5729 uintptr_t a = reinterpret_cast<uintptr_t>(addr);
5730 int mod = a % Map::kSize;
5731 return mod >= Map::kPointerFieldsBeginOffset &&
5732 mod < Map::kPointerFieldsEndOffset;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005733}
5734
5735
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005736bool EverythingsAPointer(Object** addr) {
5737 return true;
5738}
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005739
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005740
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005741static void CheckStoreBuffer(Heap* heap,
5742 Object** current,
5743 Object** limit,
5744 Object**** store_buffer_position,
5745 Object*** store_buffer_top,
5746 CheckStoreBufferFilter filter,
5747 Address special_garbage_start,
5748 Address special_garbage_end) {
5749 Map* free_space_map = heap->free_space_map();
5750 for ( ; current < limit; current++) {
5751 Object* o = *current;
5752 Address current_address = reinterpret_cast<Address>(current);
5753 // Skip free space.
5754 if (o == free_space_map) {
5755 Address current_address = reinterpret_cast<Address>(current);
5756 FreeSpace* free_space =
5757 FreeSpace::cast(HeapObject::FromAddress(current_address));
5758 int skip = free_space->Size();
5759 ASSERT(current_address + skip <= reinterpret_cast<Address>(limit));
5760 ASSERT(skip > 0);
5761 current_address += skip - kPointerSize;
5762 current = reinterpret_cast<Object**>(current_address);
5763 continue;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005764 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005765 // Skip the current linear allocation space between top and limit which is
5766 // unmarked with the free space map, but can contain junk.
5767 if (current_address == special_garbage_start &&
5768 special_garbage_end != special_garbage_start) {
5769 current_address = special_garbage_end - kPointerSize;
5770 current = reinterpret_cast<Object**>(current_address);
5771 continue;
5772 }
5773 if (!(*filter)(current)) continue;
5774 ASSERT(current_address < special_garbage_start ||
5775 current_address >= special_garbage_end);
5776 ASSERT(reinterpret_cast<uintptr_t>(o) != kFreeListZapValue);
5777 // We have to check that the pointer does not point into new space
5778 // without trying to cast it to a heap object since the hash field of
5779 // a string can contain values like 1 and 3 which are tagged null
5780 // pointers.
5781 if (!heap->InNewSpace(o)) continue;
5782 while (**store_buffer_position < current &&
5783 *store_buffer_position < store_buffer_top) {
5784 (*store_buffer_position)++;
5785 }
5786 if (**store_buffer_position != current ||
5787 *store_buffer_position == store_buffer_top) {
5788 Object** obj_start = current;
5789 while (!(*obj_start)->IsMap()) obj_start--;
5790 UNREACHABLE();
5791 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005792 }
5793}
5794
5795
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005796// Check that the store buffer contains all intergenerational pointers by
5797// scanning a page and ensuring that all pointers to young space are in the
5798// store buffer.
5799void Heap::OldPointerSpaceCheckStoreBuffer() {
5800 OldSpace* space = old_pointer_space();
5801 PageIterator pages(space);
5802
5803 store_buffer()->SortUniq();
5804
5805 while (pages.has_next()) {
5806 Page* page = pages.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005807 Object** current = reinterpret_cast<Object**>(page->area_start());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005808
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005809 Address end = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005810
5811 Object*** store_buffer_position = store_buffer()->Start();
5812 Object*** store_buffer_top = store_buffer()->Top();
5813
5814 Object** limit = reinterpret_cast<Object**>(end);
5815 CheckStoreBuffer(this,
5816 current,
5817 limit,
5818 &store_buffer_position,
5819 store_buffer_top,
5820 &EverythingsAPointer,
5821 space->top(),
5822 space->limit());
5823 }
5824}
5825
5826
5827void Heap::MapSpaceCheckStoreBuffer() {
5828 MapSpace* space = map_space();
5829 PageIterator pages(space);
5830
5831 store_buffer()->SortUniq();
5832
5833 while (pages.has_next()) {
5834 Page* page = pages.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005835 Object** current = reinterpret_cast<Object**>(page->area_start());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005836
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005837 Address end = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005838
5839 Object*** store_buffer_position = store_buffer()->Start();
5840 Object*** store_buffer_top = store_buffer()->Top();
5841
5842 Object** limit = reinterpret_cast<Object**>(end);
5843 CheckStoreBuffer(this,
5844 current,
5845 limit,
5846 &store_buffer_position,
5847 store_buffer_top,
5848 &IsAMapPointerAddress,
5849 space->top(),
5850 space->limit());
5851 }
5852}
5853
5854
5855void Heap::LargeObjectSpaceCheckStoreBuffer() {
5856 LargeObjectIterator it(lo_space());
5857 for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) {
5858 // We only have code, sequential strings, or fixed arrays in large
5859 // object space, and only fixed arrays can possibly contain pointers to
5860 // the young generation.
5861 if (object->IsFixedArray()) {
5862 Object*** store_buffer_position = store_buffer()->Start();
5863 Object*** store_buffer_top = store_buffer()->Top();
5864 Object** current = reinterpret_cast<Object**>(object->address());
5865 Object** limit =
5866 reinterpret_cast<Object**>(object->address() + object->Size());
5867 CheckStoreBuffer(this,
5868 current,
5869 limit,
5870 &store_buffer_position,
5871 store_buffer_top,
5872 &EverythingsAPointer,
5873 NULL,
5874 NULL);
5875 }
5876 }
5877}
5878#endif
5879
5880
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005881void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) {
5882 IterateStrongRoots(v, mode);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005883 IterateWeakRoots(v, mode);
5884}
5885
5886
5887void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005888 v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex]));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005889 v->Synchronize(VisitorSynchronization::kSymbolTable);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005890 if (mode != VISIT_ALL_IN_SCAVENGE &&
5891 mode != VISIT_ALL_IN_SWEEP_NEWSPACE) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005892 // Scavenge collections have special processing for this.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005893 external_string_table_.Iterate(v);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005894 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005895 v->Synchronize(VisitorSynchronization::kExternalStringsTable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005896}
5897
5898
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005899void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005900 v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005901 v->Synchronize(VisitorSynchronization::kStrongRootList);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005902
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00005903 v->VisitPointer(BitCast<Object**>(&hidden_symbol_));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005904 v->Synchronize(VisitorSynchronization::kSymbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005905
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005906 isolate_->bootstrapper()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005907 v->Synchronize(VisitorSynchronization::kBootstrapper);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005908 isolate_->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005909 v->Synchronize(VisitorSynchronization::kTop);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005910 Relocatable::Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005911 v->Synchronize(VisitorSynchronization::kRelocatable);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005912
5913#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005914 isolate_->debug()->Iterate(v);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005915 if (isolate_->deoptimizer_data() != NULL) {
5916 isolate_->deoptimizer_data()->Iterate(v);
5917 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005918#endif
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005919 v->Synchronize(VisitorSynchronization::kDebug);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005920 isolate_->compilation_cache()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005921 v->Synchronize(VisitorSynchronization::kCompilationCache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005922
5923 // Iterate over local handles in handle scopes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005924 isolate_->handle_scope_implementer()->Iterate(v);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005925 isolate_->IterateDeferredHandles(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005926 v->Synchronize(VisitorSynchronization::kHandleScope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005927
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005928 // Iterate over the builtin code objects and code stubs in the
5929 // heap. Note that it is not necessary to iterate over code objects
5930 // on scavenge collections.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005931 if (mode != VISIT_ALL_IN_SCAVENGE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005932 isolate_->builtins()->IterateBuiltins(v);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005933 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005934 v->Synchronize(VisitorSynchronization::kBuiltins);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005935
5936 // Iterate over global handles.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005937 switch (mode) {
5938 case VISIT_ONLY_STRONG:
5939 isolate_->global_handles()->IterateStrongRoots(v);
5940 break;
5941 case VISIT_ALL_IN_SCAVENGE:
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005942 isolate_->global_handles()->IterateNewSpaceStrongAndDependentRoots(v);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005943 break;
5944 case VISIT_ALL_IN_SWEEP_NEWSPACE:
5945 case VISIT_ALL:
5946 isolate_->global_handles()->IterateAllRoots(v);
5947 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005948 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005949 v->Synchronize(VisitorSynchronization::kGlobalHandles);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005950
5951 // Iterate over pointers being held by inactive threads.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005952 isolate_->thread_manager()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005953 v->Synchronize(VisitorSynchronization::kThreadManager);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005954
5955 // Iterate over the pointers the Serialization/Deserialization code is
5956 // holding.
5957 // During garbage collection this keeps the partial snapshot cache alive.
5958 // During deserialization of the startup snapshot this creates the partial
5959 // snapshot cache and deserializes the objects it refers to. During
5960 // serialization this does nothing, since the partial snapshot cache is
5961 // empty. However the next thing we do is create the partial snapshot,
5962 // filling up the partial snapshot cache with objects it needs as we go.
5963 SerializerDeserializer::Iterate(v);
5964 // We don't do a v->Synchronize call here, because in debug mode that will
5965 // output a flag to the snapshot. However at this point the serializer and
5966 // deserializer are deliberately a little unsynchronized (see above) so the
5967 // checking of the sync flag in the snapshot would fail.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005968}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969
5970
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005971// TODO(1236194): Since the heap size is configurable on the command line
5972// and through the API, we should gracefully handle the case that the heap
5973// size is not big enough to fit all the initial objects.
ager@chromium.org01fe7df2010-11-10 11:59:11 +00005974bool Heap::ConfigureHeap(int max_semispace_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005975 intptr_t max_old_gen_size,
5976 intptr_t max_executable_size) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005977 if (HasBeenSetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005978
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00005979 if (FLAG_stress_compaction) {
5980 // This will cause more frequent GCs when stressing.
5981 max_semispace_size_ = Page::kPageSize;
5982 }
5983
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005984 if (max_semispace_size > 0) {
5985 if (max_semispace_size < Page::kPageSize) {
5986 max_semispace_size = Page::kPageSize;
5987 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00005988 PrintPID("Max semispace size cannot be less than %dkbytes\n",
5989 Page::kPageSize >> 10);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005990 }
5991 }
5992 max_semispace_size_ = max_semispace_size;
5993 }
ager@chromium.org3811b432009-10-28 14:53:37 +00005994
5995 if (Snapshot::IsEnabled()) {
5996 // If we are using a snapshot we always reserve the default amount
5997 // of memory for each semispace because code in the snapshot has
5998 // write-barrier code that relies on the size and alignment of new
5999 // space. We therefore cannot use a larger max semispace size
6000 // than the default reserved semispace size.
6001 if (max_semispace_size_ > reserved_semispace_size_) {
6002 max_semispace_size_ = reserved_semispace_size_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006003 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006004 PrintPID("Max semispace size cannot be more than %dkbytes\n",
6005 reserved_semispace_size_ >> 10);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006006 }
ager@chromium.org3811b432009-10-28 14:53:37 +00006007 }
6008 } else {
6009 // If we are not using snapshots we reserve space for the actual
6010 // max semispace size.
6011 reserved_semispace_size_ = max_semispace_size_;
6012 }
6013
6014 if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size;
ager@chromium.org01fe7df2010-11-10 11:59:11 +00006015 if (max_executable_size > 0) {
6016 max_executable_size_ = RoundUp(max_executable_size, Page::kPageSize);
6017 }
6018
6019 // The max executable size must be less than or equal to the max old
6020 // generation size.
6021 if (max_executable_size_ > max_old_generation_size_) {
6022 max_executable_size_ = max_old_generation_size_;
6023 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006024
6025 // The new space size must be a power of two to support single-bit testing
6026 // for containment.
ager@chromium.org3811b432009-10-28 14:53:37 +00006027 max_semispace_size_ = RoundUpToPowerOf2(max_semispace_size_);
6028 reserved_semispace_size_ = RoundUpToPowerOf2(reserved_semispace_size_);
6029 initial_semispace_size_ = Min(initial_semispace_size_, max_semispace_size_);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006030 external_allocation_limit_ = 16 * max_semispace_size_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006031
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006032 // The old generation is paged and needs at least one page for each space.
6033 int paged_space_count = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1;
6034 max_old_generation_size_ = Max(static_cast<intptr_t>(paged_space_count *
6035 Page::kPageSize),
6036 RoundUp(max_old_generation_size_,
6037 Page::kPageSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006039 configured_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040 return true;
6041}
6042
6043
kasper.lund7276f142008-07-30 08:49:36 +00006044bool Heap::ConfigureHeapDefault() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006045 return ConfigureHeap(static_cast<intptr_t>(FLAG_max_new_space_size / 2) * KB,
6046 static_cast<intptr_t>(FLAG_max_old_space_size) * MB,
6047 static_cast<intptr_t>(FLAG_max_executable_size) * MB);
kasper.lund7276f142008-07-30 08:49:36 +00006048}
6049
6050
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006051void Heap::RecordStats(HeapStats* stats, bool take_snapshot) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006052 *stats->start_marker = HeapStats::kStartMarker;
6053 *stats->end_marker = HeapStats::kEndMarker;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006054 *stats->new_space_size = new_space_.SizeAsInt();
6055 *stats->new_space_capacity = static_cast<int>(new_space_.Capacity());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006056 *stats->old_pointer_space_size = old_pointer_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006057 *stats->old_pointer_space_capacity = old_pointer_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006058 *stats->old_data_space_size = old_data_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006059 *stats->old_data_space_capacity = old_data_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006060 *stats->code_space_size = code_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006061 *stats->code_space_capacity = code_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006062 *stats->map_space_size = map_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006063 *stats->map_space_capacity = map_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006064 *stats->cell_space_size = cell_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006065 *stats->cell_space_capacity = cell_space_->Capacity();
6066 *stats->lo_space_size = lo_space_->Size();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006067 isolate_->global_handles()->RecordStats(stats);
6068 *stats->memory_allocator_size = isolate()->memory_allocator()->Size();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006069 *stats->memory_allocator_capacity =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006070 isolate()->memory_allocator()->Size() +
6071 isolate()->memory_allocator()->Available();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006072 *stats->os_error = OS::GetLastError();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006073 isolate()->memory_allocator()->Available();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006074 if (take_snapshot) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006075 HeapIterator iterator;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006076 for (HeapObject* obj = iterator.next();
6077 obj != NULL;
6078 obj = iterator.next()) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006079 InstanceType type = obj->map()->instance_type();
6080 ASSERT(0 <= type && type <= LAST_TYPE);
6081 stats->objects_per_type[type]++;
6082 stats->size_per_type[type] += obj->Size();
6083 }
6084 }
ager@chromium.org60121232009-12-03 11:25:37 +00006085}
6086
6087
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00006088intptr_t Heap::PromotedSpaceSizeOfObjects() {
6089 return old_pointer_space_->SizeOfObjects()
6090 + old_data_space_->SizeOfObjects()
6091 + code_space_->SizeOfObjects()
6092 + map_space_->SizeOfObjects()
6093 + cell_space_->SizeOfObjects()
6094 + lo_space_->SizeOfObjects();
6095}
6096
6097
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00006098intptr_t Heap::PromotedExternalMemorySize() {
kasper.lund7276f142008-07-30 08:49:36 +00006099 if (amount_of_external_allocated_memory_
6100 <= amount_of_external_allocated_memory_at_last_global_gc_) return 0;
6101 return amount_of_external_allocated_memory_
6102 - amount_of_external_allocated_memory_at_last_global_gc_;
6103}
6104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006105#ifdef DEBUG
6106
6107// Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject.
6108static const int kMarkTag = 2;
6109
6110
6111class HeapDebugUtils {
6112 public:
6113 explicit HeapDebugUtils(Heap* heap)
6114 : search_for_any_global_(false),
6115 search_target_(NULL),
6116 found_target_(false),
6117 object_stack_(20),
6118 heap_(heap) {
6119 }
6120
6121 class MarkObjectVisitor : public ObjectVisitor {
6122 public:
6123 explicit MarkObjectVisitor(HeapDebugUtils* utils) : utils_(utils) { }
6124
6125 void VisitPointers(Object** start, Object** end) {
6126 // Copy all HeapObject pointers in [start, end)
6127 for (Object** p = start; p < end; p++) {
6128 if ((*p)->IsHeapObject())
6129 utils_->MarkObjectRecursively(p);
6130 }
6131 }
6132
6133 HeapDebugUtils* utils_;
6134 };
6135
6136 void MarkObjectRecursively(Object** p) {
6137 if (!(*p)->IsHeapObject()) return;
6138
6139 HeapObject* obj = HeapObject::cast(*p);
6140
6141 Object* map = obj->map();
6142
6143 if (!map->IsHeapObject()) return; // visited before
6144
6145 if (found_target_) return; // stop if target found
6146 object_stack_.Add(obj);
6147 if ((search_for_any_global_ && obj->IsJSGlobalObject()) ||
6148 (!search_for_any_global_ && (obj == search_target_))) {
6149 found_target_ = true;
6150 return;
6151 }
6152
6153 // not visited yet
6154 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
6155
6156 Address map_addr = map_p->address();
6157
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006158 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_addr + kMarkTag));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006159
6160 MarkObjectRecursively(&map);
6161
6162 MarkObjectVisitor mark_visitor(this);
6163
6164 obj->IterateBody(map_p->instance_type(), obj->SizeFromMap(map_p),
6165 &mark_visitor);
6166
6167 if (!found_target_) // don't pop if found the target
6168 object_stack_.RemoveLast();
6169 }
6170
6171
6172 class UnmarkObjectVisitor : public ObjectVisitor {
6173 public:
6174 explicit UnmarkObjectVisitor(HeapDebugUtils* utils) : utils_(utils) { }
6175
6176 void VisitPointers(Object** start, Object** end) {
6177 // Copy all HeapObject pointers in [start, end)
6178 for (Object** p = start; p < end; p++) {
6179 if ((*p)->IsHeapObject())
6180 utils_->UnmarkObjectRecursively(p);
6181 }
6182 }
6183
6184 HeapDebugUtils* utils_;
6185 };
6186
6187
6188 void UnmarkObjectRecursively(Object** p) {
6189 if (!(*p)->IsHeapObject()) return;
6190
6191 HeapObject* obj = HeapObject::cast(*p);
6192
6193 Object* map = obj->map();
6194
6195 if (map->IsHeapObject()) return; // unmarked already
6196
6197 Address map_addr = reinterpret_cast<Address>(map);
6198
6199 map_addr -= kMarkTag;
6200
6201 ASSERT_TAG_ALIGNED(map_addr);
6202
6203 HeapObject* map_p = HeapObject::FromAddress(map_addr);
6204
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006205 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_p));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006206
6207 UnmarkObjectRecursively(reinterpret_cast<Object**>(&map_p));
6208
6209 UnmarkObjectVisitor unmark_visitor(this);
6210
6211 obj->IterateBody(Map::cast(map_p)->instance_type(),
6212 obj->SizeFromMap(Map::cast(map_p)),
6213 &unmark_visitor);
6214 }
6215
6216
6217 void MarkRootObjectRecursively(Object** root) {
6218 if (search_for_any_global_) {
6219 ASSERT(search_target_ == NULL);
6220 } else {
6221 ASSERT(search_target_->IsHeapObject());
6222 }
6223 found_target_ = false;
6224 object_stack_.Clear();
6225
6226 MarkObjectRecursively(root);
6227 UnmarkObjectRecursively(root);
6228
6229 if (found_target_) {
6230 PrintF("=====================================\n");
6231 PrintF("==== Path to object ====\n");
6232 PrintF("=====================================\n\n");
6233
6234 ASSERT(!object_stack_.is_empty());
6235 for (int i = 0; i < object_stack_.length(); i++) {
6236 if (i > 0) PrintF("\n |\n |\n V\n\n");
6237 Object* obj = object_stack_[i];
6238 obj->Print();
6239 }
6240 PrintF("=====================================\n");
6241 }
6242 }
6243
6244 // Helper class for visiting HeapObjects recursively.
6245 class MarkRootVisitor: public ObjectVisitor {
6246 public:
6247 explicit MarkRootVisitor(HeapDebugUtils* utils) : utils_(utils) { }
6248
6249 void VisitPointers(Object** start, Object** end) {
6250 // Visit all HeapObject pointers in [start, end)
6251 for (Object** p = start; p < end; p++) {
6252 if ((*p)->IsHeapObject())
6253 utils_->MarkRootObjectRecursively(p);
6254 }
6255 }
6256
6257 HeapDebugUtils* utils_;
6258 };
6259
6260 bool search_for_any_global_;
6261 Object* search_target_;
6262 bool found_target_;
6263 List<Object*> object_stack_;
6264 Heap* heap_;
6265
6266 friend class Heap;
6267};
6268
6269#endif
kasper.lund7276f142008-07-30 08:49:36 +00006270
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00006271
6272V8_DECLARE_ONCE(initialize_gc_once);
6273
6274static void InitializeGCOnce() {
6275 InitializeScavengingVisitorsTables();
6276 NewSpaceScavenger::Initialize();
6277 MarkCompactCollector::Initialize();
6278}
6279
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006280bool Heap::SetUp(bool create_heap_objects) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006281#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006282 allocation_timeout_ = FLAG_gc_interval;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006283 debug_utils_ = new HeapDebugUtils(this);
6284#endif
6285
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006286 // Initialize heap spaces and initial maps and objects. Whenever something
6287 // goes wrong, just return false. The caller should check the results and
6288 // call Heap::TearDown() to release allocated memory.
6289 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006290 // If the heap is not yet configured (e.g. through the API), configure it.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006291 // Configuration is based on the flags new-space-size (really the semispace
6292 // size) and old-space-size if set or the initial values of semispace_size_
6293 // and old_generation_size_ otherwise.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006294 if (!configured_) {
kasper.lund7276f142008-07-30 08:49:36 +00006295 if (!ConfigureHeapDefault()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006296 }
6297
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00006298 CallOnce(&initialize_gc_once, &InitializeGCOnce);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006299
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006300 MarkMapPointersAsEncoded(false);
6301
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006302 // Set up memory allocator.
6303 if (!isolate_->memory_allocator()->SetUp(MaxReserved(), MaxExecutableSize()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006304 return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006305
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006306 // Set up new space.
6307 if (!new_space_.SetUp(reserved_semispace_size_, max_semispace_size_)) {
ager@chromium.org3811b432009-10-28 14:53:37 +00006308 return false;
6309 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006310
ager@chromium.orga1645e22009-09-09 19:27:10 +00006311 // Initialize old pointer space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006312 old_pointer_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006313 new OldSpace(this,
6314 max_old_generation_size_,
6315 OLD_POINTER_SPACE,
6316 NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006317 if (old_pointer_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006318 if (!old_pointer_space_->SetUp()) return false;
ager@chromium.orga1645e22009-09-09 19:27:10 +00006319
6320 // Initialize old data space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006321 old_data_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006322 new OldSpace(this,
6323 max_old_generation_size_,
6324 OLD_DATA_SPACE,
6325 NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006326 if (old_data_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006327 if (!old_data_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006328
6329 // Initialize the code space, set its maximum capacity to the old
kasper.lund7276f142008-07-30 08:49:36 +00006330 // generation size. It needs executable memory.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006331 // On 64-bit platform(s), we put all code objects in a 2 GB range of
6332 // virtual address space, so that they can call each other with near calls.
6333 if (code_range_size_ > 0) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006334 if (!isolate_->code_range()->SetUp(code_range_size_)) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006335 return false;
6336 }
6337 }
6338
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006339 code_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006340 new OldSpace(this, max_old_generation_size_, CODE_SPACE, EXECUTABLE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006341 if (code_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006342 if (!code_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006343
6344 // Initialize map space.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00006345 map_space_ = new MapSpace(this, max_old_generation_size_, MAP_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006346 if (map_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006347 if (!map_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006348
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006349 // Initialize global property cell space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006350 cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006351 if (cell_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006352 if (!cell_space_->SetUp()) return false;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006353
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006354 // The large object code space may contain code or data. We set the memory
6355 // to be non-executable here for safety, but this means we need to enable it
6356 // explicitly when allocating large code objects.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006357 lo_space_ = new LargeObjectSpace(this, max_old_generation_size_, LO_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006358 if (lo_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006359 if (!lo_space_->SetUp()) return false;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006360
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006361 // Set up the seed that is used to randomize the string hash function.
6362 ASSERT(hash_seed() == 0);
6363 if (FLAG_randomize_hashes) {
6364 if (FLAG_hash_seed == 0) {
6365 set_hash_seed(
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006366 Smi::FromInt(V8::RandomPrivate(isolate()) & 0x3fffffff));
6367 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006368 set_hash_seed(Smi::FromInt(FLAG_hash_seed));
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006369 }
6370 }
6371
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006372 if (create_heap_objects) {
6373 // Create initial maps.
6374 if (!CreateInitialMaps()) return false;
6375 if (!CreateApiObjects()) return false;
6376
6377 // Create initial objects
6378 if (!CreateInitialObjects()) return false;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00006379
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006380 native_contexts_list_ = undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006381 }
6382
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006383 LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity()));
6384 LOG(isolate_, IntPtrTEvent("heap-available", Available()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006385
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006386 store_buffer()->SetUp();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006387
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006388 if (FLAG_parallel_recompilation) relocation_mutex_ = OS::CreateMutex();
6389
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006390 return true;
6391}
6392
6393
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006394void Heap::SetStackLimits() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006395 ASSERT(isolate_ != NULL);
6396 ASSERT(isolate_ == isolate());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006397 // On 64 bit machines, pointers are generally out of range of Smis. We write
6398 // something that looks like an out of range Smi to the GC.
6399
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006400 // Set up the special root array entries containing the stack limits.
6401 // These are actually addresses, but the tag makes the GC ignore it.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006402 roots_[kStackLimitRootIndex] =
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006403 reinterpret_cast<Object*>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006404 (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006405 roots_[kRealStackLimitRootIndex] =
6406 reinterpret_cast<Object*>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006407 (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006408}
6409
6410
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006411void Heap::TearDown() {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006412#ifdef VERIFY_HEAP
danno@chromium.org1044a4d2012-04-30 12:34:39 +00006413 if (FLAG_verify_heap) {
6414 Verify();
6415 }
6416#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006417
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006418 if (FLAG_print_cumulative_gc_stat) {
6419 PrintF("\n\n");
6420 PrintF("gc_count=%d ", gc_count_);
6421 PrintF("mark_sweep_count=%d ", ms_count_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006422 PrintF("max_gc_pause=%d ", get_max_gc_pause());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006423 PrintF("total_gc_time=%d ", total_gc_time_ms_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006424 PrintF("min_in_mutator=%d ", get_min_in_mutator());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006425 PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ",
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006426 get_max_alive_after_gc());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006427 PrintF("\n\n");
6428 }
6429
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006430 isolate_->global_handles()->TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006431
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006432 external_string_table_.TearDown();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00006433
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006434 new_space_.TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006435
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006436 if (old_pointer_space_ != NULL) {
6437 old_pointer_space_->TearDown();
6438 delete old_pointer_space_;
6439 old_pointer_space_ = NULL;
6440 }
6441
6442 if (old_data_space_ != NULL) {
6443 old_data_space_->TearDown();
6444 delete old_data_space_;
6445 old_data_space_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006446 }
6447
6448 if (code_space_ != NULL) {
6449 code_space_->TearDown();
6450 delete code_space_;
6451 code_space_ = NULL;
6452 }
6453
6454 if (map_space_ != NULL) {
6455 map_space_->TearDown();
6456 delete map_space_;
6457 map_space_ = NULL;
6458 }
6459
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006460 if (cell_space_ != NULL) {
6461 cell_space_->TearDown();
6462 delete cell_space_;
6463 cell_space_ = NULL;
6464 }
6465
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006466 if (lo_space_ != NULL) {
6467 lo_space_->TearDown();
6468 delete lo_space_;
6469 lo_space_ = NULL;
6470 }
6471
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006472 store_buffer()->TearDown();
6473 incremental_marking()->TearDown();
6474
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006475 isolate_->memory_allocator()->TearDown();
6476
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006477 delete relocation_mutex_;
6478
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006479#ifdef DEBUG
6480 delete debug_utils_;
6481 debug_utils_ = NULL;
6482#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006483}
6484
6485
6486void Heap::Shrink() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006487 // Try to shrink all paged spaces.
6488 PagedSpaces spaces;
danno@chromium.org2c456792011-11-11 12:00:53 +00006489 for (PagedSpace* space = spaces.next();
6490 space != NULL;
6491 space = spaces.next()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006492 space->ReleaseAllUnusedPages();
danno@chromium.org2c456792011-11-11 12:00:53 +00006493 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006494}
6495
6496
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006497void Heap::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) {
6498 ASSERT(callback != NULL);
6499 GCPrologueCallbackPair pair(callback, gc_type);
6500 ASSERT(!gc_prologue_callbacks_.Contains(pair));
6501 return gc_prologue_callbacks_.Add(pair);
6502}
6503
6504
6505void Heap::RemoveGCPrologueCallback(GCPrologueCallback callback) {
6506 ASSERT(callback != NULL);
6507 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
6508 if (gc_prologue_callbacks_[i].callback == callback) {
6509 gc_prologue_callbacks_.Remove(i);
6510 return;
6511 }
6512 }
6513 UNREACHABLE();
6514}
6515
6516
6517void Heap::AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type) {
6518 ASSERT(callback != NULL);
6519 GCEpilogueCallbackPair pair(callback, gc_type);
6520 ASSERT(!gc_epilogue_callbacks_.Contains(pair));
6521 return gc_epilogue_callbacks_.Add(pair);
6522}
6523
6524
6525void Heap::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
6526 ASSERT(callback != NULL);
6527 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
6528 if (gc_epilogue_callbacks_[i].callback == callback) {
6529 gc_epilogue_callbacks_.Remove(i);
6530 return;
6531 }
6532 }
6533 UNREACHABLE();
6534}
6535
6536
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006537#ifdef DEBUG
6538
6539class PrintHandleVisitor: public ObjectVisitor {
6540 public:
6541 void VisitPointers(Object** start, Object** end) {
6542 for (Object** p = start; p < end; p++)
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006543 PrintF(" handle %p to %p\n",
6544 reinterpret_cast<void*>(p),
6545 reinterpret_cast<void*>(*p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006546 }
6547};
6548
6549void Heap::PrintHandles() {
6550 PrintF("Handles:\n");
6551 PrintHandleVisitor v;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006552 isolate_->handle_scope_implementer()->Iterate(&v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006553}
6554
6555#endif
6556
6557
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006558Space* AllSpaces::next() {
6559 switch (counter_++) {
6560 case NEW_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006561 return HEAP->new_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006562 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006563 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006564 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006565 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006566 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006567 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006568 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006569 return HEAP->map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006570 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006571 return HEAP->cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006572 case LO_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006573 return HEAP->lo_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006574 default:
6575 return NULL;
6576 }
6577}
6578
6579
6580PagedSpace* PagedSpaces::next() {
6581 switch (counter_++) {
6582 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006583 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006584 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006585 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006586 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006587 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006588 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006589 return HEAP->map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006590 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006591 return HEAP->cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006592 default:
6593 return NULL;
6594 }
6595}
6596
6597
6598
6599OldSpace* OldSpaces::next() {
6600 switch (counter_++) {
6601 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006602 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006603 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006604 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006605 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006606 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006607 default:
6608 return NULL;
6609 }
6610}
6611
6612
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006613SpaceIterator::SpaceIterator()
6614 : current_space_(FIRST_SPACE),
6615 iterator_(NULL),
6616 size_func_(NULL) {
6617}
6618
6619
6620SpaceIterator::SpaceIterator(HeapObjectCallback size_func)
6621 : current_space_(FIRST_SPACE),
6622 iterator_(NULL),
6623 size_func_(size_func) {
kasper.lund7276f142008-07-30 08:49:36 +00006624}
6625
6626
6627SpaceIterator::~SpaceIterator() {
6628 // Delete active iterator if any.
6629 delete iterator_;
6630}
6631
6632
6633bool SpaceIterator::has_next() {
6634 // Iterate until no more spaces.
6635 return current_space_ != LAST_SPACE;
6636}
6637
6638
6639ObjectIterator* SpaceIterator::next() {
6640 if (iterator_ != NULL) {
6641 delete iterator_;
6642 iterator_ = NULL;
6643 // Move to the next space
6644 current_space_++;
6645 if (current_space_ > LAST_SPACE) {
6646 return NULL;
6647 }
6648 }
6649
6650 // Return iterator for the new current space.
6651 return CreateIterator();
6652}
6653
6654
6655// Create an iterator for the space to iterate.
6656ObjectIterator* SpaceIterator::CreateIterator() {
6657 ASSERT(iterator_ == NULL);
6658
6659 switch (current_space_) {
6660 case NEW_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006661 iterator_ = new SemiSpaceIterator(HEAP->new_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006662 break;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006663 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006664 iterator_ = new HeapObjectIterator(HEAP->old_pointer_space(), size_func_);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006665 break;
6666 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006667 iterator_ = new HeapObjectIterator(HEAP->old_data_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006668 break;
6669 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006670 iterator_ = new HeapObjectIterator(HEAP->code_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006671 break;
6672 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006673 iterator_ = new HeapObjectIterator(HEAP->map_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006674 break;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006675 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006676 iterator_ = new HeapObjectIterator(HEAP->cell_space(), size_func_);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006677 break;
kasper.lund7276f142008-07-30 08:49:36 +00006678 case LO_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006679 iterator_ = new LargeObjectIterator(HEAP->lo_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006680 break;
6681 }
6682
6683 // Return the newly allocated iterator;
6684 ASSERT(iterator_ != NULL);
6685 return iterator_;
6686}
6687
6688
whesse@chromium.org023421e2010-12-21 12:19:12 +00006689class HeapObjectsFilter {
6690 public:
6691 virtual ~HeapObjectsFilter() {}
6692 virtual bool SkipObject(HeapObject* object) = 0;
6693};
6694
6695
whesse@chromium.org023421e2010-12-21 12:19:12 +00006696class UnreachableObjectsFilter : public HeapObjectsFilter {
6697 public:
6698 UnreachableObjectsFilter() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006699 MarkReachableObjects();
6700 }
6701
6702 ~UnreachableObjectsFilter() {
6703 Isolate::Current()->heap()->mark_compact_collector()->ClearMarkbits();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006704 }
6705
6706 bool SkipObject(HeapObject* object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006707 MarkBit mark_bit = Marking::MarkBitFrom(object);
6708 return !mark_bit.Get();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006709 }
6710
6711 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006712 class MarkingVisitor : public ObjectVisitor {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006713 public:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006714 MarkingVisitor() : marking_stack_(10) {}
whesse@chromium.org023421e2010-12-21 12:19:12 +00006715
6716 void VisitPointers(Object** start, Object** end) {
6717 for (Object** p = start; p < end; p++) {
6718 if (!(*p)->IsHeapObject()) continue;
6719 HeapObject* obj = HeapObject::cast(*p);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006720 MarkBit mark_bit = Marking::MarkBitFrom(obj);
6721 if (!mark_bit.Get()) {
6722 mark_bit.Set();
6723 marking_stack_.Add(obj);
whesse@chromium.org023421e2010-12-21 12:19:12 +00006724 }
6725 }
6726 }
6727
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006728 void TransitiveClosure() {
6729 while (!marking_stack_.is_empty()) {
6730 HeapObject* obj = marking_stack_.RemoveLast();
6731 obj->Iterate(this);
6732 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00006733 }
6734
6735 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006736 List<HeapObject*> marking_stack_;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006737 };
6738
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006739 void MarkReachableObjects() {
6740 Heap* heap = Isolate::Current()->heap();
6741 MarkingVisitor visitor;
6742 heap->IterateRoots(&visitor, VISIT_ALL);
6743 visitor.TransitiveClosure();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006744 }
6745
6746 AssertNoAllocation no_alloc;
6747};
6748
6749
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006750HeapIterator::HeapIterator()
6751 : filtering_(HeapIterator::kNoFiltering),
6752 filter_(NULL) {
6753 Init();
6754}
6755
6756
whesse@chromium.org023421e2010-12-21 12:19:12 +00006757HeapIterator::HeapIterator(HeapIterator::HeapObjectsFiltering filtering)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006758 : filtering_(filtering),
6759 filter_(NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006760 Init();
6761}
6762
6763
6764HeapIterator::~HeapIterator() {
6765 Shutdown();
6766}
6767
6768
6769void HeapIterator::Init() {
6770 // Start the iteration.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006771 space_iterator_ = new SpaceIterator;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006772 switch (filtering_) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006773 case kFilterUnreachable:
6774 filter_ = new UnreachableObjectsFilter;
6775 break;
6776 default:
6777 break;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006778 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006779 object_iterator_ = space_iterator_->next();
6780}
6781
6782
6783void HeapIterator::Shutdown() {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006784#ifdef DEBUG
whesse@chromium.org023421e2010-12-21 12:19:12 +00006785 // Assert that in filtering mode we have iterated through all
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006786 // objects. Otherwise, heap will be left in an inconsistent state.
whesse@chromium.org023421e2010-12-21 12:19:12 +00006787 if (filtering_ != kNoFiltering) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006788 ASSERT(object_iterator_ == NULL);
6789 }
6790#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006791 // Make sure the last iterator is deallocated.
6792 delete space_iterator_;
6793 space_iterator_ = NULL;
6794 object_iterator_ = NULL;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006795 delete filter_;
6796 filter_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006797}
6798
6799
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006800HeapObject* HeapIterator::next() {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006801 if (filter_ == NULL) return NextObject();
6802
6803 HeapObject* obj = NextObject();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006804 while (obj != NULL && filter_->SkipObject(obj)) obj = NextObject();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006805 return obj;
6806}
6807
6808
6809HeapObject* HeapIterator::NextObject() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006810 // No iterator means we are done.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006811 if (object_iterator_ == NULL) return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006812
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006813 if (HeapObject* obj = object_iterator_->next_object()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006814 // If the current iterator has more objects we are fine.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006815 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006816 } else {
6817 // Go though the spaces looking for one that has objects.
6818 while (space_iterator_->has_next()) {
6819 object_iterator_ = space_iterator_->next();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006820 if (HeapObject* obj = object_iterator_->next_object()) {
6821 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006822 }
6823 }
6824 }
6825 // Done with the last space.
6826 object_iterator_ = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006827 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006828}
6829
6830
6831void HeapIterator::reset() {
6832 // Restart the iterator.
6833 Shutdown();
6834 Init();
6835}
6836
6837
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006838#if defined(DEBUG) || defined(LIVE_OBJECT_LIST)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006839
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006840Object* const PathTracer::kAnyGlobalObject = reinterpret_cast<Object*>(NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006841
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006842class PathTracer::MarkVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006843 public:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006844 explicit MarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006845 void VisitPointers(Object** start, Object** end) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006846 // Scan all HeapObject pointers in [start, end)
6847 for (Object** p = start; !tracer_->found() && (p < end); p++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006848 if ((*p)->IsHeapObject())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006849 tracer_->MarkRecursively(p, this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006850 }
6851 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006852
6853 private:
6854 PathTracer* tracer_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006855};
6856
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006857
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006858class PathTracer::UnmarkVisitor: public ObjectVisitor {
6859 public:
6860 explicit UnmarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
6861 void VisitPointers(Object** start, Object** end) {
6862 // Scan all HeapObject pointers in [start, end)
6863 for (Object** p = start; p < end; p++) {
6864 if ((*p)->IsHeapObject())
6865 tracer_->UnmarkRecursively(p, this);
6866 }
6867 }
6868
6869 private:
6870 PathTracer* tracer_;
6871};
6872
6873
6874void PathTracer::VisitPointers(Object** start, Object** end) {
6875 bool done = ((what_to_find_ == FIND_FIRST) && found_target_);
6876 // Visit all HeapObject pointers in [start, end)
6877 for (Object** p = start; !done && (p < end); p++) {
6878 if ((*p)->IsHeapObject()) {
6879 TracePathFrom(p);
6880 done = ((what_to_find_ == FIND_FIRST) && found_target_);
6881 }
6882 }
6883}
6884
6885
6886void PathTracer::Reset() {
6887 found_target_ = false;
6888 object_stack_.Clear();
6889}
6890
6891
6892void PathTracer::TracePathFrom(Object** root) {
6893 ASSERT((search_target_ == kAnyGlobalObject) ||
6894 search_target_->IsHeapObject());
6895 found_target_in_trace_ = false;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00006896 Reset();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006897
6898 MarkVisitor mark_visitor(this);
6899 MarkRecursively(root, &mark_visitor);
6900
6901 UnmarkVisitor unmark_visitor(this);
6902 UnmarkRecursively(root, &unmark_visitor);
6903
6904 ProcessResults();
6905}
6906
6907
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006908static bool SafeIsNativeContext(HeapObject* obj) {
6909 return obj->map() == obj->GetHeap()->raw_unchecked_native_context_map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006910}
6911
6912
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006913void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006914 if (!(*p)->IsHeapObject()) return;
6915
6916 HeapObject* obj = HeapObject::cast(*p);
6917
6918 Object* map = obj->map();
6919
6920 if (!map->IsHeapObject()) return; // visited before
6921
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006922 if (found_target_in_trace_) return; // stop if target found
6923 object_stack_.Add(obj);
6924 if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) ||
6925 (obj == search_target_)) {
6926 found_target_in_trace_ = true;
6927 found_target_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006928 return;
6929 }
6930
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006931 bool is_native_context = SafeIsNativeContext(obj);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006932
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006933 // not visited yet
6934 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
6935
6936 Address map_addr = map_p->address();
6937
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006938 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_addr + kMarkTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006939
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006940 // Scan the object body.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006941 if (is_native_context && (visit_mode_ == VISIT_ONLY_STRONG)) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006942 // This is specialized to scan Context's properly.
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00006943 Object** start = reinterpret_cast<Object**>(obj->address() +
6944 Context::kHeaderSize);
6945 Object** end = reinterpret_cast<Object**>(obj->address() +
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006946 Context::kHeaderSize + Context::FIRST_WEAK_SLOT * kPointerSize);
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00006947 mark_visitor->VisitPointers(start, end);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006948 } else {
6949 obj->IterateBody(map_p->instance_type(),
6950 obj->SizeFromMap(map_p),
6951 mark_visitor);
6952 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006953
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006954 // Scan the map after the body because the body is a lot more interesting
6955 // when doing leak detection.
6956 MarkRecursively(&map, mark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006957
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006958 if (!found_target_in_trace_) // don't pop if found the target
6959 object_stack_.RemoveLast();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006960}
6961
6962
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006963void PathTracer::UnmarkRecursively(Object** p, UnmarkVisitor* unmark_visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006964 if (!(*p)->IsHeapObject()) return;
6965
6966 HeapObject* obj = HeapObject::cast(*p);
6967
6968 Object* map = obj->map();
6969
6970 if (map->IsHeapObject()) return; // unmarked already
6971
6972 Address map_addr = reinterpret_cast<Address>(map);
6973
6974 map_addr -= kMarkTag;
6975
6976 ASSERT_TAG_ALIGNED(map_addr);
6977
6978 HeapObject* map_p = HeapObject::FromAddress(map_addr);
6979
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006980 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006981
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006982 UnmarkRecursively(reinterpret_cast<Object**>(&map_p), unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006983
6984 obj->IterateBody(Map::cast(map_p)->instance_type(),
6985 obj->SizeFromMap(Map::cast(map_p)),
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006986 unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006987}
6988
6989
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006990void PathTracer::ProcessResults() {
6991 if (found_target_) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006992 PrintF("=====================================\n");
6993 PrintF("==== Path to object ====\n");
6994 PrintF("=====================================\n\n");
6995
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006996 ASSERT(!object_stack_.is_empty());
6997 for (int i = 0; i < object_stack_.length(); i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006998 if (i > 0) PrintF("\n |\n |\n V\n\n");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006999 Object* obj = object_stack_[i];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007000 obj->Print();
7001 }
7002 PrintF("=====================================\n");
7003 }
7004}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007005#endif // DEBUG || LIVE_OBJECT_LIST
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007006
7007
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007008#ifdef DEBUG
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00007009// Triggers a depth-first traversal of reachable objects from one
7010// given root object and finds a path to a specific heap object and
7011// prints it.
7012void Heap::TracePathToObjectFrom(Object* target, Object* root) {
7013 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
7014 tracer.VisitPointer(&root);
7015}
7016
7017
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007018// Triggers a depth-first traversal of reachable objects from roots
7019// and finds a path to a specific heap object and prints it.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007020void Heap::TracePathToObject(Object* target) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007021 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
7022 IterateRoots(&tracer, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007023}
7024
7025
7026// Triggers a depth-first traversal of reachable objects from roots
7027// and finds a path to any global object and prints it. Useful for
7028// determining the source for leaks of global objects.
7029void Heap::TracePathToGlobal() {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007030 PathTracer tracer(PathTracer::kAnyGlobalObject,
7031 PathTracer::FIND_ALL,
7032 VISIT_ALL);
7033 IterateRoots(&tracer, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007034}
7035#endif
7036
7037
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007038static intptr_t CountTotalHolesSize() {
7039 intptr_t holes_size = 0;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007040 OldSpaces spaces;
7041 for (OldSpace* space = spaces.next();
7042 space != NULL;
7043 space = spaces.next()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007044 holes_size += space->Waste() + space->Available();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007045 }
7046 return holes_size;
7047}
7048
7049
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007050GCTracer::GCTracer(Heap* heap,
7051 const char* gc_reason,
7052 const char* collector_reason)
kasper.lund7276f142008-07-30 08:49:36 +00007053 : start_time_(0.0),
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007054 start_object_size_(0),
7055 start_memory_size_(0),
kasper.lund7276f142008-07-30 08:49:36 +00007056 gc_count_(0),
7057 full_gc_count_(0),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007058 allocated_since_last_gc_(0),
7059 spent_in_mutator_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007060 promoted_objects_size_(0),
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007061 heap_(heap),
7062 gc_reason_(gc_reason),
7063 collector_reason_(collector_reason) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007064 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
kasper.lund7276f142008-07-30 08:49:36 +00007065 start_time_ = OS::TimeCurrentMillis();
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007066 start_object_size_ = heap_->SizeOfObjects();
7067 start_memory_size_ = heap_->isolate()->memory_allocator()->Size();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007068
7069 for (int i = 0; i < Scope::kNumberOfScopes; i++) {
7070 scopes_[i] = 0;
7071 }
7072
7073 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize();
7074
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007075 allocated_since_last_gc_ =
7076 heap_->SizeOfObjects() - heap_->alive_after_last_gc_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007077
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007078 if (heap_->last_gc_end_timestamp_ > 0) {
7079 spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007080 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007081
7082 steps_count_ = heap_->incremental_marking()->steps_count();
7083 steps_took_ = heap_->incremental_marking()->steps_took();
7084 longest_step_ = heap_->incremental_marking()->longest_step();
7085 steps_count_since_last_gc_ =
7086 heap_->incremental_marking()->steps_count_since_last_gc();
7087 steps_took_since_last_gc_ =
7088 heap_->incremental_marking()->steps_took_since_last_gc();
kasper.lund7276f142008-07-30 08:49:36 +00007089}
7090
7091
7092GCTracer::~GCTracer() {
kasper.lund7276f142008-07-30 08:49:36 +00007093 // Printf ONE line iff flag is set.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007094 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
7095
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007096 bool first_gc = (heap_->last_gc_end_timestamp_ == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007097
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007098 heap_->alive_after_last_gc_ = heap_->SizeOfObjects();
7099 heap_->last_gc_end_timestamp_ = OS::TimeCurrentMillis();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007101 int time = static_cast<int>(heap_->last_gc_end_timestamp_ - start_time_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007102
7103 // Update cumulative GC statistics if required.
7104 if (FLAG_print_cumulative_gc_stat) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007105 heap_->total_gc_time_ms_ += time;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007106 heap_->max_gc_pause_ = Max(heap_->max_gc_pause_, time);
7107 heap_->max_alive_after_gc_ = Max(heap_->max_alive_after_gc_,
7108 heap_->alive_after_last_gc_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007109 if (!first_gc) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007110 heap_->min_in_mutator_ = Min(heap_->min_in_mutator_,
7111 static_cast<int>(spent_in_mutator_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007112 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007113 } else if (FLAG_trace_gc_verbose) {
7114 heap_->total_gc_time_ms_ += time;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007115 }
7116
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007117 if (collector_ == SCAVENGER && FLAG_trace_gc_ignore_scavenger) return;
7118
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00007119 PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init());
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007120
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007121 if (!FLAG_trace_gc_nvp) {
7122 int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]);
7123
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007124 double end_memory_size_mb =
7125 static_cast<double>(heap_->isolate()->memory_allocator()->Size()) / MB;
7126
7127 PrintF("%s %.1f (%.1f) -> %.1f (%.1f) MB, ",
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007128 CollectorString(),
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007129 static_cast<double>(start_object_size_) / MB,
7130 static_cast<double>(start_memory_size_) / MB,
7131 SizeOfHeapObjects(),
7132 end_memory_size_mb);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007133
7134 if (external_time > 0) PrintF("%d / ", external_time);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007135 PrintF("%d ms", time);
7136 if (steps_count_ > 0) {
7137 if (collector_ == SCAVENGER) {
7138 PrintF(" (+ %d ms in %d steps since last GC)",
7139 static_cast<int>(steps_took_since_last_gc_),
7140 steps_count_since_last_gc_);
7141 } else {
7142 PrintF(" (+ %d ms in %d steps since start of marking, "
7143 "biggest step %f ms)",
7144 static_cast<int>(steps_took_),
7145 steps_count_,
7146 longest_step_);
7147 }
7148 }
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007149
7150 if (gc_reason_ != NULL) {
7151 PrintF(" [%s]", gc_reason_);
7152 }
7153
7154 if (collector_reason_ != NULL) {
7155 PrintF(" [%s]", collector_reason_);
7156 }
7157
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007158 PrintF(".\n");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007159 } else {
7160 PrintF("pause=%d ", time);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007161 PrintF("mutator=%d ", static_cast<int>(spent_in_mutator_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007162 PrintF("gc=");
7163 switch (collector_) {
7164 case SCAVENGER:
7165 PrintF("s");
7166 break;
7167 case MARK_COMPACTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007168 PrintF("ms");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007169 break;
7170 default:
7171 UNREACHABLE();
7172 }
7173 PrintF(" ");
7174
7175 PrintF("external=%d ", static_cast<int>(scopes_[Scope::EXTERNAL]));
7176 PrintF("mark=%d ", static_cast<int>(scopes_[Scope::MC_MARK]));
7177 PrintF("sweep=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP]));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007178 PrintF("sweepns=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP_NEWSPACE]));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00007179 PrintF("evacuate=%d ", static_cast<int>(scopes_[Scope::MC_EVACUATE_PAGES]));
7180 PrintF("new_new=%d ",
7181 static_cast<int>(scopes_[Scope::MC_UPDATE_NEW_TO_NEW_POINTERS]));
7182 PrintF("root_new=%d ",
7183 static_cast<int>(scopes_[Scope::MC_UPDATE_ROOT_TO_NEW_POINTERS]));
7184 PrintF("old_new=%d ",
7185 static_cast<int>(scopes_[Scope::MC_UPDATE_OLD_TO_NEW_POINTERS]));
7186 PrintF("compaction_ptrs=%d ",
7187 static_cast<int>(scopes_[Scope::MC_UPDATE_POINTERS_TO_EVACUATED]));
7188 PrintF("intracompaction_ptrs=%d ", static_cast<int>(scopes_[
7189 Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED]));
7190 PrintF("misc_compaction=%d ",
7191 static_cast<int>(scopes_[Scope::MC_UPDATE_MISC_POINTERS]));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007192
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007193 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_object_size_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007194 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007195 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ",
7196 in_free_list_or_wasted_before_gc_);
7197 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007198
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007199 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_);
7200 PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007201
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007202 if (collector_ == SCAVENGER) {
7203 PrintF("stepscount=%d ", steps_count_since_last_gc_);
7204 PrintF("stepstook=%d ", static_cast<int>(steps_took_since_last_gc_));
7205 } else {
7206 PrintF("stepscount=%d ", steps_count_);
7207 PrintF("stepstook=%d ", static_cast<int>(steps_took_));
7208 }
7209
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007210 PrintF("\n");
7211 }
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007212
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007213 heap_->PrintShortHeapStatistics();
kasper.lund7276f142008-07-30 08:49:36 +00007214}
7215
7216
7217const char* GCTracer::CollectorString() {
7218 switch (collector_) {
7219 case SCAVENGER:
7220 return "Scavenge";
7221 case MARK_COMPACTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007222 return "Mark-sweep";
kasper.lund7276f142008-07-30 08:49:36 +00007223 }
7224 return "Unknown GC";
7225}
7226
7227
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007228int KeyedLookupCache::Hash(Map* map, String* name) {
7229 // Uses only lower 32 bits if pointers are larger.
7230 uintptr_t addr_hash =
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007231 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00007232 return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007233}
7234
7235
7236int KeyedLookupCache::Lookup(Map* map, String* name) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007237 int index = (Hash(map, name) & kHashMask);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007238 for (int i = 0; i < kEntriesPerBucket; i++) {
7239 Key& key = keys_[index + i];
7240 if ((key.map == map) && key.name->Equals(name)) {
7241 return field_offsets_[index + i];
7242 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007243 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007244 return kNotFound;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007245}
7246
7247
7248void KeyedLookupCache::Update(Map* map, String* name, int field_offset) {
7249 String* symbol;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007250 if (HEAP->LookupSymbolIfExists(name, &symbol)) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007251 int index = (Hash(map, symbol) & kHashMask);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007252 // After a GC there will be free slots, so we use them in order (this may
7253 // help to get the most frequently used one in position 0).
7254 for (int i = 0; i< kEntriesPerBucket; i++) {
7255 Key& key = keys_[index];
7256 Object* free_entry_indicator = NULL;
7257 if (key.map == free_entry_indicator) {
7258 key.map = map;
7259 key.name = symbol;
7260 field_offsets_[index + i] = field_offset;
7261 return;
7262 }
7263 }
7264 // No free entry found in this bucket, so we move them all down one and
7265 // put the new entry at position zero.
7266 for (int i = kEntriesPerBucket - 1; i > 0; i--) {
7267 Key& key = keys_[index + i];
7268 Key& key2 = keys_[index + i - 1];
7269 key = key2;
7270 field_offsets_[index + i] = field_offsets_[index + i - 1];
7271 }
7272
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007273 // Write the new first entry.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007274 Key& key = keys_[index];
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007275 key.map = map;
7276 key.name = symbol;
7277 field_offsets_[index] = field_offset;
7278 }
7279}
7280
7281
7282void KeyedLookupCache::Clear() {
7283 for (int index = 0; index < kLength; index++) keys_[index].map = NULL;
7284}
7285
7286
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007287void DescriptorLookupCache::Clear() {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007288 for (int index = 0; index < kLength; index++) keys_[index].source = NULL;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007289}
7290
7291
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007292#ifdef DEBUG
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007293void Heap::GarbageCollectionGreedyCheck() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007294 ASSERT(FLAG_gc_greedy);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007295 if (isolate_->bootstrapper()->IsActive()) return;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007296 if (disallow_allocation_failure()) return;
7297 CollectGarbage(NEW_SPACE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007298}
7299#endif
7300
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007301
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007302TranscendentalCache::SubCache::SubCache(Type t)
7303 : type_(t),
7304 isolate_(Isolate::Current()) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007305 uint32_t in0 = 0xffffffffu; // Bit-pattern for a NaN that isn't
7306 uint32_t in1 = 0xffffffffu; // generated by the FPU.
7307 for (int i = 0; i < kCacheSize; i++) {
7308 elements_[i].in[0] = in0;
7309 elements_[i].in[1] = in1;
7310 elements_[i].output = NULL;
7311 }
7312}
7313
7314
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007315void TranscendentalCache::Clear() {
7316 for (int i = 0; i < kNumberOfCaches; i++) {
7317 if (caches_[i] != NULL) {
7318 delete caches_[i];
7319 caches_[i] = NULL;
7320 }
7321 }
7322}
7323
7324
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007325void ExternalStringTable::CleanUp() {
7326 int last = 0;
7327 for (int i = 0; i < new_space_strings_.length(); ++i) {
danno@chromium.org72204d52012-10-31 10:02:10 +00007328 if (new_space_strings_[i] == heap_->the_hole_value()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007329 continue;
7330 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007331 if (heap_->InNewSpace(new_space_strings_[i])) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007332 new_space_strings_[last++] = new_space_strings_[i];
7333 } else {
7334 old_space_strings_.Add(new_space_strings_[i]);
7335 }
7336 }
7337 new_space_strings_.Rewind(last);
7338 last = 0;
7339 for (int i = 0; i < old_space_strings_.length(); ++i) {
danno@chromium.org72204d52012-10-31 10:02:10 +00007340 if (old_space_strings_[i] == heap_->the_hole_value()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007341 continue;
7342 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007343 ASSERT(!heap_->InNewSpace(old_space_strings_[i]));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007344 old_space_strings_[last++] = old_space_strings_[i];
7345 }
7346 old_space_strings_.Rewind(last);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007347#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007348 if (FLAG_verify_heap) {
7349 Verify();
7350 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007351#endif
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007352}
7353
7354
7355void ExternalStringTable::TearDown() {
7356 new_space_strings_.Free();
7357 old_space_strings_.Free();
7358}
7359
7360
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007361void Heap::QueueMemoryChunkForFree(MemoryChunk* chunk) {
7362 chunk->set_next_chunk(chunks_queued_for_free_);
7363 chunks_queued_for_free_ = chunk;
7364}
7365
7366
7367void Heap::FreeQueuedChunks() {
7368 if (chunks_queued_for_free_ == NULL) return;
7369 MemoryChunk* next;
7370 MemoryChunk* chunk;
7371 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
7372 next = chunk->next_chunk();
7373 chunk->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
7374
7375 if (chunk->owner()->identity() == LO_SPACE) {
7376 // StoreBuffer::Filter relies on MemoryChunk::FromAnyPointerAddress.
7377 // If FromAnyPointerAddress encounters a slot that belongs to a large
7378 // chunk queued for deletion it will fail to find the chunk because
7379 // it try to perform a search in the list of pages owned by of the large
7380 // object space and queued chunks were detached from that list.
7381 // To work around this we split large chunk into normal kPageSize aligned
danno@chromium.org2c456792011-11-11 12:00:53 +00007382 // pieces and initialize size, owner and flags field of every piece.
7383 // If FromAnyPointerAddress encounters a slot that belongs to one of
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007384 // these smaller pieces it will treat it as a slot on a normal Page.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007385 Address chunk_end = chunk->address() + chunk->size();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007386 MemoryChunk* inner = MemoryChunk::FromAddress(
7387 chunk->address() + Page::kPageSize);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007388 MemoryChunk* inner_last = MemoryChunk::FromAddress(chunk_end - 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007389 while (inner <= inner_last) {
7390 // Size of a large chunk is always a multiple of
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007391 // OS::AllocateAlignment() so there is always
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007392 // enough space for a fake MemoryChunk header.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007393 Address area_end = Min(inner->address() + Page::kPageSize, chunk_end);
7394 // Guard against overflow.
7395 if (area_end < inner->address()) area_end = chunk_end;
7396 inner->SetArea(inner->address(), area_end);
danno@chromium.org2c456792011-11-11 12:00:53 +00007397 inner->set_size(Page::kPageSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007398 inner->set_owner(lo_space());
7399 inner->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
7400 inner = MemoryChunk::FromAddress(
7401 inner->address() + Page::kPageSize);
7402 }
7403 }
7404 }
7405 isolate_->heap()->store_buffer()->Compact();
7406 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED);
7407 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
7408 next = chunk->next_chunk();
7409 isolate_->memory_allocator()->Free(chunk);
7410 }
7411 chunks_queued_for_free_ = NULL;
7412}
7413
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00007414
7415void Heap::RememberUnmappedPage(Address page, bool compacted) {
7416 uintptr_t p = reinterpret_cast<uintptr_t>(page);
7417 // Tag the page pointer to make it findable in the dump file.
7418 if (compacted) {
7419 p ^= 0xc1ead & (Page::kPageSize - 1); // Cleared.
7420 } else {
7421 p ^= 0x1d1ed & (Page::kPageSize - 1); // I died.
7422 }
7423 remembered_unmapped_pages_[remembered_unmapped_pages_index_] =
7424 reinterpret_cast<Address>(p);
7425 remembered_unmapped_pages_index_++;
7426 remembered_unmapped_pages_index_ %= kRememberedUnmappedPages;
7427}
7428
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00007429
7430void Heap::ClearObjectStats(bool clear_last_time_stats) {
7431 memset(object_counts_, 0, sizeof(object_counts_));
7432 memset(object_sizes_, 0, sizeof(object_sizes_));
7433 if (clear_last_time_stats) {
7434 memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_));
7435 memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_));
7436 }
7437}
7438
7439
7440static LazyMutex checkpoint_object_stats_mutex = LAZY_MUTEX_INITIALIZER;
7441
7442
7443void Heap::CheckpointObjectStats() {
7444 ScopedLock lock(checkpoint_object_stats_mutex.Pointer());
7445 Counters* counters = isolate()->counters();
7446#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7447 counters->count_of_##name()->Increment( \
7448 static_cast<int>(object_counts_[name])); \
7449 counters->count_of_##name()->Decrement( \
7450 static_cast<int>(object_counts_last_time_[name])); \
7451 counters->size_of_##name()->Increment( \
7452 static_cast<int>(object_sizes_[name])); \
7453 counters->size_of_##name()->Decrement( \
7454 static_cast<int>(object_sizes_last_time_[name]));
7455 INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7456#undef ADJUST_LAST_TIME_OBJECT_COUNT
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007457 int index;
7458#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7459 index = FIRST_CODE_KIND_SUB_TYPE + Code::name; \
7460 counters->count_of_CODE_TYPE_##name()->Increment( \
7461 static_cast<int>(object_counts_[index])); \
7462 counters->count_of_CODE_TYPE_##name()->Decrement( \
7463 static_cast<int>(object_counts_last_time_[index])); \
7464 counters->size_of_CODE_TYPE_##name()->Increment( \
7465 static_cast<int>(object_sizes_[index])); \
7466 counters->size_of_CODE_TYPE_##name()->Decrement( \
7467 static_cast<int>(object_sizes_last_time_[index]));
7468 CODE_KIND_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7469#undef ADJUST_LAST_TIME_OBJECT_COUNT
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007470#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7471 index = FIRST_FIXED_ARRAY_SUB_TYPE + name; \
7472 counters->count_of_FIXED_ARRAY_##name()->Increment( \
7473 static_cast<int>(object_counts_[index])); \
7474 counters->count_of_FIXED_ARRAY_##name()->Decrement( \
7475 static_cast<int>(object_counts_last_time_[index])); \
7476 counters->size_of_FIXED_ARRAY_##name()->Increment( \
7477 static_cast<int>(object_sizes_[index])); \
7478 counters->size_of_FIXED_ARRAY_##name()->Decrement( \
7479 static_cast<int>(object_sizes_last_time_[index]));
7480 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7481#undef ADJUST_LAST_TIME_OBJECT_COUNT
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007482
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00007483 memcpy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
7484 memcpy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
7485 ClearObjectStats();
7486}
7487
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007488} } // namespace v8::internal