blob: ec98ca5267aa3f113f33b47ed83ff8b553c9d015 [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),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000120#endif // DEBUG
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000121 new_space_high_promotion_mode_active_(false),
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000122 old_gen_promotion_limit_(kMinimumPromotionLimit),
123 old_gen_allocation_limit_(kMinimumAllocationLimit),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000124 old_gen_limit_factor_(1),
125 size_of_old_gen_at_last_old_space_gc_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 external_allocation_limit_(0),
127 amount_of_external_allocated_memory_(0),
128 amount_of_external_allocated_memory_at_last_global_gc_(0),
129 old_gen_exhausted_(false),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000130 store_buffer_rebuilder_(store_buffer()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000131 hidden_symbol_(NULL),
132 global_gc_prologue_callback_(NULL),
133 global_gc_epilogue_callback_(NULL),
134 gc_safe_size_of_old_object_(NULL),
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000135 total_regexp_code_generated_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000136 tracer_(NULL),
137 young_survivors_after_last_gc_(0),
138 high_survival_rate_period_length_(0),
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000139 low_survival_rate_period_length_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000140 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
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000553
554 error_object_list_.DeferredFormatStackTrace(isolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000555}
556
557
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000558void Heap::CollectAllGarbage(int flags, const char* gc_reason) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000559 // Since we are ignoring the return value, the exact choice of space does
560 // not matter, so long as we do not specify NEW_SPACE, which would not
561 // cause a full GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000562 mark_compact_collector_.SetFlags(flags);
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000563 CollectGarbage(OLD_POINTER_SPACE, gc_reason);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000564 mark_compact_collector_.SetFlags(kNoGCFlags);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000565}
566
567
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000568void Heap::CollectAllAvailableGarbage(const char* gc_reason) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000569 // Since we are ignoring the return value, the exact choice of space does
570 // not matter, so long as we do not specify NEW_SPACE, which would not
571 // cause a full GC.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000572 // Major GC would invoke weak handle callbacks on weakly reachable
573 // handles, but won't collect weakly reachable objects until next
574 // major GC. Therefore if we collect aggressively and weak handle callback
575 // has been invoked, we rerun major GC to release objects which become
576 // garbage.
577 // Note: as weak callbacks can execute arbitrary code, we cannot
578 // hope that eventually there will be no weak callbacks invocations.
579 // Therefore stop recollecting after several attempts.
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000580 mark_compact_collector()->SetFlags(kMakeHeapIterableMask |
581 kReduceMemoryFootprintMask);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000582 isolate_->compilation_cache()->Clear();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000583 const int kMaxNumberOfAttempts = 7;
584 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000585 if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR, gc_reason, NULL)) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000586 break;
587 }
588 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000589 mark_compact_collector()->SetFlags(kNoGCFlags);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000590 new_space_.Shrink();
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000591 UncommitFromSpace();
592 Shrink();
danno@chromium.orgc612e022011-11-10 11:38:15 +0000593 incremental_marking()->UncommitMarkingDeque();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000594}
595
596
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000597bool Heap::CollectGarbage(AllocationSpace space,
598 GarbageCollector collector,
599 const char* gc_reason,
600 const char* collector_reason) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000601 // The VM is in the GC state until exiting this function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 VMState state(isolate_, GC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000603
604#ifdef DEBUG
605 // Reset the allocation timeout to the GC interval, but make sure to
606 // allow at least a few allocations after a collection. The reason
607 // for this is that we have a lot of allocation sequences and we
608 // assume that a garbage collection will allow the subsequent
609 // allocation attempts to go through.
610 allocation_timeout_ = Max(6, FLAG_gc_interval);
611#endif
612
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000613 if (collector == SCAVENGER && !incremental_marking()->IsStopped()) {
614 if (FLAG_trace_incremental_marking) {
615 PrintF("[IncrementalMarking] Scavenge during marking.\n");
616 }
617 }
618
619 if (collector == MARK_COMPACTOR &&
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000620 !mark_compact_collector()->abort_incremental_marking() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000621 !incremental_marking()->IsStopped() &&
622 !incremental_marking()->should_hurry() &&
623 FLAG_incremental_marking_steps) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000624 // Make progress in incremental marking.
625 const intptr_t kStepSizeWhenDelayedByScavenge = 1 * MB;
626 incremental_marking()->Step(kStepSizeWhenDelayedByScavenge,
627 IncrementalMarking::NO_GC_VIA_STACK_GUARD);
628 if (!incremental_marking()->IsComplete()) {
629 if (FLAG_trace_incremental_marking) {
630 PrintF("[IncrementalMarking] Delaying MarkSweep.\n");
631 }
632 collector = SCAVENGER;
633 collector_reason = "incremental marking delaying mark-sweep";
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000634 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000635 }
636
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000637 bool next_gc_likely_to_collect_more = false;
638
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000639 { GCTracer tracer(this, gc_reason, collector_reason);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640 GarbageCollectionPrologue();
kasper.lund7276f142008-07-30 08:49:36 +0000641 // The GC count was incremented in the prologue. Tell the tracer about
642 // it.
643 tracer.set_gc_count(gc_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000644
kasper.lund7276f142008-07-30 08:49:36 +0000645 // Tell the tracer which collector we've selected.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000646 tracer.set_collector(collector);
647
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000648 {
649 HistogramTimerScope histogram_timer_scope(
650 (collector == SCAVENGER) ? isolate_->counters()->gc_scavenger()
651 : isolate_->counters()->gc_compactor());
652 next_gc_likely_to_collect_more =
653 PerformGarbageCollection(collector, &tracer);
654 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000655
656 GarbageCollectionEpilogue();
657 }
658
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000659 // Start incremental marking for the next cycle. The heap snapshot
660 // generator needs incremental marking to stay off after it aborted.
661 if (!mark_compact_collector()->abort_incremental_marking() &&
662 incremental_marking()->IsStopped() &&
663 incremental_marking()->WorthActivating() &&
664 NextGCIsLikelyToBeFull()) {
665 incremental_marking()->Start();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000666 }
667
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000668 return next_gc_likely_to_collect_more;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000669}
670
671
kasper.lund7276f142008-07-30 08:49:36 +0000672void Heap::PerformScavenge() {
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000673 GCTracer tracer(this, NULL, NULL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000674 if (incremental_marking()->IsStopped()) {
675 PerformGarbageCollection(SCAVENGER, &tracer);
676 } else {
677 PerformGarbageCollection(MARK_COMPACTOR, &tracer);
678 }
kasper.lund7276f142008-07-30 08:49:36 +0000679}
680
681
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000682#ifdef VERIFY_HEAP
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000683// Helper class for verifying the symbol table.
684class SymbolTableVerifier : public ObjectVisitor {
685 public:
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000686 void VisitPointers(Object** start, Object** end) {
687 // Visit all HeapObject pointers in [start, end).
688 for (Object** p = start; p < end; p++) {
689 if ((*p)->IsHeapObject()) {
690 // Check that the symbol is actually a symbol.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000691 CHECK((*p)->IsTheHole() || (*p)->IsUndefined() || (*p)->IsSymbol());
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000692 }
693 }
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000694 }
695};
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000696
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000697
698static void VerifySymbolTable() {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000699 SymbolTableVerifier verifier;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000700 HEAP->symbol_table()->IterateElements(&verifier);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000701}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000702#endif // VERIFY_HEAP
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000703
704
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000705static bool AbortIncrementalMarkingAndCollectGarbage(
706 Heap* heap,
707 AllocationSpace space,
708 const char* gc_reason = NULL) {
709 heap->mark_compact_collector()->SetFlags(Heap::kAbortIncrementalMarkingMask);
710 bool result = heap->CollectGarbage(space, gc_reason);
711 heap->mark_compact_collector()->SetFlags(Heap::kNoGCFlags);
712 return result;
713}
714
715
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000716void Heap::ReserveSpace(
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000717 int *sizes,
718 Address *locations_out) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000719 bool gc_performed = true;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000720 int counter = 0;
721 static const int kThreshold = 20;
722 while (gc_performed && counter++ < kThreshold) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000723 gc_performed = false;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000724 ASSERT(NEW_SPACE == FIRST_PAGED_SPACE - 1);
725 for (int space = NEW_SPACE; space <= LAST_PAGED_SPACE; space++) {
726 if (sizes[space] != 0) {
727 MaybeObject* allocation;
728 if (space == NEW_SPACE) {
729 allocation = new_space()->AllocateRaw(sizes[space]);
730 } else {
731 allocation = paged_space(space)->AllocateRaw(sizes[space]);
732 }
733 FreeListNode* node;
734 if (!allocation->To<FreeListNode>(&node)) {
735 if (space == NEW_SPACE) {
736 Heap::CollectGarbage(NEW_SPACE,
737 "failed to reserve space in the new space");
738 } else {
739 AbortIncrementalMarkingAndCollectGarbage(
740 this,
741 static_cast<AllocationSpace>(space),
742 "failed to reserve space in paged space");
743 }
744 gc_performed = true;
745 break;
746 } else {
747 // Mark with a free list node, in case we have a GC before
748 // deserializing.
749 node->set_size(this, sizes[space]);
750 locations_out[space] = node->address();
751 }
752 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000753 }
754 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000755
756 if (gc_performed) {
757 // Failed to reserve the space after several attempts.
758 V8::FatalProcessOutOfMemory("Heap::ReserveSpace");
759 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000760}
761
762
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000763void Heap::EnsureFromSpaceIsCommitted() {
764 if (new_space_.CommitFromSpaceIfNeeded()) return;
765
766 // Committing memory to from space failed.
767 // Try shrinking and try again.
768 Shrink();
769 if (new_space_.CommitFromSpaceIfNeeded()) return;
770
771 // Committing memory to from space failed again.
772 // Memory is exhausted and we will die.
773 V8::FatalProcessOutOfMemory("Committing semi space failed.");
774}
775
776
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000777void Heap::ClearJSFunctionResultCaches() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000778 if (isolate_->bootstrapper()->IsActive()) return;
ager@chromium.orgac091b72010-05-05 07:34:42 +0000779
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000780 Object* context = native_contexts_list_;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000781 while (!context->IsUndefined()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000782 // Get the caches for this context. GC can happen when the context
783 // is not fully initialized, so the caches can be undefined.
784 Object* caches_or_undefined =
785 Context::cast(context)->get(Context::JSFUNCTION_RESULT_CACHES_INDEX);
786 if (!caches_or_undefined->IsUndefined()) {
787 FixedArray* caches = FixedArray::cast(caches_or_undefined);
788 // Clear the caches:
789 int length = caches->length();
790 for (int i = 0; i < length; i++) {
791 JSFunctionResultCache::cast(caches->get(i))->Clear();
792 }
ager@chromium.orgac091b72010-05-05 07:34:42 +0000793 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000794 // Get the next context:
795 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000796 }
ager@chromium.orgac091b72010-05-05 07:34:42 +0000797}
798
799
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000800
ricow@chromium.org65fae842010-08-25 15:26:24 +0000801void Heap::ClearNormalizedMapCaches() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000802 if (isolate_->bootstrapper()->IsActive() &&
803 !incremental_marking()->IsMarking()) {
804 return;
805 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000806
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000807 Object* context = native_contexts_list_;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000808 while (!context->IsUndefined()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000809 // GC can happen when the context is not fully initialized,
810 // so the cache can be undefined.
811 Object* cache =
812 Context::cast(context)->get(Context::NORMALIZED_MAP_CACHE_INDEX);
813 if (!cache->IsUndefined()) {
814 NormalizedMapCache::cast(cache)->Clear();
815 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000816 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
817 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000818}
819
820
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000821void Heap::UpdateSurvivalRateTrend(int start_new_space_size) {
822 double survival_rate =
823 (static_cast<double>(young_survivors_after_last_gc_) * 100) /
824 start_new_space_size;
825
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000826 if (survival_rate > kYoungSurvivalRateHighThreshold) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000827 high_survival_rate_period_length_++;
828 } else {
829 high_survival_rate_period_length_ = 0;
830 }
831
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000832 if (survival_rate < kYoungSurvivalRateLowThreshold) {
833 low_survival_rate_period_length_++;
834 } else {
835 low_survival_rate_period_length_ = 0;
836 }
837
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000838 double survival_rate_diff = survival_rate_ - survival_rate;
839
840 if (survival_rate_diff > kYoungSurvivalRateAllowedDeviation) {
841 set_survival_rate_trend(DECREASING);
842 } else if (survival_rate_diff < -kYoungSurvivalRateAllowedDeviation) {
843 set_survival_rate_trend(INCREASING);
844 } else {
845 set_survival_rate_trend(STABLE);
846 }
847
848 survival_rate_ = survival_rate;
849}
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000850
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000851bool Heap::PerformGarbageCollection(GarbageCollector collector,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000852 GCTracer* tracer) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000853 bool next_gc_likely_to_collect_more = false;
854
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000855 if (collector != SCAVENGER) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000856 PROFILE(isolate_, CodeMovingGCEvent());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000857 }
858
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000859#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000860 if (FLAG_verify_heap) {
861 VerifySymbolTable();
862 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000863#endif
864
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000865 if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) {
866 ASSERT(!allocation_allowed_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000867 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000868 global_gc_prologue_callback_();
869 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000870
871 GCType gc_type =
872 collector == MARK_COMPACTOR ? kGCTypeMarkSweepCompact : kGCTypeScavenge;
873
874 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
875 if (gc_type & gc_prologue_callbacks_[i].gc_type) {
876 gc_prologue_callbacks_[i].callback(gc_type, kNoGCCallbackFlags);
877 }
878 }
879
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000880 EnsureFromSpaceIsCommitted();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000881
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000882 int start_new_space_size = Heap::new_space()->SizeAsInt();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000883
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000884 if (IsHighSurvivalRate()) {
885 // We speed up the incremental marker if it is running so that it
886 // does not fall behind the rate of promotion, which would cause a
887 // constantly growing old space.
888 incremental_marking()->NotifyOfHighPromotionRate();
889 }
890
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891 if (collector == MARK_COMPACTOR) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000892 // Perform mark-sweep with optional compaction.
kasper.lund7276f142008-07-30 08:49:36 +0000893 MarkCompact(tracer);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000894 sweep_generation_++;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000895 bool high_survival_rate_during_scavenges = IsHighSurvivalRate() &&
896 IsStableOrIncreasingSurvivalTrend();
897
898 UpdateSurvivalRateTrend(start_new_space_size);
899
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000900 size_of_old_gen_at_last_old_space_gc_ = PromotedSpaceSizeOfObjects();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000901
lrn@chromium.org303ada72010-10-27 09:33:13 +0000902 if (high_survival_rate_during_scavenges &&
903 IsStableOrIncreasingSurvivalTrend()) {
904 // Stable high survival rates of young objects both during partial and
905 // full collection indicate that mutator is either building or modifying
906 // a structure with a long lifetime.
907 // In this case we aggressively raise old generation memory limits to
908 // postpone subsequent mark-sweep collection and thus trade memory
909 // space for the mutation speed.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000910 old_gen_limit_factor_ = 2;
911 } else {
912 old_gen_limit_factor_ = 1;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000913 }
914
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000915 old_gen_promotion_limit_ =
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000916 OldGenPromotionLimit(size_of_old_gen_at_last_old_space_gc_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000917 old_gen_allocation_limit_ =
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000918 OldGenAllocationLimit(size_of_old_gen_at_last_old_space_gc_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000919
lrn@chromium.org303ada72010-10-27 09:33:13 +0000920 old_gen_exhausted_ = false;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000921 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000922 tracer_ = tracer;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000923 Scavenge();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000924 tracer_ = NULL;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000925
926 UpdateSurvivalRateTrend(start_new_space_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000927 }
ager@chromium.org439e85a2009-08-26 13:15:29 +0000928
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000929 if (!new_space_high_promotion_mode_active_ &&
930 new_space_.Capacity() == new_space_.MaximumCapacity() &&
931 IsStableOrIncreasingSurvivalTrend() &&
932 IsHighSurvivalRate()) {
933 // Stable high survival rates even though young generation is at
934 // maximum capacity indicates that most objects will be promoted.
935 // To decrease scavenger pauses and final mark-sweep pauses, we
936 // have to limit maximal capacity of the young generation.
937 new_space_high_promotion_mode_active_ = true;
938 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000939 PrintPID("Limited new space size due to high promotion rate: %d MB\n",
940 new_space_.InitialCapacity() / MB);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000941 }
942 } else if (new_space_high_promotion_mode_active_ &&
943 IsStableOrDecreasingSurvivalTrend() &&
944 IsLowSurvivalRate()) {
945 // Decreasing low survival rates might indicate that the above high
946 // promotion mode is over and we should allow the young generation
947 // to grow again.
948 new_space_high_promotion_mode_active_ = false;
949 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000950 PrintPID("Unlimited new space size due to low promotion rate: %d MB\n",
951 new_space_.MaximumCapacity() / MB);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000952 }
953 }
954
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000955 if (new_space_high_promotion_mode_active_ &&
956 new_space_.Capacity() > new_space_.InitialCapacity()) {
957 new_space_.Shrink();
958 }
959
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000960 isolate_->counters()->objs_since_last_young()->Set(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000961
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000962 // Callbacks that fire after this point might trigger nested GCs and
963 // restart incremental marking, the assertion can't be moved down.
964 ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped());
965
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000966 gc_post_processing_depth_++;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000967 { DisableAssertNoAllocation allow_allocation;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000968 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000969 next_gc_likely_to_collect_more =
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000970 isolate_->global_handles()->PostGarbageCollectionProcessing(
971 collector, tracer);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000972 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000973 gc_post_processing_depth_--;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000974
ager@chromium.org3811b432009-10-28 14:53:37 +0000975 // Update relocatables.
976 Relocatable::PostGarbageCollectionProcessing();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000977
kasper.lund7276f142008-07-30 08:49:36 +0000978 if (collector == MARK_COMPACTOR) {
979 // Register the amount of external allocated memory.
980 amount_of_external_allocated_memory_at_last_global_gc_ =
981 amount_of_external_allocated_memory_;
982 }
983
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000984 GCCallbackFlags callback_flags = kNoGCCallbackFlags;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000985 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
986 if (gc_type & gc_epilogue_callbacks_[i].gc_type) {
987 gc_epilogue_callbacks_[i].callback(gc_type, callback_flags);
988 }
989 }
990
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991 if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) {
992 ASSERT(!allocation_allowed_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000993 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000994 global_gc_epilogue_callback_();
995 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000996
997#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000998 if (FLAG_verify_heap) {
999 VerifySymbolTable();
1000 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001001#endif
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001002
1003 return next_gc_likely_to_collect_more;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001004}
1005
1006
kasper.lund7276f142008-07-30 08:49:36 +00001007void Heap::MarkCompact(GCTracer* tracer) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001008 gc_state_ = MARK_COMPACT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001009 LOG(isolate_, ResourceEvent("markcompact", "begin"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001011 mark_compact_collector_.Prepare(tracer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001013 ms_count_++;
1014 tracer->set_full_gc_count(ms_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001016 MarkCompactPrologue();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001018 mark_compact_collector_.CollectGarbage();
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001019
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001020 LOG(isolate_, ResourceEvent("markcompact", "end"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001021
1022 gc_state_ = NOT_IN_GC;
1023
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001024 isolate_->counters()->objs_since_last_full()->Set(0);
kasperl@chromium.org8b2bb262010-03-01 09:46:28 +00001025
1026 contexts_disposed_ = 0;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001027
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001028 flush_monomorphic_ics_ = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001029}
1030
1031
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001032void Heap::MarkCompactPrologue() {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001033 // At any old GC clear the keyed lookup cache to enable collection of unused
1034 // maps.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035 isolate_->keyed_lookup_cache()->Clear();
1036 isolate_->context_slot_cache()->Clear();
1037 isolate_->descriptor_lookup_cache()->Clear();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001038 RegExpResultsCache::Clear(string_split_cache());
1039 RegExpResultsCache::Clear(regexp_multiple_cache());
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001040
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001041 isolate_->compilation_cache()->MarkCompactPrologue();
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001042
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001043 CompletelyClearInstanceofCache();
1044
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001045 FlushNumberStringCache();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001046 if (FLAG_cleanup_code_caches_at_gc) {
1047 polymorphic_code_cache()->set_cache(undefined_value());
1048 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001049
1050 ClearNormalizedMapCaches();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051}
1052
1053
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001054Object* Heap::FindCodeObject(Address a) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001055 return isolate()->inner_pointer_to_code_cache()->
1056 GcSafeFindCodeForInnerPointer(a);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057}
1058
1059
1060// Helper class for copying HeapObjects
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001061class ScavengeVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001063 explicit ScavengeVisitor(Heap* heap) : heap_(heap) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001065 void VisitPointer(Object** p) { ScavengePointer(p); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001066
1067 void VisitPointers(Object** start, Object** end) {
1068 // Copy all HeapObject pointers in [start, end)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001069 for (Object** p = start; p < end; p++) ScavengePointer(p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001070 }
1071
1072 private:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001073 void ScavengePointer(Object** p) {
1074 Object* object = *p;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001075 if (!heap_->InNewSpace(object)) return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001076 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
1077 reinterpret_cast<HeapObject*>(object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001079
1080 Heap* heap_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001081};
1082
1083
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001084#ifdef VERIFY_HEAP
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001085// Visitor class to verify pointers in code or data space do not point into
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001086// new space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001087class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088 public:
1089 void VisitPointers(Object** start, Object**end) {
1090 for (Object** current = start; current < end; current++) {
1091 if ((*current)->IsHeapObject()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001092 CHECK(!HEAP->InNewSpace(HeapObject::cast(*current)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001093 }
1094 }
1095 }
1096};
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001097
1098
1099static void VerifyNonPointerSpacePointers() {
1100 // Verify that there are no pointers to new space in spaces where we
1101 // do not expect them.
1102 VerifyNonPointerSpacePointersVisitor v;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001103 HeapObjectIterator code_it(HEAP->code_space());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001104 for (HeapObject* object = code_it.Next();
1105 object != NULL; object = code_it.Next())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001106 object->Iterate(&v);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001107
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001108 // The old data space was normally swept conservatively so that the iterator
1109 // doesn't work, so we normally skip the next bit.
1110 if (!HEAP->old_data_space()->was_swept_conservatively()) {
1111 HeapObjectIterator data_it(HEAP->old_data_space());
1112 for (HeapObject* object = data_it.Next();
1113 object != NULL; object = data_it.Next())
1114 object->Iterate(&v);
1115 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001116}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001117#endif // VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001119
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001120void Heap::CheckNewSpaceExpansionCriteria() {
1121 if (new_space_.Capacity() < new_space_.MaximumCapacity() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001122 survived_since_last_expansion_ > new_space_.Capacity() &&
1123 !new_space_high_promotion_mode_active_) {
1124 // Grow the size of new space if there is room to grow, enough data
1125 // has survived scavenge since the last expansion and we are not in
1126 // high promotion mode.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001127 new_space_.Grow();
1128 survived_since_last_expansion_ = 0;
1129 }
1130}
1131
1132
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001133static bool IsUnscavengedHeapObject(Heap* heap, Object** p) {
1134 return heap->InNewSpace(*p) &&
1135 !HeapObject::cast(*p)->map_word().IsForwardingAddress();
1136}
1137
1138
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001139void Heap::ScavengeStoreBufferCallback(
1140 Heap* heap,
1141 MemoryChunk* page,
1142 StoreBufferEvent event) {
1143 heap->store_buffer_rebuilder_.Callback(page, event);
1144}
1145
1146
1147void StoreBufferRebuilder::Callback(MemoryChunk* page, StoreBufferEvent event) {
1148 if (event == kStoreBufferStartScanningPagesEvent) {
1149 start_of_current_page_ = NULL;
1150 current_page_ = NULL;
1151 } else if (event == kStoreBufferScanningPageEvent) {
1152 if (current_page_ != NULL) {
1153 // If this page already overflowed the store buffer during this iteration.
1154 if (current_page_->scan_on_scavenge()) {
1155 // Then we should wipe out the entries that have been added for it.
1156 store_buffer_->SetTop(start_of_current_page_);
1157 } else if (store_buffer_->Top() - start_of_current_page_ >=
1158 (store_buffer_->Limit() - store_buffer_->Top()) >> 2) {
1159 // Did we find too many pointers in the previous page? The heuristic is
1160 // that no page can take more then 1/5 the remaining slots in the store
1161 // buffer.
1162 current_page_->set_scan_on_scavenge(true);
1163 store_buffer_->SetTop(start_of_current_page_);
1164 } else {
1165 // In this case the page we scanned took a reasonable number of slots in
1166 // the store buffer. It has now been rehabilitated and is no longer
1167 // marked scan_on_scavenge.
1168 ASSERT(!current_page_->scan_on_scavenge());
1169 }
1170 }
1171 start_of_current_page_ = store_buffer_->Top();
1172 current_page_ = page;
1173 } else if (event == kStoreBufferFullEvent) {
1174 // The current page overflowed the store buffer again. Wipe out its entries
1175 // in the store buffer and mark it scan-on-scavenge again. This may happen
1176 // several times while scanning.
1177 if (current_page_ == NULL) {
1178 // Store Buffer overflowed while scanning promoted objects. These are not
1179 // in any particular page, though they are likely to be clustered by the
1180 // allocation routines.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001181 store_buffer_->EnsureSpace(StoreBuffer::kStoreBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001182 } else {
1183 // Store Buffer overflowed while scanning a particular old space page for
1184 // pointers to new space.
1185 ASSERT(current_page_ == page);
1186 ASSERT(page != NULL);
1187 current_page_->set_scan_on_scavenge(true);
1188 ASSERT(start_of_current_page_ != store_buffer_->Top());
1189 store_buffer_->SetTop(start_of_current_page_);
1190 }
1191 } else {
1192 UNREACHABLE();
1193 }
1194}
1195
1196
danno@chromium.orgc612e022011-11-10 11:38:15 +00001197void PromotionQueue::Initialize() {
1198 // Assumes that a NewSpacePage exactly fits a number of promotion queue
1199 // entries (where each is a pair of intptr_t). This allows us to simplify
1200 // the test fpr when to switch pages.
1201 ASSERT((Page::kPageSize - MemoryChunk::kBodyOffset) % (2 * kPointerSize)
1202 == 0);
1203 limit_ = reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceStart());
1204 front_ = rear_ =
1205 reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceEnd());
1206 emergency_stack_ = NULL;
1207 guard_ = false;
1208}
1209
1210
1211void PromotionQueue::RelocateQueueHead() {
1212 ASSERT(emergency_stack_ == NULL);
1213
1214 Page* p = Page::FromAllocationTop(reinterpret_cast<Address>(rear_));
1215 intptr_t* head_start = rear_;
1216 intptr_t* head_end =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001217 Min(front_, reinterpret_cast<intptr_t*>(p->area_end()));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001218
1219 int entries_count =
1220 static_cast<int>(head_end - head_start) / kEntrySizeInWords;
1221
1222 emergency_stack_ = new List<Entry>(2 * entries_count);
1223
1224 while (head_start != head_end) {
1225 int size = static_cast<int>(*(head_start++));
1226 HeapObject* obj = reinterpret_cast<HeapObject*>(*(head_start++));
1227 emergency_stack_->Add(Entry(obj, size));
1228 }
1229 rear_ = head_end;
1230}
1231
1232
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001233class ScavengeWeakObjectRetainer : public WeakObjectRetainer {
1234 public:
1235 explicit ScavengeWeakObjectRetainer(Heap* heap) : heap_(heap) { }
1236
1237 virtual Object* RetainAs(Object* object) {
1238 if (!heap_->InFromSpace(object)) {
1239 return object;
1240 }
1241
1242 MapWord map_word = HeapObject::cast(object)->map_word();
1243 if (map_word.IsForwardingAddress()) {
1244 return map_word.ToForwardingAddress();
1245 }
1246 return NULL;
1247 }
1248
1249 private:
1250 Heap* heap_;
1251};
1252
1253
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001254void Heap::Scavenge() {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001255 RelocationLock relocation_lock(this);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001256
1257#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001258 if (FLAG_verify_heap) VerifyNonPointerSpacePointers();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001259#endif
1260
1261 gc_state_ = SCAVENGE;
1262
1263 // Implements Cheney's copying algorithm
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001264 LOG(isolate_, ResourceEvent("scavenge", "begin"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001266 // Clear descriptor cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 isolate_->descriptor_lookup_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001268
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001269 // Used for updating survived_since_last_expansion_ at function end.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001270 intptr_t survived_watermark = PromotedSpaceSizeOfObjects();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001271
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001272 CheckNewSpaceExpansionCriteria();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001273
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001274 SelectScavengingVisitorsTable();
1275
1276 incremental_marking()->PrepareForScavenge();
1277
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001278 AdvanceSweepers(static_cast<int>(new_space_.Size()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001279
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280 // Flip the semispaces. After flipping, to space is empty, from space has
1281 // live objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001282 new_space_.Flip();
1283 new_space_.ResetAllocationInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001285 // We need to sweep newly copied objects which can be either in the
1286 // to space or promoted to the old generation. For to-space
1287 // objects, we treat the bottom of the to space as a queue. Newly
1288 // copied and unswept objects lie between a 'front' mark and the
1289 // allocation pointer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290 //
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001291 // Promoted objects can go into various old-generation spaces, and
1292 // can be allocated internally in the spaces (from the free list).
1293 // We treat the top of the to space as a queue of addresses of
1294 // promoted objects. The addresses of newly promoted and unswept
1295 // objects lie between a 'front' mark and a 'rear' mark that is
1296 // updated as a side effect of promoting an object.
1297 //
1298 // There is guaranteed to be enough room at the top of the to space
1299 // for the addresses of promoted objects: every object promoted
1300 // frees up its size in bytes from the top of the new space, and
1301 // objects are at least one pointer in size.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001302 Address new_space_front = new_space_.ToSpaceStart();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001303 promotion_queue_.Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001305#ifdef DEBUG
1306 store_buffer()->Clean();
1307#endif
1308
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001309 ScavengeVisitor scavenge_visitor(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310 // Copy roots.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001311 IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001312
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001313 // Copy objects reachable from the old generation.
1314 {
1315 StoreBufferRebuildScope scope(this,
1316 store_buffer(),
1317 &ScavengeStoreBufferCallback);
1318 store_buffer()->IteratePointersToNewSpace(&ScavengeObject);
1319 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001320
1321 // Copy objects reachable from cells by scavenging cell values directly.
1322 HeapObjectIterator cell_iterator(cell_space_);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001323 for (HeapObject* heap_object = cell_iterator.Next();
1324 heap_object != NULL;
1325 heap_object = cell_iterator.Next()) {
1326 if (heap_object->IsJSGlobalPropertyCell()) {
1327 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(heap_object);
1328 Address value_address = cell->ValueAddress();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001329 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address));
1330 }
1331 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001332
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001333 // Copy objects reachable from the code flushing candidates list.
1334 MarkCompactCollector* collector = mark_compact_collector();
1335 if (collector->is_code_flushing_enabled()) {
1336 collector->code_flusher()->IteratePointersToFromSpace(&scavenge_visitor);
1337 }
1338
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001339 // Scavenge object reachable from the native contexts list directly.
1340 scavenge_visitor.VisitPointer(BitCast<Object**>(&native_contexts_list_));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001341
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001342 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001343
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001344 while (isolate()->global_handles()->IterateObjectGroups(
1345 &scavenge_visitor, &IsUnscavengedHeapObject)) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001346 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
1347 }
1348 isolate()->global_handles()->RemoveObjectGroups();
1349
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001350 isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles(
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001351 &IsUnscavengedHeapObject);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001352 isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots(
1353 &scavenge_visitor);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001354 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
1355
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001356 UpdateNewSpaceReferencesInExternalStringTable(
1357 &UpdateNewSpaceReferenceInExternalStringTableEntry);
1358
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001359 error_object_list_.UpdateReferencesInNewSpace(this);
1360
danno@chromium.orgc612e022011-11-10 11:38:15 +00001361 promotion_queue_.Destroy();
1362
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001363 LiveObjectList::UpdateReferencesForScavengeGC();
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001364 if (!FLAG_watch_ic_patching) {
1365 isolate()->runtime_profiler()->UpdateSamplesAfterScavenge();
1366 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001367 incremental_marking()->UpdateMarkingDequeAfterScavenge();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001368
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001369 ScavengeWeakObjectRetainer weak_object_retainer(this);
1370 ProcessWeakReferences(&weak_object_retainer);
1371
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001372 ASSERT(new_space_front == new_space_.top());
1373
1374 // Set age mark.
1375 new_space_.set_age_mark(new_space_.top());
1376
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001377 new_space_.LowerInlineAllocationLimit(
1378 new_space_.inline_allocation_limit_step());
1379
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001380 // Update how much has survived scavenge.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001381 IncrementYoungSurvivorsCounter(static_cast<int>(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001382 (PromotedSpaceSizeOfObjects() - survived_watermark) + new_space_.Size()));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001383
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001384 LOG(isolate_, ResourceEvent("scavenge", "end"));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001385
1386 gc_state_ = NOT_IN_GC;
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001387
1388 scavenges_since_last_idle_round_++;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001389}
1390
1391
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001392String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
1393 Object** p) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001394 MapWord first_word = HeapObject::cast(*p)->map_word();
1395
1396 if (!first_word.IsForwardingAddress()) {
1397 // Unreachable external string can be finalized.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001398 heap->FinalizeExternalString(String::cast(*p));
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001399 return NULL;
1400 }
1401
1402 // String is still reachable.
1403 return String::cast(first_word.ToForwardingAddress());
1404}
1405
1406
1407void Heap::UpdateNewSpaceReferencesInExternalStringTable(
1408 ExternalStringTableUpdaterCallback updater_func) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001409#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001410 if (FLAG_verify_heap) {
1411 external_string_table_.Verify();
1412 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001413#endif
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001415 if (external_string_table_.new_space_strings_.is_empty()) return;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001416
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001417 Object** start = &external_string_table_.new_space_strings_[0];
1418 Object** end = start + external_string_table_.new_space_strings_.length();
1419 Object** last = start;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001420
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001421 for (Object** p = start; p < end; ++p) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001422 ASSERT(InFromSpace(*p));
1423 String* target = updater_func(this, p);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001424
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001425 if (target == NULL) continue;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001426
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001427 ASSERT(target->IsExternalString());
1428
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001429 if (InNewSpace(target)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001430 // String is still in new space. Update the table entry.
1431 *last = target;
1432 ++last;
1433 } else {
1434 // String got promoted. Move it to the old string list.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001435 external_string_table_.AddOldString(target);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001436 }
1437 }
1438
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001439 ASSERT(last <= end);
1440 external_string_table_.ShrinkNewStrings(static_cast<int>(last - start));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001441}
1442
1443
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001444void Heap::UpdateReferencesInExternalStringTable(
1445 ExternalStringTableUpdaterCallback updater_func) {
1446
1447 // Update old space string references.
1448 if (external_string_table_.old_space_strings_.length() > 0) {
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001449 Object** start = &external_string_table_.old_space_strings_[0];
1450 Object** end = start + external_string_table_.old_space_strings_.length();
1451 for (Object** p = start; p < end; ++p) *p = updater_func(this, p);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001452 }
1453
1454 UpdateNewSpaceReferencesInExternalStringTable(updater_func);
1455}
1456
1457
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001458static Object* ProcessFunctionWeakReferences(Heap* heap,
1459 Object* function,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001460 WeakObjectRetainer* retainer,
1461 bool record_slots) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001462 Object* undefined = heap->undefined_value();
1463 Object* head = undefined;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001464 JSFunction* tail = NULL;
1465 Object* candidate = function;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001466 while (candidate != undefined) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001467 // Check whether to keep the candidate in the list.
1468 JSFunction* candidate_function = reinterpret_cast<JSFunction*>(candidate);
1469 Object* retain = retainer->RetainAs(candidate);
1470 if (retain != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001471 if (head == undefined) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001472 // First element in the list.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001473 head = retain;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001474 } else {
1475 // Subsequent elements in the list.
1476 ASSERT(tail != NULL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001477 tail->set_next_function_link(retain);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001478 if (record_slots) {
1479 Object** next_function =
1480 HeapObject::RawField(tail, JSFunction::kNextFunctionLinkOffset);
1481 heap->mark_compact_collector()->RecordSlot(
1482 next_function, next_function, retain);
1483 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001484 }
1485 // Retained function is new tail.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001486 candidate_function = reinterpret_cast<JSFunction*>(retain);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001487 tail = candidate_function;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001488
1489 ASSERT(retain->IsUndefined() || retain->IsJSFunction());
1490
1491 if (retain == undefined) break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001492 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001493
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001494 // Move to next element in the list.
1495 candidate = candidate_function->next_function_link();
1496 }
1497
1498 // Terminate the list if there is one or more elements.
1499 if (tail != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001500 tail->set_next_function_link(undefined);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001501 }
1502
1503 return head;
1504}
1505
1506
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001507void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001508 Object* undefined = undefined_value();
1509 Object* head = undefined;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001510 Context* tail = NULL;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001511 Object* candidate = native_contexts_list_;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001512
1513 // We don't record weak slots during marking or scavenges.
1514 // Instead we do it once when we complete mark-compact cycle.
1515 // Note that write barrier has no effect if we are already in the middle of
1516 // compacting mark-sweep cycle and we have to record slots manually.
1517 bool record_slots =
1518 gc_state() == MARK_COMPACT &&
1519 mark_compact_collector()->is_compacting();
1520
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001521 while (candidate != undefined) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001522 // Check whether to keep the candidate in the list.
1523 Context* candidate_context = reinterpret_cast<Context*>(candidate);
1524 Object* retain = retainer->RetainAs(candidate);
1525 if (retain != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001526 if (head == undefined) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001527 // First element in the list.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001528 head = retain;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001529 } else {
1530 // Subsequent elements in the list.
1531 ASSERT(tail != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001532 tail->set_unchecked(this,
1533 Context::NEXT_CONTEXT_LINK,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001534 retain,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001535 UPDATE_WRITE_BARRIER);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001536
1537 if (record_slots) {
1538 Object** next_context =
1539 HeapObject::RawField(
1540 tail, FixedArray::SizeFor(Context::NEXT_CONTEXT_LINK));
1541 mark_compact_collector()->RecordSlot(
1542 next_context, next_context, retain);
1543 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001544 }
1545 // Retained context is new tail.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001546 candidate_context = reinterpret_cast<Context*>(retain);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001547 tail = candidate_context;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001548
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001549 if (retain == undefined) break;
1550
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001551 // Process the weak list of optimized functions for the context.
1552 Object* function_list_head =
1553 ProcessFunctionWeakReferences(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001554 this,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001555 candidate_context->get(Context::OPTIMIZED_FUNCTIONS_LIST),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001556 retainer,
1557 record_slots);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001558 candidate_context->set_unchecked(this,
1559 Context::OPTIMIZED_FUNCTIONS_LIST,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001560 function_list_head,
1561 UPDATE_WRITE_BARRIER);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001562 if (record_slots) {
1563 Object** optimized_functions =
1564 HeapObject::RawField(
1565 tail, FixedArray::SizeFor(Context::OPTIMIZED_FUNCTIONS_LIST));
1566 mark_compact_collector()->RecordSlot(
1567 optimized_functions, optimized_functions, function_list_head);
1568 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001569 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001570
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001571 // Move to next element in the list.
1572 candidate = candidate_context->get(Context::NEXT_CONTEXT_LINK);
1573 }
1574
1575 // Terminate the list if there is one or more elements.
1576 if (tail != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001577 tail->set_unchecked(this,
1578 Context::NEXT_CONTEXT_LINK,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001579 Heap::undefined_value(),
1580 UPDATE_WRITE_BARRIER);
1581 }
1582
1583 // Update the head of the list of contexts.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001584 native_contexts_list_ = head;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001585}
1586
1587
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001588void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) {
1589 AssertNoAllocation no_allocation;
1590
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001591 // Both the external string table and the symbol table may contain
1592 // external strings, but neither lists them exhaustively, nor is the
1593 // intersection set empty. Therefore we iterate over the external string
1594 // table first, ignoring symbols, and then over the symbol table.
1595
1596 class ExternalStringTableVisitorAdapter : public ObjectVisitor {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001597 public:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001598 explicit ExternalStringTableVisitorAdapter(
1599 v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001600 virtual void VisitPointers(Object** start, Object** end) {
1601 for (Object** p = start; p < end; p++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001602 // Visit non-symbol external strings,
1603 // since symbols are listed in the symbol table.
1604 if (!(*p)->IsSymbol()) {
1605 ASSERT((*p)->IsExternalString());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001606 visitor_->VisitExternalString(Utils::ToLocal(
1607 Handle<String>(String::cast(*p))));
1608 }
1609 }
1610 }
1611 private:
1612 v8::ExternalResourceVisitor* visitor_;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001613 } external_string_table_visitor(visitor);
1614
1615 external_string_table_.Iterate(&external_string_table_visitor);
1616
1617 class SymbolTableVisitorAdapter : public ObjectVisitor {
1618 public:
1619 explicit SymbolTableVisitorAdapter(
1620 v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
1621 virtual void VisitPointers(Object** start, Object** end) {
1622 for (Object** p = start; p < end; p++) {
1623 if ((*p)->IsExternalString()) {
1624 ASSERT((*p)->IsSymbol());
1625 visitor_->VisitExternalString(Utils::ToLocal(
1626 Handle<String>(String::cast(*p))));
1627 }
1628 }
1629 }
1630 private:
1631 v8::ExternalResourceVisitor* visitor_;
1632 } symbol_table_visitor(visitor);
1633
1634 symbol_table()->IterateElements(&symbol_table_visitor);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001635}
1636
1637
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001638class NewSpaceScavenger : public StaticNewSpaceVisitor<NewSpaceScavenger> {
1639 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001640 static inline void VisitPointer(Heap* heap, Object** p) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001641 Object* object = *p;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001642 if (!heap->InNewSpace(object)) return;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001643 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
1644 reinterpret_cast<HeapObject*>(object));
1645 }
1646};
1647
1648
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001649Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
1650 Address new_space_front) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001651 do {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001652 SemiSpace::AssertValidRange(new_space_front, new_space_.top());
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001653 // The addresses new_space_front and new_space_.top() define a
1654 // queue of unprocessed copied objects. Process them until the
1655 // queue is empty.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001656 while (new_space_front != new_space_.top()) {
1657 if (!NewSpacePage::IsAtEnd(new_space_front)) {
1658 HeapObject* object = HeapObject::FromAddress(new_space_front);
1659 new_space_front +=
1660 NewSpaceScavenger::IterateBody(object->map(), object);
1661 } else {
1662 new_space_front =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001663 NewSpacePage::FromLimit(new_space_front)->next_page()->area_start();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001664 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001665 }
1666
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001667 // Promote and process all the to-be-promoted objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001668 {
1669 StoreBufferRebuildScope scope(this,
1670 store_buffer(),
1671 &ScavengeStoreBufferCallback);
1672 while (!promotion_queue()->is_empty()) {
1673 HeapObject* target;
1674 int size;
1675 promotion_queue()->remove(&target, &size);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001676
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001677 // Promoted object might be already partially visited
1678 // during old space pointer iteration. Thus we search specificly
1679 // for pointers to from semispace instead of looking for pointers
1680 // to new space.
1681 ASSERT(!target->IsMap());
1682 IterateAndMarkPointersToFromSpace(target->address(),
1683 target->address() + size,
1684 &ScavengeObject);
1685 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001686 }
1687
1688 // Take another spin if there are now unswept objects in new space
1689 // (there are currently no more unswept promoted objects).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001690 } while (new_space_front != new_space_.top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001691
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001692 return new_space_front;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001693}
1694
1695
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001696STATIC_ASSERT((FixedDoubleArray::kHeaderSize & kDoubleAlignmentMask) == 0);
1697
1698
1699INLINE(static HeapObject* EnsureDoubleAligned(Heap* heap,
1700 HeapObject* object,
1701 int size));
1702
1703static HeapObject* EnsureDoubleAligned(Heap* heap,
1704 HeapObject* object,
1705 int size) {
1706 if ((OffsetFrom(object->address()) & kDoubleAlignmentMask) != 0) {
1707 heap->CreateFillerObjectAt(object->address(), kPointerSize);
1708 return HeapObject::FromAddress(object->address() + kPointerSize);
1709 } else {
1710 heap->CreateFillerObjectAt(object->address() + size - kPointerSize,
1711 kPointerSize);
1712 return object;
1713 }
1714}
1715
1716
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001717enum LoggingAndProfiling {
1718 LOGGING_AND_PROFILING_ENABLED,
1719 LOGGING_AND_PROFILING_DISABLED
1720};
1721
1722
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001723enum MarksHandling { TRANSFER_MARKS, IGNORE_MARKS };
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001724
1725
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001726template<MarksHandling marks_handling,
1727 LoggingAndProfiling logging_and_profiling_mode>
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001728class ScavengingVisitor : public StaticVisitorBase {
1729 public:
1730 static void Initialize() {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001731 table_.Register(kVisitSeqOneByteString, &EvacuateSeqOneByteString);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001732 table_.Register(kVisitSeqTwoByteString, &EvacuateSeqTwoByteString);
1733 table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate);
1734 table_.Register(kVisitByteArray, &EvacuateByteArray);
1735 table_.Register(kVisitFixedArray, &EvacuateFixedArray);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001736 table_.Register(kVisitFixedDoubleArray, &EvacuateFixedDoubleArray);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001737
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001738 table_.Register(kVisitNativeContext,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001739 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001740 template VisitSpecialized<Context::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001741
1742 table_.Register(kVisitConsString,
1743 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001744 template VisitSpecialized<ConsString::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001745
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001746 table_.Register(kVisitSlicedString,
1747 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1748 template VisitSpecialized<SlicedString::kSize>);
1749
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001750 table_.Register(kVisitSharedFunctionInfo,
1751 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001752 template VisitSpecialized<SharedFunctionInfo::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001753
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001754 table_.Register(kVisitJSWeakMap,
1755 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1756 Visit);
1757
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001758 table_.Register(kVisitJSRegExp,
1759 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1760 Visit);
1761
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001762 if (marks_handling == IGNORE_MARKS) {
1763 table_.Register(kVisitJSFunction,
1764 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1765 template VisitSpecialized<JSFunction::kSize>);
1766 } else {
1767 table_.Register(kVisitJSFunction, &EvacuateJSFunction);
1768 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001769
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001770 table_.RegisterSpecializations<ObjectEvacuationStrategy<DATA_OBJECT>,
1771 kVisitDataObject,
1772 kVisitDataObjectGeneric>();
1773
1774 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>,
1775 kVisitJSObject,
1776 kVisitJSObjectGeneric>();
1777
1778 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>,
1779 kVisitStruct,
1780 kVisitStructGeneric>();
1781 }
1782
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001783 static VisitorDispatchTable<ScavengingCallback>* GetTable() {
1784 return &table_;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001785 }
1786
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001787 private:
1788 enum ObjectContents { DATA_OBJECT, POINTER_OBJECT };
1789 enum SizeRestriction { SMALL, UNKNOWN_SIZE };
1790
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001791 static void RecordCopiedObject(Heap* heap, HeapObject* obj) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001792 bool should_record = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001793#ifdef DEBUG
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001794 should_record = FLAG_heap_stats;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001795#endif
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001796 should_record = should_record || FLAG_log_gc;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001797 if (should_record) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 if (heap->new_space()->Contains(obj)) {
1799 heap->new_space()->RecordAllocation(obj);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001800 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001801 heap->new_space()->RecordPromotion(obj);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001802 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001803 }
1804 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001805
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001806 // Helper function used by CopyObject to copy a source object to an
1807 // allocated target object and update the forwarding pointer in the source
1808 // object. Returns the target object.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001809 INLINE(static void MigrateObject(Heap* heap,
1810 HeapObject* source,
1811 HeapObject* target,
1812 int size)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001813 // Copy the content of source to target.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001814 heap->CopyBlock(target->address(), source->address(), size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001815
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001816 // Set the forwarding address.
1817 source->set_map_word(MapWord::FromForwardingAddress(target));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001818
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001819 if (logging_and_profiling_mode == LOGGING_AND_PROFILING_ENABLED) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001820 // Update NewSpace stats if necessary.
1821 RecordCopiedObject(heap, target);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001822 HEAP_PROFILE(heap, ObjectMoveEvent(source->address(), target->address()));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001823 Isolate* isolate = heap->isolate();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001824 if (isolate->logger()->is_logging_code_events() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001825 CpuProfiler::is_profiling(isolate)) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001826 if (target->IsSharedFunctionInfo()) {
1827 PROFILE(isolate, SharedFunctionInfoMoveEvent(
1828 source->address(), target->address()));
1829 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001830 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001831 }
1832
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001833 if (marks_handling == TRANSFER_MARKS) {
1834 if (Marking::TransferColor(source, target)) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001835 MemoryChunk::IncrementLiveBytesFromGC(target->address(), size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001836 }
1837 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001838 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001839
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001840
1841 template<ObjectContents object_contents,
1842 SizeRestriction size_restriction,
1843 int alignment>
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001844 static inline void EvacuateObject(Map* map,
1845 HeapObject** slot,
1846 HeapObject* object,
1847 int object_size) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001848 SLOW_ASSERT((size_restriction != SMALL) ||
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001849 (object_size <= Page::kMaxNonCodeHeapObjectSize));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001850 SLOW_ASSERT(object->Size() == object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001851
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001852 int allocation_size = object_size;
1853 if (alignment != kObjectAlignment) {
1854 ASSERT(alignment == kDoubleAlignment);
1855 allocation_size += kPointerSize;
1856 }
1857
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001858 Heap* heap = map->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001859 if (heap->ShouldBePromoted(object->address(), object_size)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001860 MaybeObject* maybe_result;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001861
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001862 if ((size_restriction != SMALL) &&
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001863 (allocation_size > Page::kMaxNonCodeHeapObjectSize)) {
1864 maybe_result = heap->lo_space()->AllocateRaw(allocation_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001865 NOT_EXECUTABLE);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001866 } else {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001867 if (object_contents == DATA_OBJECT) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001868 maybe_result = heap->old_data_space()->AllocateRaw(allocation_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001869 } else {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001870 maybe_result =
1871 heap->old_pointer_space()->AllocateRaw(allocation_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001872 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001873 }
1874
lrn@chromium.org303ada72010-10-27 09:33:13 +00001875 Object* result = NULL; // Initialization to please compiler.
1876 if (maybe_result->ToObject(&result)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001877 HeapObject* target = HeapObject::cast(result);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001878
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001879 if (alignment != kObjectAlignment) {
1880 target = EnsureDoubleAligned(heap, target, allocation_size);
1881 }
1882
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001883 // Order is important: slot might be inside of the target if target
1884 // was allocated over a dead object and slot comes from the store
1885 // buffer.
1886 *slot = target;
1887 MigrateObject(heap, object, target, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001888
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001889 if (object_contents == POINTER_OBJECT) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001890 if (map->instance_type() == JS_FUNCTION_TYPE) {
1891 heap->promotion_queue()->insert(
1892 target, JSFunction::kNonWeakFieldsEndOffset);
1893 } else {
1894 heap->promotion_queue()->insert(target, object_size);
1895 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001896 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001897
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001898 heap->tracer()->increment_promoted_objects_size(object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001899 return;
1900 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001901 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001902 MaybeObject* allocation = heap->new_space()->AllocateRaw(allocation_size);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001903 heap->promotion_queue()->SetNewLimit(heap->new_space()->top());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001904 Object* result = allocation->ToObjectUnchecked();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001905 HeapObject* target = HeapObject::cast(result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001906
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001907 if (alignment != kObjectAlignment) {
1908 target = EnsureDoubleAligned(heap, target, allocation_size);
1909 }
1910
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001911 // Order is important: slot might be inside of the target if target
1912 // was allocated over a dead object and slot comes from the store
1913 // buffer.
1914 *slot = target;
1915 MigrateObject(heap, object, target, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001916 return;
1917 }
1918
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001919
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001920 static inline void EvacuateJSFunction(Map* map,
1921 HeapObject** slot,
1922 HeapObject* object) {
1923 ObjectEvacuationStrategy<POINTER_OBJECT>::
1924 template VisitSpecialized<JSFunction::kSize>(map, slot, object);
1925
1926 HeapObject* target = *slot;
1927 MarkBit mark_bit = Marking::MarkBitFrom(target);
1928 if (Marking::IsBlack(mark_bit)) {
1929 // This object is black and it might not be rescanned by marker.
1930 // We should explicitly record code entry slot for compaction because
1931 // promotion queue processing (IterateAndMarkPointersToFromSpace) will
1932 // miss it as it is not HeapObject-tagged.
1933 Address code_entry_slot =
1934 target->address() + JSFunction::kCodeEntryOffset;
1935 Code* code = Code::cast(Code::GetObjectFromEntryAddress(code_entry_slot));
1936 map->GetHeap()->mark_compact_collector()->
1937 RecordCodeEntrySlot(code_entry_slot, code);
1938 }
1939 }
1940
1941
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001942 static inline void EvacuateFixedArray(Map* map,
1943 HeapObject** slot,
1944 HeapObject* object) {
1945 int object_size = FixedArray::BodyDescriptor::SizeOf(map, object);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001946 EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(map,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001947 slot,
1948 object,
1949 object_size);
1950 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001951
1952
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001953 static inline void EvacuateFixedDoubleArray(Map* map,
1954 HeapObject** slot,
1955 HeapObject* object) {
1956 int length = reinterpret_cast<FixedDoubleArray*>(object)->length();
1957 int object_size = FixedDoubleArray::SizeFor(length);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001958 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kDoubleAlignment>(
1959 map,
1960 slot,
1961 object,
1962 object_size);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001963 }
1964
1965
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001966 static inline void EvacuateByteArray(Map* map,
1967 HeapObject** slot,
1968 HeapObject* object) {
1969 int object_size = reinterpret_cast<ByteArray*>(object)->ByteArraySize();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001970 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
1971 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001972 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001973
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001974
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001975 static inline void EvacuateSeqOneByteString(Map* map,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001976 HeapObject** slot,
1977 HeapObject* object) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001978 int object_size = SeqOneByteString::cast(object)->
1979 SeqOneByteStringSize(map->instance_type());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001980 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
1981 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001982 }
1983
1984
1985 static inline void EvacuateSeqTwoByteString(Map* map,
1986 HeapObject** slot,
1987 HeapObject* object) {
1988 int object_size = SeqTwoByteString::cast(object)->
1989 SeqTwoByteStringSize(map->instance_type());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001990 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
1991 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001992 }
1993
1994
1995 static inline bool IsShortcutCandidate(int type) {
1996 return ((type & kShortcutTypeMask) == kShortcutTypeTag);
1997 }
1998
1999 static inline void EvacuateShortcutCandidate(Map* map,
2000 HeapObject** slot,
2001 HeapObject* object) {
2002 ASSERT(IsShortcutCandidate(map->instance_type()));
2003
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002004 Heap* heap = map->GetHeap();
2005
2006 if (marks_handling == IGNORE_MARKS &&
2007 ConsString::cast(object)->unchecked_second() ==
2008 heap->empty_string()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002009 HeapObject* first =
2010 HeapObject::cast(ConsString::cast(object)->unchecked_first());
2011
2012 *slot = first;
2013
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002014 if (!heap->InNewSpace(first)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002015 object->set_map_word(MapWord::FromForwardingAddress(first));
2016 return;
2017 }
2018
2019 MapWord first_word = first->map_word();
2020 if (first_word.IsForwardingAddress()) {
2021 HeapObject* target = first_word.ToForwardingAddress();
2022
2023 *slot = target;
2024 object->set_map_word(MapWord::FromForwardingAddress(target));
2025 return;
2026 }
2027
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002028 heap->DoScavengeObject(first->map(), slot, first);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002029 object->set_map_word(MapWord::FromForwardingAddress(*slot));
2030 return;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002031 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002032
2033 int object_size = ConsString::kSize;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002034 EvacuateObject<POINTER_OBJECT, SMALL, kObjectAlignment>(
2035 map, slot, object, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002036 }
2037
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002038 template<ObjectContents object_contents>
2039 class ObjectEvacuationStrategy {
2040 public:
2041 template<int object_size>
2042 static inline void VisitSpecialized(Map* map,
2043 HeapObject** slot,
2044 HeapObject* object) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002045 EvacuateObject<object_contents, SMALL, kObjectAlignment>(
2046 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002047 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002048
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002049 static inline void Visit(Map* map,
2050 HeapObject** slot,
2051 HeapObject* object) {
2052 int object_size = map->instance_size();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002053 EvacuateObject<object_contents, SMALL, kObjectAlignment>(
2054 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002055 }
2056 };
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002057
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002058 static VisitorDispatchTable<ScavengingCallback> table_;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002059};
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002060
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002061
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002062template<MarksHandling marks_handling,
2063 LoggingAndProfiling logging_and_profiling_mode>
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002064VisitorDispatchTable<ScavengingCallback>
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002065 ScavengingVisitor<marks_handling, logging_and_profiling_mode>::table_;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002066
2067
2068static void InitializeScavengingVisitorsTables() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002069 ScavengingVisitor<TRANSFER_MARKS,
2070 LOGGING_AND_PROFILING_DISABLED>::Initialize();
2071 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_DISABLED>::Initialize();
2072 ScavengingVisitor<TRANSFER_MARKS,
2073 LOGGING_AND_PROFILING_ENABLED>::Initialize();
2074 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_ENABLED>::Initialize();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002075}
2076
2077
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002078void Heap::SelectScavengingVisitorsTable() {
2079 bool logging_and_profiling =
2080 isolate()->logger()->is_logging() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002081 CpuProfiler::is_profiling(isolate()) ||
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002082 (isolate()->heap_profiler() != NULL &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002083 isolate()->heap_profiler()->is_profiling());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002084
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002085 if (!incremental_marking()->IsMarking()) {
2086 if (!logging_and_profiling) {
2087 scavenging_visitors_table_.CopyFrom(
2088 ScavengingVisitor<IGNORE_MARKS,
2089 LOGGING_AND_PROFILING_DISABLED>::GetTable());
2090 } else {
2091 scavenging_visitors_table_.CopyFrom(
2092 ScavengingVisitor<IGNORE_MARKS,
2093 LOGGING_AND_PROFILING_ENABLED>::GetTable());
2094 }
2095 } else {
2096 if (!logging_and_profiling) {
2097 scavenging_visitors_table_.CopyFrom(
2098 ScavengingVisitor<TRANSFER_MARKS,
2099 LOGGING_AND_PROFILING_DISABLED>::GetTable());
2100 } else {
2101 scavenging_visitors_table_.CopyFrom(
2102 ScavengingVisitor<TRANSFER_MARKS,
2103 LOGGING_AND_PROFILING_ENABLED>::GetTable());
2104 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002105
2106 if (incremental_marking()->IsCompacting()) {
2107 // When compacting forbid short-circuiting of cons-strings.
2108 // Scavenging code relies on the fact that new space object
2109 // can't be evacuated into evacuation candidate but
2110 // short-circuiting violates this assumption.
2111 scavenging_visitors_table_.Register(
2112 StaticVisitorBase::kVisitShortcutCandidate,
2113 scavenging_visitors_table_.GetVisitorById(
2114 StaticVisitorBase::kVisitConsString));
2115 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002116 }
2117}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002118
2119
2120void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002121 SLOW_ASSERT(HEAP->InFromSpace(object));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002122 MapWord first_word = object->map_word();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002123 SLOW_ASSERT(!first_word.IsForwardingAddress());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002124 Map* map = first_word.ToMap();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002125 map->GetHeap()->DoScavengeObject(map, p, object);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002126}
2127
2128
lrn@chromium.org303ada72010-10-27 09:33:13 +00002129MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type,
2130 int instance_size) {
2131 Object* result;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002132 MaybeObject* maybe_result = AllocateRawMap();
2133 if (!maybe_result->ToObject(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002134
2135 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002136 reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002137 reinterpret_cast<Map*>(result)->set_instance_type(instance_type);
2138 reinterpret_cast<Map*>(result)->set_instance_size(instance_size);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002139 reinterpret_cast<Map*>(result)->set_visitor_id(
2140 StaticVisitorBase::GetVisitorId(instance_type, instance_size));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002141 reinterpret_cast<Map*>(result)->set_inobject_properties(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002142 reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002143 reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002144 reinterpret_cast<Map*>(result)->set_bit_field(0);
2145 reinterpret_cast<Map*>(result)->set_bit_field2(0);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002146 int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) |
2147 Map::OwnsDescriptors::encode(true);
2148 reinterpret_cast<Map*>(result)->set_bit_field3(bit_field3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002149 return result;
2150}
2151
2152
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002153MaybeObject* Heap::AllocateMap(InstanceType instance_type,
2154 int instance_size,
2155 ElementsKind elements_kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002156 Object* result;
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002157 MaybeObject* maybe_result = AllocateRawMap();
2158 if (!maybe_result->To(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002159
2160 Map* map = reinterpret_cast<Map*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002161 map->set_map_no_write_barrier(meta_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002162 map->set_instance_type(instance_type);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002163 map->set_visitor_id(
2164 StaticVisitorBase::GetVisitorId(instance_type, instance_size));
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002165 map->set_prototype(null_value(), SKIP_WRITE_BARRIER);
2166 map->set_constructor(null_value(), SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002167 map->set_instance_size(instance_size);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002168 map->set_inobject_properties(0);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002169 map->set_pre_allocated_property_fields(0);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002170 map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002171 map->init_back_pointer(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002172 map->set_unused_property_fields(0);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002173 map->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002174 map->set_bit_field(0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002175 map->set_bit_field2(1 << Map::kIsExtensible);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002176 int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) |
2177 Map::OwnsDescriptors::encode(true);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002178 map->set_bit_field3(bit_field3);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002179 map->set_elements_kind(elements_kind);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002180
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002181 return map;
2182}
2183
2184
lrn@chromium.org303ada72010-10-27 09:33:13 +00002185MaybeObject* Heap::AllocateCodeCache() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002186 CodeCache* code_cache;
2187 { MaybeObject* maybe_code_cache = AllocateStruct(CODE_CACHE_TYPE);
2188 if (!maybe_code_cache->To(&code_cache)) return maybe_code_cache;
lrn@chromium.org303ada72010-10-27 09:33:13 +00002189 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002190 code_cache->set_default_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
2191 code_cache->set_normal_type_cache(undefined_value(), SKIP_WRITE_BARRIER);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002192 return code_cache;
2193}
2194
2195
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002196MaybeObject* Heap::AllocatePolymorphicCodeCache() {
2197 return AllocateStruct(POLYMORPHIC_CODE_CACHE_TYPE);
2198}
2199
2200
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002201MaybeObject* Heap::AllocateAccessorPair() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002202 AccessorPair* accessors;
2203 { MaybeObject* maybe_accessors = AllocateStruct(ACCESSOR_PAIR_TYPE);
2204 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002205 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002206 accessors->set_getter(the_hole_value(), SKIP_WRITE_BARRIER);
2207 accessors->set_setter(the_hole_value(), SKIP_WRITE_BARRIER);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002208 return accessors;
2209}
2210
2211
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002212MaybeObject* Heap::AllocateTypeFeedbackInfo() {
2213 TypeFeedbackInfo* info;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002214 { MaybeObject* maybe_info = AllocateStruct(TYPE_FEEDBACK_INFO_TYPE);
2215 if (!maybe_info->To(&info)) return maybe_info;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002216 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002217 info->initialize_storage();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002218 info->set_type_feedback_cells(TypeFeedbackCells::cast(empty_fixed_array()),
2219 SKIP_WRITE_BARRIER);
2220 return info;
2221}
2222
2223
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002224MaybeObject* Heap::AllocateAliasedArgumentsEntry(int aliased_context_slot) {
2225 AliasedArgumentsEntry* entry;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002226 { MaybeObject* maybe_entry = AllocateStruct(ALIASED_ARGUMENTS_ENTRY_TYPE);
2227 if (!maybe_entry->To(&entry)) return maybe_entry;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002228 }
2229 entry->set_aliased_context_slot(aliased_context_slot);
2230 return entry;
2231}
2232
2233
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002234const Heap::StringTypeTable Heap::string_type_table[] = {
2235#define STRING_TYPE_ELEMENT(type, size, name, camel_name) \
2236 {type, size, k##camel_name##MapRootIndex},
2237 STRING_TYPE_LIST(STRING_TYPE_ELEMENT)
2238#undef STRING_TYPE_ELEMENT
2239};
2240
2241
2242const Heap::ConstantSymbolTable Heap::constant_symbol_table[] = {
2243#define CONSTANT_SYMBOL_ELEMENT(name, contents) \
2244 {contents, k##name##RootIndex},
2245 SYMBOL_LIST(CONSTANT_SYMBOL_ELEMENT)
2246#undef CONSTANT_SYMBOL_ELEMENT
2247};
2248
2249
2250const Heap::StructTable Heap::struct_table[] = {
2251#define STRUCT_TABLE_ELEMENT(NAME, Name, name) \
2252 { NAME##_TYPE, Name::kSize, k##Name##MapRootIndex },
2253 STRUCT_LIST(STRUCT_TABLE_ELEMENT)
2254#undef STRUCT_TABLE_ELEMENT
2255};
2256
2257
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002258bool Heap::CreateInitialMaps() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002259 Object* obj;
2260 { MaybeObject* maybe_obj = AllocatePartialMap(MAP_TYPE, Map::kSize);
2261 if (!maybe_obj->ToObject(&obj)) return false;
2262 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002263 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002264 Map* new_meta_map = reinterpret_cast<Map*>(obj);
2265 set_meta_map(new_meta_map);
2266 new_meta_map->set_map(new_meta_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002267
lrn@chromium.org303ada72010-10-27 09:33:13 +00002268 { MaybeObject* maybe_obj =
2269 AllocatePartialMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2270 if (!maybe_obj->ToObject(&obj)) return false;
2271 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002272 set_fixed_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002273
lrn@chromium.org303ada72010-10-27 09:33:13 +00002274 { MaybeObject* maybe_obj = AllocatePartialMap(ODDBALL_TYPE, Oddball::kSize);
2275 if (!maybe_obj->ToObject(&obj)) return false;
2276 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002277 set_oddball_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002278
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002279 // Allocate the empty array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002280 { MaybeObject* maybe_obj = AllocateEmptyFixedArray();
2281 if (!maybe_obj->ToObject(&obj)) return false;
2282 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002283 set_empty_fixed_array(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002284
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002285 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002286 if (!maybe_obj->ToObject(&obj)) return false;
2287 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002288 set_null_value(Oddball::cast(obj));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002289 Oddball::cast(obj)->set_kind(Oddball::kNull);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002290
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002291 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE);
2292 if (!maybe_obj->ToObject(&obj)) return false;
2293 }
2294 set_undefined_value(Oddball::cast(obj));
2295 Oddball::cast(obj)->set_kind(Oddball::kUndefined);
2296 ASSERT(!InNewSpace(undefined_value()));
2297
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002298 // Allocate the empty descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002299 { MaybeObject* maybe_obj = AllocateEmptyFixedArray();
2300 if (!maybe_obj->ToObject(&obj)) return false;
2301 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002302 set_empty_descriptor_array(DescriptorArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002303
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002304 // Fix the instance_descriptors for the existing maps.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002305 meta_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002306 meta_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002307 meta_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002308
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002309 fixed_array_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002310 fixed_array_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002311 fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002312
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002313 oddball_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002314 oddball_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002315 oddball_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002316
2317 // Fix prototype object for existing maps.
2318 meta_map()->set_prototype(null_value());
2319 meta_map()->set_constructor(null_value());
2320
2321 fixed_array_map()->set_prototype(null_value());
2322 fixed_array_map()->set_constructor(null_value());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002323
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002324 oddball_map()->set_prototype(null_value());
2325 oddball_map()->set_constructor(null_value());
2326
lrn@chromium.org303ada72010-10-27 09:33:13 +00002327 { MaybeObject* maybe_obj =
2328 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2329 if (!maybe_obj->ToObject(&obj)) return false;
2330 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002331 set_fixed_cow_array_map(Map::cast(obj));
2332 ASSERT(fixed_array_map() != fixed_cow_array_map());
2333
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002334 { MaybeObject* maybe_obj =
2335 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2336 if (!maybe_obj->ToObject(&obj)) return false;
2337 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002338 set_scope_info_map(Map::cast(obj));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002339
lrn@chromium.org303ada72010-10-27 09:33:13 +00002340 { MaybeObject* maybe_obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
2341 if (!maybe_obj->ToObject(&obj)) return false;
2342 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002343 set_heap_number_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002344
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002345 { MaybeObject* maybe_obj = AllocateMap(FOREIGN_TYPE, Foreign::kSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002346 if (!maybe_obj->ToObject(&obj)) return false;
2347 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002348 set_foreign_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002349
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002350 for (unsigned i = 0; i < ARRAY_SIZE(string_type_table); i++) {
2351 const StringTypeTable& entry = string_type_table[i];
lrn@chromium.org303ada72010-10-27 09:33:13 +00002352 { MaybeObject* maybe_obj = AllocateMap(entry.type, entry.size);
2353 if (!maybe_obj->ToObject(&obj)) return false;
2354 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002355 roots_[entry.index] = Map::cast(obj);
2356 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002357
lrn@chromium.org303ada72010-10-27 09:33:13 +00002358 { MaybeObject* maybe_obj = AllocateMap(STRING_TYPE, kVariableSizeSentinel);
2359 if (!maybe_obj->ToObject(&obj)) return false;
2360 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002361 set_undetectable_string_map(Map::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002362 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002363
lrn@chromium.org303ada72010-10-27 09:33:13 +00002364 { MaybeObject* maybe_obj =
2365 AllocateMap(ASCII_STRING_TYPE, kVariableSizeSentinel);
2366 if (!maybe_obj->ToObject(&obj)) return false;
2367 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002368 set_undetectable_ascii_string_map(Map::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002369 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002370
lrn@chromium.org303ada72010-10-27 09:33:13 +00002371 { MaybeObject* maybe_obj =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002372 AllocateMap(FIXED_DOUBLE_ARRAY_TYPE, kVariableSizeSentinel);
2373 if (!maybe_obj->ToObject(&obj)) return false;
2374 }
2375 set_fixed_double_array_map(Map::cast(obj));
2376
2377 { MaybeObject* maybe_obj =
lrn@chromium.org303ada72010-10-27 09:33:13 +00002378 AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel);
2379 if (!maybe_obj->ToObject(&obj)) return false;
2380 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002381 set_byte_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002382
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002383 { MaybeObject* maybe_obj =
2384 AllocateMap(FREE_SPACE_TYPE, kVariableSizeSentinel);
2385 if (!maybe_obj->ToObject(&obj)) return false;
2386 }
2387 set_free_space_map(Map::cast(obj));
2388
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002389 { MaybeObject* maybe_obj = AllocateByteArray(0, TENURED);
2390 if (!maybe_obj->ToObject(&obj)) return false;
2391 }
2392 set_empty_byte_array(ByteArray::cast(obj));
2393
lrn@chromium.org303ada72010-10-27 09:33:13 +00002394 { MaybeObject* maybe_obj =
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002395 AllocateMap(EXTERNAL_PIXEL_ARRAY_TYPE, ExternalArray::kAlignedSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002396 if (!maybe_obj->ToObject(&obj)) return false;
2397 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002398 set_external_pixel_array_map(Map::cast(obj));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002399
lrn@chromium.org303ada72010-10-27 09:33:13 +00002400 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_BYTE_ARRAY_TYPE,
2401 ExternalArray::kAlignedSize);
2402 if (!maybe_obj->ToObject(&obj)) return false;
2403 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002404 set_external_byte_array_map(Map::cast(obj));
2405
lrn@chromium.org303ada72010-10-27 09:33:13 +00002406 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE,
2407 ExternalArray::kAlignedSize);
2408 if (!maybe_obj->ToObject(&obj)) return false;
2409 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002410 set_external_unsigned_byte_array_map(Map::cast(obj));
2411
lrn@chromium.org303ada72010-10-27 09:33:13 +00002412 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_SHORT_ARRAY_TYPE,
2413 ExternalArray::kAlignedSize);
2414 if (!maybe_obj->ToObject(&obj)) return false;
2415 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002416 set_external_short_array_map(Map::cast(obj));
2417
lrn@chromium.org303ada72010-10-27 09:33:13 +00002418 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE,
2419 ExternalArray::kAlignedSize);
2420 if (!maybe_obj->ToObject(&obj)) return false;
2421 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002422 set_external_unsigned_short_array_map(Map::cast(obj));
2423
lrn@chromium.org303ada72010-10-27 09:33:13 +00002424 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_INT_ARRAY_TYPE,
2425 ExternalArray::kAlignedSize);
2426 if (!maybe_obj->ToObject(&obj)) return false;
2427 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002428 set_external_int_array_map(Map::cast(obj));
2429
lrn@chromium.org303ada72010-10-27 09:33:13 +00002430 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE,
2431 ExternalArray::kAlignedSize);
2432 if (!maybe_obj->ToObject(&obj)) return false;
2433 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002434 set_external_unsigned_int_array_map(Map::cast(obj));
2435
lrn@chromium.org303ada72010-10-27 09:33:13 +00002436 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_FLOAT_ARRAY_TYPE,
2437 ExternalArray::kAlignedSize);
2438 if (!maybe_obj->ToObject(&obj)) return false;
2439 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002440 set_external_float_array_map(Map::cast(obj));
2441
whesse@chromium.org7b260152011-06-20 15:33:18 +00002442 { MaybeObject* maybe_obj =
2443 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2444 if (!maybe_obj->ToObject(&obj)) return false;
2445 }
2446 set_non_strict_arguments_elements_map(Map::cast(obj));
2447
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002448 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_DOUBLE_ARRAY_TYPE,
2449 ExternalArray::kAlignedSize);
2450 if (!maybe_obj->ToObject(&obj)) return false;
2451 }
2452 set_external_double_array_map(Map::cast(obj));
2453
lrn@chromium.org303ada72010-10-27 09:33:13 +00002454 { MaybeObject* maybe_obj = AllocateMap(CODE_TYPE, kVariableSizeSentinel);
2455 if (!maybe_obj->ToObject(&obj)) return false;
2456 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002457 set_code_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002458
lrn@chromium.org303ada72010-10-27 09:33:13 +00002459 { MaybeObject* maybe_obj = AllocateMap(JS_GLOBAL_PROPERTY_CELL_TYPE,
2460 JSGlobalPropertyCell::kSize);
2461 if (!maybe_obj->ToObject(&obj)) return false;
2462 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002463 set_global_property_cell_map(Map::cast(obj));
2464
lrn@chromium.org303ada72010-10-27 09:33:13 +00002465 { MaybeObject* maybe_obj = AllocateMap(FILLER_TYPE, kPointerSize);
2466 if (!maybe_obj->ToObject(&obj)) return false;
2467 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002468 set_one_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002469
lrn@chromium.org303ada72010-10-27 09:33:13 +00002470 { MaybeObject* maybe_obj = AllocateMap(FILLER_TYPE, 2 * kPointerSize);
2471 if (!maybe_obj->ToObject(&obj)) return false;
2472 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002473 set_two_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002474
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002475 for (unsigned i = 0; i < ARRAY_SIZE(struct_table); i++) {
2476 const StructTable& entry = struct_table[i];
lrn@chromium.org303ada72010-10-27 09:33:13 +00002477 { MaybeObject* maybe_obj = AllocateMap(entry.type, entry.size);
2478 if (!maybe_obj->ToObject(&obj)) return false;
2479 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002480 roots_[entry.index] = Map::cast(obj);
2481 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002482
lrn@chromium.org303ada72010-10-27 09:33:13 +00002483 { MaybeObject* maybe_obj =
2484 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2485 if (!maybe_obj->ToObject(&obj)) return false;
2486 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002487 set_hash_table_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002488
lrn@chromium.org303ada72010-10-27 09:33:13 +00002489 { MaybeObject* maybe_obj =
2490 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2491 if (!maybe_obj->ToObject(&obj)) return false;
2492 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002493 set_function_context_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002494
lrn@chromium.org303ada72010-10-27 09:33:13 +00002495 { MaybeObject* maybe_obj =
2496 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2497 if (!maybe_obj->ToObject(&obj)) return false;
2498 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002499 set_catch_context_map(Map::cast(obj));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002500
lrn@chromium.org303ada72010-10-27 09:33:13 +00002501 { MaybeObject* maybe_obj =
2502 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2503 if (!maybe_obj->ToObject(&obj)) return false;
2504 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002505 set_with_context_map(Map::cast(obj));
2506
2507 { MaybeObject* maybe_obj =
2508 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2509 if (!maybe_obj->ToObject(&obj)) return false;
2510 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002511 set_block_context_map(Map::cast(obj));
2512
2513 { MaybeObject* maybe_obj =
2514 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2515 if (!maybe_obj->ToObject(&obj)) return false;
2516 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002517 set_module_context_map(Map::cast(obj));
2518
2519 { MaybeObject* maybe_obj =
2520 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2521 if (!maybe_obj->ToObject(&obj)) return false;
2522 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002523 set_global_context_map(Map::cast(obj));
2524
2525 { MaybeObject* maybe_obj =
2526 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2527 if (!maybe_obj->ToObject(&obj)) return false;
2528 }
2529 Map* native_context_map = Map::cast(obj);
2530 native_context_map->set_dictionary_map(true);
2531 native_context_map->set_visitor_id(StaticVisitorBase::kVisitNativeContext);
2532 set_native_context_map(native_context_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002533
lrn@chromium.org303ada72010-10-27 09:33:13 +00002534 { MaybeObject* maybe_obj = AllocateMap(SHARED_FUNCTION_INFO_TYPE,
2535 SharedFunctionInfo::kAlignedSize);
2536 if (!maybe_obj->ToObject(&obj)) return false;
2537 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002538 set_shared_function_info_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002539
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002540 { MaybeObject* maybe_obj = AllocateMap(JS_MESSAGE_OBJECT_TYPE,
2541 JSMessageObject::kSize);
2542 if (!maybe_obj->ToObject(&obj)) return false;
2543 }
2544 set_message_object_map(Map::cast(obj));
2545
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002546 Map* external_map;
2547 { MaybeObject* maybe_obj =
2548 AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize + kPointerSize);
2549 if (!maybe_obj->To(&external_map)) return false;
2550 }
2551 external_map->set_is_extensible(false);
2552 set_external_map(external_map);
2553
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002554 ASSERT(!InNewSpace(empty_fixed_array()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002555 return true;
2556}
2557
2558
lrn@chromium.org303ada72010-10-27 09:33:13 +00002559MaybeObject* Heap::AllocateHeapNumber(double value, PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002560 // Statically ensure that it is safe to allocate heap numbers in paged
2561 // spaces.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002562 STATIC_ASSERT(HeapNumber::kSize <= Page::kNonCodeObjectAreaSize);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002563 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002564
lrn@chromium.org303ada72010-10-27 09:33:13 +00002565 Object* result;
2566 { MaybeObject* maybe_result =
2567 AllocateRaw(HeapNumber::kSize, space, OLD_DATA_SPACE);
2568 if (!maybe_result->ToObject(&result)) return maybe_result;
2569 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002570
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002571 HeapObject::cast(result)->set_map_no_write_barrier(heap_number_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002572 HeapNumber::cast(result)->set_value(value);
2573 return result;
2574}
2575
2576
lrn@chromium.org303ada72010-10-27 09:33:13 +00002577MaybeObject* Heap::AllocateHeapNumber(double value) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002578 // Use general version, if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002579 if (always_allocate()) return AllocateHeapNumber(value, TENURED);
2580
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002581 // This version of AllocateHeapNumber is optimized for
2582 // allocation in new space.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002583 STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxNonCodeHeapObjectSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002584 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002585 Object* result;
2586 { MaybeObject* maybe_result = new_space_.AllocateRaw(HeapNumber::kSize);
2587 if (!maybe_result->ToObject(&result)) return maybe_result;
2588 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002589 HeapObject::cast(result)->set_map_no_write_barrier(heap_number_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002590 HeapNumber::cast(result)->set_value(value);
2591 return result;
2592}
2593
2594
lrn@chromium.org303ada72010-10-27 09:33:13 +00002595MaybeObject* Heap::AllocateJSGlobalPropertyCell(Object* value) {
2596 Object* result;
2597 { MaybeObject* maybe_result = AllocateRawCell();
2598 if (!maybe_result->ToObject(&result)) return maybe_result;
2599 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002600 HeapObject::cast(result)->set_map_no_write_barrier(
2601 global_property_cell_map());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002602 JSGlobalPropertyCell::cast(result)->set_value(value);
2603 return result;
2604}
2605
2606
lrn@chromium.org303ada72010-10-27 09:33:13 +00002607MaybeObject* Heap::CreateOddball(const char* to_string,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002608 Object* to_number,
2609 byte kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002610 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002611 { MaybeObject* maybe_result = Allocate(oddball_map(), OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002612 if (!maybe_result->ToObject(&result)) return maybe_result;
2613 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002614 return Oddball::cast(result)->Initialize(to_string, to_number, kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002615}
2616
2617
2618bool Heap::CreateApiObjects() {
2619 Object* obj;
2620
lrn@chromium.org303ada72010-10-27 09:33:13 +00002621 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
2622 if (!maybe_obj->ToObject(&obj)) return false;
2623 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002624 // Don't use Smi-only elements optimizations for objects with the neander
2625 // map. There are too many cases where element values are set directly with a
2626 // bottleneck to trap the Smi-only -> fast elements transition, and there
2627 // appears to be no benefit for optimize this case.
2628 Map* new_neander_map = Map::cast(obj);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002629 new_neander_map->set_elements_kind(TERMINAL_FAST_ELEMENTS_KIND);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002630 set_neander_map(new_neander_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002631
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002632 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(neander_map());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002633 if (!maybe_obj->ToObject(&obj)) return false;
2634 }
2635 Object* elements;
2636 { MaybeObject* maybe_elements = AllocateFixedArray(2);
2637 if (!maybe_elements->ToObject(&elements)) return false;
2638 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002639 FixedArray::cast(elements)->set(0, Smi::FromInt(0));
2640 JSObject::cast(obj)->set_elements(FixedArray::cast(elements));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002641 set_message_listeners(JSObject::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002642
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002643 return true;
2644}
2645
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002646
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002647void Heap::CreateJSEntryStub() {
2648 JSEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002649 set_js_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002650}
2651
2652
2653void Heap::CreateJSConstructEntryStub() {
2654 JSConstructEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002655 set_js_construct_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002656}
2657
2658
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002659void Heap::CreateFixedStubs() {
2660 // Here we create roots for fixed stubs. They are needed at GC
2661 // for cooking and uncooking (check out frames.cc).
2662 // The eliminates the need for doing dictionary lookup in the
2663 // stub cache for these stubs.
2664 HandleScope scope;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002665 // gcc-4.4 has problem generating correct code of following snippet:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002666 // { JSEntryStub stub;
2667 // js_entry_code_ = *stub.GetCode();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002668 // }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002669 // { JSConstructEntryStub stub;
2670 // js_construct_entry_code_ = *stub.GetCode();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002671 // }
2672 // To workaround the problem, make separate functions without inlining.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002673 Heap::CreateJSEntryStub();
2674 Heap::CreateJSConstructEntryStub();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002675
2676 // Create stubs that should be there, so we don't unexpectedly have to
2677 // create them if we need them during the creation of another stub.
2678 // Stub creation mixes raw pointers and handles in an unsafe manner so
2679 // we cannot create stubs while we are creating stubs.
2680 CodeStub::GenerateStubsAheadOfTime();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002681}
2682
2683
2684bool Heap::CreateInitialObjects() {
2685 Object* obj;
2686
2687 // The -0 value must be set before NumberFromDouble works.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002688 { MaybeObject* maybe_obj = AllocateHeapNumber(-0.0, TENURED);
2689 if (!maybe_obj->ToObject(&obj)) return false;
2690 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002691 set_minus_zero_value(HeapNumber::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002692 ASSERT(signbit(minus_zero_value()->Number()) != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002693
lrn@chromium.org303ada72010-10-27 09:33:13 +00002694 { MaybeObject* maybe_obj = AllocateHeapNumber(OS::nan_value(), TENURED);
2695 if (!maybe_obj->ToObject(&obj)) return false;
2696 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002697 set_nan_value(HeapNumber::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002698
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002699 { MaybeObject* maybe_obj = AllocateHeapNumber(V8_INFINITY, TENURED);
2700 if (!maybe_obj->ToObject(&obj)) return false;
2701 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002702 set_infinity_value(HeapNumber::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002703
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00002704 // The hole has not been created yet, but we want to put something
2705 // predictable in the gaps in the symbol table, so lets make that Smi zero.
2706 set_the_hole_value(reinterpret_cast<Oddball*>(Smi::FromInt(0)));
2707
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002708 // Allocate initial symbol table.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002709 { MaybeObject* maybe_obj = SymbolTable::Allocate(kInitialSymbolTableSize);
2710 if (!maybe_obj->ToObject(&obj)) return false;
2711 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002712 // Don't use set_symbol_table() due to asserts.
2713 roots_[kSymbolTableRootIndex] = obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002714
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002715 // Finish initializing oddballs after creating symboltable.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002716 { MaybeObject* maybe_obj =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002717 undefined_value()->Initialize("undefined",
2718 nan_value(),
2719 Oddball::kUndefined);
2720 if (!maybe_obj->ToObject(&obj)) return false;
2721 }
2722
2723 // Initialize the null_value.
2724 { MaybeObject* maybe_obj =
2725 null_value()->Initialize("null", Smi::FromInt(0), Oddball::kNull);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002726 if (!maybe_obj->ToObject(&obj)) return false;
2727 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002728
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002729 { MaybeObject* maybe_obj = CreateOddball("true",
2730 Smi::FromInt(1),
2731 Oddball::kTrue);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002732 if (!maybe_obj->ToObject(&obj)) return false;
2733 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002734 set_true_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002735
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002736 { MaybeObject* maybe_obj = CreateOddball("false",
2737 Smi::FromInt(0),
2738 Oddball::kFalse);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002739 if (!maybe_obj->ToObject(&obj)) return false;
2740 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002741 set_false_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002742
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002743 { MaybeObject* maybe_obj = CreateOddball("hole",
2744 Smi::FromInt(-1),
2745 Oddball::kTheHole);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002746 if (!maybe_obj->ToObject(&obj)) return false;
2747 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002748 set_the_hole_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002749
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002750 { MaybeObject* maybe_obj = CreateOddball("arguments_marker",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002751 Smi::FromInt(-4),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002752 Oddball::kArgumentMarker);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002753 if (!maybe_obj->ToObject(&obj)) return false;
2754 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002755 set_arguments_marker(Oddball::cast(obj));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002756
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002757 { MaybeObject* maybe_obj = CreateOddball("no_interceptor_result_sentinel",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002758 Smi::FromInt(-2),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002759 Oddball::kOther);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002760 if (!maybe_obj->ToObject(&obj)) return false;
2761 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002762 set_no_interceptor_result_sentinel(obj);
2763
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002764 { MaybeObject* maybe_obj = CreateOddball("termination_exception",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002765 Smi::FromInt(-3),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002766 Oddball::kOther);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002767 if (!maybe_obj->ToObject(&obj)) return false;
2768 }
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00002769 set_termination_exception(obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002770
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002771 // Allocate the empty string.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002772 { MaybeObject* maybe_obj = AllocateRawOneByteString(0, TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002773 if (!maybe_obj->ToObject(&obj)) return false;
2774 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002775 set_empty_string(String::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002776
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002777 for (unsigned i = 0; i < ARRAY_SIZE(constant_symbol_table); i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002778 { MaybeObject* maybe_obj =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002779 LookupUtf8Symbol(constant_symbol_table[i].contents);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002780 if (!maybe_obj->ToObject(&obj)) return false;
2781 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002782 roots_[constant_symbol_table[i].index] = String::cast(obj);
2783 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002784
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002785 // Allocate the hidden symbol which is used to identify the hidden properties
2786 // in JSObjects. The hash code has a special value so that it will not match
2787 // the empty string when searching for the property. It cannot be part of the
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002788 // loop above because it needs to be allocated manually with the special
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002789 // hash code in place. The hash code for the hidden_symbol is zero to ensure
2790 // that it will always be at the first entry in property descriptors.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002791 { MaybeObject* maybe_obj =
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002792 AllocateSymbol(CStrVector(""), 0, String::kEmptyStringHash);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002793 if (!maybe_obj->ToObject(&obj)) return false;
2794 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002795 hidden_symbol_ = String::cast(obj);
2796
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002797 // Allocate the foreign for __proto__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002798 { MaybeObject* maybe_obj =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002799 AllocateForeign((Address) &Accessors::ObjectPrototype);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002800 if (!maybe_obj->ToObject(&obj)) return false;
2801 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002802 set_prototype_accessors(Foreign::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002803
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002804 // Allocate the code_stubs dictionary. The initial size is set to avoid
2805 // expanding the dictionary during bootstrapping.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002806 { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(128);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002807 if (!maybe_obj->ToObject(&obj)) return false;
2808 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002809 set_code_stubs(UnseededNumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002810
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002811
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002812 // Allocate the non_monomorphic_cache used in stub-cache.cc. The initial size
2813 // is set to avoid expanding the dictionary during bootstrapping.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002814 { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(64);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002815 if (!maybe_obj->ToObject(&obj)) return false;
2816 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002817 set_non_monomorphic_cache(UnseededNumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002818
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002819 { MaybeObject* maybe_obj = AllocatePolymorphicCodeCache();
2820 if (!maybe_obj->ToObject(&obj)) return false;
2821 }
2822 set_polymorphic_code_cache(PolymorphicCodeCache::cast(obj));
2823
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002824 set_instanceof_cache_function(Smi::FromInt(0));
2825 set_instanceof_cache_map(Smi::FromInt(0));
2826 set_instanceof_cache_answer(Smi::FromInt(0));
2827
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002828 CreateFixedStubs();
2829
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002830 // Allocate the dictionary of intrinsic function names.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002831 { MaybeObject* maybe_obj = StringDictionary::Allocate(Runtime::kNumFunctions);
2832 if (!maybe_obj->ToObject(&obj)) return false;
2833 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002834 { MaybeObject* maybe_obj = Runtime::InitializeIntrinsicFunctionNames(this,
2835 obj);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002836 if (!maybe_obj->ToObject(&obj)) return false;
2837 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002838 set_intrinsic_function_names(StringDictionary::cast(obj));
2839
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002840 { MaybeObject* maybe_obj = AllocateInitialNumberStringCache();
2841 if (!maybe_obj->ToObject(&obj)) return false;
2842 }
2843 set_number_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002844
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002845 // Allocate cache for single character ASCII strings.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002846 { MaybeObject* maybe_obj =
2847 AllocateFixedArray(String::kMaxAsciiCharCode + 1, TENURED);
2848 if (!maybe_obj->ToObject(&obj)) return false;
2849 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002850 set_single_character_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002851
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002852 // Allocate cache for string split.
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002853 { MaybeObject* maybe_obj = AllocateFixedArray(
2854 RegExpResultsCache::kRegExpResultsCacheSize, TENURED);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002855 if (!maybe_obj->ToObject(&obj)) return false;
2856 }
2857 set_string_split_cache(FixedArray::cast(obj));
2858
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002859 { MaybeObject* maybe_obj = AllocateFixedArray(
2860 RegExpResultsCache::kRegExpResultsCacheSize, TENURED);
2861 if (!maybe_obj->ToObject(&obj)) return false;
2862 }
2863 set_regexp_multiple_cache(FixedArray::cast(obj));
2864
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002865 // Allocate cache for external strings pointing to native source code.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002866 { MaybeObject* maybe_obj = AllocateFixedArray(Natives::GetBuiltinsCount());
2867 if (!maybe_obj->ToObject(&obj)) return false;
2868 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002869 set_natives_source_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002870
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002871 // Allocate object to hold object observation state.
2872 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
2873 if (!maybe_obj->ToObject(&obj)) return false;
2874 }
2875 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(Map::cast(obj));
2876 if (!maybe_obj->ToObject(&obj)) return false;
2877 }
2878 set_observation_state(JSObject::cast(obj));
2879
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002880 // Handling of script id generation is in FACTORY->NewScript.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002881 set_last_script_id(undefined_value());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002882
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002883 // Initialize keyed lookup cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002884 isolate_->keyed_lookup_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002885
2886 // Initialize context slot cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002887 isolate_->context_slot_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002888
2889 // Initialize descriptor cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002890 isolate_->descriptor_lookup_cache()->Clear();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002891
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002892 // Initialize compilation cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002893 isolate_->compilation_cache()->Clear();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002894
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002895 return true;
2896}
2897
2898
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002899bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) {
2900 RootListIndex writable_roots[] = {
2901 kStoreBufferTopRootIndex,
2902 kStackLimitRootIndex,
2903 kInstanceofCacheFunctionRootIndex,
2904 kInstanceofCacheMapRootIndex,
2905 kInstanceofCacheAnswerRootIndex,
2906 kCodeStubsRootIndex,
2907 kNonMonomorphicCacheRootIndex,
2908 kPolymorphicCodeCacheRootIndex,
2909 kLastScriptIdRootIndex,
2910 kEmptyScriptRootIndex,
2911 kRealStackLimitRootIndex,
2912 kArgumentsAdaptorDeoptPCOffsetRootIndex,
2913 kConstructStubDeoptPCOffsetRootIndex,
2914 kGetterStubDeoptPCOffsetRootIndex,
2915 kSetterStubDeoptPCOffsetRootIndex,
2916 kSymbolTableRootIndex,
2917 };
2918
2919 for (unsigned int i = 0; i < ARRAY_SIZE(writable_roots); i++) {
2920 if (root_index == writable_roots[i])
2921 return true;
2922 }
2923 return false;
2924}
2925
2926
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002927Object* RegExpResultsCache::Lookup(Heap* heap,
2928 String* key_string,
2929 Object* key_pattern,
2930 ResultsCacheType type) {
2931 FixedArray* cache;
2932 if (!key_string->IsSymbol()) return Smi::FromInt(0);
2933 if (type == STRING_SPLIT_SUBSTRINGS) {
2934 ASSERT(key_pattern->IsString());
2935 if (!key_pattern->IsSymbol()) return Smi::FromInt(0);
2936 cache = heap->string_split_cache();
2937 } else {
2938 ASSERT(type == REGEXP_MULTIPLE_INDICES);
2939 ASSERT(key_pattern->IsFixedArray());
2940 cache = heap->regexp_multiple_cache();
2941 }
2942
2943 uint32_t hash = key_string->Hash();
2944 uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) &
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002945 ~(kArrayEntriesPerCacheEntry - 1));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002946 if (cache->get(index + kStringOffset) == key_string &&
2947 cache->get(index + kPatternOffset) == key_pattern) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002948 return cache->get(index + kArrayOffset);
2949 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002950 index =
2951 ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1));
2952 if (cache->get(index + kStringOffset) == key_string &&
2953 cache->get(index + kPatternOffset) == key_pattern) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002954 return cache->get(index + kArrayOffset);
2955 }
2956 return Smi::FromInt(0);
2957}
2958
2959
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002960void RegExpResultsCache::Enter(Heap* heap,
2961 String* key_string,
2962 Object* key_pattern,
2963 FixedArray* value_array,
2964 ResultsCacheType type) {
2965 FixedArray* cache;
2966 if (!key_string->IsSymbol()) return;
2967 if (type == STRING_SPLIT_SUBSTRINGS) {
2968 ASSERT(key_pattern->IsString());
2969 if (!key_pattern->IsSymbol()) return;
2970 cache = heap->string_split_cache();
2971 } else {
2972 ASSERT(type == REGEXP_MULTIPLE_INDICES);
2973 ASSERT(key_pattern->IsFixedArray());
2974 cache = heap->regexp_multiple_cache();
2975 }
2976
2977 uint32_t hash = key_string->Hash();
2978 uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) &
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002979 ~(kArrayEntriesPerCacheEntry - 1));
2980 if (cache->get(index + kStringOffset) == Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002981 cache->set(index + kStringOffset, key_string);
2982 cache->set(index + kPatternOffset, key_pattern);
2983 cache->set(index + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002984 } else {
2985 uint32_t index2 =
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002986 ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1));
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002987 if (cache->get(index2 + kStringOffset) == Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002988 cache->set(index2 + kStringOffset, key_string);
2989 cache->set(index2 + kPatternOffset, key_pattern);
2990 cache->set(index2 + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002991 } else {
2992 cache->set(index2 + kStringOffset, Smi::FromInt(0));
2993 cache->set(index2 + kPatternOffset, Smi::FromInt(0));
2994 cache->set(index2 + kArrayOffset, Smi::FromInt(0));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002995 cache->set(index + kStringOffset, key_string);
2996 cache->set(index + kPatternOffset, key_pattern);
2997 cache->set(index + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002998 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002999 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003000 // If the array is a reasonably short list of substrings, convert it into a
3001 // list of symbols.
3002 if (type == STRING_SPLIT_SUBSTRINGS && value_array->length() < 100) {
3003 for (int i = 0; i < value_array->length(); i++) {
3004 String* str = String::cast(value_array->get(i));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003005 Object* symbol;
3006 MaybeObject* maybe_symbol = heap->LookupSymbol(str);
3007 if (maybe_symbol->ToObject(&symbol)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003008 value_array->set(i, symbol);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003009 }
3010 }
3011 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003012 // Convert backing store to a copy-on-write array.
3013 value_array->set_map_no_write_barrier(heap->fixed_cow_array_map());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003014}
3015
3016
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003017void RegExpResultsCache::Clear(FixedArray* cache) {
3018 for (int i = 0; i < kRegExpResultsCacheSize; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003019 cache->set(i, Smi::FromInt(0));
3020 }
3021}
3022
3023
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003024MaybeObject* Heap::AllocateInitialNumberStringCache() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003025 MaybeObject* maybe_obj =
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003026 AllocateFixedArray(kInitialNumberStringCacheSize * 2, TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003027 return maybe_obj;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003028}
3029
3030
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003031int Heap::FullSizeNumberStringCacheLength() {
3032 // Compute the size of the number string cache based on the max newspace size.
3033 // The number string cache has a minimum size based on twice the initial cache
3034 // size to ensure that it is bigger after being made 'full size'.
3035 int number_string_cache_size = max_semispace_size_ / 512;
3036 number_string_cache_size = Max(kInitialNumberStringCacheSize * 2,
3037 Min(0x4000, number_string_cache_size));
3038 // There is a string and a number per entry so the length is twice the number
3039 // of entries.
3040 return number_string_cache_size * 2;
3041}
3042
3043
3044void Heap::AllocateFullSizeNumberStringCache() {
3045 // The idea is to have a small number string cache in the snapshot to keep
3046 // boot-time memory usage down. If we expand the number string cache already
3047 // while creating the snapshot then that didn't work out.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003048 ASSERT(!Serializer::enabled() || FLAG_extra_code != NULL);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003049 MaybeObject* maybe_obj =
3050 AllocateFixedArray(FullSizeNumberStringCacheLength(), TENURED);
3051 Object* new_cache;
3052 if (maybe_obj->ToObject(&new_cache)) {
3053 // We don't bother to repopulate the cache with entries from the old cache.
3054 // It will be repopulated soon enough with new strings.
3055 set_number_string_cache(FixedArray::cast(new_cache));
3056 }
3057 // If allocation fails then we just return without doing anything. It is only
3058 // a cache, so best effort is OK here.
3059}
3060
3061
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003062void Heap::FlushNumberStringCache() {
3063 // Flush the number to string cache.
3064 int len = number_string_cache()->length();
3065 for (int i = 0; i < len; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003066 number_string_cache()->set_undefined(this, i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003067 }
3068}
3069
3070
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003071static inline int double_get_hash(double d) {
3072 DoubleRepresentation rep(d);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003073 return static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003074}
3075
3076
3077static inline int smi_get_hash(Smi* smi) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003078 return smi->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003079}
3080
3081
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003082Object* Heap::GetNumberStringCache(Object* number) {
3083 int hash;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003084 int mask = (number_string_cache()->length() >> 1) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003085 if (number->IsSmi()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003086 hash = smi_get_hash(Smi::cast(number)) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003087 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003088 hash = double_get_hash(number->Number()) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003089 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003090 Object* key = number_string_cache()->get(hash * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003091 if (key == number) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003092 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003093 } else if (key->IsHeapNumber() &&
3094 number->IsHeapNumber() &&
3095 key->Number() == number->Number()) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003096 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003097 }
3098 return undefined_value();
3099}
3100
3101
3102void Heap::SetNumberStringCache(Object* number, String* string) {
3103 int hash;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003104 int mask = (number_string_cache()->length() >> 1) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003105 if (number->IsSmi()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003106 hash = smi_get_hash(Smi::cast(number)) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003107 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003108 hash = double_get_hash(number->Number()) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003109 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003110 if (number_string_cache()->get(hash * 2) != undefined_value() &&
3111 number_string_cache()->length() != FullSizeNumberStringCacheLength()) {
3112 // The first time we have a hash collision, we move to the full sized
3113 // number string cache.
3114 AllocateFullSizeNumberStringCache();
3115 return;
3116 }
3117 number_string_cache()->set(hash * 2, number);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003118 number_string_cache()->set(hash * 2 + 1, string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003119}
3120
3121
lrn@chromium.org303ada72010-10-27 09:33:13 +00003122MaybeObject* Heap::NumberToString(Object* number,
3123 bool check_number_string_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003124 isolate_->counters()->number_to_string_runtime()->Increment();
ager@chromium.org357bf652010-04-12 11:30:10 +00003125 if (check_number_string_cache) {
3126 Object* cached = GetNumberStringCache(number);
3127 if (cached != undefined_value()) {
3128 return cached;
3129 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003130 }
3131
3132 char arr[100];
3133 Vector<char> buffer(arr, ARRAY_SIZE(arr));
3134 const char* str;
3135 if (number->IsSmi()) {
3136 int num = Smi::cast(number)->value();
3137 str = IntToCString(num, buffer);
3138 } else {
3139 double num = HeapNumber::cast(number)->value();
3140 str = DoubleToCString(num, buffer);
3141 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003142
lrn@chromium.org303ada72010-10-27 09:33:13 +00003143 Object* js_string;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003144 MaybeObject* maybe_js_string = AllocateStringFromOneByte(CStrVector(str));
lrn@chromium.org303ada72010-10-27 09:33:13 +00003145 if (maybe_js_string->ToObject(&js_string)) {
3146 SetNumberStringCache(number, String::cast(js_string));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003147 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00003148 return maybe_js_string;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003149}
3150
3151
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003152MaybeObject* Heap::Uint32ToString(uint32_t value,
3153 bool check_number_string_cache) {
3154 Object* number;
3155 MaybeObject* maybe = NumberFromUint32(value);
3156 if (!maybe->To<Object>(&number)) return maybe;
3157 return NumberToString(number, check_number_string_cache);
3158}
3159
3160
ager@chromium.org3811b432009-10-28 14:53:37 +00003161Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) {
3162 return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]);
3163}
3164
3165
3166Heap::RootListIndex Heap::RootIndexForExternalArrayType(
3167 ExternalArrayType array_type) {
3168 switch (array_type) {
3169 case kExternalByteArray:
3170 return kExternalByteArrayMapRootIndex;
3171 case kExternalUnsignedByteArray:
3172 return kExternalUnsignedByteArrayMapRootIndex;
3173 case kExternalShortArray:
3174 return kExternalShortArrayMapRootIndex;
3175 case kExternalUnsignedShortArray:
3176 return kExternalUnsignedShortArrayMapRootIndex;
3177 case kExternalIntArray:
3178 return kExternalIntArrayMapRootIndex;
3179 case kExternalUnsignedIntArray:
3180 return kExternalUnsignedIntArrayMapRootIndex;
3181 case kExternalFloatArray:
3182 return kExternalFloatArrayMapRootIndex;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003183 case kExternalDoubleArray:
3184 return kExternalDoubleArrayMapRootIndex;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003185 case kExternalPixelArray:
3186 return kExternalPixelArrayMapRootIndex;
ager@chromium.org3811b432009-10-28 14:53:37 +00003187 default:
3188 UNREACHABLE();
3189 return kUndefinedValueRootIndex;
3190 }
3191}
3192
3193
lrn@chromium.org303ada72010-10-27 09:33:13 +00003194MaybeObject* Heap::NumberFromDouble(double value, PretenureFlag pretenure) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003195 // We need to distinguish the minus zero value and this cannot be
3196 // done after conversion to int. Doing this by comparing bit
3197 // patterns is faster than using fpclassify() et al.
3198 static const DoubleRepresentation minus_zero(-0.0);
3199
3200 DoubleRepresentation rep(value);
3201 if (rep.bits == minus_zero.bits) {
3202 return AllocateHeapNumber(-0.0, pretenure);
3203 }
3204
3205 int int_value = FastD2I(value);
3206 if (value == int_value && Smi::IsValid(int_value)) {
3207 return Smi::FromInt(int_value);
3208 }
3209
3210 // Materialize the value in the heap.
3211 return AllocateHeapNumber(value, pretenure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003212}
3213
3214
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003215MaybeObject* Heap::AllocateForeign(Address address, PretenureFlag pretenure) {
3216 // Statically ensure that it is safe to allocate foreigns in paged spaces.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003217 STATIC_ASSERT(Foreign::kSize <= Page::kMaxNonCodeHeapObjectSize);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003218 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003219 Foreign* result;
3220 MaybeObject* maybe_result = Allocate(foreign_map(), space);
3221 if (!maybe_result->To(&result)) return maybe_result;
3222 result->set_foreign_address(address);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003223 return result;
3224}
3225
3226
lrn@chromium.org303ada72010-10-27 09:33:13 +00003227MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003228 SharedFunctionInfo* share;
3229 MaybeObject* maybe = Allocate(shared_function_info_map(), OLD_POINTER_SPACE);
3230 if (!maybe->To<SharedFunctionInfo>(&share)) return maybe;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003231
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003232 // Set pointer fields.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003233 share->set_name(name);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003234 Code* illegal = isolate_->builtins()->builtin(Builtins::kIllegal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003235 share->set_code(illegal);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003236 share->ClearOptimizedCodeMap();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003237 share->set_scope_info(ScopeInfo::Empty());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003238 Code* construct_stub =
3239 isolate_->builtins()->builtin(Builtins::kJSConstructStubGeneric);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003240 share->set_construct_stub(construct_stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003241 share->set_instance_class_name(Object_symbol());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003242 share->set_function_data(undefined_value(), SKIP_WRITE_BARRIER);
3243 share->set_script(undefined_value(), SKIP_WRITE_BARRIER);
3244 share->set_debug_info(undefined_value(), SKIP_WRITE_BARRIER);
3245 share->set_inferred_name(empty_string(), SKIP_WRITE_BARRIER);
3246 share->set_initial_map(undefined_value(), SKIP_WRITE_BARRIER);
3247 share->set_this_property_assignments(undefined_value(), SKIP_WRITE_BARRIER);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003248 share->set_ast_node_count(0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003249 share->set_stress_deopt_counter(FLAG_deopt_every_n_times);
3250 share->set_counters(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003251
3252 // Set integer fields (smi or int, depending on the architecture).
3253 share->set_length(0);
3254 share->set_formal_parameter_count(0);
3255 share->set_expected_nof_properties(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003256 share->set_num_literals(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003257 share->set_start_position_and_type(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003258 share->set_end_position(0);
3259 share->set_function_token_position(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003260 // All compiler hints default to false or 0.
3261 share->set_compiler_hints(0);
3262 share->set_this_property_assignments_count(0);
3263 share->set_opt_count(0);
3264
3265 return share;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003266}
3267
3268
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003269MaybeObject* Heap::AllocateJSMessageObject(String* type,
3270 JSArray* arguments,
3271 int start_position,
3272 int end_position,
3273 Object* script,
3274 Object* stack_trace,
3275 Object* stack_frames) {
3276 Object* result;
3277 { MaybeObject* maybe_result = Allocate(message_object_map(), NEW_SPACE);
3278 if (!maybe_result->ToObject(&result)) return maybe_result;
3279 }
3280 JSMessageObject* message = JSMessageObject::cast(result);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003281 message->set_properties(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003282 message->initialize_elements();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003283 message->set_elements(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003284 message->set_type(type);
3285 message->set_arguments(arguments);
3286 message->set_start_position(start_position);
3287 message->set_end_position(end_position);
3288 message->set_script(script);
3289 message->set_stack_trace(stack_trace);
3290 message->set_stack_frames(stack_frames);
3291 return result;
3292}
3293
3294
3295
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003296// Returns true for a character in a range. Both limits are inclusive.
3297static inline bool Between(uint32_t character, uint32_t from, uint32_t to) {
3298 // This makes uses of the the unsigned wraparound.
3299 return character - from <= to - from;
3300}
3301
3302
lrn@chromium.org303ada72010-10-27 09:33:13 +00003303MUST_USE_RESULT static inline MaybeObject* MakeOrFindTwoCharacterString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003304 Heap* heap,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003305 uint16_t c1,
3306 uint16_t c2) {
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003307 String* symbol;
3308 // Numeric strings have a different hash algorithm not known by
3309 // LookupTwoCharsSymbolIfExists, so we skip this step for such strings.
3310 if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003311 heap->symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) {
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003312 return symbol;
3313 // Now we know the length is 2, we might as well make use of that fact
3314 // when building the new string.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003315 } else if (static_cast<unsigned>(c1 | c2) <= String::kMaxAsciiCharCodeU) {
3316 // We can do this.
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003317 ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1)); // because of this.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003318 Object* result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003319 { MaybeObject* maybe_result = heap->AllocateRawOneByteString(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003320 if (!maybe_result->ToObject(&result)) return maybe_result;
3321 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003322 char* dest = SeqOneByteString::cast(result)->GetChars();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003323 dest[0] = static_cast<char>(c1);
3324 dest[1] = static_cast<char>(c2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003325 return result;
3326 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003327 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003328 { MaybeObject* maybe_result = heap->AllocateRawTwoByteString(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003329 if (!maybe_result->ToObject(&result)) return maybe_result;
3330 }
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003331 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
3332 dest[0] = c1;
3333 dest[1] = c2;
3334 return result;
3335 }
3336}
3337
3338
lrn@chromium.org303ada72010-10-27 09:33:13 +00003339MaybeObject* Heap::AllocateConsString(String* first, String* second) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003340 int first_length = first->length();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003341 if (first_length == 0) {
3342 return second;
3343 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003344
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003345 int second_length = second->length();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003346 if (second_length == 0) {
3347 return first;
3348 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003349
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003350 int length = first_length + second_length;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003351
3352 // Optimization for 2-byte strings often used as keys in a decompression
3353 // dictionary. Check whether we already have the string in the symbol
3354 // table to prevent creation of many unneccesary strings.
3355 if (length == 2) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003356 uint16_t c1 = first->Get(0);
3357 uint16_t c2 = second->Get(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003358 return MakeOrFindTwoCharacterString(this, c1, c2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003359 }
3360
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003361 bool first_is_ascii = first->IsOneByteRepresentation();
3362 bool second_is_ascii = second->IsOneByteRepresentation();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003363 bool is_ascii = first_is_ascii && second_is_ascii;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003364
ager@chromium.org3e875802009-06-29 08:26:34 +00003365 // Make sure that an out of memory exception is thrown if the length
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003366 // of the new cons string is too large.
3367 if (length > String::kMaxLength || length < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003368 isolate()->context()->mark_out_of_memory();
ager@chromium.org3e875802009-06-29 08:26:34 +00003369 return Failure::OutOfMemoryException();
3370 }
3371
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003372 bool is_ascii_data_in_two_byte_string = false;
3373 if (!is_ascii) {
3374 // At least one of the strings uses two-byte representation so we
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003375 // can't use the fast case code for short ASCII strings below, but
3376 // we can try to save memory if all chars actually fit in ASCII.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003377 is_ascii_data_in_two_byte_string =
3378 first->HasOnlyAsciiChars() && second->HasOnlyAsciiChars();
3379 if (is_ascii_data_in_two_byte_string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003380 isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003381 }
3382 }
3383
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003384 // If the resulting string is small make a flat string.
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003385 if (length < ConsString::kMinLength) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003386 // Note that neither of the two inputs can be a slice because:
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003387 STATIC_ASSERT(ConsString::kMinLength <= SlicedString::kMinLength);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003388 ASSERT(first->IsFlat());
3389 ASSERT(second->IsFlat());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003390 if (is_ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003391 Object* result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003392 { MaybeObject* maybe_result = AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003393 if (!maybe_result->ToObject(&result)) return maybe_result;
3394 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003395 // Copy the characters into the new object.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003396 char* dest = SeqOneByteString::cast(result)->GetChars();
ager@chromium.org3e875802009-06-29 08:26:34 +00003397 // Copy first part.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003398 const char* src;
3399 if (first->IsExternalString()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003400 src = ExternalAsciiString::cast(first)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003401 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003402 src = SeqOneByteString::cast(first)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003403 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003404 for (int i = 0; i < first_length; i++) *dest++ = src[i];
3405 // Copy second part.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003406 if (second->IsExternalString()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003407 src = ExternalAsciiString::cast(second)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003408 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003409 src = SeqOneByteString::cast(second)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003410 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003411 for (int i = 0; i < second_length; i++) *dest++ = src[i];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003412 return result;
3413 } else {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003414 if (is_ascii_data_in_two_byte_string) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003415 Object* result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003416 { MaybeObject* maybe_result = AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003417 if (!maybe_result->ToObject(&result)) return maybe_result;
3418 }
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003419 // Copy the characters into the new object.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003420 char* dest = SeqOneByteString::cast(result)->GetChars();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003421 String::WriteToFlat(first, dest, 0, first_length);
3422 String::WriteToFlat(second, dest + first_length, 0, second_length);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003423 isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003424 return result;
3425 }
3426
lrn@chromium.org303ada72010-10-27 09:33:13 +00003427 Object* result;
3428 { MaybeObject* maybe_result = AllocateRawTwoByteString(length);
3429 if (!maybe_result->ToObject(&result)) return maybe_result;
3430 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003431 // Copy the characters into the new object.
3432 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003433 String::WriteToFlat(first, dest, 0, first_length);
3434 String::WriteToFlat(second, dest + first_length, 0, second_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003435 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003436 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003437 }
3438
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003439 Map* map = (is_ascii || is_ascii_data_in_two_byte_string) ?
3440 cons_ascii_string_map() : cons_string_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003441
lrn@chromium.org303ada72010-10-27 09:33:13 +00003442 Object* result;
3443 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3444 if (!maybe_result->ToObject(&result)) return maybe_result;
3445 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003446
3447 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003448 ConsString* cons_string = ConsString::cast(result);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003449 WriteBarrierMode mode = cons_string->GetWriteBarrierMode(no_gc);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003450 cons_string->set_length(length);
3451 cons_string->set_hash_field(String::kEmptyHashField);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003452 cons_string->set_first(first, mode);
3453 cons_string->set_second(second, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003454 return result;
3455}
3456
3457
lrn@chromium.org303ada72010-10-27 09:33:13 +00003458MaybeObject* Heap::AllocateSubString(String* buffer,
ager@chromium.org04921a82011-06-27 13:21:41 +00003459 int start,
3460 int end,
3461 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003462 int length = end - start;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003463 if (length <= 0) {
ager@chromium.org04921a82011-06-27 13:21:41 +00003464 return empty_string();
3465 } else if (length == 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003466 return LookupSingleCharacterStringFromCode(buffer->Get(start));
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003467 } else if (length == 2) {
3468 // Optimization for 2-byte strings often used as keys in a decompression
3469 // dictionary. Check whether we already have the string in the symbol
3470 // table to prevent creation of many unneccesary strings.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003471 uint16_t c1 = buffer->Get(start);
3472 uint16_t c2 = buffer->Get(start + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003473 return MakeOrFindTwoCharacterString(this, c1, c2);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003474 }
3475
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003476 // Make an attempt to flatten the buffer to reduce access time.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003477 buffer = buffer->TryFlattenGetString();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003478
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003479 if (!FLAG_string_slices ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003480 !buffer->IsFlat() ||
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003481 length < SlicedString::kMinLength ||
3482 pretenure == TENURED) {
3483 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003484 // WriteToFlat takes care of the case when an indirect string has a
3485 // different encoding from its underlying string. These encodings may
3486 // differ because of externalization.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003487 bool is_ascii = buffer->IsOneByteRepresentation();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003488 { MaybeObject* maybe_result = is_ascii
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003489 ? AllocateRawOneByteString(length, pretenure)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003490 : AllocateRawTwoByteString(length, pretenure);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003491 if (!maybe_result->ToObject(&result)) return maybe_result;
3492 }
3493 String* string_result = String::cast(result);
3494 // Copy the characters into the new object.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003495 if (is_ascii) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003496 ASSERT(string_result->IsOneByteRepresentation());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003497 char* dest = SeqOneByteString::cast(string_result)->GetChars();
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003498 String::WriteToFlat(buffer, dest, start, end);
3499 } else {
3500 ASSERT(string_result->IsTwoByteRepresentation());
3501 uc16* dest = SeqTwoByteString::cast(string_result)->GetChars();
3502 String::WriteToFlat(buffer, dest, start, end);
3503 }
3504 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003505 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003506
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003507 ASSERT(buffer->IsFlat());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003508#if VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003509 if (FLAG_verify_heap) {
3510 buffer->StringVerify();
3511 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003512#endif
3513
3514 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003515 // When slicing an indirect string we use its encoding for a newly created
3516 // slice and don't check the encoding of the underlying string. This is safe
3517 // even if the encodings are different because of externalization. If an
3518 // indirect ASCII string is pointing to a two-byte string, the two-byte char
3519 // codes of the underlying string must still fit into ASCII (because
3520 // externalization must not change char codes).
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003521 { Map* map = buffer->IsOneByteRepresentation()
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003522 ? sliced_ascii_string_map()
3523 : sliced_string_map();
3524 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3525 if (!maybe_result->ToObject(&result)) return maybe_result;
3526 }
3527
3528 AssertNoAllocation no_gc;
3529 SlicedString* sliced_string = SlicedString::cast(result);
3530 sliced_string->set_length(length);
3531 sliced_string->set_hash_field(String::kEmptyHashField);
3532 if (buffer->IsConsString()) {
3533 ConsString* cons = ConsString::cast(buffer);
3534 ASSERT(cons->second()->length() == 0);
3535 sliced_string->set_parent(cons->first());
3536 sliced_string->set_offset(start);
3537 } else if (buffer->IsSlicedString()) {
3538 // Prevent nesting sliced strings.
3539 SlicedString* parent_slice = SlicedString::cast(buffer);
3540 sliced_string->set_parent(parent_slice->parent());
3541 sliced_string->set_offset(start + parent_slice->offset());
3542 } else {
3543 sliced_string->set_parent(buffer);
3544 sliced_string->set_offset(start);
3545 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003546 ASSERT(sliced_string->parent()->IsSeqString() ||
3547 sliced_string->parent()->IsExternalString());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003548 return result;
3549}
3550
3551
lrn@chromium.org303ada72010-10-27 09:33:13 +00003552MaybeObject* Heap::AllocateExternalStringFromAscii(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003553 const ExternalAsciiString::Resource* resource) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003554 size_t length = resource->length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003555 if (length > static_cast<size_t>(String::kMaxLength)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003556 isolate()->context()->mark_out_of_memory();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003557 return Failure::OutOfMemoryException();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003558 }
3559
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00003560 ASSERT(String::IsAscii(resource->data(), static_cast<int>(length)));
3561
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003562 Map* map = external_ascii_string_map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003563 Object* result;
3564 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3565 if (!maybe_result->ToObject(&result)) return maybe_result;
3566 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003567
3568 ExternalAsciiString* external_string = ExternalAsciiString::cast(result);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003569 external_string->set_length(static_cast<int>(length));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003570 external_string->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003571 external_string->set_resource(resource);
3572
3573 return result;
3574}
3575
3576
lrn@chromium.org303ada72010-10-27 09:33:13 +00003577MaybeObject* Heap::AllocateExternalStringFromTwoByte(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003578 const ExternalTwoByteString::Resource* resource) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003579 size_t length = resource->length();
3580 if (length > static_cast<size_t>(String::kMaxLength)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003581 isolate()->context()->mark_out_of_memory();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003582 return Failure::OutOfMemoryException();
3583 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003584
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003585 // For small strings we check whether the resource contains only
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003586 // ASCII characters. If yes, we use a different string map.
3587 static const size_t kAsciiCheckLengthLimit = 32;
3588 bool is_ascii = length <= kAsciiCheckLengthLimit &&
3589 String::IsAscii(resource->data(), static_cast<int>(length));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003590 Map* map = is_ascii ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003591 external_string_with_ascii_data_map() : external_string_map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003592 Object* result;
3593 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3594 if (!maybe_result->ToObject(&result)) return maybe_result;
3595 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003596
3597 ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003598 external_string->set_length(static_cast<int>(length));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003599 external_string->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003600 external_string->set_resource(resource);
3601
3602 return result;
3603}
3604
3605
lrn@chromium.org303ada72010-10-27 09:33:13 +00003606MaybeObject* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003607 if (code <= String::kMaxAsciiCharCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003608 Object* value = single_character_string_cache()->get(code);
3609 if (value != undefined_value()) return value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003610
3611 char buffer[1];
3612 buffer[0] = static_cast<char>(code);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003613 Object* result;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003614 MaybeObject* maybe_result =
3615 LookupOneByteSymbol(Vector<const char>(buffer, 1));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003616
lrn@chromium.org303ada72010-10-27 09:33:13 +00003617 if (!maybe_result->ToObject(&result)) return maybe_result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003618 single_character_string_cache()->set(code, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003619 return result;
3620 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003621
lrn@chromium.org303ada72010-10-27 09:33:13 +00003622 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003623 { MaybeObject* maybe_result = AllocateRawTwoByteString(1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003624 if (!maybe_result->ToObject(&result)) return maybe_result;
3625 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00003626 String* answer = String::cast(result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003627 answer->Set(0, code);
ager@chromium.org870a0b62008-11-04 11:43:05 +00003628 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629}
3630
3631
lrn@chromium.org303ada72010-10-27 09:33:13 +00003632MaybeObject* Heap::AllocateByteArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003633 if (length < 0 || length > ByteArray::kMaxLength) {
3634 return Failure::OutOfMemoryException();
3635 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003636 if (pretenure == NOT_TENURED) {
3637 return AllocateByteArray(length);
3638 }
3639 int size = ByteArray::SizeFor(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003640 Object* result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003641 { MaybeObject* maybe_result = (size <= Page::kMaxNonCodeHeapObjectSize)
lrn@chromium.org303ada72010-10-27 09:33:13 +00003642 ? old_data_space_->AllocateRaw(size)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003643 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003644 if (!maybe_result->ToObject(&result)) return maybe_result;
3645 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003646
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003647 reinterpret_cast<ByteArray*>(result)->set_map_no_write_barrier(
3648 byte_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003649 reinterpret_cast<ByteArray*>(result)->set_length(length);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003650 return result;
3651}
3652
3653
lrn@chromium.org303ada72010-10-27 09:33:13 +00003654MaybeObject* Heap::AllocateByteArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003655 if (length < 0 || length > ByteArray::kMaxLength) {
3656 return Failure::OutOfMemoryException();
3657 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003658 int size = ByteArray::SizeFor(length);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003659 AllocationSpace space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003660 (size > Page::kMaxNonCodeHeapObjectSize) ? LO_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003661 Object* result;
3662 { MaybeObject* maybe_result = AllocateRaw(size, space, OLD_DATA_SPACE);
3663 if (!maybe_result->ToObject(&result)) return maybe_result;
3664 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003665
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003666 reinterpret_cast<ByteArray*>(result)->set_map_no_write_barrier(
3667 byte_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003668 reinterpret_cast<ByteArray*>(result)->set_length(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003669 return result;
3670}
3671
3672
ager@chromium.org6f10e412009-02-13 10:11:16 +00003673void Heap::CreateFillerObjectAt(Address addr, int size) {
3674 if (size == 0) return;
3675 HeapObject* filler = HeapObject::FromAddress(addr);
3676 if (size == kPointerSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003677 filler->set_map_no_write_barrier(one_pointer_filler_map());
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00003678 } else if (size == 2 * kPointerSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003679 filler->set_map_no_write_barrier(two_pointer_filler_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +00003680 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003681 filler->set_map_no_write_barrier(free_space_map());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003682 FreeSpace::cast(filler)->set_size(size);
ager@chromium.org6f10e412009-02-13 10:11:16 +00003683 }
3684}
3685
3686
lrn@chromium.org303ada72010-10-27 09:33:13 +00003687MaybeObject* Heap::AllocateExternalArray(int length,
3688 ExternalArrayType array_type,
3689 void* external_pointer,
3690 PretenureFlag pretenure) {
ager@chromium.org3811b432009-10-28 14:53:37 +00003691 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003692 Object* result;
3693 { MaybeObject* maybe_result = AllocateRaw(ExternalArray::kAlignedSize,
3694 space,
3695 OLD_DATA_SPACE);
3696 if (!maybe_result->ToObject(&result)) return maybe_result;
3697 }
ager@chromium.org3811b432009-10-28 14:53:37 +00003698
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003699 reinterpret_cast<ExternalArray*>(result)->set_map_no_write_barrier(
ager@chromium.org3811b432009-10-28 14:53:37 +00003700 MapForExternalArrayType(array_type));
3701 reinterpret_cast<ExternalArray*>(result)->set_length(length);
3702 reinterpret_cast<ExternalArray*>(result)->set_external_pointer(
3703 external_pointer);
3704
3705 return result;
3706}
3707
3708
lrn@chromium.org303ada72010-10-27 09:33:13 +00003709MaybeObject* Heap::CreateCode(const CodeDesc& desc,
3710 Code::Flags flags,
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003711 Handle<Object> self_reference,
3712 bool immovable) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003713 // Allocate ByteArray before the Code object, so that we do not risk
3714 // leaving uninitialized Code object (and breaking the heap).
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003715 ByteArray* reloc_info;
3716 MaybeObject* maybe_reloc_info = AllocateByteArray(desc.reloc_size, TENURED);
3717 if (!maybe_reloc_info->To(&reloc_info)) return maybe_reloc_info;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003718
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003719 // Compute size.
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003720 int body_size = RoundUp(desc.instr_size, kObjectAlignment);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003721 int obj_size = Code::SizeFor(body_size);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003722 ASSERT(IsAligned(static_cast<intptr_t>(obj_size), kCodeAlignment));
lrn@chromium.org303ada72010-10-27 09:33:13 +00003723 MaybeObject* maybe_result;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003724 // Large code objects and code objects which should stay at a fixed address
3725 // are allocated in large object space.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003726 HeapObject* result;
3727 bool force_lo_space = obj_size > code_space()->AreaSize();
3728 if (force_lo_space) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003729 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003730 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003731 maybe_result = code_space_->AllocateRaw(obj_size);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003732 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003733 if (!maybe_result->To<HeapObject>(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003734
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003735 if (immovable && !force_lo_space &&
3736 // Objects on the first page of each space are never moved.
3737 !code_space_->FirstPage()->Contains(result->address())) {
3738 // Discard the first code allocation, which was on a page where it could be
3739 // moved.
3740 CreateFillerObjectAt(result->address(), obj_size);
3741 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
3742 if (!maybe_result->To<HeapObject>(&result)) return maybe_result;
3743 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003744
3745 // Initialize the object
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003746 result->set_map_no_write_barrier(code_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003747 Code* code = Code::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003748 ASSERT(!isolate_->code_range()->exists() ||
3749 isolate_->code_range()->contains(code->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003750 code->set_instruction_size(desc.instr_size);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003751 code->set_relocation_info(reloc_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003752 code->set_flags(flags);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003753 if (code->is_call_stub() || code->is_keyed_call_stub()) {
3754 code->set_check_type(RECEIVER_MAP_CHECK);
3755 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003756 code->set_deoptimization_data(empty_fixed_array(), SKIP_WRITE_BARRIER);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003757 code->InitializeTypeFeedbackInfoNoWriteBarrier(undefined_value());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003758 code->set_handler_table(empty_fixed_array(), SKIP_WRITE_BARRIER);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00003759 code->set_gc_metadata(Smi::FromInt(0));
danno@chromium.org88aa0582012-03-23 15:11:57 +00003760 code->set_ic_age(global_ic_age_);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003761 code->set_prologue_offset(kPrologueOffsetNotSet);
kasperl@chromium.org061ef742009-02-27 12:16:20 +00003762 // Allow self references to created code object by patching the handle to
3763 // point to the newly allocated Code object.
3764 if (!self_reference.is_null()) {
3765 *(self_reference.location()) = code;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003766 }
3767 // Migrate generated code.
3768 // The generated code can contain Object** values (typically from handles)
3769 // that are dereferenced during the copy to point directly to the actual heap
3770 // objects. These pointers can include references to the code object itself,
3771 // through the self_reference parameter.
3772 code->CopyFrom(desc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003773
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003774#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003775 if (FLAG_verify_heap) {
3776 code->Verify();
3777 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003778#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003779 return code;
3780}
3781
3782
lrn@chromium.org303ada72010-10-27 09:33:13 +00003783MaybeObject* Heap::CopyCode(Code* code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003784 // Allocate an object the same size as the code object.
3785 int obj_size = code->Size();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003786 MaybeObject* maybe_result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003787 if (obj_size > code_space()->AreaSize()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003788 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003789 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003790 maybe_result = code_space_->AllocateRaw(obj_size);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003791 }
3792
lrn@chromium.org303ada72010-10-27 09:33:13 +00003793 Object* result;
3794 if (!maybe_result->ToObject(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003795
3796 // Copy code object.
3797 Address old_addr = code->address();
3798 Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003799 CopyBlock(new_addr, old_addr, obj_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003800 // Relocate the copy.
3801 Code* new_code = Code::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003802 ASSERT(!isolate_->code_range()->exists() ||
3803 isolate_->code_range()->contains(code->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003804 new_code->Relocate(new_addr - old_addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003805 return new_code;
3806}
3807
3808
lrn@chromium.org303ada72010-10-27 09:33:13 +00003809MaybeObject* Heap::CopyCode(Code* code, Vector<byte> reloc_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003810 // Allocate ByteArray before the Code object, so that we do not risk
3811 // leaving uninitialized Code object (and breaking the heap).
lrn@chromium.org303ada72010-10-27 09:33:13 +00003812 Object* reloc_info_array;
3813 { MaybeObject* maybe_reloc_info_array =
3814 AllocateByteArray(reloc_info.length(), TENURED);
3815 if (!maybe_reloc_info_array->ToObject(&reloc_info_array)) {
3816 return maybe_reloc_info_array;
3817 }
3818 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003819
3820 int new_body_size = RoundUp(code->instruction_size(), kObjectAlignment);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003821
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003822 int new_obj_size = Code::SizeFor(new_body_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003823
3824 Address old_addr = code->address();
3825
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00003826 size_t relocation_offset =
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003827 static_cast<size_t>(code->instruction_end() - old_addr);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003828
lrn@chromium.org303ada72010-10-27 09:33:13 +00003829 MaybeObject* maybe_result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003830 if (new_obj_size > code_space()->AreaSize()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003831 maybe_result = lo_space_->AllocateRaw(new_obj_size, EXECUTABLE);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003832 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003833 maybe_result = code_space_->AllocateRaw(new_obj_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003834 }
3835
lrn@chromium.org303ada72010-10-27 09:33:13 +00003836 Object* result;
3837 if (!maybe_result->ToObject(&result)) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003838
3839 // Copy code object.
3840 Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
3841
3842 // Copy header and instructions.
3843 memcpy(new_addr, old_addr, relocation_offset);
3844
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003845 Code* new_code = Code::cast(result);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003846 new_code->set_relocation_info(ByteArray::cast(reloc_info_array));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003847
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003848 // Copy patched rinfo.
3849 memcpy(new_code->relocation_start(), reloc_info.start(), reloc_info.length());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003850
3851 // Relocate the copy.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003852 ASSERT(!isolate_->code_range()->exists() ||
3853 isolate_->code_range()->contains(code->address()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003854 new_code->Relocate(new_addr - old_addr);
3855
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003856#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003857 if (FLAG_verify_heap) {
3858 code->Verify();
3859 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003860#endif
3861 return new_code;
3862}
3863
3864
lrn@chromium.org303ada72010-10-27 09:33:13 +00003865MaybeObject* Heap::Allocate(Map* map, AllocationSpace space) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003866 ASSERT(gc_state_ == NOT_IN_GC);
3867 ASSERT(map->instance_type() != MAP_TYPE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003868 // If allocation failures are disallowed, we may allocate in a different
3869 // space when new space is full and the object is not a large object.
3870 AllocationSpace retry_space =
3871 (space != NEW_SPACE) ? space : TargetSpaceId(map->instance_type());
lrn@chromium.org303ada72010-10-27 09:33:13 +00003872 Object* result;
3873 { MaybeObject* maybe_result =
3874 AllocateRaw(map->instance_size(), space, retry_space);
3875 if (!maybe_result->ToObject(&result)) return maybe_result;
3876 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003877 // No need for write barrier since object is white and map is in old space.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003878 HeapObject::cast(result)->set_map_no_write_barrier(map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003879 return result;
3880}
3881
3882
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003883void Heap::InitializeFunction(JSFunction* function,
3884 SharedFunctionInfo* shared,
3885 Object* prototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003886 ASSERT(!prototype->IsMap());
3887 function->initialize_properties();
3888 function->initialize_elements();
3889 function->set_shared(shared);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00003890 function->set_code(shared->code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003891 function->set_prototype_or_initial_map(prototype);
3892 function->set_context(undefined_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003893 function->set_literals_or_bindings(empty_fixed_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003894 function->set_next_function_link(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003895}
3896
3897
lrn@chromium.org303ada72010-10-27 09:33:13 +00003898MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00003899 // Allocate the prototype. Make sure to use the object function
3900 // from the function's context, since the function can be from a
3901 // different context.
3902 JSFunction* object_function =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003903 function->context()->native_context()->object_function();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003904
3905 // Each function prototype gets a copy of the object function map.
3906 // This avoid unwanted sharing of maps between prototypes of different
3907 // constructors.
3908 Map* new_map;
3909 ASSERT(object_function->has_initial_map());
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003910 MaybeObject* maybe_map = object_function->initial_map()->Copy();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003911 if (!maybe_map->To(&new_map)) return maybe_map;
3912
lrn@chromium.org303ada72010-10-27 09:33:13 +00003913 Object* prototype;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003914 MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map);
3915 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
3916
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003917 // When creating the prototype for the function we must set its
3918 // constructor to the function.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003919 MaybeObject* maybe_failure =
3920 JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
3921 constructor_symbol(), function, DONT_ENUM);
3922 if (maybe_failure->IsFailure()) return maybe_failure;
3923
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003924 return prototype;
3925}
3926
3927
lrn@chromium.org303ada72010-10-27 09:33:13 +00003928MaybeObject* Heap::AllocateFunction(Map* function_map,
3929 SharedFunctionInfo* shared,
3930 Object* prototype,
3931 PretenureFlag pretenure) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003932 AllocationSpace space =
3933 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003934 Object* result;
3935 { MaybeObject* maybe_result = Allocate(function_map, space);
3936 if (!maybe_result->ToObject(&result)) return maybe_result;
3937 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003938 InitializeFunction(JSFunction::cast(result), shared, prototype);
3939 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003940}
3941
3942
lrn@chromium.org303ada72010-10-27 09:33:13 +00003943MaybeObject* Heap::AllocateArgumentsObject(Object* callee, int length) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003944 // To get fast allocation and map sharing for arguments objects we
3945 // allocate them based on an arguments boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003946
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003947 JSObject* boilerplate;
3948 int arguments_object_size;
3949 bool strict_mode_callee = callee->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003950 !JSFunction::cast(callee)->shared()->is_classic_mode();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003951 if (strict_mode_callee) {
3952 boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003953 isolate()->context()->native_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003954 strict_mode_arguments_boilerplate();
3955 arguments_object_size = kArgumentsObjectSizeStrict;
3956 } else {
3957 boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003958 isolate()->context()->native_context()->arguments_boilerplate();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003959 arguments_object_size = kArgumentsObjectSize;
3960 }
3961
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003962 // This calls Copy directly rather than using Heap::AllocateRaw so we
3963 // duplicate the check here.
3964 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
3965
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003966 // Check that the size of the boilerplate matches our
3967 // expectations. The ArgumentsAccessStub::GenerateNewObject relies
3968 // on the size being a known constant.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003969 ASSERT(arguments_object_size == boilerplate->map()->instance_size());
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003970
3971 // Do the allocation.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003972 Object* result;
3973 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003974 AllocateRaw(arguments_object_size, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003975 if (!maybe_result->ToObject(&result)) return maybe_result;
3976 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00003978 // Copy the content. The arguments boilerplate doesn't have any
3979 // fields that point to new space so it's safe to skip the write
3980 // barrier here.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003981 CopyBlock(HeapObject::cast(result)->address(),
3982 boilerplate->address(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003983 JSObject::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003984
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003985 // Set the length property.
3986 JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsLengthIndex,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003987 Smi::FromInt(length),
3988 SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003989 // Set the callee property for non-strict mode arguments object only.
3990 if (!strict_mode_callee) {
3991 JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsCalleeIndex,
3992 callee);
3993 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003994
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003995 // Check the state of the object
3996 ASSERT(JSObject::cast(result)->HasFastProperties());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003997 ASSERT(JSObject::cast(result)->HasFastObjectElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998
3999 return result;
4000}
4001
4002
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004003static bool HasDuplicates(DescriptorArray* descriptors) {
4004 int count = descriptors->number_of_descriptors();
4005 if (count > 1) {
4006 String* prev_key = descriptors->GetKey(0);
4007 for (int i = 1; i != count; i++) {
4008 String* current_key = descriptors->GetKey(i);
4009 if (prev_key == current_key) return true;
4010 prev_key = current_key;
4011 }
4012 }
4013 return false;
4014}
4015
4016
lrn@chromium.org303ada72010-10-27 09:33:13 +00004017MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004018 ASSERT(!fun->has_initial_map());
4019
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004020 // First create a new map with the size and number of in-object properties
4021 // suggested by the function.
4022 int instance_size = fun->shared()->CalculateInstanceSize();
4023 int in_object_properties = fun->shared()->CalculateInObjectProperties();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004024 Map* map;
4025 MaybeObject* maybe_map = AllocateMap(JS_OBJECT_TYPE, instance_size);
4026 if (!maybe_map->To(&map)) return maybe_map;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027
4028 // Fetch or allocate prototype.
4029 Object* prototype;
4030 if (fun->has_instance_prototype()) {
4031 prototype = fun->instance_prototype();
4032 } else {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004033 MaybeObject* maybe_prototype = AllocateFunctionPrototype(fun);
4034 if (!maybe_prototype->To(&prototype)) return maybe_prototype;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004035 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004036 map->set_inobject_properties(in_object_properties);
4037 map->set_unused_property_fields(in_object_properties);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004038 map->set_prototype(prototype);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004039 ASSERT(map->has_fast_object_elements());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004040
ager@chromium.org5c838252010-02-19 08:53:10 +00004041 // If the function has only simple this property assignments add
4042 // field descriptors for these to the initial map as the object
4043 // cannot be constructed without having these properties. Guard by
4044 // the inline_new flag so we only change the map if we generate a
4045 // specialized construct stub.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004046 ASSERT(in_object_properties <= Map::kMaxPreAllocatedPropertyFields);
ager@chromium.org5c838252010-02-19 08:53:10 +00004047 if (fun->shared()->CanGenerateInlineConstructor(prototype)) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004048 int count = fun->shared()->this_property_assignments_count();
4049 if (count > in_object_properties) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004050 // Inline constructor can only handle inobject properties.
4051 fun->shared()->ForbidInlineConstructor();
4052 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004053 DescriptorArray* descriptors;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00004054 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(count);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004055 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
4056
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004057 DescriptorArray::WhitenessWitness witness(descriptors);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004058 for (int i = 0; i < count; i++) {
4059 String* name = fun->shared()->GetThisPropertyAssignmentName(i);
4060 ASSERT(name->IsSymbol());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004061 FieldDescriptor field(name, i, NONE, i + 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004062 descriptors->Set(i, &field, witness);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004063 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004064 descriptors->Sort();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004065
4066 // The descriptors may contain duplicates because the compiler does not
4067 // guarantee the uniqueness of property names (it would have required
4068 // quadratic time). Once the descriptors are sorted we can check for
4069 // duplicates in linear time.
4070 if (HasDuplicates(descriptors)) {
4071 fun->shared()->ForbidInlineConstructor();
4072 } else {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004073 map->InitializeDescriptors(descriptors);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004074 map->set_pre_allocated_property_fields(count);
4075 map->set_unused_property_fields(in_object_properties - count);
4076 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004077 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004078 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004079
4080 fun->shared()->StartInobjectSlackTracking(map);
4081
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 return map;
4083}
4084
4085
4086void Heap::InitializeJSObjectFromMap(JSObject* obj,
4087 FixedArray* properties,
4088 Map* map) {
4089 obj->set_properties(properties);
4090 obj->initialize_elements();
4091 // TODO(1240798): Initialize the object's body using valid initial values
4092 // according to the object's initial map. For example, if the map's
4093 // instance type is JS_ARRAY_TYPE, the length field should be initialized
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004094 // to a number (e.g. Smi::FromInt(0)) and the elements initialized to a
4095 // fixed array (e.g. Heap::empty_fixed_array()). Currently, the object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004096 // verification code has to cope with (temporarily) invalid objects. See
4097 // for example, JSArray::JSArrayVerify).
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004098 Object* filler;
4099 // We cannot always fill with one_pointer_filler_map because objects
4100 // created from API functions expect their internal fields to be initialized
4101 // with undefined_value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004102 // Pre-allocated fields need to be initialized with undefined_value as well
4103 // so that object accesses before the constructor completes (e.g. in the
4104 // debugger) will not cause a crash.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004105 if (map->constructor()->IsJSFunction() &&
4106 JSFunction::cast(map->constructor())->shared()->
4107 IsInobjectSlackTrackingInProgress()) {
4108 // We might want to shrink the object later.
4109 ASSERT(obj->GetInternalFieldCount() == 0);
4110 filler = Heap::one_pointer_filler_map();
4111 } else {
4112 filler = Heap::undefined_value();
4113 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004114 obj->InitializeBody(map, Heap::undefined_value(), filler);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004115}
4116
4117
lrn@chromium.org303ada72010-10-27 09:33:13 +00004118MaybeObject* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119 // JSFunctions should be allocated using AllocateFunction to be
4120 // properly initialized.
4121 ASSERT(map->instance_type() != JS_FUNCTION_TYPE);
4122
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00004123 // Both types of global objects should be allocated using
4124 // AllocateGlobalObject to be properly initialized.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004125 ASSERT(map->instance_type() != JS_GLOBAL_OBJECT_TYPE);
4126 ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE);
4127
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004128 // Allocate the backing storage for the properties.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004129 int prop_size =
4130 map->pre_allocated_property_fields() +
4131 map->unused_property_fields() -
4132 map->inobject_properties();
4133 ASSERT(prop_size >= 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004134 Object* properties;
4135 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, pretenure);
4136 if (!maybe_properties->ToObject(&properties)) return maybe_properties;
4137 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004138
4139 // Allocate the JSObject.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004140 AllocationSpace space =
4141 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004142 if (map->instance_size() > Page::kMaxNonCodeHeapObjectSize) space = LO_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004143 Object* obj;
4144 { MaybeObject* maybe_obj = Allocate(map, space);
4145 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4146 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004147
4148 // Initialize the JSObject.
4149 InitializeJSObjectFromMap(JSObject::cast(obj),
4150 FixedArray::cast(properties),
4151 map);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004152 ASSERT(JSObject::cast(obj)->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004153 return obj;
4154}
4155
4156
lrn@chromium.org303ada72010-10-27 09:33:13 +00004157MaybeObject* Heap::AllocateJSObject(JSFunction* constructor,
4158 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004159 // Allocate the initial map if absent.
4160 if (!constructor->has_initial_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004161 Object* initial_map;
4162 { MaybeObject* maybe_initial_map = AllocateInitialMap(constructor);
4163 if (!maybe_initial_map->ToObject(&initial_map)) return maybe_initial_map;
4164 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004165 constructor->set_initial_map(Map::cast(initial_map));
4166 Map::cast(initial_map)->set_constructor(constructor);
4167 }
4168 // Allocate the object based on the constructors initial map.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004169 MaybeObject* result = AllocateJSObjectFromMap(
4170 constructor->initial_map(), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004171#ifdef DEBUG
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004172 // Make sure result is NOT a global object if valid.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004173 Object* non_failure;
4174 ASSERT(!result->ToObject(&non_failure) || !non_failure->IsGlobalObject());
4175#endif
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004176 return result;
4177}
4178
4179
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004180MaybeObject* Heap::AllocateJSModule(Context* context, ScopeInfo* scope_info) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004181 // Allocate a fresh map. Modules do not have a prototype.
4182 Map* map;
4183 MaybeObject* maybe_map = AllocateMap(JS_MODULE_TYPE, JSModule::kSize);
4184 if (!maybe_map->To(&map)) return maybe_map;
4185 // Allocate the object based on the map.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004186 JSModule* module;
4187 MaybeObject* maybe_module = AllocateJSObjectFromMap(map, TENURED);
4188 if (!maybe_module->To(&module)) return maybe_module;
4189 module->set_context(context);
4190 module->set_scope_info(scope_info);
4191 return module;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004192}
4193
4194
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004195MaybeObject* Heap::AllocateJSArrayAndStorage(
4196 ElementsKind elements_kind,
4197 int length,
4198 int capacity,
4199 ArrayStorageAllocationMode mode,
4200 PretenureFlag pretenure) {
4201 ASSERT(capacity >= length);
4202 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
4203 JSArray* array;
4204 if (!maybe_array->To(&array)) return maybe_array;
4205
4206 if (capacity == 0) {
4207 array->set_length(Smi::FromInt(0));
4208 array->set_elements(empty_fixed_array());
4209 return array;
4210 }
4211
4212 FixedArrayBase* elms;
4213 MaybeObject* maybe_elms = NULL;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004214 if (IsFastDoubleElementsKind(elements_kind)) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004215 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
4216 maybe_elms = AllocateUninitializedFixedDoubleArray(capacity);
4217 } else {
4218 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
4219 maybe_elms = AllocateFixedDoubleArrayWithHoles(capacity);
4220 }
4221 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004222 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004223 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
4224 maybe_elms = AllocateUninitializedFixedArray(capacity);
4225 } else {
4226 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
4227 maybe_elms = AllocateFixedArrayWithHoles(capacity);
4228 }
4229 }
4230 if (!maybe_elms->To(&elms)) return maybe_elms;
4231
4232 array->set_elements(elms);
4233 array->set_length(Smi::FromInt(length));
4234 return array;
4235}
4236
4237
4238MaybeObject* Heap::AllocateJSArrayWithElements(
4239 FixedArrayBase* elements,
4240 ElementsKind elements_kind,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004241 int length,
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004242 PretenureFlag pretenure) {
4243 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
4244 JSArray* array;
4245 if (!maybe_array->To(&array)) return maybe_array;
4246
4247 array->set_elements(elements);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004248 array->set_length(Smi::FromInt(length));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004249 array->ValidateElements();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004250 return array;
4251}
4252
4253
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004254MaybeObject* Heap::AllocateJSProxy(Object* handler, Object* prototype) {
4255 // Allocate map.
4256 // TODO(rossberg): Once we optimize proxies, think about a scheme to share
4257 // maps. Will probably depend on the identity of the handler object, too.
danno@chromium.org40cb8782011-05-25 07:58:50 +00004258 Map* map;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004259 MaybeObject* maybe_map_obj = AllocateMap(JS_PROXY_TYPE, JSProxy::kSize);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004260 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004261 map->set_prototype(prototype);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004262
4263 // Allocate the proxy object.
lrn@chromium.org34e60782011-09-15 07:25:40 +00004264 JSProxy* result;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004265 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004266 if (!maybe_result->To<JSProxy>(&result)) return maybe_result;
4267 result->InitializeBody(map->instance_size(), Smi::FromInt(0));
4268 result->set_handler(handler);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004269 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004270 return result;
4271}
4272
4273
4274MaybeObject* Heap::AllocateJSFunctionProxy(Object* handler,
4275 Object* call_trap,
4276 Object* construct_trap,
4277 Object* prototype) {
4278 // Allocate map.
4279 // TODO(rossberg): Once we optimize proxies, think about a scheme to share
4280 // maps. Will probably depend on the identity of the handler object, too.
4281 Map* map;
4282 MaybeObject* maybe_map_obj =
4283 AllocateMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize);
4284 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
4285 map->set_prototype(prototype);
4286
4287 // Allocate the proxy object.
4288 JSFunctionProxy* result;
4289 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
4290 if (!maybe_result->To<JSFunctionProxy>(&result)) return maybe_result;
4291 result->InitializeBody(map->instance_size(), Smi::FromInt(0));
4292 result->set_handler(handler);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004293 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004294 result->set_call_trap(call_trap);
4295 result->set_construct_trap(construct_trap);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004296 return result;
4297}
4298
4299
lrn@chromium.org303ada72010-10-27 09:33:13 +00004300MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004301 ASSERT(constructor->has_initial_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004302 Map* map = constructor->initial_map();
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004303 ASSERT(map->is_dictionary_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004304
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004305 // Make sure no field properties are described in the initial map.
4306 // This guarantees us that normalizing the properties does not
4307 // require us to change property values to JSGlobalPropertyCells.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004308 ASSERT(map->NextFreePropertyIndex() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004309
4310 // Make sure we don't have a ton of pre-allocated slots in the
4311 // global objects. They will be unused once we normalize the object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004312 ASSERT(map->unused_property_fields() == 0);
4313 ASSERT(map->inobject_properties() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004314
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004315 // Initial size of the backing store to avoid resize of the storage during
4316 // bootstrapping. The size differs between the JS global object ad the
4317 // builtins object.
4318 int initial_size = map->instance_type() == JS_GLOBAL_OBJECT_TYPE ? 64 : 512;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004319
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004320 // Allocate a dictionary object for backing storage.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004321 StringDictionary* dictionary;
4322 MaybeObject* maybe_dictionary =
4323 StringDictionary::Allocate(
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004324 map->NumberOfOwnDescriptors() * 2 + initial_size);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004325 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004326
4327 // The global object might be created from an object template with accessors.
4328 // Fill these accessors into the dictionary.
4329 DescriptorArray* descs = map->instance_descriptors();
4330 for (int i = 0; i < descs->number_of_descriptors(); i++) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004331 PropertyDetails details = descs->GetDetails(i);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004332 ASSERT(details.type() == CALLBACKS); // Only accessors are expected.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004333 PropertyDetails d = PropertyDetails(details.attributes(),
4334 CALLBACKS,
4335 details.descriptor_index());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004336 Object* value = descs->GetCallbacksObject(i);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004337 MaybeObject* maybe_value = AllocateJSGlobalPropertyCell(value);
4338 if (!maybe_value->ToObject(&value)) return maybe_value;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004339
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004340 MaybeObject* maybe_added = dictionary->Add(descs->GetKey(i), value, d);
4341 if (!maybe_added->To(&dictionary)) return maybe_added;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004342 }
4343
4344 // Allocate the global object and initialize it with the backing store.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004345 JSObject* global;
4346 MaybeObject* maybe_global = Allocate(map, OLD_POINTER_SPACE);
4347 if (!maybe_global->To(&global)) return maybe_global;
4348
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004349 InitializeJSObjectFromMap(global, dictionary, map);
4350
4351 // Create a new map for the global object.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004352 Map* new_map;
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004353 MaybeObject* maybe_map = map->CopyDropDescriptors();
4354 if (!maybe_map->To(&new_map)) return maybe_map;
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004355 new_map->set_dictionary_map(true);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004356
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004357 // Set up the global object as a normalized object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004358 global->set_map(new_map);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004359 global->set_properties(dictionary);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004360
4361 // Make sure result is a global object with properties in dictionary.
4362 ASSERT(global->IsGlobalObject());
4363 ASSERT(!global->HasFastProperties());
4364 return global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004365}
4366
4367
lrn@chromium.org303ada72010-10-27 09:33:13 +00004368MaybeObject* Heap::CopyJSObject(JSObject* source) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004369 // Never used to copy functions. If functions need to be copied we
4370 // have to be careful to clear the literals array.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004371 SLOW_ASSERT(!source->IsJSFunction());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004372
4373 // Make the clone.
4374 Map* map = source->map();
4375 int object_size = map->instance_size();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004376 Object* clone;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004377
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004378 WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER;
4379
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004380 // If we're forced to always allocate, we use the general allocation
4381 // functions which may leave us with an object in old space.
4382 if (always_allocate()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004383 { MaybeObject* maybe_clone =
4384 AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE);
4385 if (!maybe_clone->ToObject(&clone)) return maybe_clone;
4386 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004387 Address clone_address = HeapObject::cast(clone)->address();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004388 CopyBlock(clone_address,
4389 source->address(),
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004390 object_size);
4391 // Update write barrier for all fields that lie beyond the header.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004392 RecordWrites(clone_address,
4393 JSObject::kHeaderSize,
antonm@chromium.org8e5e3382010-03-24 09:56:30 +00004394 (object_size - JSObject::kHeaderSize) / kPointerSize);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004395 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004396 wb_mode = SKIP_WRITE_BARRIER;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004397 { MaybeObject* maybe_clone = new_space_.AllocateRaw(object_size);
4398 if (!maybe_clone->ToObject(&clone)) return maybe_clone;
4399 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004400 SLOW_ASSERT(InNewSpace(clone));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004401 // Since we know the clone is allocated in new space, we can copy
ager@chromium.org32912102009-01-16 10:38:43 +00004402 // the contents without worrying about updating the write barrier.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004403 CopyBlock(HeapObject::cast(clone)->address(),
4404 source->address(),
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004405 object_size);
4406 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004407
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004408 SLOW_ASSERT(
4409 JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004410 FixedArrayBase* elements = FixedArrayBase::cast(source->elements());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004411 FixedArray* properties = FixedArray::cast(source->properties());
4412 // Update elements if necessary.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00004413 if (elements->length() > 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004414 Object* elem;
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004415 { MaybeObject* maybe_elem;
4416 if (elements->map() == fixed_cow_array_map()) {
4417 maybe_elem = FixedArray::cast(elements);
4418 } else if (source->HasFastDoubleElements()) {
4419 maybe_elem = CopyFixedDoubleArray(FixedDoubleArray::cast(elements));
4420 } else {
4421 maybe_elem = CopyFixedArray(FixedArray::cast(elements));
4422 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004423 if (!maybe_elem->ToObject(&elem)) return maybe_elem;
4424 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004425 JSObject::cast(clone)->set_elements(FixedArrayBase::cast(elem), wb_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004426 }
4427 // Update properties if necessary.
4428 if (properties->length() > 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004429 Object* prop;
4430 { MaybeObject* maybe_prop = CopyFixedArray(properties);
4431 if (!maybe_prop->ToObject(&prop)) return maybe_prop;
4432 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004433 JSObject::cast(clone)->set_properties(FixedArray::cast(prop), wb_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004434 }
4435 // Return the new clone.
4436 return clone;
4437}
4438
4439
lrn@chromium.org34e60782011-09-15 07:25:40 +00004440MaybeObject* Heap::ReinitializeJSReceiver(
4441 JSReceiver* object, InstanceType type, int size) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004442 ASSERT(type >= FIRST_JS_OBJECT_TYPE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004443
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004444 // Allocate fresh map.
4445 // TODO(rossberg): Once we optimize proxies, cache these maps.
4446 Map* map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004447 MaybeObject* maybe = AllocateMap(type, size);
4448 if (!maybe->To<Map>(&map)) return maybe;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004449
lrn@chromium.org34e60782011-09-15 07:25:40 +00004450 // Check that the receiver has at least the size of the fresh object.
4451 int size_difference = object->map()->instance_size() - map->instance_size();
4452 ASSERT(size_difference >= 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004453
4454 map->set_prototype(object->map()->prototype());
4455
4456 // Allocate the backing storage for the properties.
4457 int prop_size = map->unused_property_fields() - map->inobject_properties();
4458 Object* properties;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004459 maybe = AllocateFixedArray(prop_size, TENURED);
4460 if (!maybe->ToObject(&properties)) return maybe;
4461
4462 // Functions require some allocation, which might fail here.
4463 SharedFunctionInfo* shared = NULL;
4464 if (type == JS_FUNCTION_TYPE) {
4465 String* name;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004466 maybe = LookupOneByteSymbol(STATIC_ASCII_VECTOR("<freezing call trap>"));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004467 if (!maybe->To<String>(&name)) return maybe;
4468 maybe = AllocateSharedFunctionInfo(name);
4469 if (!maybe->To<SharedFunctionInfo>(&shared)) return maybe;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004470 }
4471
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004472 // Because of possible retries of this function after failure,
4473 // we must NOT fail after this point, where we have changed the type!
4474
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004475 // Reset the map for the object.
4476 object->set_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004477 JSObject* jsobj = JSObject::cast(object);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004478
4479 // Reinitialize the object from the constructor map.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004480 InitializeJSObjectFromMap(jsobj, FixedArray::cast(properties), map);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004481
4482 // Functions require some minimal initialization.
4483 if (type == JS_FUNCTION_TYPE) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004484 map->set_function_with_prototype(true);
4485 InitializeFunction(JSFunction::cast(object), shared, the_hole_value());
4486 JSFunction::cast(object)->set_context(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004487 isolate()->context()->native_context());
lrn@chromium.org34e60782011-09-15 07:25:40 +00004488 }
4489
4490 // Put in filler if the new object is smaller than the old.
4491 if (size_difference > 0) {
4492 CreateFillerObjectAt(
4493 object->address() + map->instance_size(), size_difference);
4494 }
4495
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004496 return object;
4497}
4498
4499
lrn@chromium.org303ada72010-10-27 09:33:13 +00004500MaybeObject* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor,
4501 JSGlobalProxy* object) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004502 ASSERT(constructor->has_initial_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004503 Map* map = constructor->initial_map();
4504
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004505 // Check that the already allocated object has the same size and type as
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004506 // objects allocated using the constructor.
4507 ASSERT(map->instance_size() == object->map()->instance_size());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004508 ASSERT(map->instance_type() == object->map()->instance_type());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004509
4510 // Allocate the backing storage for the properties.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004511 int prop_size = map->unused_property_fields() - map->inobject_properties();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004512 Object* properties;
4513 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, TENURED);
4514 if (!maybe_properties->ToObject(&properties)) return maybe_properties;
4515 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004516
4517 // Reset the map for the object.
4518 object->set_map(constructor->initial_map());
4519
4520 // Reinitialize the object from the constructor map.
4521 InitializeJSObjectFromMap(object, FixedArray::cast(properties), map);
4522 return object;
4523}
4524
4525
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004526MaybeObject* Heap::AllocateStringFromOneByte(Vector<const char> string,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004527 PretenureFlag pretenure) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004528 int length = string.length();
4529 if (length == 1) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004530 return Heap::LookupSingleCharacterStringFromCode(string[0]);
4531 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004532 Object* result;
4533 { MaybeObject* maybe_result =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004534 AllocateRawOneByteString(string.length(), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004535 if (!maybe_result->ToObject(&result)) return maybe_result;
4536 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004537
4538 // Copy the characters into the new object.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004539 CopyChars(SeqOneByteString::cast(result)->GetChars(), string.start(), length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004540 return result;
4541}
4542
4543
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004544MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector<const char> string,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004545 int non_ascii_start,
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004546 PretenureFlag pretenure) {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004547 // Continue counting the number of characters in the UTF-8 string, starting
4548 // from the first non-ascii character or word.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004549 Access<UnicodeCache::Utf8Decoder>
4550 decoder(isolate_->unicode_cache()->utf8_decoder());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004551 decoder->Reset(string.start() + non_ascii_start,
4552 string.length() - non_ascii_start);
4553 int utf16_length = decoder->Utf16Length();
4554 ASSERT(utf16_length > 0);
4555 // Allocate string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004556 Object* result;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004557 {
4558 int chars = non_ascii_start + utf16_length;
4559 MaybeObject* maybe_result = AllocateRawTwoByteString(chars, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004560 if (!maybe_result->ToObject(&result)) return maybe_result;
4561 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004562 // Convert and copy the characters into the new object.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004563 SeqTwoByteString* twobyte = SeqTwoByteString::cast(result);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004564 // Copy ascii portion.
4565 uint16_t* data = twobyte->GetChars();
4566 if (non_ascii_start != 0) {
4567 const char* ascii_data = string.start();
4568 for (int i = 0; i < non_ascii_start; i++) {
4569 *data++ = *ascii_data++;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004570 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004571 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004572 // Now write the remainder.
4573 decoder->WriteUtf16(data, utf16_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004574 return result;
4575}
4576
4577
lrn@chromium.org303ada72010-10-27 09:33:13 +00004578MaybeObject* Heap::AllocateStringFromTwoByte(Vector<const uc16> string,
4579 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004580 // Check if the string is an ASCII string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004581 Object* result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004582 int length = string.length();
4583 const uc16* start = string.start();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004584
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004585 if (String::IsAscii(start, length)) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004586 MaybeObject* maybe_result = AllocateRawOneByteString(length, pretenure);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004587 if (!maybe_result->ToObject(&result)) return maybe_result;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004588 CopyChars(SeqOneByteString::cast(result)->GetChars(), start, length);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004589 } else { // It's not an ASCII string.
4590 MaybeObject* maybe_result = AllocateRawTwoByteString(length, pretenure);
4591 if (!maybe_result->ToObject(&result)) return maybe_result;
4592 CopyChars(SeqTwoByteString::cast(result)->GetChars(), start, length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004593 }
4594 return result;
4595}
4596
4597
4598Map* Heap::SymbolMapForString(String* string) {
4599 // If the string is in new space it cannot be used as a symbol.
4600 if (InNewSpace(string)) return NULL;
4601
4602 // Find the corresponding symbol map for strings.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004603 switch (string->map()->instance_type()) {
4604 case STRING_TYPE: return symbol_map();
4605 case ASCII_STRING_TYPE: return ascii_symbol_map();
4606 case CONS_STRING_TYPE: return cons_symbol_map();
4607 case CONS_ASCII_STRING_TYPE: return cons_ascii_symbol_map();
4608 case EXTERNAL_STRING_TYPE: return external_symbol_map();
4609 case EXTERNAL_ASCII_STRING_TYPE: return external_ascii_symbol_map();
4610 case EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
4611 return external_symbol_with_ascii_data_map();
4612 case SHORT_EXTERNAL_STRING_TYPE: return short_external_symbol_map();
4613 case SHORT_EXTERNAL_ASCII_STRING_TYPE:
4614 return short_external_ascii_symbol_map();
4615 case SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
4616 return short_external_symbol_with_ascii_data_map();
4617 default: return NULL; // No match found.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004618 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004619}
4620
4621
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004622template<typename T>
4623class AllocateInternalSymbolHelper {
4624 public:
4625 static void WriteOneByteData(T t, char* chars, int len);
4626 static void WriteTwoByteData(T t, uint16_t* chars, int len);
4627 private:
4628 DISALLOW_COPY_AND_ASSIGN(AllocateInternalSymbolHelper);
4629};
4630
4631
4632template<>
4633class AllocateInternalSymbolHelper< Vector<const char> > {
4634 public:
4635 static inline void WriteOneByteData(Vector<const char> vector,
4636 char* chars,
4637 int len) {
4638 // Only works for ascii.
4639 ASSERT(vector.length() == len);
4640 memcpy(chars, vector.start(), len);
4641 }
4642
4643 static inline void WriteTwoByteData(Vector<const char> vector,
4644 uint16_t* chars,
4645 int len) {
4646 const uint8_t* stream = reinterpret_cast<const uint8_t*>(vector.start());
4647 unsigned stream_length = vector.length();
4648 while (stream_length != 0) {
4649 unsigned consumed = 0;
4650 uint32_t c = unibrow::Utf8::ValueOf(stream, stream_length, &consumed);
4651 ASSERT(c != unibrow::Utf8::kBadChar);
4652 ASSERT(consumed <= stream_length);
4653 stream_length -= consumed;
4654 stream += consumed;
4655 if (c > unibrow::Utf16::kMaxNonSurrogateCharCode) {
4656 len -= 2;
4657 if (len < 0) break;
4658 *chars++ = unibrow::Utf16::LeadSurrogate(c);
4659 *chars++ = unibrow::Utf16::TrailSurrogate(c);
4660 } else {
4661 len -= 1;
4662 if (len < 0) break;
4663 *chars++ = c;
4664 }
4665 }
4666 ASSERT(stream_length == 0);
4667 ASSERT(len == 0);
4668 }
4669
4670 private:
4671 DISALLOW_COPY_AND_ASSIGN(AllocateInternalSymbolHelper);
4672};
4673
4674
4675template<>
4676class AllocateInternalSymbolHelper<String*> {
4677 public:
4678 static inline void WriteOneByteData(String* s, char* chars, int len) {
4679 ASSERT(s->length() == len);
4680 String::WriteToFlat(s, chars, 0, len);
4681 }
4682
4683 static inline void WriteTwoByteData(String* s, uint16_t* chars, int len) {
4684 ASSERT(s->length() == len);
4685 String::WriteToFlat(s, chars, 0, len);
4686 }
4687
4688 private:
4689 DISALLOW_COPY_AND_ASSIGN(AllocateInternalSymbolHelper<String*>);
4690};
4691
4692
4693template<bool is_one_byte, typename T>
4694MaybeObject* Heap::AllocateInternalSymbol(T t,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004695 int chars,
4696 uint32_t hash_field) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004697 typedef AllocateInternalSymbolHelper<T> H;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004698 ASSERT(chars >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004699 // Compute map and object size.
4700 int size;
4701 Map* map;
4702
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004703 if (is_one_byte) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004704 if (chars > SeqOneByteString::kMaxLength) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004705 return Failure::OutOfMemoryException();
4706 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004707 map = ascii_symbol_map();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004708 size = SeqOneByteString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004709 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004710 if (chars > SeqTwoByteString::kMaxLength) {
4711 return Failure::OutOfMemoryException();
4712 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004713 map = symbol_map();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004714 size = SeqTwoByteString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004715 }
4716
4717 // Allocate string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004718 Object* result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004719 { MaybeObject* maybe_result = (size > Page::kMaxNonCodeHeapObjectSize)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004720 ? lo_space_->AllocateRaw(size, NOT_EXECUTABLE)
lrn@chromium.org303ada72010-10-27 09:33:13 +00004721 : old_data_space_->AllocateRaw(size);
4722 if (!maybe_result->ToObject(&result)) return maybe_result;
4723 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004724
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004725 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(map);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004726 // Set length and hash fields of the allocated string.
ager@chromium.org870a0b62008-11-04 11:43:05 +00004727 String* answer = String::cast(result);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004728 answer->set_length(chars);
4729 answer->set_hash_field(hash_field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004730
ager@chromium.org870a0b62008-11-04 11:43:05 +00004731 ASSERT_EQ(size, answer->Size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004732
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004733 if (is_one_byte) {
4734 H::WriteOneByteData(t, SeqOneByteString::cast(answer)->GetChars(), chars);
4735 } else {
4736 H::WriteTwoByteData(t, SeqTwoByteString::cast(answer)->GetChars(), chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004737 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00004738 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004739}
4740
4741
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004742// Need explicit instantiations.
4743template
4744MaybeObject* Heap::AllocateInternalSymbol<true>(String*, int, uint32_t);
4745template
4746MaybeObject* Heap::AllocateInternalSymbol<false>(String*, int, uint32_t);
4747template
4748MaybeObject* Heap::AllocateInternalSymbol<false>(Vector<const char>,
4749 int,
4750 uint32_t);
4751
4752
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004753MaybeObject* Heap::AllocateRawOneByteString(int length,
4754 PretenureFlag pretenure) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004755 if (length < 0 || length > SeqOneByteString::kMaxLength) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004756 return Failure::OutOfMemoryException();
4757 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004758
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004759 int size = SeqOneByteString::SizeFor(length);
4760 ASSERT(size <= SeqOneByteString::kMaxSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004761
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004762 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
4763 AllocationSpace retry_space = OLD_DATA_SPACE;
4764
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004765 if (space == NEW_SPACE) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004766 if (size > kMaxObjectSizeInNewSpace) {
4767 // Allocate in large object space, retry space will be ignored.
4768 space = LO_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004769 } else if (size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004770 // Allocate in new space, retry in large object space.
4771 retry_space = LO_SPACE;
4772 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004773 } else if (space == OLD_DATA_SPACE &&
4774 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004775 space = LO_SPACE;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004776 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004777 Object* result;
4778 { MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
4779 if (!maybe_result->ToObject(&result)) return maybe_result;
4780 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004781
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004782 // Partially initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004783 HeapObject::cast(result)->set_map_no_write_barrier(ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004784 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004785 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004786 ASSERT_EQ(size, HeapObject::cast(result)->Size());
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004787
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004788#ifdef VERIFY_HEAP
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004789 if (FLAG_verify_heap) {
4790 // Initialize string's content to ensure ASCII-ness (character range 0-127)
4791 // as required when verifying the heap.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004792 char* dest = SeqOneByteString::cast(result)->GetChars();
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004793 memset(dest, 0x0F, length * kCharSize);
4794 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004795#endif
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004796
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004797 return result;
4798}
4799
4800
lrn@chromium.org303ada72010-10-27 09:33:13 +00004801MaybeObject* Heap::AllocateRawTwoByteString(int length,
4802 PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004803 if (length < 0 || length > SeqTwoByteString::kMaxLength) {
4804 return Failure::OutOfMemoryException();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004805 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004806 int size = SeqTwoByteString::SizeFor(length);
4807 ASSERT(size <= SeqTwoByteString::kMaxSize);
4808 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
4809 AllocationSpace retry_space = OLD_DATA_SPACE;
4810
4811 if (space == NEW_SPACE) {
4812 if (size > kMaxObjectSizeInNewSpace) {
4813 // Allocate in large object space, retry space will be ignored.
4814 space = LO_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004815 } else if (size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004816 // Allocate in new space, retry in large object space.
4817 retry_space = LO_SPACE;
4818 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004819 } else if (space == OLD_DATA_SPACE &&
4820 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004821 space = LO_SPACE;
4822 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004823 Object* result;
4824 { MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
4825 if (!maybe_result->ToObject(&result)) return maybe_result;
4826 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004827
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004828 // Partially initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004829 HeapObject::cast(result)->set_map_no_write_barrier(string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004830 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004831 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004832 ASSERT_EQ(size, HeapObject::cast(result)->Size());
4833 return result;
4834}
4835
4836
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004837MaybeObject* Heap::AllocateJSArray(
4838 ElementsKind elements_kind,
4839 PretenureFlag pretenure) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004840 Context* native_context = isolate()->context()->native_context();
4841 JSFunction* array_function = native_context->array_function();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004842 Map* map = array_function->initial_map();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004843 Object* maybe_map_array = native_context->js_array_maps();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004844 if (!maybe_map_array->IsUndefined()) {
4845 Object* maybe_transitioned_map =
4846 FixedArray::cast(maybe_map_array)->get(elements_kind);
4847 if (!maybe_transitioned_map->IsUndefined()) {
4848 map = Map::cast(maybe_transitioned_map);
4849 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004850 }
4851
4852 return AllocateJSObjectFromMap(map, pretenure);
4853}
4854
4855
lrn@chromium.org303ada72010-10-27 09:33:13 +00004856MaybeObject* Heap::AllocateEmptyFixedArray() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004857 int size = FixedArray::SizeFor(0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004858 Object* result;
4859 { MaybeObject* maybe_result =
4860 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
4861 if (!maybe_result->ToObject(&result)) return maybe_result;
4862 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004863 // Initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004864 reinterpret_cast<FixedArray*>(result)->set_map_no_write_barrier(
4865 fixed_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004866 reinterpret_cast<FixedArray*>(result)->set_length(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004867 return result;
4868}
4869
4870
lrn@chromium.org303ada72010-10-27 09:33:13 +00004871MaybeObject* Heap::AllocateRawFixedArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004872 if (length < 0 || length > FixedArray::kMaxLength) {
4873 return Failure::OutOfMemoryException();
4874 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004875 ASSERT(length > 0);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004876 // Use the general function if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004877 if (always_allocate()) return AllocateFixedArray(length, TENURED);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004878 // Allocate the raw data for a fixed array.
4879 int size = FixedArray::SizeFor(length);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004880 return size <= kMaxObjectSizeInNewSpace
4881 ? new_space_.AllocateRaw(size)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004882 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004883}
4884
4885
lrn@chromium.org303ada72010-10-27 09:33:13 +00004886MaybeObject* Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004887 int len = src->length();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004888 Object* obj;
4889 { MaybeObject* maybe_obj = AllocateRawFixedArray(len);
4890 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4891 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004892 if (InNewSpace(obj)) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004893 HeapObject* dst = HeapObject::cast(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004894 dst->set_map_no_write_barrier(map);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004895 CopyBlock(dst->address() + kPointerSize,
4896 src->address() + kPointerSize,
4897 FixedArray::SizeFor(len) - kPointerSize);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004898 return obj;
4899 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004900 HeapObject::cast(obj)->set_map_no_write_barrier(map);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004901 FixedArray* result = FixedArray::cast(obj);
4902 result->set_length(len);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004903
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004904 // Copy the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004905 AssertNoAllocation no_gc;
4906 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004907 for (int i = 0; i < len; i++) result->set(i, src->get(i), mode);
4908 return result;
4909}
4910
4911
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004912MaybeObject* Heap::CopyFixedDoubleArrayWithMap(FixedDoubleArray* src,
4913 Map* map) {
4914 int len = src->length();
4915 Object* obj;
4916 { MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(len, NOT_TENURED);
4917 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4918 }
4919 HeapObject* dst = HeapObject::cast(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004920 dst->set_map_no_write_barrier(map);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004921 CopyBlock(
4922 dst->address() + FixedDoubleArray::kLengthOffset,
4923 src->address() + FixedDoubleArray::kLengthOffset,
4924 FixedDoubleArray::SizeFor(len) - FixedDoubleArray::kLengthOffset);
4925 return obj;
4926}
4927
4928
lrn@chromium.org303ada72010-10-27 09:33:13 +00004929MaybeObject* Heap::AllocateFixedArray(int length) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004930 ASSERT(length >= 0);
ager@chromium.org32912102009-01-16 10:38:43 +00004931 if (length == 0) return empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004932 Object* result;
4933 { MaybeObject* maybe_result = AllocateRawFixedArray(length);
4934 if (!maybe_result->ToObject(&result)) return maybe_result;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004935 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004936 // Initialize header.
4937 FixedArray* array = reinterpret_cast<FixedArray*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004938 array->set_map_no_write_barrier(fixed_array_map());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004939 array->set_length(length);
4940 // Initialize body.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004941 ASSERT(!InNewSpace(undefined_value()));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004942 MemsetPointer(array->data_start(), undefined_value(), length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004943 return result;
4944}
4945
4946
lrn@chromium.org303ada72010-10-27 09:33:13 +00004947MaybeObject* Heap::AllocateRawFixedArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004948 if (length < 0 || length > FixedArray::kMaxLength) {
4949 return Failure::OutOfMemoryException();
4950 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004951
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004952 AllocationSpace space =
4953 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004954 int size = FixedArray::SizeFor(length);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004955 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
4956 // Too big for new space.
4957 space = LO_SPACE;
4958 } else if (space == OLD_POINTER_SPACE &&
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004959 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004960 // Too big for old pointer space.
4961 space = LO_SPACE;
4962 }
4963
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004964 AllocationSpace retry_space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004965 (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_POINTER_SPACE : LO_SPACE;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004966
4967 return AllocateRaw(size, space, retry_space);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004968}
4969
4970
lrn@chromium.org303ada72010-10-27 09:33:13 +00004971MUST_USE_RESULT static MaybeObject* AllocateFixedArrayWithFiller(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004972 Heap* heap,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004973 int length,
4974 PretenureFlag pretenure,
4975 Object* filler) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004976 ASSERT(length >= 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004977 ASSERT(heap->empty_fixed_array()->IsFixedArray());
4978 if (length == 0) return heap->empty_fixed_array();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004979
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004980 ASSERT(!heap->InNewSpace(filler));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004981 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004982 { MaybeObject* maybe_result = heap->AllocateRawFixedArray(length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004983 if (!maybe_result->ToObject(&result)) return maybe_result;
4984 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004985
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004986 HeapObject::cast(result)->set_map_no_write_barrier(heap->fixed_array_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004987 FixedArray* array = FixedArray::cast(result);
4988 array->set_length(length);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004989 MemsetPointer(array->data_start(), filler, length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004990 return array;
4991}
4992
4993
lrn@chromium.org303ada72010-10-27 09:33:13 +00004994MaybeObject* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004995 return AllocateFixedArrayWithFiller(this,
4996 length,
4997 pretenure,
4998 undefined_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004999}
5000
5001
lrn@chromium.org303ada72010-10-27 09:33:13 +00005002MaybeObject* Heap::AllocateFixedArrayWithHoles(int length,
5003 PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005004 return AllocateFixedArrayWithFiller(this,
5005 length,
5006 pretenure,
5007 the_hole_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005008}
5009
5010
lrn@chromium.org303ada72010-10-27 09:33:13 +00005011MaybeObject* Heap::AllocateUninitializedFixedArray(int length) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005012 if (length == 0) return empty_fixed_array();
5013
lrn@chromium.org303ada72010-10-27 09:33:13 +00005014 Object* obj;
5015 { MaybeObject* maybe_obj = AllocateRawFixedArray(length);
5016 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5017 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005018
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005019 reinterpret_cast<FixedArray*>(obj)->set_map_no_write_barrier(
5020 fixed_array_map());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005021 FixedArray::cast(obj)->set_length(length);
5022 return obj;
5023}
5024
5025
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005026MaybeObject* Heap::AllocateEmptyFixedDoubleArray() {
5027 int size = FixedDoubleArray::SizeFor(0);
5028 Object* result;
5029 { MaybeObject* maybe_result =
5030 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
5031 if (!maybe_result->ToObject(&result)) return maybe_result;
5032 }
5033 // Initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005034 reinterpret_cast<FixedDoubleArray*>(result)->set_map_no_write_barrier(
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005035 fixed_double_array_map());
5036 reinterpret_cast<FixedDoubleArray*>(result)->set_length(0);
5037 return result;
5038}
5039
5040
5041MaybeObject* Heap::AllocateUninitializedFixedDoubleArray(
5042 int length,
5043 PretenureFlag pretenure) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005044 if (length == 0) return empty_fixed_array();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005045
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005046 Object* elements_object;
5047 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
5048 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj;
5049 FixedDoubleArray* elements =
5050 reinterpret_cast<FixedDoubleArray*>(elements_object);
5051
5052 elements->set_map_no_write_barrier(fixed_double_array_map());
5053 elements->set_length(length);
5054 return elements;
5055}
5056
5057
5058MaybeObject* Heap::AllocateFixedDoubleArrayWithHoles(
5059 int length,
5060 PretenureFlag pretenure) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005061 if (length == 0) return empty_fixed_array();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005062
5063 Object* elements_object;
5064 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
5065 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj;
5066 FixedDoubleArray* elements =
5067 reinterpret_cast<FixedDoubleArray*>(elements_object);
5068
5069 for (int i = 0; i < length; ++i) {
5070 elements->set_the_hole(i);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005071 }
5072
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005073 elements->set_map_no_write_barrier(fixed_double_array_map());
5074 elements->set_length(length);
5075 return elements;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005076}
5077
5078
5079MaybeObject* Heap::AllocateRawFixedDoubleArray(int length,
5080 PretenureFlag pretenure) {
5081 if (length < 0 || length > FixedDoubleArray::kMaxLength) {
5082 return Failure::OutOfMemoryException();
5083 }
5084
5085 AllocationSpace space =
5086 (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
5087 int size = FixedDoubleArray::SizeFor(length);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005088
5089#ifndef V8_HOST_ARCH_64_BIT
5090 size += kPointerSize;
5091#endif
5092
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005093 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
5094 // Too big for new space.
5095 space = LO_SPACE;
5096 } else if (space == OLD_DATA_SPACE &&
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005097 size > Page::kMaxNonCodeHeapObjectSize) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005098 // Too big for old data space.
5099 space = LO_SPACE;
5100 }
5101
5102 AllocationSpace retry_space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005103 (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_DATA_SPACE : LO_SPACE;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005104
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005105 HeapObject* object;
5106 { MaybeObject* maybe_object = AllocateRaw(size, space, retry_space);
5107 if (!maybe_object->To<HeapObject>(&object)) return maybe_object;
5108 }
5109
5110 return EnsureDoubleAligned(this, object, size);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005111}
5112
5113
lrn@chromium.org303ada72010-10-27 09:33:13 +00005114MaybeObject* Heap::AllocateHashTable(int length, PretenureFlag pretenure) {
5115 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005116 { MaybeObject* maybe_result = AllocateFixedArray(length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005117 if (!maybe_result->ToObject(&result)) return maybe_result;
5118 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005119 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(
5120 hash_table_map());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005121 ASSERT(result->IsHashTable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005122 return result;
5123}
5124
5125
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005126MaybeObject* Heap::AllocateNativeContext() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005127 Object* result;
5128 { MaybeObject* maybe_result =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005129 AllocateFixedArray(Context::NATIVE_CONTEXT_SLOTS);
5130 if (!maybe_result->ToObject(&result)) return maybe_result;
5131 }
5132 Context* context = reinterpret_cast<Context*>(result);
5133 context->set_map_no_write_barrier(native_context_map());
5134 context->set_js_array_maps(undefined_value());
5135 ASSERT(context->IsNativeContext());
5136 ASSERT(result->IsContext());
5137 return result;
5138}
5139
5140
5141MaybeObject* Heap::AllocateGlobalContext(JSFunction* function,
5142 ScopeInfo* scope_info) {
5143 Object* result;
5144 { MaybeObject* maybe_result =
5145 AllocateFixedArray(scope_info->ContextLength(), TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005146 if (!maybe_result->ToObject(&result)) return maybe_result;
5147 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005148 Context* context = reinterpret_cast<Context*>(result);
danno@chromium.orgeb831462012-08-24 11:57:08 +00005149 context->set_map_no_write_barrier(global_context_map());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005150 context->set_closure(function);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005151 context->set_previous(function->context());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005152 context->set_extension(scope_info);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005153 context->set_global_object(function->context()->global_object());
danno@chromium.orgeb831462012-08-24 11:57:08 +00005154 ASSERT(context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005155 ASSERT(result->IsContext());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005156 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005157}
5158
5159
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005160MaybeObject* Heap::AllocateModuleContext(ScopeInfo* scope_info) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005161 Object* result;
5162 { MaybeObject* maybe_result =
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005163 AllocateFixedArray(scope_info->ContextLength(), TENURED);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005164 if (!maybe_result->ToObject(&result)) return maybe_result;
5165 }
5166 Context* context = reinterpret_cast<Context*>(result);
5167 context->set_map_no_write_barrier(module_context_map());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005168 // Instance link will be set later.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005169 context->set_extension(Smi::FromInt(0));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005170 return context;
5171}
5172
5173
lrn@chromium.org303ada72010-10-27 09:33:13 +00005174MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005175 ASSERT(length >= Context::MIN_CONTEXT_SLOTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005176 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005177 { MaybeObject* maybe_result = AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005178 if (!maybe_result->ToObject(&result)) return maybe_result;
5179 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005180 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005181 context->set_map_no_write_barrier(function_context_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005182 context->set_closure(function);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005183 context->set_previous(function->context());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005184 context->set_extension(Smi::FromInt(0));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005185 context->set_global_object(function->context()->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005186 return context;
5187}
5188
5189
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005190MaybeObject* Heap::AllocateCatchContext(JSFunction* function,
5191 Context* previous,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005192 String* name,
5193 Object* thrown_object) {
5194 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == Context::THROWN_OBJECT_INDEX);
5195 Object* result;
5196 { MaybeObject* maybe_result =
5197 AllocateFixedArray(Context::MIN_CONTEXT_SLOTS + 1);
5198 if (!maybe_result->ToObject(&result)) return maybe_result;
5199 }
5200 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005201 context->set_map_no_write_barrier(catch_context_map());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005202 context->set_closure(function);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005203 context->set_previous(previous);
5204 context->set_extension(name);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005205 context->set_global_object(previous->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005206 context->set(Context::THROWN_OBJECT_INDEX, thrown_object);
5207 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005208}
5209
5210
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005211MaybeObject* Heap::AllocateWithContext(JSFunction* function,
5212 Context* previous,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005213 JSObject* extension) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005214 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005215 { MaybeObject* maybe_result = AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005216 if (!maybe_result->ToObject(&result)) return maybe_result;
5217 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005218 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005219 context->set_map_no_write_barrier(with_context_map());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005220 context->set_closure(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005221 context->set_previous(previous);
5222 context->set_extension(extension);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005223 context->set_global_object(previous->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005224 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005225}
5226
5227
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005228MaybeObject* Heap::AllocateBlockContext(JSFunction* function,
5229 Context* previous,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005230 ScopeInfo* scope_info) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005231 Object* result;
5232 { MaybeObject* maybe_result =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005233 AllocateFixedArrayWithHoles(scope_info->ContextLength());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005234 if (!maybe_result->ToObject(&result)) return maybe_result;
5235 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005236 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005237 context->set_map_no_write_barrier(block_context_map());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005238 context->set_closure(function);
5239 context->set_previous(previous);
5240 context->set_extension(scope_info);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005241 context->set_global_object(previous->global_object());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005242 return context;
5243}
5244
5245
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005246MaybeObject* Heap::AllocateScopeInfo(int length) {
5247 FixedArray* scope_info;
5248 MaybeObject* maybe_scope_info = AllocateFixedArray(length, TENURED);
5249 if (!maybe_scope_info->To(&scope_info)) return maybe_scope_info;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005250 scope_info->set_map_no_write_barrier(scope_info_map());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005251 return scope_info;
5252}
5253
5254
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00005255MaybeObject* Heap::AllocateExternal(void* value) {
5256 Foreign* foreign;
5257 { MaybeObject* maybe_result = AllocateForeign(static_cast<Address>(value));
5258 if (!maybe_result->To(&foreign)) return maybe_result;
5259 }
5260 JSObject* external;
5261 { MaybeObject* maybe_result = AllocateJSObjectFromMap(external_map());
5262 if (!maybe_result->To(&external)) return maybe_result;
5263 }
5264 external->SetInternalField(0, foreign);
5265 return external;
5266}
5267
5268
lrn@chromium.org303ada72010-10-27 09:33:13 +00005269MaybeObject* Heap::AllocateStruct(InstanceType type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005270 Map* map;
5271 switch (type) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005272#define MAKE_CASE(NAME, Name, name) \
5273 case NAME##_TYPE: map = name##_map(); break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005274STRUCT_LIST(MAKE_CASE)
5275#undef MAKE_CASE
5276 default:
5277 UNREACHABLE();
5278 return Failure::InternalError();
5279 }
5280 int size = map->instance_size();
5281 AllocationSpace space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005282 (size > Page::kMaxNonCodeHeapObjectSize) ? LO_SPACE : OLD_POINTER_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005283 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005284 { MaybeObject* maybe_result = Allocate(map, space);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005285 if (!maybe_result->ToObject(&result)) return maybe_result;
5286 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005287 Struct::cast(result)->InitializeBody(size);
5288 return result;
5289}
5290
5291
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005292bool Heap::IsHeapIterable() {
5293 return (!old_pointer_space()->was_swept_conservatively() &&
5294 !old_data_space()->was_swept_conservatively());
5295}
5296
5297
5298void Heap::EnsureHeapIsIterable() {
5299 ASSERT(IsAllocationAllowed());
5300 if (!IsHeapIterable()) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005301 CollectAllGarbage(kMakeHeapIterableMask, "Heap::EnsureHeapIsIterable");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005302 }
5303 ASSERT(IsHeapIterable());
5304}
5305
5306
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005307void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005308 incremental_marking()->Step(step_size,
5309 IncrementalMarking::NO_GC_VIA_STACK_GUARD);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005310
5311 if (incremental_marking()->IsComplete()) {
5312 bool uncommit = false;
5313 if (gc_count_at_last_idle_gc_ == gc_count_) {
5314 // No GC since the last full GC, the mutator is probably not active.
5315 isolate_->compilation_cache()->Clear();
5316 uncommit = true;
5317 }
5318 CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental");
5319 gc_count_at_last_idle_gc_ = gc_count_;
5320 if (uncommit) {
5321 new_space_.Shrink();
5322 UncommitFromSpace();
5323 }
5324 }
5325}
5326
5327
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005328bool Heap::IdleNotification(int hint) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005329 // Hints greater than this value indicate that
5330 // the embedder is requesting a lot of GC work.
danno@chromium.org88aa0582012-03-23 15:11:57 +00005331 const int kMaxHint = 1000;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005332 // Minimal hint that allows to do full GC.
5333 const int kMinHintForFullGC = 100;
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005334 intptr_t size_factor = Min(Max(hint, 20), kMaxHint) / 4;
5335 // The size factor is in range [5..250]. The numbers here are chosen from
5336 // experiments. If you changes them, make sure to test with
5337 // chrome/performance_ui_tests --gtest_filter="GeneralMixMemoryTest.*
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00005338 intptr_t step_size =
5339 size_factor * IncrementalMarking::kAllocatedThreshold;
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005340
5341 if (contexts_disposed_ > 0) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005342 if (hint >= kMaxHint) {
5343 // The embedder is requesting a lot of GC work after context disposal,
5344 // we age inline caches so that they don't keep objects from
5345 // the old context alive.
5346 AgeInlineCaches();
5347 }
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005348 int mark_sweep_time = Min(TimeMarkSweepWouldTakeInMs(), 1000);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005349 if (hint >= mark_sweep_time && !FLAG_expose_gc &&
5350 incremental_marking()->IsStopped()) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005351 HistogramTimerScope scope(isolate_->counters()->gc_context());
5352 CollectAllGarbage(kReduceMemoryFootprintMask,
5353 "idle notification: contexts disposed");
5354 } else {
5355 AdvanceIdleIncrementalMarking(step_size);
5356 contexts_disposed_ = 0;
5357 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005358 // After context disposal there is likely a lot of garbage remaining, reset
5359 // the idle notification counters in order to trigger more incremental GCs
5360 // on subsequent idle notifications.
5361 StartIdleRound();
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005362 return false;
5363 }
5364
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005365 if (!FLAG_incremental_marking || FLAG_expose_gc || Serializer::enabled()) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005366 return IdleGlobalGC();
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005367 }
5368
5369 // By doing small chunks of GC work in each IdleNotification,
5370 // perform a round of incremental GCs and after that wait until
5371 // the mutator creates enough garbage to justify a new round.
5372 // An incremental GC progresses as follows:
5373 // 1. many incremental marking steps,
5374 // 2. one old space mark-sweep-compact,
5375 // 3. many lazy sweep steps.
5376 // Use mark-sweep-compact events to count incremental GCs in a round.
5377
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005378
5379 if (incremental_marking()->IsStopped()) {
5380 if (!IsSweepingComplete() &&
5381 !AdvanceSweepers(static_cast<int>(step_size))) {
5382 return false;
5383 }
5384 }
5385
5386 if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) {
5387 if (EnoughGarbageSinceLastIdleRound()) {
5388 StartIdleRound();
5389 } else {
5390 return true;
5391 }
5392 }
5393
5394 int new_mark_sweeps = ms_count_ - ms_count_at_last_idle_notification_;
5395 mark_sweeps_since_idle_round_started_ += new_mark_sweeps;
5396 ms_count_at_last_idle_notification_ = ms_count_;
5397
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005398 int remaining_mark_sweeps = kMaxMarkSweepsInIdleRound -
5399 mark_sweeps_since_idle_round_started_;
5400
5401 if (remaining_mark_sweeps <= 0) {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005402 FinishIdleRound();
5403 return true;
5404 }
5405
5406 if (incremental_marking()->IsStopped()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005407 // If there are no more than two GCs left in this idle round and we are
5408 // allowed to do a full GC, then make those GCs full in order to compact
5409 // the code space.
5410 // TODO(ulan): Once we enable code compaction for incremental marking,
5411 // we can get rid of this special case and always start incremental marking.
5412 if (remaining_mark_sweeps <= 2 && hint >= kMinHintForFullGC) {
5413 CollectAllGarbage(kReduceMemoryFootprintMask,
5414 "idle notification: finalize idle round");
5415 } else {
5416 incremental_marking()->Start();
5417 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005418 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005419 if (!incremental_marking()->IsStopped()) {
5420 AdvanceIdleIncrementalMarking(step_size);
5421 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005422 return false;
5423}
5424
5425
5426bool Heap::IdleGlobalGC() {
ager@chromium.orga1645e22009-09-09 19:27:10 +00005427 static const int kIdlesBeforeScavenge = 4;
5428 static const int kIdlesBeforeMarkSweep = 7;
5429 static const int kIdlesBeforeMarkCompact = 8;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005430 static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005431 static const unsigned int kGCsBetweenCleanup = 4;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005432
5433 if (!last_idle_notification_gc_count_init_) {
5434 last_idle_notification_gc_count_ = gc_count_;
5435 last_idle_notification_gc_count_init_ = true;
5436 }
ager@chromium.org96c75b52009-08-26 09:13:16 +00005437
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005438 bool uncommit = true;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005439 bool finished = false;
5440
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005441 // Reset the number of idle notifications received when a number of
5442 // GCs have taken place. This allows another round of cleanup based
5443 // on idle notifications if enough work has been carried out to
5444 // provoke a number of garbage collections.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005445 if (gc_count_ - last_idle_notification_gc_count_ < kGCsBetweenCleanup) {
5446 number_idle_notifications_ =
5447 Min(number_idle_notifications_ + 1, kMaxIdleCount);
ager@chromium.org96c75b52009-08-26 09:13:16 +00005448 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005449 number_idle_notifications_ = 0;
5450 last_idle_notification_gc_count_ = gc_count_;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005451 }
5452
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005453 if (number_idle_notifications_ == kIdlesBeforeScavenge) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005454 CollectGarbage(NEW_SPACE, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005455 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005456 last_idle_notification_gc_count_ = gc_count_;
5457 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005458 // Before doing the mark-sweep collections we clear the
5459 // compilation cache to avoid hanging on to source code and
5460 // generated code for cached functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005461 isolate_->compilation_cache()->Clear();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005462
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005463 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005464 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005465 last_idle_notification_gc_count_ = gc_count_;
ager@chromium.orga1645e22009-09-09 19:27:10 +00005466
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005467 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005468 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005469 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005470 last_idle_notification_gc_count_ = gc_count_;
5471 number_idle_notifications_ = 0;
ager@chromium.orga1645e22009-09-09 19:27:10 +00005472 finished = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005473 } else if (number_idle_notifications_ > kIdlesBeforeMarkCompact) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005474 // If we have received more than kIdlesBeforeMarkCompact idle
5475 // notifications we do not perform any cleanup because we don't
5476 // expect to gain much by doing so.
5477 finished = true;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005478 }
5479
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005480 if (uncommit) UncommitFromSpace();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005481
ager@chromium.org96c75b52009-08-26 09:13:16 +00005482 return finished;
5483}
5484
5485
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005486#ifdef DEBUG
5487
5488void Heap::Print() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005489 if (!HasBeenSetUp()) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005490 isolate()->PrintStack();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005491 AllSpaces spaces;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005492 for (Space* space = spaces.next(); space != NULL; space = spaces.next())
5493 space->Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005494}
5495
5496
5497void Heap::ReportCodeStatistics(const char* title) {
5498 PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title);
5499 PagedSpace::ResetCodeStatistics();
5500 // We do not look for code in new space, map space, or old space. If code
5501 // somehow ends up in those spaces, we would miss it here.
5502 code_space_->CollectCodeStatistics();
5503 lo_space_->CollectCodeStatistics();
5504 PagedSpace::ReportCodeStatistics();
5505}
5506
5507
5508// This function expects that NewSpace's allocated objects histogram is
5509// populated (via a call to CollectStatistics or else as a side effect of a
5510// just-completed scavenge collection).
5511void Heap::ReportHeapStatistics(const char* title) {
5512 USE(title);
5513 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n",
5514 title, gc_count_);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005515 PrintF("old_gen_promotion_limit_ %" V8_PTR_PREFIX "d\n",
5516 old_gen_promotion_limit_);
5517 PrintF("old_gen_allocation_limit_ %" V8_PTR_PREFIX "d\n",
5518 old_gen_allocation_limit_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005519 PrintF("old_gen_limit_factor_ %d\n", old_gen_limit_factor_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005520
5521 PrintF("\n");
5522 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005523 isolate_->global_handles()->PrintStats();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005524 PrintF("\n");
5525
5526 PrintF("Heap statistics : ");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005527 isolate_->memory_allocator()->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005528 PrintF("To space : ");
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005529 new_space_.ReportStatistics();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005530 PrintF("Old pointer space : ");
5531 old_pointer_space_->ReportStatistics();
5532 PrintF("Old data space : ");
5533 old_data_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005534 PrintF("Code space : ");
5535 code_space_->ReportStatistics();
5536 PrintF("Map space : ");
5537 map_space_->ReportStatistics();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005538 PrintF("Cell space : ");
5539 cell_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005540 PrintF("Large object space : ");
5541 lo_space_->ReportStatistics();
5542 PrintF(">>>>>> ========================================= >>>>>>\n");
5543}
5544
5545#endif // DEBUG
5546
5547bool Heap::Contains(HeapObject* value) {
5548 return Contains(value->address());
5549}
5550
5551
5552bool Heap::Contains(Address addr) {
5553 if (OS::IsOutsideAllocatedSpace(addr)) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005554 return HasBeenSetUp() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005555 (new_space_.ToSpaceContains(addr) ||
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005556 old_pointer_space_->Contains(addr) ||
5557 old_data_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005558 code_space_->Contains(addr) ||
5559 map_space_->Contains(addr) ||
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005560 cell_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005561 lo_space_->SlowContains(addr));
5562}
5563
5564
5565bool Heap::InSpace(HeapObject* value, AllocationSpace space) {
5566 return InSpace(value->address(), space);
5567}
5568
5569
5570bool Heap::InSpace(Address addr, AllocationSpace space) {
5571 if (OS::IsOutsideAllocatedSpace(addr)) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005572 if (!HasBeenSetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005573
5574 switch (space) {
5575 case NEW_SPACE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005576 return new_space_.ToSpaceContains(addr);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005577 case OLD_POINTER_SPACE:
5578 return old_pointer_space_->Contains(addr);
5579 case OLD_DATA_SPACE:
5580 return old_data_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005581 case CODE_SPACE:
5582 return code_space_->Contains(addr);
5583 case MAP_SPACE:
5584 return map_space_->Contains(addr);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005585 case CELL_SPACE:
5586 return cell_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005587 case LO_SPACE:
5588 return lo_space_->SlowContains(addr);
5589 }
5590
5591 return false;
5592}
5593
5594
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005595#ifdef VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005596void Heap::Verify() {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005597 CHECK(HasBeenSetUp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005598
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005599 store_buffer()->Verify();
5600
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005601 VerifyPointersVisitor visitor;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005602 IterateRoots(&visitor, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005603
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005604 new_space_.Verify();
5605
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005606 old_pointer_space_->Verify(&visitor);
5607 map_space_->Verify(&visitor);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005608
5609 VerifyPointersVisitor no_dirty_regions_visitor;
5610 old_data_space_->Verify(&no_dirty_regions_visitor);
5611 code_space_->Verify(&no_dirty_regions_visitor);
5612 cell_space_->Verify(&no_dirty_regions_visitor);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005613
5614 lo_space_->Verify();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005615}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005616#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005617
5618
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005619MaybeObject* Heap::LookupUtf8Symbol(Vector<const char> string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005620 Object* symbol = NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005621 Object* new_table;
5622 { MaybeObject* maybe_new_table =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005623 symbol_table()->LookupUtf8Symbol(string, &symbol);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005624 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5625 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005626 // Can't use set_symbol_table because SymbolTable::cast knows that
5627 // SymbolTable is a singleton and checks for identity.
5628 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005629 ASSERT(symbol != NULL);
5630 return symbol;
5631}
5632
5633
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005634MaybeObject* Heap::LookupOneByteSymbol(Vector<const char> string) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005635 Object* symbol = NULL;
5636 Object* new_table;
5637 { MaybeObject* maybe_new_table =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005638 symbol_table()->LookupOneByteSymbol(string, &symbol);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005639 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5640 }
5641 // Can't use set_symbol_table because SymbolTable::cast knows that
5642 // SymbolTable is a singleton and checks for identity.
5643 roots_[kSymbolTableRootIndex] = new_table;
5644 ASSERT(symbol != NULL);
5645 return symbol;
5646}
5647
5648
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005649MaybeObject* Heap::LookupOneByteSymbol(Handle<SeqOneByteString> string,
danno@chromium.org40cb8782011-05-25 07:58:50 +00005650 int from,
5651 int length) {
5652 Object* symbol = NULL;
5653 Object* new_table;
5654 { MaybeObject* maybe_new_table =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005655 symbol_table()->LookupSubStringOneByteSymbol(string,
danno@chromium.org40cb8782011-05-25 07:58:50 +00005656 from,
5657 length,
5658 &symbol);
5659 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5660 }
5661 // Can't use set_symbol_table because SymbolTable::cast knows that
5662 // SymbolTable is a singleton and checks for identity.
5663 roots_[kSymbolTableRootIndex] = new_table;
5664 ASSERT(symbol != NULL);
5665 return symbol;
5666}
5667
5668
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005669MaybeObject* Heap::LookupTwoByteSymbol(Vector<const uc16> string) {
5670 Object* symbol = NULL;
5671 Object* new_table;
5672 { MaybeObject* maybe_new_table =
5673 symbol_table()->LookupTwoByteSymbol(string, &symbol);
5674 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5675 }
5676 // Can't use set_symbol_table because SymbolTable::cast knows that
5677 // SymbolTable is a singleton and checks for identity.
5678 roots_[kSymbolTableRootIndex] = new_table;
5679 ASSERT(symbol != NULL);
5680 return symbol;
5681}
5682
5683
lrn@chromium.org303ada72010-10-27 09:33:13 +00005684MaybeObject* Heap::LookupSymbol(String* string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005685 if (string->IsSymbol()) return string;
5686 Object* symbol = NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005687 Object* new_table;
5688 { MaybeObject* maybe_new_table =
5689 symbol_table()->LookupString(string, &symbol);
5690 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5691 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005692 // Can't use set_symbol_table because SymbolTable::cast knows that
5693 // SymbolTable is a singleton and checks for identity.
5694 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005695 ASSERT(symbol != NULL);
5696 return symbol;
5697}
5698
5699
ager@chromium.org7c537e22008-10-16 08:43:32 +00005700bool Heap::LookupSymbolIfExists(String* string, String** symbol) {
5701 if (string->IsSymbol()) {
5702 *symbol = string;
5703 return true;
5704 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005705 return symbol_table()->LookupSymbolIfExists(string, symbol);
ager@chromium.org7c537e22008-10-16 08:43:32 +00005706}
5707
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005708
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005709void Heap::ZapFromSpace() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005710 NewSpacePageIterator it(new_space_.FromSpaceStart(),
5711 new_space_.FromSpaceEnd());
5712 while (it.has_next()) {
5713 NewSpacePage* page = it.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005714 for (Address cursor = page->area_start(), limit = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005715 cursor < limit;
5716 cursor += kPointerSize) {
5717 Memory::Address_at(cursor) = kFromSpaceZapValue;
5718 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005719 }
5720}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005721
5722
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005723void Heap::IterateAndMarkPointersToFromSpace(Address start,
5724 Address end,
5725 ObjectSlotCallback callback) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005726 Address slot_address = start;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005727
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005728 // We are not collecting slots on new space objects during mutation
5729 // thus we have to scan for pointers to evacuation candidates when we
5730 // promote objects. But we should not record any slots in non-black
5731 // objects. Grey object's slots would be rescanned.
5732 // White object might not survive until the end of collection
5733 // it would be a violation of the invariant to record it's slots.
5734 bool record_slots = false;
5735 if (incremental_marking()->IsCompacting()) {
5736 MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::FromAddress(start));
5737 record_slots = Marking::IsBlack(mark_bit);
5738 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005739
5740 while (slot_address < end) {
5741 Object** slot = reinterpret_cast<Object**>(slot_address);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005742 Object* object = *slot;
5743 // If the store buffer becomes overfull we mark pages as being exempt from
5744 // the store buffer. These pages are scanned to find pointers that point
5745 // to the new space. In that case we may hit newly promoted objects and
5746 // fix the pointers before the promotion queue gets to them. Thus the 'if'.
5747 if (object->IsHeapObject()) {
5748 if (Heap::InFromSpace(object)) {
5749 callback(reinterpret_cast<HeapObject**>(slot),
5750 HeapObject::cast(object));
5751 Object* new_object = *slot;
5752 if (InNewSpace(new_object)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005753 SLOW_ASSERT(Heap::InToSpace(new_object));
5754 SLOW_ASSERT(new_object->IsHeapObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005755 store_buffer_.EnterDirectlyIntoStoreBuffer(
5756 reinterpret_cast<Address>(slot));
5757 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005758 SLOW_ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_object));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005759 } else if (record_slots &&
5760 MarkCompactCollector::IsOnEvacuationCandidate(object)) {
5761 mark_compact_collector()->RecordSlot(slot, slot, object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005762 }
5763 }
5764 slot_address += kPointerSize;
5765 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005766}
5767
5768
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005769#ifdef DEBUG
5770typedef bool (*CheckStoreBufferFilter)(Object** addr);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005771
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005772
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005773bool IsAMapPointerAddress(Object** addr) {
5774 uintptr_t a = reinterpret_cast<uintptr_t>(addr);
5775 int mod = a % Map::kSize;
5776 return mod >= Map::kPointerFieldsBeginOffset &&
5777 mod < Map::kPointerFieldsEndOffset;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005778}
5779
5780
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005781bool EverythingsAPointer(Object** addr) {
5782 return true;
5783}
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005784
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005785
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005786static void CheckStoreBuffer(Heap* heap,
5787 Object** current,
5788 Object** limit,
5789 Object**** store_buffer_position,
5790 Object*** store_buffer_top,
5791 CheckStoreBufferFilter filter,
5792 Address special_garbage_start,
5793 Address special_garbage_end) {
5794 Map* free_space_map = heap->free_space_map();
5795 for ( ; current < limit; current++) {
5796 Object* o = *current;
5797 Address current_address = reinterpret_cast<Address>(current);
5798 // Skip free space.
5799 if (o == free_space_map) {
5800 Address current_address = reinterpret_cast<Address>(current);
5801 FreeSpace* free_space =
5802 FreeSpace::cast(HeapObject::FromAddress(current_address));
5803 int skip = free_space->Size();
5804 ASSERT(current_address + skip <= reinterpret_cast<Address>(limit));
5805 ASSERT(skip > 0);
5806 current_address += skip - kPointerSize;
5807 current = reinterpret_cast<Object**>(current_address);
5808 continue;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005809 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005810 // Skip the current linear allocation space between top and limit which is
5811 // unmarked with the free space map, but can contain junk.
5812 if (current_address == special_garbage_start &&
5813 special_garbage_end != special_garbage_start) {
5814 current_address = special_garbage_end - kPointerSize;
5815 current = reinterpret_cast<Object**>(current_address);
5816 continue;
5817 }
5818 if (!(*filter)(current)) continue;
5819 ASSERT(current_address < special_garbage_start ||
5820 current_address >= special_garbage_end);
5821 ASSERT(reinterpret_cast<uintptr_t>(o) != kFreeListZapValue);
5822 // We have to check that the pointer does not point into new space
5823 // without trying to cast it to a heap object since the hash field of
5824 // a string can contain values like 1 and 3 which are tagged null
5825 // pointers.
5826 if (!heap->InNewSpace(o)) continue;
5827 while (**store_buffer_position < current &&
5828 *store_buffer_position < store_buffer_top) {
5829 (*store_buffer_position)++;
5830 }
5831 if (**store_buffer_position != current ||
5832 *store_buffer_position == store_buffer_top) {
5833 Object** obj_start = current;
5834 while (!(*obj_start)->IsMap()) obj_start--;
5835 UNREACHABLE();
5836 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005837 }
5838}
5839
5840
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005841// Check that the store buffer contains all intergenerational pointers by
5842// scanning a page and ensuring that all pointers to young space are in the
5843// store buffer.
5844void Heap::OldPointerSpaceCheckStoreBuffer() {
5845 OldSpace* space = old_pointer_space();
5846 PageIterator pages(space);
5847
5848 store_buffer()->SortUniq();
5849
5850 while (pages.has_next()) {
5851 Page* page = pages.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005852 Object** current = reinterpret_cast<Object**>(page->area_start());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005853
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005854 Address end = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005855
5856 Object*** store_buffer_position = store_buffer()->Start();
5857 Object*** store_buffer_top = store_buffer()->Top();
5858
5859 Object** limit = reinterpret_cast<Object**>(end);
5860 CheckStoreBuffer(this,
5861 current,
5862 limit,
5863 &store_buffer_position,
5864 store_buffer_top,
5865 &EverythingsAPointer,
5866 space->top(),
5867 space->limit());
5868 }
5869}
5870
5871
5872void Heap::MapSpaceCheckStoreBuffer() {
5873 MapSpace* space = map_space();
5874 PageIterator pages(space);
5875
5876 store_buffer()->SortUniq();
5877
5878 while (pages.has_next()) {
5879 Page* page = pages.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005880 Object** current = reinterpret_cast<Object**>(page->area_start());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005881
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005882 Address end = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005883
5884 Object*** store_buffer_position = store_buffer()->Start();
5885 Object*** store_buffer_top = store_buffer()->Top();
5886
5887 Object** limit = reinterpret_cast<Object**>(end);
5888 CheckStoreBuffer(this,
5889 current,
5890 limit,
5891 &store_buffer_position,
5892 store_buffer_top,
5893 &IsAMapPointerAddress,
5894 space->top(),
5895 space->limit());
5896 }
5897}
5898
5899
5900void Heap::LargeObjectSpaceCheckStoreBuffer() {
5901 LargeObjectIterator it(lo_space());
5902 for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) {
5903 // We only have code, sequential strings, or fixed arrays in large
5904 // object space, and only fixed arrays can possibly contain pointers to
5905 // the young generation.
5906 if (object->IsFixedArray()) {
5907 Object*** store_buffer_position = store_buffer()->Start();
5908 Object*** store_buffer_top = store_buffer()->Top();
5909 Object** current = reinterpret_cast<Object**>(object->address());
5910 Object** limit =
5911 reinterpret_cast<Object**>(object->address() + object->Size());
5912 CheckStoreBuffer(this,
5913 current,
5914 limit,
5915 &store_buffer_position,
5916 store_buffer_top,
5917 &EverythingsAPointer,
5918 NULL,
5919 NULL);
5920 }
5921 }
5922}
5923#endif
5924
5925
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005926void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) {
5927 IterateStrongRoots(v, mode);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005928 IterateWeakRoots(v, mode);
5929}
5930
5931
5932void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005933 v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex]));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005934 v->Synchronize(VisitorSynchronization::kSymbolTable);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005935 if (mode != VISIT_ALL_IN_SCAVENGE &&
5936 mode != VISIT_ALL_IN_SWEEP_NEWSPACE) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005937 // Scavenge collections have special processing for this.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005938 external_string_table_.Iterate(v);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005939 error_object_list_.Iterate(v);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005940 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005941 v->Synchronize(VisitorSynchronization::kExternalStringsTable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005942}
5943
5944
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005945void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005946 v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005947 v->Synchronize(VisitorSynchronization::kStrongRootList);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005948
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00005949 v->VisitPointer(BitCast<Object**>(&hidden_symbol_));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005950 v->Synchronize(VisitorSynchronization::kSymbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005951
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005952 isolate_->bootstrapper()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005953 v->Synchronize(VisitorSynchronization::kBootstrapper);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005954 isolate_->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005955 v->Synchronize(VisitorSynchronization::kTop);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005956 Relocatable::Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005957 v->Synchronize(VisitorSynchronization::kRelocatable);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005958
5959#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005960 isolate_->debug()->Iterate(v);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005961 if (isolate_->deoptimizer_data() != NULL) {
5962 isolate_->deoptimizer_data()->Iterate(v);
5963 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005964#endif
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005965 v->Synchronize(VisitorSynchronization::kDebug);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005966 isolate_->compilation_cache()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005967 v->Synchronize(VisitorSynchronization::kCompilationCache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005968
5969 // Iterate over local handles in handle scopes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005970 isolate_->handle_scope_implementer()->Iterate(v);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005971 isolate_->IterateDeferredHandles(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005972 v->Synchronize(VisitorSynchronization::kHandleScope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005973
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005974 // Iterate over the builtin code objects and code stubs in the
5975 // heap. Note that it is not necessary to iterate over code objects
5976 // on scavenge collections.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005977 if (mode != VISIT_ALL_IN_SCAVENGE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005978 isolate_->builtins()->IterateBuiltins(v);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005979 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005980 v->Synchronize(VisitorSynchronization::kBuiltins);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981
5982 // Iterate over global handles.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005983 switch (mode) {
5984 case VISIT_ONLY_STRONG:
5985 isolate_->global_handles()->IterateStrongRoots(v);
5986 break;
5987 case VISIT_ALL_IN_SCAVENGE:
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005988 isolate_->global_handles()->IterateNewSpaceStrongAndDependentRoots(v);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005989 break;
5990 case VISIT_ALL_IN_SWEEP_NEWSPACE:
5991 case VISIT_ALL:
5992 isolate_->global_handles()->IterateAllRoots(v);
5993 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005994 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005995 v->Synchronize(VisitorSynchronization::kGlobalHandles);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005996
5997 // Iterate over pointers being held by inactive threads.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005998 isolate_->thread_manager()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005999 v->Synchronize(VisitorSynchronization::kThreadManager);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006000
6001 // Iterate over the pointers the Serialization/Deserialization code is
6002 // holding.
6003 // During garbage collection this keeps the partial snapshot cache alive.
6004 // During deserialization of the startup snapshot this creates the partial
6005 // snapshot cache and deserializes the objects it refers to. During
6006 // serialization this does nothing, since the partial snapshot cache is
6007 // empty. However the next thing we do is create the partial snapshot,
6008 // filling up the partial snapshot cache with objects it needs as we go.
6009 SerializerDeserializer::Iterate(v);
6010 // We don't do a v->Synchronize call here, because in debug mode that will
6011 // output a flag to the snapshot. However at this point the serializer and
6012 // deserializer are deliberately a little unsynchronized (see above) so the
6013 // checking of the sync flag in the snapshot would fail.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006014}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006015
6016
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006017// TODO(1236194): Since the heap size is configurable on the command line
6018// and through the API, we should gracefully handle the case that the heap
6019// size is not big enough to fit all the initial objects.
ager@chromium.org01fe7df2010-11-10 11:59:11 +00006020bool Heap::ConfigureHeap(int max_semispace_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006021 intptr_t max_old_gen_size,
6022 intptr_t max_executable_size) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006023 if (HasBeenSetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006024
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00006025 if (FLAG_stress_compaction) {
6026 // This will cause more frequent GCs when stressing.
6027 max_semispace_size_ = Page::kPageSize;
6028 }
6029
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006030 if (max_semispace_size > 0) {
6031 if (max_semispace_size < Page::kPageSize) {
6032 max_semispace_size = Page::kPageSize;
6033 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006034 PrintPID("Max semispace size cannot be less than %dkbytes\n",
6035 Page::kPageSize >> 10);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006036 }
6037 }
6038 max_semispace_size_ = max_semispace_size;
6039 }
ager@chromium.org3811b432009-10-28 14:53:37 +00006040
6041 if (Snapshot::IsEnabled()) {
6042 // If we are using a snapshot we always reserve the default amount
6043 // of memory for each semispace because code in the snapshot has
6044 // write-barrier code that relies on the size and alignment of new
6045 // space. We therefore cannot use a larger max semispace size
6046 // than the default reserved semispace size.
6047 if (max_semispace_size_ > reserved_semispace_size_) {
6048 max_semispace_size_ = reserved_semispace_size_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006049 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006050 PrintPID("Max semispace size cannot be more than %dkbytes\n",
6051 reserved_semispace_size_ >> 10);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006052 }
ager@chromium.org3811b432009-10-28 14:53:37 +00006053 }
6054 } else {
6055 // If we are not using snapshots we reserve space for the actual
6056 // max semispace size.
6057 reserved_semispace_size_ = max_semispace_size_;
6058 }
6059
6060 if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size;
ager@chromium.org01fe7df2010-11-10 11:59:11 +00006061 if (max_executable_size > 0) {
6062 max_executable_size_ = RoundUp(max_executable_size, Page::kPageSize);
6063 }
6064
6065 // The max executable size must be less than or equal to the max old
6066 // generation size.
6067 if (max_executable_size_ > max_old_generation_size_) {
6068 max_executable_size_ = max_old_generation_size_;
6069 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006070
6071 // The new space size must be a power of two to support single-bit testing
6072 // for containment.
ager@chromium.org3811b432009-10-28 14:53:37 +00006073 max_semispace_size_ = RoundUpToPowerOf2(max_semispace_size_);
6074 reserved_semispace_size_ = RoundUpToPowerOf2(reserved_semispace_size_);
6075 initial_semispace_size_ = Min(initial_semispace_size_, max_semispace_size_);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006076 external_allocation_limit_ = 16 * max_semispace_size_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006077
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006078 // The old generation is paged and needs at least one page for each space.
6079 int paged_space_count = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1;
6080 max_old_generation_size_ = Max(static_cast<intptr_t>(paged_space_count *
6081 Page::kPageSize),
6082 RoundUp(max_old_generation_size_,
6083 Page::kPageSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006084
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006085 configured_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006086 return true;
6087}
6088
6089
kasper.lund7276f142008-07-30 08:49:36 +00006090bool Heap::ConfigureHeapDefault() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006091 return ConfigureHeap(static_cast<intptr_t>(FLAG_max_new_space_size / 2) * KB,
6092 static_cast<intptr_t>(FLAG_max_old_space_size) * MB,
6093 static_cast<intptr_t>(FLAG_max_executable_size) * MB);
kasper.lund7276f142008-07-30 08:49:36 +00006094}
6095
6096
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006097void Heap::RecordStats(HeapStats* stats, bool take_snapshot) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006098 *stats->start_marker = HeapStats::kStartMarker;
6099 *stats->end_marker = HeapStats::kEndMarker;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006100 *stats->new_space_size = new_space_.SizeAsInt();
6101 *stats->new_space_capacity = static_cast<int>(new_space_.Capacity());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006102 *stats->old_pointer_space_size = old_pointer_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006103 *stats->old_pointer_space_capacity = old_pointer_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006104 *stats->old_data_space_size = old_data_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006105 *stats->old_data_space_capacity = old_data_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006106 *stats->code_space_size = code_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006107 *stats->code_space_capacity = code_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006108 *stats->map_space_size = map_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006109 *stats->map_space_capacity = map_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006110 *stats->cell_space_size = cell_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006111 *stats->cell_space_capacity = cell_space_->Capacity();
6112 *stats->lo_space_size = lo_space_->Size();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006113 isolate_->global_handles()->RecordStats(stats);
6114 *stats->memory_allocator_size = isolate()->memory_allocator()->Size();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006115 *stats->memory_allocator_capacity =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006116 isolate()->memory_allocator()->Size() +
6117 isolate()->memory_allocator()->Available();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006118 *stats->os_error = OS::GetLastError();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006119 isolate()->memory_allocator()->Available();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006120 if (take_snapshot) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006121 HeapIterator iterator;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006122 for (HeapObject* obj = iterator.next();
6123 obj != NULL;
6124 obj = iterator.next()) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006125 InstanceType type = obj->map()->instance_type();
6126 ASSERT(0 <= type && type <= LAST_TYPE);
6127 stats->objects_per_type[type]++;
6128 stats->size_per_type[type] += obj->Size();
6129 }
6130 }
ager@chromium.org60121232009-12-03 11:25:37 +00006131}
6132
6133
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00006134intptr_t Heap::PromotedSpaceSizeOfObjects() {
6135 return old_pointer_space_->SizeOfObjects()
6136 + old_data_space_->SizeOfObjects()
6137 + code_space_->SizeOfObjects()
6138 + map_space_->SizeOfObjects()
6139 + cell_space_->SizeOfObjects()
6140 + lo_space_->SizeOfObjects();
6141}
6142
6143
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00006144intptr_t Heap::PromotedExternalMemorySize() {
kasper.lund7276f142008-07-30 08:49:36 +00006145 if (amount_of_external_allocated_memory_
6146 <= amount_of_external_allocated_memory_at_last_global_gc_) return 0;
6147 return amount_of_external_allocated_memory_
6148 - amount_of_external_allocated_memory_at_last_global_gc_;
6149}
6150
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00006151
6152V8_DECLARE_ONCE(initialize_gc_once);
6153
6154static void InitializeGCOnce() {
6155 InitializeScavengingVisitorsTables();
6156 NewSpaceScavenger::Initialize();
6157 MarkCompactCollector::Initialize();
6158}
6159
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006160bool Heap::SetUp(bool create_heap_objects) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006161#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006162 allocation_timeout_ = FLAG_gc_interval;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006163#endif
6164
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006165 // Initialize heap spaces and initial maps and objects. Whenever something
6166 // goes wrong, just return false. The caller should check the results and
6167 // call Heap::TearDown() to release allocated memory.
6168 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006169 // If the heap is not yet configured (e.g. through the API), configure it.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006170 // Configuration is based on the flags new-space-size (really the semispace
6171 // size) and old-space-size if set or the initial values of semispace_size_
6172 // and old_generation_size_ otherwise.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006173 if (!configured_) {
kasper.lund7276f142008-07-30 08:49:36 +00006174 if (!ConfigureHeapDefault()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006175 }
6176
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00006177 CallOnce(&initialize_gc_once, &InitializeGCOnce);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006178
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006179 MarkMapPointersAsEncoded(false);
6180
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006181 // Set up memory allocator.
6182 if (!isolate_->memory_allocator()->SetUp(MaxReserved(), MaxExecutableSize()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006183 return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006184
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006185 // Set up new space.
6186 if (!new_space_.SetUp(reserved_semispace_size_, max_semispace_size_)) {
ager@chromium.org3811b432009-10-28 14:53:37 +00006187 return false;
6188 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006189
ager@chromium.orga1645e22009-09-09 19:27:10 +00006190 // Initialize old pointer space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006191 old_pointer_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006192 new OldSpace(this,
6193 max_old_generation_size_,
6194 OLD_POINTER_SPACE,
6195 NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006196 if (old_pointer_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006197 if (!old_pointer_space_->SetUp()) return false;
ager@chromium.orga1645e22009-09-09 19:27:10 +00006198
6199 // Initialize old data space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006200 old_data_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006201 new OldSpace(this,
6202 max_old_generation_size_,
6203 OLD_DATA_SPACE,
6204 NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006205 if (old_data_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006206 if (!old_data_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006207
6208 // Initialize the code space, set its maximum capacity to the old
kasper.lund7276f142008-07-30 08:49:36 +00006209 // generation size. It needs executable memory.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006210 // On 64-bit platform(s), we put all code objects in a 2 GB range of
6211 // virtual address space, so that they can call each other with near calls.
6212 if (code_range_size_ > 0) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006213 if (!isolate_->code_range()->SetUp(code_range_size_)) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006214 return false;
6215 }
6216 }
6217
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006218 code_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006219 new OldSpace(this, max_old_generation_size_, CODE_SPACE, EXECUTABLE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006220 if (code_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006221 if (!code_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006222
6223 // Initialize map space.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00006224 map_space_ = new MapSpace(this, max_old_generation_size_, MAP_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006225 if (map_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006226 if (!map_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006227
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006228 // Initialize global property cell space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006229 cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006230 if (cell_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006231 if (!cell_space_->SetUp()) return false;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006232
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006233 // The large object code space may contain code or data. We set the memory
6234 // to be non-executable here for safety, but this means we need to enable it
6235 // explicitly when allocating large code objects.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006236 lo_space_ = new LargeObjectSpace(this, max_old_generation_size_, LO_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006237 if (lo_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006238 if (!lo_space_->SetUp()) return false;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006239
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006240 // Set up the seed that is used to randomize the string hash function.
6241 ASSERT(hash_seed() == 0);
6242 if (FLAG_randomize_hashes) {
6243 if (FLAG_hash_seed == 0) {
6244 set_hash_seed(
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006245 Smi::FromInt(V8::RandomPrivate(isolate()) & 0x3fffffff));
6246 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006247 set_hash_seed(Smi::FromInt(FLAG_hash_seed));
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006248 }
6249 }
6250
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006251 if (create_heap_objects) {
6252 // Create initial maps.
6253 if (!CreateInitialMaps()) return false;
6254 if (!CreateApiObjects()) return false;
6255
6256 // Create initial objects
6257 if (!CreateInitialObjects()) return false;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00006258
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006259 native_contexts_list_ = undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006260 }
6261
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006262 LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity()));
6263 LOG(isolate_, IntPtrTEvent("heap-available", Available()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006264
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006265 store_buffer()->SetUp();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006266
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006267 if (FLAG_parallel_recompilation) relocation_mutex_ = OS::CreateMutex();
6268
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006269 return true;
6270}
6271
6272
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006273void Heap::SetStackLimits() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006274 ASSERT(isolate_ != NULL);
6275 ASSERT(isolate_ == isolate());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006276 // On 64 bit machines, pointers are generally out of range of Smis. We write
6277 // something that looks like an out of range Smi to the GC.
6278
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006279 // Set up the special root array entries containing the stack limits.
6280 // These are actually addresses, but the tag makes the GC ignore it.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006281 roots_[kStackLimitRootIndex] =
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006282 reinterpret_cast<Object*>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006283 (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006284 roots_[kRealStackLimitRootIndex] =
6285 reinterpret_cast<Object*>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006286 (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006287}
6288
6289
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006290void Heap::TearDown() {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006291#ifdef VERIFY_HEAP
danno@chromium.org1044a4d2012-04-30 12:34:39 +00006292 if (FLAG_verify_heap) {
6293 Verify();
6294 }
6295#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006296
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006297 if (FLAG_print_cumulative_gc_stat) {
6298 PrintF("\n\n");
6299 PrintF("gc_count=%d ", gc_count_);
6300 PrintF("mark_sweep_count=%d ", ms_count_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006301 PrintF("max_gc_pause=%d ", get_max_gc_pause());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006302 PrintF("total_gc_time=%d ", total_gc_time_ms_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006303 PrintF("min_in_mutator=%d ", get_min_in_mutator());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006304 PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ",
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006305 get_max_alive_after_gc());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006306 PrintF("\n\n");
6307 }
6308
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006309 isolate_->global_handles()->TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006311 external_string_table_.TearDown();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00006312
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00006313 error_object_list_.TearDown();
6314
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006315 new_space_.TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006316
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006317 if (old_pointer_space_ != NULL) {
6318 old_pointer_space_->TearDown();
6319 delete old_pointer_space_;
6320 old_pointer_space_ = NULL;
6321 }
6322
6323 if (old_data_space_ != NULL) {
6324 old_data_space_->TearDown();
6325 delete old_data_space_;
6326 old_data_space_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006327 }
6328
6329 if (code_space_ != NULL) {
6330 code_space_->TearDown();
6331 delete code_space_;
6332 code_space_ = NULL;
6333 }
6334
6335 if (map_space_ != NULL) {
6336 map_space_->TearDown();
6337 delete map_space_;
6338 map_space_ = NULL;
6339 }
6340
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006341 if (cell_space_ != NULL) {
6342 cell_space_->TearDown();
6343 delete cell_space_;
6344 cell_space_ = NULL;
6345 }
6346
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006347 if (lo_space_ != NULL) {
6348 lo_space_->TearDown();
6349 delete lo_space_;
6350 lo_space_ = NULL;
6351 }
6352
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006353 store_buffer()->TearDown();
6354 incremental_marking()->TearDown();
6355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006356 isolate_->memory_allocator()->TearDown();
6357
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006358 delete relocation_mutex_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006359}
6360
6361
6362void Heap::Shrink() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006363 // Try to shrink all paged spaces.
6364 PagedSpaces spaces;
danno@chromium.org2c456792011-11-11 12:00:53 +00006365 for (PagedSpace* space = spaces.next();
6366 space != NULL;
6367 space = spaces.next()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006368 space->ReleaseAllUnusedPages();
danno@chromium.org2c456792011-11-11 12:00:53 +00006369 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006370}
6371
6372
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006373void Heap::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) {
6374 ASSERT(callback != NULL);
6375 GCPrologueCallbackPair pair(callback, gc_type);
6376 ASSERT(!gc_prologue_callbacks_.Contains(pair));
6377 return gc_prologue_callbacks_.Add(pair);
6378}
6379
6380
6381void Heap::RemoveGCPrologueCallback(GCPrologueCallback callback) {
6382 ASSERT(callback != NULL);
6383 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
6384 if (gc_prologue_callbacks_[i].callback == callback) {
6385 gc_prologue_callbacks_.Remove(i);
6386 return;
6387 }
6388 }
6389 UNREACHABLE();
6390}
6391
6392
6393void Heap::AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type) {
6394 ASSERT(callback != NULL);
6395 GCEpilogueCallbackPair pair(callback, gc_type);
6396 ASSERT(!gc_epilogue_callbacks_.Contains(pair));
6397 return gc_epilogue_callbacks_.Add(pair);
6398}
6399
6400
6401void Heap::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
6402 ASSERT(callback != NULL);
6403 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
6404 if (gc_epilogue_callbacks_[i].callback == callback) {
6405 gc_epilogue_callbacks_.Remove(i);
6406 return;
6407 }
6408 }
6409 UNREACHABLE();
6410}
6411
6412
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006413#ifdef DEBUG
6414
6415class PrintHandleVisitor: public ObjectVisitor {
6416 public:
6417 void VisitPointers(Object** start, Object** end) {
6418 for (Object** p = start; p < end; p++)
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006419 PrintF(" handle %p to %p\n",
6420 reinterpret_cast<void*>(p),
6421 reinterpret_cast<void*>(*p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006422 }
6423};
6424
6425void Heap::PrintHandles() {
6426 PrintF("Handles:\n");
6427 PrintHandleVisitor v;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006428 isolate_->handle_scope_implementer()->Iterate(&v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006429}
6430
6431#endif
6432
6433
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006434Space* AllSpaces::next() {
6435 switch (counter_++) {
6436 case NEW_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006437 return HEAP->new_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006438 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006439 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006440 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006441 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006442 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006443 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006444 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006445 return HEAP->map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006446 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006447 return HEAP->cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006448 case LO_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006449 return HEAP->lo_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006450 default:
6451 return NULL;
6452 }
6453}
6454
6455
6456PagedSpace* PagedSpaces::next() {
6457 switch (counter_++) {
6458 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006459 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006460 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006461 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006462 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006463 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006464 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006465 return HEAP->map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006466 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006467 return HEAP->cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006468 default:
6469 return NULL;
6470 }
6471}
6472
6473
6474
6475OldSpace* OldSpaces::next() {
6476 switch (counter_++) {
6477 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006478 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006479 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006480 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006481 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006482 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006483 default:
6484 return NULL;
6485 }
6486}
6487
6488
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006489SpaceIterator::SpaceIterator()
6490 : current_space_(FIRST_SPACE),
6491 iterator_(NULL),
6492 size_func_(NULL) {
6493}
6494
6495
6496SpaceIterator::SpaceIterator(HeapObjectCallback size_func)
6497 : current_space_(FIRST_SPACE),
6498 iterator_(NULL),
6499 size_func_(size_func) {
kasper.lund7276f142008-07-30 08:49:36 +00006500}
6501
6502
6503SpaceIterator::~SpaceIterator() {
6504 // Delete active iterator if any.
6505 delete iterator_;
6506}
6507
6508
6509bool SpaceIterator::has_next() {
6510 // Iterate until no more spaces.
6511 return current_space_ != LAST_SPACE;
6512}
6513
6514
6515ObjectIterator* SpaceIterator::next() {
6516 if (iterator_ != NULL) {
6517 delete iterator_;
6518 iterator_ = NULL;
6519 // Move to the next space
6520 current_space_++;
6521 if (current_space_ > LAST_SPACE) {
6522 return NULL;
6523 }
6524 }
6525
6526 // Return iterator for the new current space.
6527 return CreateIterator();
6528}
6529
6530
6531// Create an iterator for the space to iterate.
6532ObjectIterator* SpaceIterator::CreateIterator() {
6533 ASSERT(iterator_ == NULL);
6534
6535 switch (current_space_) {
6536 case NEW_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006537 iterator_ = new SemiSpaceIterator(HEAP->new_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006538 break;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006539 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006540 iterator_ = new HeapObjectIterator(HEAP->old_pointer_space(), size_func_);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006541 break;
6542 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006543 iterator_ = new HeapObjectIterator(HEAP->old_data_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006544 break;
6545 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006546 iterator_ = new HeapObjectIterator(HEAP->code_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006547 break;
6548 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006549 iterator_ = new HeapObjectIterator(HEAP->map_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006550 break;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006551 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006552 iterator_ = new HeapObjectIterator(HEAP->cell_space(), size_func_);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006553 break;
kasper.lund7276f142008-07-30 08:49:36 +00006554 case LO_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006555 iterator_ = new LargeObjectIterator(HEAP->lo_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006556 break;
6557 }
6558
6559 // Return the newly allocated iterator;
6560 ASSERT(iterator_ != NULL);
6561 return iterator_;
6562}
6563
6564
whesse@chromium.org023421e2010-12-21 12:19:12 +00006565class HeapObjectsFilter {
6566 public:
6567 virtual ~HeapObjectsFilter() {}
6568 virtual bool SkipObject(HeapObject* object) = 0;
6569};
6570
6571
whesse@chromium.org023421e2010-12-21 12:19:12 +00006572class UnreachableObjectsFilter : public HeapObjectsFilter {
6573 public:
6574 UnreachableObjectsFilter() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006575 MarkReachableObjects();
6576 }
6577
6578 ~UnreachableObjectsFilter() {
6579 Isolate::Current()->heap()->mark_compact_collector()->ClearMarkbits();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006580 }
6581
6582 bool SkipObject(HeapObject* object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006583 MarkBit mark_bit = Marking::MarkBitFrom(object);
6584 return !mark_bit.Get();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006585 }
6586
6587 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006588 class MarkingVisitor : public ObjectVisitor {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006589 public:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006590 MarkingVisitor() : marking_stack_(10) {}
whesse@chromium.org023421e2010-12-21 12:19:12 +00006591
6592 void VisitPointers(Object** start, Object** end) {
6593 for (Object** p = start; p < end; p++) {
6594 if (!(*p)->IsHeapObject()) continue;
6595 HeapObject* obj = HeapObject::cast(*p);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006596 MarkBit mark_bit = Marking::MarkBitFrom(obj);
6597 if (!mark_bit.Get()) {
6598 mark_bit.Set();
6599 marking_stack_.Add(obj);
whesse@chromium.org023421e2010-12-21 12:19:12 +00006600 }
6601 }
6602 }
6603
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006604 void TransitiveClosure() {
6605 while (!marking_stack_.is_empty()) {
6606 HeapObject* obj = marking_stack_.RemoveLast();
6607 obj->Iterate(this);
6608 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00006609 }
6610
6611 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006612 List<HeapObject*> marking_stack_;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006613 };
6614
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006615 void MarkReachableObjects() {
6616 Heap* heap = Isolate::Current()->heap();
6617 MarkingVisitor visitor;
6618 heap->IterateRoots(&visitor, VISIT_ALL);
6619 visitor.TransitiveClosure();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006620 }
6621
6622 AssertNoAllocation no_alloc;
6623};
6624
6625
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006626HeapIterator::HeapIterator()
6627 : filtering_(HeapIterator::kNoFiltering),
6628 filter_(NULL) {
6629 Init();
6630}
6631
6632
whesse@chromium.org023421e2010-12-21 12:19:12 +00006633HeapIterator::HeapIterator(HeapIterator::HeapObjectsFiltering filtering)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006634 : filtering_(filtering),
6635 filter_(NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006636 Init();
6637}
6638
6639
6640HeapIterator::~HeapIterator() {
6641 Shutdown();
6642}
6643
6644
6645void HeapIterator::Init() {
6646 // Start the iteration.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006647 space_iterator_ = new SpaceIterator;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006648 switch (filtering_) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006649 case kFilterUnreachable:
6650 filter_ = new UnreachableObjectsFilter;
6651 break;
6652 default:
6653 break;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006654 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006655 object_iterator_ = space_iterator_->next();
6656}
6657
6658
6659void HeapIterator::Shutdown() {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006660#ifdef DEBUG
whesse@chromium.org023421e2010-12-21 12:19:12 +00006661 // Assert that in filtering mode we have iterated through all
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006662 // objects. Otherwise, heap will be left in an inconsistent state.
whesse@chromium.org023421e2010-12-21 12:19:12 +00006663 if (filtering_ != kNoFiltering) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006664 ASSERT(object_iterator_ == NULL);
6665 }
6666#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006667 // Make sure the last iterator is deallocated.
6668 delete space_iterator_;
6669 space_iterator_ = NULL;
6670 object_iterator_ = NULL;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006671 delete filter_;
6672 filter_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006673}
6674
6675
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006676HeapObject* HeapIterator::next() {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006677 if (filter_ == NULL) return NextObject();
6678
6679 HeapObject* obj = NextObject();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006680 while (obj != NULL && filter_->SkipObject(obj)) obj = NextObject();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006681 return obj;
6682}
6683
6684
6685HeapObject* HeapIterator::NextObject() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006686 // No iterator means we are done.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006687 if (object_iterator_ == NULL) return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006688
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006689 if (HeapObject* obj = object_iterator_->next_object()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006690 // If the current iterator has more objects we are fine.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006691 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006692 } else {
6693 // Go though the spaces looking for one that has objects.
6694 while (space_iterator_->has_next()) {
6695 object_iterator_ = space_iterator_->next();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006696 if (HeapObject* obj = object_iterator_->next_object()) {
6697 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006698 }
6699 }
6700 }
6701 // Done with the last space.
6702 object_iterator_ = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006703 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006704}
6705
6706
6707void HeapIterator::reset() {
6708 // Restart the iterator.
6709 Shutdown();
6710 Init();
6711}
6712
6713
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006714#if defined(DEBUG) || defined(LIVE_OBJECT_LIST)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006715
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006716Object* const PathTracer::kAnyGlobalObject = reinterpret_cast<Object*>(NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006717
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006718class PathTracer::MarkVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006719 public:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006720 explicit MarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006721 void VisitPointers(Object** start, Object** end) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006722 // Scan all HeapObject pointers in [start, end)
6723 for (Object** p = start; !tracer_->found() && (p < end); p++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006724 if ((*p)->IsHeapObject())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006725 tracer_->MarkRecursively(p, this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006726 }
6727 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006728
6729 private:
6730 PathTracer* tracer_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006731};
6732
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006733
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006734class PathTracer::UnmarkVisitor: public ObjectVisitor {
6735 public:
6736 explicit UnmarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
6737 void VisitPointers(Object** start, Object** end) {
6738 // Scan all HeapObject pointers in [start, end)
6739 for (Object** p = start; p < end; p++) {
6740 if ((*p)->IsHeapObject())
6741 tracer_->UnmarkRecursively(p, this);
6742 }
6743 }
6744
6745 private:
6746 PathTracer* tracer_;
6747};
6748
6749
6750void PathTracer::VisitPointers(Object** start, Object** end) {
6751 bool done = ((what_to_find_ == FIND_FIRST) && found_target_);
6752 // Visit all HeapObject pointers in [start, end)
6753 for (Object** p = start; !done && (p < end); p++) {
6754 if ((*p)->IsHeapObject()) {
6755 TracePathFrom(p);
6756 done = ((what_to_find_ == FIND_FIRST) && found_target_);
6757 }
6758 }
6759}
6760
6761
6762void PathTracer::Reset() {
6763 found_target_ = false;
6764 object_stack_.Clear();
6765}
6766
6767
6768void PathTracer::TracePathFrom(Object** root) {
6769 ASSERT((search_target_ == kAnyGlobalObject) ||
6770 search_target_->IsHeapObject());
6771 found_target_in_trace_ = false;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00006772 Reset();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006773
6774 MarkVisitor mark_visitor(this);
6775 MarkRecursively(root, &mark_visitor);
6776
6777 UnmarkVisitor unmark_visitor(this);
6778 UnmarkRecursively(root, &unmark_visitor);
6779
6780 ProcessResults();
6781}
6782
6783
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006784static bool SafeIsNativeContext(HeapObject* obj) {
6785 return obj->map() == obj->GetHeap()->raw_unchecked_native_context_map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006786}
6787
6788
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006789void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006790 if (!(*p)->IsHeapObject()) return;
6791
6792 HeapObject* obj = HeapObject::cast(*p);
6793
6794 Object* map = obj->map();
6795
6796 if (!map->IsHeapObject()) return; // visited before
6797
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006798 if (found_target_in_trace_) return; // stop if target found
6799 object_stack_.Add(obj);
6800 if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) ||
6801 (obj == search_target_)) {
6802 found_target_in_trace_ = true;
6803 found_target_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006804 return;
6805 }
6806
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006807 bool is_native_context = SafeIsNativeContext(obj);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006808
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006809 // not visited yet
6810 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
6811
6812 Address map_addr = map_p->address();
6813
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006814 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_addr + kMarkTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006815
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006816 // Scan the object body.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006817 if (is_native_context && (visit_mode_ == VISIT_ONLY_STRONG)) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006818 // This is specialized to scan Context's properly.
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00006819 Object** start = reinterpret_cast<Object**>(obj->address() +
6820 Context::kHeaderSize);
6821 Object** end = reinterpret_cast<Object**>(obj->address() +
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006822 Context::kHeaderSize + Context::FIRST_WEAK_SLOT * kPointerSize);
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00006823 mark_visitor->VisitPointers(start, end);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006824 } else {
6825 obj->IterateBody(map_p->instance_type(),
6826 obj->SizeFromMap(map_p),
6827 mark_visitor);
6828 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006829
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006830 // Scan the map after the body because the body is a lot more interesting
6831 // when doing leak detection.
6832 MarkRecursively(&map, mark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006833
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006834 if (!found_target_in_trace_) // don't pop if found the target
6835 object_stack_.RemoveLast();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006836}
6837
6838
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006839void PathTracer::UnmarkRecursively(Object** p, UnmarkVisitor* unmark_visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006840 if (!(*p)->IsHeapObject()) return;
6841
6842 HeapObject* obj = HeapObject::cast(*p);
6843
6844 Object* map = obj->map();
6845
6846 if (map->IsHeapObject()) return; // unmarked already
6847
6848 Address map_addr = reinterpret_cast<Address>(map);
6849
6850 map_addr -= kMarkTag;
6851
6852 ASSERT_TAG_ALIGNED(map_addr);
6853
6854 HeapObject* map_p = HeapObject::FromAddress(map_addr);
6855
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006856 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006857
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006858 UnmarkRecursively(reinterpret_cast<Object**>(&map_p), unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006859
6860 obj->IterateBody(Map::cast(map_p)->instance_type(),
6861 obj->SizeFromMap(Map::cast(map_p)),
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006862 unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006863}
6864
6865
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006866void PathTracer::ProcessResults() {
6867 if (found_target_) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006868 PrintF("=====================================\n");
6869 PrintF("==== Path to object ====\n");
6870 PrintF("=====================================\n\n");
6871
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006872 ASSERT(!object_stack_.is_empty());
6873 for (int i = 0; i < object_stack_.length(); i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006874 if (i > 0) PrintF("\n |\n |\n V\n\n");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006875 Object* obj = object_stack_[i];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006876 obj->Print();
6877 }
6878 PrintF("=====================================\n");
6879 }
6880}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006881#endif // DEBUG || LIVE_OBJECT_LIST
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006882
6883
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006884#ifdef DEBUG
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00006885// Triggers a depth-first traversal of reachable objects from one
6886// given root object and finds a path to a specific heap object and
6887// prints it.
6888void Heap::TracePathToObjectFrom(Object* target, Object* root) {
6889 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
6890 tracer.VisitPointer(&root);
6891}
6892
6893
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006894// Triggers a depth-first traversal of reachable objects from roots
6895// and finds a path to a specific heap object and prints it.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00006896void Heap::TracePathToObject(Object* target) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006897 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
6898 IterateRoots(&tracer, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006899}
6900
6901
6902// Triggers a depth-first traversal of reachable objects from roots
6903// and finds a path to any global object and prints it. Useful for
6904// determining the source for leaks of global objects.
6905void Heap::TracePathToGlobal() {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006906 PathTracer tracer(PathTracer::kAnyGlobalObject,
6907 PathTracer::FIND_ALL,
6908 VISIT_ALL);
6909 IterateRoots(&tracer, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006910}
6911#endif
6912
6913
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006914static intptr_t CountTotalHolesSize() {
6915 intptr_t holes_size = 0;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006916 OldSpaces spaces;
6917 for (OldSpace* space = spaces.next();
6918 space != NULL;
6919 space = spaces.next()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006920 holes_size += space->Waste() + space->Available();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006921 }
6922 return holes_size;
6923}
6924
6925
rossberg@chromium.org994edf62012-02-06 10:12:55 +00006926GCTracer::GCTracer(Heap* heap,
6927 const char* gc_reason,
6928 const char* collector_reason)
kasper.lund7276f142008-07-30 08:49:36 +00006929 : start_time_(0.0),
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00006930 start_object_size_(0),
6931 start_memory_size_(0),
kasper.lund7276f142008-07-30 08:49:36 +00006932 gc_count_(0),
6933 full_gc_count_(0),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006934 allocated_since_last_gc_(0),
6935 spent_in_mutator_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006936 promoted_objects_size_(0),
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00006937 nodes_died_in_new_space_(0),
6938 nodes_copied_in_new_space_(0),
6939 nodes_promoted_(0),
rossberg@chromium.org994edf62012-02-06 10:12:55 +00006940 heap_(heap),
6941 gc_reason_(gc_reason),
6942 collector_reason_(collector_reason) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006943 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
kasper.lund7276f142008-07-30 08:49:36 +00006944 start_time_ = OS::TimeCurrentMillis();
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00006945 start_object_size_ = heap_->SizeOfObjects();
6946 start_memory_size_ = heap_->isolate()->memory_allocator()->Size();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006947
6948 for (int i = 0; i < Scope::kNumberOfScopes; i++) {
6949 scopes_[i] = 0;
6950 }
6951
6952 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize();
6953
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006954 allocated_since_last_gc_ =
6955 heap_->SizeOfObjects() - heap_->alive_after_last_gc_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006956
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006957 if (heap_->last_gc_end_timestamp_ > 0) {
6958 spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006959 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006960
6961 steps_count_ = heap_->incremental_marking()->steps_count();
6962 steps_took_ = heap_->incremental_marking()->steps_took();
6963 longest_step_ = heap_->incremental_marking()->longest_step();
6964 steps_count_since_last_gc_ =
6965 heap_->incremental_marking()->steps_count_since_last_gc();
6966 steps_took_since_last_gc_ =
6967 heap_->incremental_marking()->steps_took_since_last_gc();
kasper.lund7276f142008-07-30 08:49:36 +00006968}
6969
6970
6971GCTracer::~GCTracer() {
kasper.lund7276f142008-07-30 08:49:36 +00006972 // Printf ONE line iff flag is set.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006973 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
6974
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006975 bool first_gc = (heap_->last_gc_end_timestamp_ == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006976
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006977 heap_->alive_after_last_gc_ = heap_->SizeOfObjects();
6978 heap_->last_gc_end_timestamp_ = OS::TimeCurrentMillis();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006979
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006980 int time = static_cast<int>(heap_->last_gc_end_timestamp_ - start_time_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006981
6982 // Update cumulative GC statistics if required.
6983 if (FLAG_print_cumulative_gc_stat) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006984 heap_->total_gc_time_ms_ += time;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006985 heap_->max_gc_pause_ = Max(heap_->max_gc_pause_, time);
6986 heap_->max_alive_after_gc_ = Max(heap_->max_alive_after_gc_,
6987 heap_->alive_after_last_gc_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006988 if (!first_gc) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006989 heap_->min_in_mutator_ = Min(heap_->min_in_mutator_,
6990 static_cast<int>(spent_in_mutator_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006991 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006992 } else if (FLAG_trace_gc_verbose) {
6993 heap_->total_gc_time_ms_ += time;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006994 }
6995
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006996 if (collector_ == SCAVENGER && FLAG_trace_gc_ignore_scavenger) return;
6997
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006998 PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init());
rossberg@chromium.org994edf62012-02-06 10:12:55 +00006999
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007000 if (!FLAG_trace_gc_nvp) {
7001 int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]);
7002
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007003 double end_memory_size_mb =
7004 static_cast<double>(heap_->isolate()->memory_allocator()->Size()) / MB;
7005
7006 PrintF("%s %.1f (%.1f) -> %.1f (%.1f) MB, ",
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007007 CollectorString(),
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007008 static_cast<double>(start_object_size_) / MB,
7009 static_cast<double>(start_memory_size_) / MB,
7010 SizeOfHeapObjects(),
7011 end_memory_size_mb);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007012
7013 if (external_time > 0) PrintF("%d / ", external_time);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007014 PrintF("%d ms", time);
7015 if (steps_count_ > 0) {
7016 if (collector_ == SCAVENGER) {
7017 PrintF(" (+ %d ms in %d steps since last GC)",
7018 static_cast<int>(steps_took_since_last_gc_),
7019 steps_count_since_last_gc_);
7020 } else {
7021 PrintF(" (+ %d ms in %d steps since start of marking, "
7022 "biggest step %f ms)",
7023 static_cast<int>(steps_took_),
7024 steps_count_,
7025 longest_step_);
7026 }
7027 }
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007028
7029 if (gc_reason_ != NULL) {
7030 PrintF(" [%s]", gc_reason_);
7031 }
7032
7033 if (collector_reason_ != NULL) {
7034 PrintF(" [%s]", collector_reason_);
7035 }
7036
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007037 PrintF(".\n");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007038 } else {
7039 PrintF("pause=%d ", time);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007040 PrintF("mutator=%d ", static_cast<int>(spent_in_mutator_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007041 PrintF("gc=");
7042 switch (collector_) {
7043 case SCAVENGER:
7044 PrintF("s");
7045 break;
7046 case MARK_COMPACTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007047 PrintF("ms");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007048 break;
7049 default:
7050 UNREACHABLE();
7051 }
7052 PrintF(" ");
7053
7054 PrintF("external=%d ", static_cast<int>(scopes_[Scope::EXTERNAL]));
7055 PrintF("mark=%d ", static_cast<int>(scopes_[Scope::MC_MARK]));
7056 PrintF("sweep=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP]));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007057 PrintF("sweepns=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP_NEWSPACE]));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00007058 PrintF("evacuate=%d ", static_cast<int>(scopes_[Scope::MC_EVACUATE_PAGES]));
7059 PrintF("new_new=%d ",
7060 static_cast<int>(scopes_[Scope::MC_UPDATE_NEW_TO_NEW_POINTERS]));
7061 PrintF("root_new=%d ",
7062 static_cast<int>(scopes_[Scope::MC_UPDATE_ROOT_TO_NEW_POINTERS]));
7063 PrintF("old_new=%d ",
7064 static_cast<int>(scopes_[Scope::MC_UPDATE_OLD_TO_NEW_POINTERS]));
7065 PrintF("compaction_ptrs=%d ",
7066 static_cast<int>(scopes_[Scope::MC_UPDATE_POINTERS_TO_EVACUATED]));
7067 PrintF("intracompaction_ptrs=%d ", static_cast<int>(scopes_[
7068 Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED]));
7069 PrintF("misc_compaction=%d ",
7070 static_cast<int>(scopes_[Scope::MC_UPDATE_MISC_POINTERS]));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007071
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007072 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_object_size_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007073 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007074 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ",
7075 in_free_list_or_wasted_before_gc_);
7076 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007077
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007078 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_);
7079 PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_);
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00007080 PrintF("nodes_died_in_new=%d ", nodes_died_in_new_space_);
7081 PrintF("nodes_copied_in_new=%d ", nodes_copied_in_new_space_);
7082 PrintF("nodes_promoted=%d ", nodes_promoted_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007083
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007084 if (collector_ == SCAVENGER) {
7085 PrintF("stepscount=%d ", steps_count_since_last_gc_);
7086 PrintF("stepstook=%d ", static_cast<int>(steps_took_since_last_gc_));
7087 } else {
7088 PrintF("stepscount=%d ", steps_count_);
7089 PrintF("stepstook=%d ", static_cast<int>(steps_took_));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007090 PrintF("longeststep=%.f ", longest_step_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007091 }
7092
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007093 PrintF("\n");
7094 }
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007095
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007096 heap_->PrintShortHeapStatistics();
kasper.lund7276f142008-07-30 08:49:36 +00007097}
7098
7099
7100const char* GCTracer::CollectorString() {
7101 switch (collector_) {
7102 case SCAVENGER:
7103 return "Scavenge";
7104 case MARK_COMPACTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007105 return "Mark-sweep";
kasper.lund7276f142008-07-30 08:49:36 +00007106 }
7107 return "Unknown GC";
7108}
7109
7110
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007111int KeyedLookupCache::Hash(Map* map, String* name) {
7112 // Uses only lower 32 bits if pointers are larger.
7113 uintptr_t addr_hash =
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007114 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00007115 return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007116}
7117
7118
7119int KeyedLookupCache::Lookup(Map* map, String* name) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007120 int index = (Hash(map, name) & kHashMask);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007121 for (int i = 0; i < kEntriesPerBucket; i++) {
7122 Key& key = keys_[index + i];
7123 if ((key.map == map) && key.name->Equals(name)) {
7124 return field_offsets_[index + i];
7125 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007126 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007127 return kNotFound;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007128}
7129
7130
7131void KeyedLookupCache::Update(Map* map, String* name, int field_offset) {
7132 String* symbol;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007133 if (HEAP->LookupSymbolIfExists(name, &symbol)) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007134 int index = (Hash(map, symbol) & kHashMask);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007135 // After a GC there will be free slots, so we use them in order (this may
7136 // help to get the most frequently used one in position 0).
7137 for (int i = 0; i< kEntriesPerBucket; i++) {
7138 Key& key = keys_[index];
7139 Object* free_entry_indicator = NULL;
7140 if (key.map == free_entry_indicator) {
7141 key.map = map;
7142 key.name = symbol;
7143 field_offsets_[index + i] = field_offset;
7144 return;
7145 }
7146 }
7147 // No free entry found in this bucket, so we move them all down one and
7148 // put the new entry at position zero.
7149 for (int i = kEntriesPerBucket - 1; i > 0; i--) {
7150 Key& key = keys_[index + i];
7151 Key& key2 = keys_[index + i - 1];
7152 key = key2;
7153 field_offsets_[index + i] = field_offsets_[index + i - 1];
7154 }
7155
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007156 // Write the new first entry.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007157 Key& key = keys_[index];
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007158 key.map = map;
7159 key.name = symbol;
7160 field_offsets_[index] = field_offset;
7161 }
7162}
7163
7164
7165void KeyedLookupCache::Clear() {
7166 for (int index = 0; index < kLength; index++) keys_[index].map = NULL;
7167}
7168
7169
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007170void DescriptorLookupCache::Clear() {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007171 for (int index = 0; index < kLength; index++) keys_[index].source = NULL;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007172}
7173
7174
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007175#ifdef DEBUG
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007176void Heap::GarbageCollectionGreedyCheck() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007177 ASSERT(FLAG_gc_greedy);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007178 if (isolate_->bootstrapper()->IsActive()) return;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007179 if (disallow_allocation_failure()) return;
7180 CollectGarbage(NEW_SPACE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007181}
7182#endif
7183
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007184
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007185TranscendentalCache::SubCache::SubCache(Type t)
7186 : type_(t),
7187 isolate_(Isolate::Current()) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007188 uint32_t in0 = 0xffffffffu; // Bit-pattern for a NaN that isn't
7189 uint32_t in1 = 0xffffffffu; // generated by the FPU.
7190 for (int i = 0; i < kCacheSize; i++) {
7191 elements_[i].in[0] = in0;
7192 elements_[i].in[1] = in1;
7193 elements_[i].output = NULL;
7194 }
7195}
7196
7197
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007198void TranscendentalCache::Clear() {
7199 for (int i = 0; i < kNumberOfCaches; i++) {
7200 if (caches_[i] != NULL) {
7201 delete caches_[i];
7202 caches_[i] = NULL;
7203 }
7204 }
7205}
7206
7207
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007208void ExternalStringTable::CleanUp() {
7209 int last = 0;
7210 for (int i = 0; i < new_space_strings_.length(); ++i) {
danno@chromium.org72204d52012-10-31 10:02:10 +00007211 if (new_space_strings_[i] == heap_->the_hole_value()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007212 continue;
7213 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007214 if (heap_->InNewSpace(new_space_strings_[i])) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007215 new_space_strings_[last++] = new_space_strings_[i];
7216 } else {
7217 old_space_strings_.Add(new_space_strings_[i]);
7218 }
7219 }
7220 new_space_strings_.Rewind(last);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007221 new_space_strings_.Trim();
7222
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007223 last = 0;
7224 for (int i = 0; i < old_space_strings_.length(); ++i) {
danno@chromium.org72204d52012-10-31 10:02:10 +00007225 if (old_space_strings_[i] == heap_->the_hole_value()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007226 continue;
7227 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007228 ASSERT(!heap_->InNewSpace(old_space_strings_[i]));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007229 old_space_strings_[last++] = old_space_strings_[i];
7230 }
7231 old_space_strings_.Rewind(last);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007232 old_space_strings_.Trim();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007233#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007234 if (FLAG_verify_heap) {
7235 Verify();
7236 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007237#endif
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007238}
7239
7240
7241void ExternalStringTable::TearDown() {
7242 new_space_strings_.Free();
7243 old_space_strings_.Free();
7244}
7245
7246
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007247// Update all references.
7248void ErrorObjectList::UpdateReferences() {
7249 for (int i = 0; i < list_.length(); i++) {
7250 HeapObject* object = HeapObject::cast(list_[i]);
7251 MapWord first_word = object->map_word();
7252 if (first_word.IsForwardingAddress()) {
7253 list_[i] = first_word.ToForwardingAddress();
7254 }
7255 }
7256}
7257
7258
7259// Unforwarded objects in new space are dead and removed from the list.
7260void ErrorObjectList::UpdateReferencesInNewSpace(Heap* heap) {
7261 if (!nested_) {
7262 int write_index = 0;
7263 for (int i = 0; i < list_.length(); i++) {
7264 MapWord first_word = HeapObject::cast(list_[i])->map_word();
7265 if (first_word.IsForwardingAddress()) {
7266 list_[write_index++] = first_word.ToForwardingAddress();
7267 }
7268 }
7269 list_.Rewind(write_index);
7270 } else {
7271 // If a GC is triggered during DeferredFormatStackTrace, we do not move
7272 // objects in the list, just remove dead ones, as to not confuse the
7273 // loop in DeferredFormatStackTrace.
7274 for (int i = 0; i < list_.length(); i++) {
7275 MapWord first_word = HeapObject::cast(list_[i])->map_word();
7276 list_[i] = first_word.IsForwardingAddress()
7277 ? first_word.ToForwardingAddress()
7278 : heap->the_hole_value();
7279 }
7280 }
7281}
7282
7283
7284void ErrorObjectList::DeferredFormatStackTrace(Isolate* isolate) {
7285 // If formatting the stack trace causes a GC, this method will be
7286 // recursively called. In that case, skip the recursive call, since
7287 // the loop modifies the list while iterating over it.
7288 if (nested_ || isolate->has_pending_exception()) return;
7289 nested_ = true;
7290 HandleScope scope(isolate);
7291 Handle<String> stack_key = isolate->factory()->stack_symbol();
7292 int write_index = 0;
7293 int budget = kBudgetPerGC;
7294 for (int i = 0; i < list_.length(); i++) {
7295 Object* object = list_[i];
7296 JSFunction* getter_fun;
7297
7298 { AssertNoAllocation assert;
7299 // Skip possible holes in the list.
7300 if (object->IsTheHole()) continue;
7301 if (isolate->heap()->InNewSpace(object) || budget == 0) {
7302 list_[write_index++] = object;
7303 continue;
7304 }
7305
7306 // Check whether the stack property is backed by the original getter.
7307 LookupResult lookup(isolate);
7308 JSObject::cast(object)->LocalLookupRealNamedProperty(*stack_key, &lookup);
7309 if (!lookup.IsFound() || lookup.type() != CALLBACKS) continue;
7310 Object* callback = lookup.GetCallbackObject();
7311 if (!callback->IsAccessorPair()) continue;
7312 Object* getter_obj = AccessorPair::cast(callback)->getter();
7313 if (!getter_obj->IsJSFunction()) continue;
7314 getter_fun = JSFunction::cast(getter_obj);
7315 String* key = isolate->heap()->hidden_stack_trace_symbol();
7316 if (key != getter_fun->GetHiddenProperty(key)) continue;
7317 }
7318
7319 budget--;
7320 HandleScope scope(isolate);
7321 bool has_exception = false;
7322 Handle<Object> object_handle(object, isolate);
7323 Handle<Object> getter_handle(getter_fun, isolate);
7324 Execution::Call(getter_handle, object_handle, 0, NULL, &has_exception);
7325 if (has_exception) {
7326 // Hit an exception (most likely a stack overflow).
7327 // Wrap up this pass and retry after another GC.
7328 isolate->clear_pending_exception();
7329 // We use the handle since calling the getter might have caused a GC.
7330 list_[write_index++] = *object_handle;
7331 budget = 0;
7332 }
7333 }
7334 list_.Rewind(write_index);
7335 list_.Trim();
7336 nested_ = false;
7337}
7338
7339
7340void ErrorObjectList::RemoveUnmarked(Heap* heap) {
7341 for (int i = 0; i < list_.length(); i++) {
7342 HeapObject* object = HeapObject::cast(list_[i]);
7343 if (!Marking::MarkBitFrom(object).Get()) {
7344 list_[i] = heap->the_hole_value();
7345 }
7346 }
7347}
7348
7349
7350void ErrorObjectList::TearDown() {
7351 list_.Free();
7352}
7353
7354
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007355void Heap::QueueMemoryChunkForFree(MemoryChunk* chunk) {
7356 chunk->set_next_chunk(chunks_queued_for_free_);
7357 chunks_queued_for_free_ = chunk;
7358}
7359
7360
7361void Heap::FreeQueuedChunks() {
7362 if (chunks_queued_for_free_ == NULL) return;
7363 MemoryChunk* next;
7364 MemoryChunk* chunk;
7365 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
7366 next = chunk->next_chunk();
7367 chunk->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
7368
7369 if (chunk->owner()->identity() == LO_SPACE) {
7370 // StoreBuffer::Filter relies on MemoryChunk::FromAnyPointerAddress.
7371 // If FromAnyPointerAddress encounters a slot that belongs to a large
7372 // chunk queued for deletion it will fail to find the chunk because
7373 // it try to perform a search in the list of pages owned by of the large
7374 // object space and queued chunks were detached from that list.
7375 // To work around this we split large chunk into normal kPageSize aligned
danno@chromium.org2c456792011-11-11 12:00:53 +00007376 // pieces and initialize size, owner and flags field of every piece.
7377 // If FromAnyPointerAddress encounters a slot that belongs to one of
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007378 // these smaller pieces it will treat it as a slot on a normal Page.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007379 Address chunk_end = chunk->address() + chunk->size();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007380 MemoryChunk* inner = MemoryChunk::FromAddress(
7381 chunk->address() + Page::kPageSize);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007382 MemoryChunk* inner_last = MemoryChunk::FromAddress(chunk_end - 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007383 while (inner <= inner_last) {
7384 // Size of a large chunk is always a multiple of
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007385 // OS::AllocateAlignment() so there is always
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007386 // enough space for a fake MemoryChunk header.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007387 Address area_end = Min(inner->address() + Page::kPageSize, chunk_end);
7388 // Guard against overflow.
7389 if (area_end < inner->address()) area_end = chunk_end;
7390 inner->SetArea(inner->address(), area_end);
danno@chromium.org2c456792011-11-11 12:00:53 +00007391 inner->set_size(Page::kPageSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007392 inner->set_owner(lo_space());
7393 inner->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
7394 inner = MemoryChunk::FromAddress(
7395 inner->address() + Page::kPageSize);
7396 }
7397 }
7398 }
7399 isolate_->heap()->store_buffer()->Compact();
7400 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED);
7401 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
7402 next = chunk->next_chunk();
7403 isolate_->memory_allocator()->Free(chunk);
7404 }
7405 chunks_queued_for_free_ = NULL;
7406}
7407
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00007408
7409void Heap::RememberUnmappedPage(Address page, bool compacted) {
7410 uintptr_t p = reinterpret_cast<uintptr_t>(page);
7411 // Tag the page pointer to make it findable in the dump file.
7412 if (compacted) {
7413 p ^= 0xc1ead & (Page::kPageSize - 1); // Cleared.
7414 } else {
7415 p ^= 0x1d1ed & (Page::kPageSize - 1); // I died.
7416 }
7417 remembered_unmapped_pages_[remembered_unmapped_pages_index_] =
7418 reinterpret_cast<Address>(p);
7419 remembered_unmapped_pages_index_++;
7420 remembered_unmapped_pages_index_ %= kRememberedUnmappedPages;
7421}
7422
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00007423
7424void Heap::ClearObjectStats(bool clear_last_time_stats) {
7425 memset(object_counts_, 0, sizeof(object_counts_));
7426 memset(object_sizes_, 0, sizeof(object_sizes_));
7427 if (clear_last_time_stats) {
7428 memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_));
7429 memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_));
7430 }
7431}
7432
7433
7434static LazyMutex checkpoint_object_stats_mutex = LAZY_MUTEX_INITIALIZER;
7435
7436
7437void Heap::CheckpointObjectStats() {
7438 ScopedLock lock(checkpoint_object_stats_mutex.Pointer());
7439 Counters* counters = isolate()->counters();
7440#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7441 counters->count_of_##name()->Increment( \
7442 static_cast<int>(object_counts_[name])); \
7443 counters->count_of_##name()->Decrement( \
7444 static_cast<int>(object_counts_last_time_[name])); \
7445 counters->size_of_##name()->Increment( \
7446 static_cast<int>(object_sizes_[name])); \
7447 counters->size_of_##name()->Decrement( \
7448 static_cast<int>(object_sizes_last_time_[name]));
7449 INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7450#undef ADJUST_LAST_TIME_OBJECT_COUNT
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007451 int index;
7452#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7453 index = FIRST_CODE_KIND_SUB_TYPE + Code::name; \
7454 counters->count_of_CODE_TYPE_##name()->Increment( \
7455 static_cast<int>(object_counts_[index])); \
7456 counters->count_of_CODE_TYPE_##name()->Decrement( \
7457 static_cast<int>(object_counts_last_time_[index])); \
7458 counters->size_of_CODE_TYPE_##name()->Increment( \
7459 static_cast<int>(object_sizes_[index])); \
7460 counters->size_of_CODE_TYPE_##name()->Decrement( \
7461 static_cast<int>(object_sizes_last_time_[index]));
7462 CODE_KIND_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7463#undef ADJUST_LAST_TIME_OBJECT_COUNT
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007464#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7465 index = FIRST_FIXED_ARRAY_SUB_TYPE + name; \
7466 counters->count_of_FIXED_ARRAY_##name()->Increment( \
7467 static_cast<int>(object_counts_[index])); \
7468 counters->count_of_FIXED_ARRAY_##name()->Decrement( \
7469 static_cast<int>(object_counts_last_time_[index])); \
7470 counters->size_of_FIXED_ARRAY_##name()->Increment( \
7471 static_cast<int>(object_sizes_[index])); \
7472 counters->size_of_FIXED_ARRAY_##name()->Decrement( \
7473 static_cast<int>(object_sizes_last_time_[index]));
7474 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7475#undef ADJUST_LAST_TIME_OBJECT_COUNT
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007476
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00007477 memcpy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
7478 memcpy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
7479 ClearObjectStats();
7480}
7481
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007482} } // namespace v8::internal