blob: dac28f34b22636ca359851615926a9e111bf258d [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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000553}
554
555
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000556void Heap::CollectAllGarbage(int flags, const char* gc_reason) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000557 // Since we are ignoring the return value, the exact choice of space does
558 // not matter, so long as we do not specify NEW_SPACE, which would not
559 // cause a full GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000560 mark_compact_collector_.SetFlags(flags);
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000561 CollectGarbage(OLD_POINTER_SPACE, gc_reason);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000562 mark_compact_collector_.SetFlags(kNoGCFlags);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000563}
564
565
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000566void Heap::CollectAllAvailableGarbage(const char* gc_reason) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000567 // Since we are ignoring the return value, the exact choice of space does
568 // not matter, so long as we do not specify NEW_SPACE, which would not
569 // cause a full GC.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000570 // Major GC would invoke weak handle callbacks on weakly reachable
571 // handles, but won't collect weakly reachable objects until next
572 // major GC. Therefore if we collect aggressively and weak handle callback
573 // has been invoked, we rerun major GC to release objects which become
574 // garbage.
575 // Note: as weak callbacks can execute arbitrary code, we cannot
576 // hope that eventually there will be no weak callbacks invocations.
577 // Therefore stop recollecting after several attempts.
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000578 mark_compact_collector()->SetFlags(kMakeHeapIterableMask |
579 kReduceMemoryFootprintMask);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000580 isolate_->compilation_cache()->Clear();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000581 const int kMaxNumberOfAttempts = 7;
582 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000583 if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR, gc_reason, NULL)) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000584 break;
585 }
586 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000587 mark_compact_collector()->SetFlags(kNoGCFlags);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000588 new_space_.Shrink();
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000589 UncommitFromSpace();
590 Shrink();
danno@chromium.orgc612e022011-11-10 11:38:15 +0000591 incremental_marking()->UncommitMarkingDeque();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000592}
593
594
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000595bool Heap::CollectGarbage(AllocationSpace space,
596 GarbageCollector collector,
597 const char* gc_reason,
598 const char* collector_reason) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599 // The VM is in the GC state until exiting this function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 VMState state(isolate_, GC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000601
602#ifdef DEBUG
603 // Reset the allocation timeout to the GC interval, but make sure to
604 // allow at least a few allocations after a collection. The reason
605 // for this is that we have a lot of allocation sequences and we
606 // assume that a garbage collection will allow the subsequent
607 // allocation attempts to go through.
608 allocation_timeout_ = Max(6, FLAG_gc_interval);
609#endif
610
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000611 if (collector == SCAVENGER && !incremental_marking()->IsStopped()) {
612 if (FLAG_trace_incremental_marking) {
613 PrintF("[IncrementalMarking] Scavenge during marking.\n");
614 }
615 }
616
617 if (collector == MARK_COMPACTOR &&
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000618 !mark_compact_collector()->abort_incremental_marking() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000619 !incremental_marking()->IsStopped() &&
620 !incremental_marking()->should_hurry() &&
621 FLAG_incremental_marking_steps) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000622 // Make progress in incremental marking.
623 const intptr_t kStepSizeWhenDelayedByScavenge = 1 * MB;
624 incremental_marking()->Step(kStepSizeWhenDelayedByScavenge,
625 IncrementalMarking::NO_GC_VIA_STACK_GUARD);
626 if (!incremental_marking()->IsComplete()) {
627 if (FLAG_trace_incremental_marking) {
628 PrintF("[IncrementalMarking] Delaying MarkSweep.\n");
629 }
630 collector = SCAVENGER;
631 collector_reason = "incremental marking delaying mark-sweep";
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000632 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000633 }
634
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000635 bool next_gc_likely_to_collect_more = false;
636
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000637 { GCTracer tracer(this, gc_reason, collector_reason);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000638 GarbageCollectionPrologue();
kasper.lund7276f142008-07-30 08:49:36 +0000639 // The GC count was incremented in the prologue. Tell the tracer about
640 // it.
641 tracer.set_gc_count(gc_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000642
kasper.lund7276f142008-07-30 08:49:36 +0000643 // Tell the tracer which collector we've selected.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000644 tracer.set_collector(collector);
645
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000646 {
647 HistogramTimerScope histogram_timer_scope(
648 (collector == SCAVENGER) ? isolate_->counters()->gc_scavenger()
649 : isolate_->counters()->gc_compactor());
650 next_gc_likely_to_collect_more =
651 PerformGarbageCollection(collector, &tracer);
652 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000653
654 GarbageCollectionEpilogue();
655 }
656
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000657 // Start incremental marking for the next cycle. The heap snapshot
658 // generator needs incremental marking to stay off after it aborted.
659 if (!mark_compact_collector()->abort_incremental_marking() &&
660 incremental_marking()->IsStopped() &&
661 incremental_marking()->WorthActivating() &&
662 NextGCIsLikelyToBeFull()) {
663 incremental_marking()->Start();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000664 }
665
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000666 return next_gc_likely_to_collect_more;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000667}
668
669
kasper.lund7276f142008-07-30 08:49:36 +0000670void Heap::PerformScavenge() {
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000671 GCTracer tracer(this, NULL, NULL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000672 if (incremental_marking()->IsStopped()) {
673 PerformGarbageCollection(SCAVENGER, &tracer);
674 } else {
675 PerformGarbageCollection(MARK_COMPACTOR, &tracer);
676 }
kasper.lund7276f142008-07-30 08:49:36 +0000677}
678
679
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000680#ifdef VERIFY_HEAP
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000681// Helper class for verifying the symbol table.
682class SymbolTableVerifier : public ObjectVisitor {
683 public:
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000684 void VisitPointers(Object** start, Object** end) {
685 // Visit all HeapObject pointers in [start, end).
686 for (Object** p = start; p < end; p++) {
687 if ((*p)->IsHeapObject()) {
688 // Check that the symbol is actually a symbol.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000689 CHECK((*p)->IsTheHole() || (*p)->IsUndefined() || (*p)->IsSymbol());
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000690 }
691 }
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000692 }
693};
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000694
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000695
696static void VerifySymbolTable() {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000697 SymbolTableVerifier verifier;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000698 HEAP->symbol_table()->IterateElements(&verifier);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000699}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000700#endif // VERIFY_HEAP
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000701
702
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000703static bool AbortIncrementalMarkingAndCollectGarbage(
704 Heap* heap,
705 AllocationSpace space,
706 const char* gc_reason = NULL) {
707 heap->mark_compact_collector()->SetFlags(Heap::kAbortIncrementalMarkingMask);
708 bool result = heap->CollectGarbage(space, gc_reason);
709 heap->mark_compact_collector()->SetFlags(Heap::kNoGCFlags);
710 return result;
711}
712
713
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000714void Heap::ReserveSpace(
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000715 int *sizes,
716 Address *locations_out) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000717 bool gc_performed = true;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000718 int counter = 0;
719 static const int kThreshold = 20;
720 while (gc_performed && counter++ < kThreshold) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000721 gc_performed = false;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000722 ASSERT(NEW_SPACE == FIRST_PAGED_SPACE - 1);
723 for (int space = NEW_SPACE; space <= LAST_PAGED_SPACE; space++) {
724 if (sizes[space] != 0) {
725 MaybeObject* allocation;
726 if (space == NEW_SPACE) {
727 allocation = new_space()->AllocateRaw(sizes[space]);
728 } else {
729 allocation = paged_space(space)->AllocateRaw(sizes[space]);
730 }
731 FreeListNode* node;
732 if (!allocation->To<FreeListNode>(&node)) {
733 if (space == NEW_SPACE) {
734 Heap::CollectGarbage(NEW_SPACE,
735 "failed to reserve space in the new space");
736 } else {
737 AbortIncrementalMarkingAndCollectGarbage(
738 this,
739 static_cast<AllocationSpace>(space),
740 "failed to reserve space in paged space");
741 }
742 gc_performed = true;
743 break;
744 } else {
745 // Mark with a free list node, in case we have a GC before
746 // deserializing.
747 node->set_size(this, sizes[space]);
748 locations_out[space] = node->address();
749 }
750 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000751 }
752 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000753
754 if (gc_performed) {
755 // Failed to reserve the space after several attempts.
756 V8::FatalProcessOutOfMemory("Heap::ReserveSpace");
757 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000758}
759
760
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000761void Heap::EnsureFromSpaceIsCommitted() {
762 if (new_space_.CommitFromSpaceIfNeeded()) return;
763
764 // Committing memory to from space failed.
765 // Try shrinking and try again.
766 Shrink();
767 if (new_space_.CommitFromSpaceIfNeeded()) return;
768
769 // Committing memory to from space failed again.
770 // Memory is exhausted and we will die.
771 V8::FatalProcessOutOfMemory("Committing semi space failed.");
772}
773
774
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000775void Heap::ClearJSFunctionResultCaches() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000776 if (isolate_->bootstrapper()->IsActive()) return;
ager@chromium.orgac091b72010-05-05 07:34:42 +0000777
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000778 Object* context = native_contexts_list_;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000779 while (!context->IsUndefined()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000780 // Get the caches for this context. GC can happen when the context
781 // is not fully initialized, so the caches can be undefined.
782 Object* caches_or_undefined =
783 Context::cast(context)->get(Context::JSFUNCTION_RESULT_CACHES_INDEX);
784 if (!caches_or_undefined->IsUndefined()) {
785 FixedArray* caches = FixedArray::cast(caches_or_undefined);
786 // Clear the caches:
787 int length = caches->length();
788 for (int i = 0; i < length; i++) {
789 JSFunctionResultCache::cast(caches->get(i))->Clear();
790 }
ager@chromium.orgac091b72010-05-05 07:34:42 +0000791 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000792 // Get the next context:
793 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000794 }
ager@chromium.orgac091b72010-05-05 07:34:42 +0000795}
796
797
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000798
ricow@chromium.org65fae842010-08-25 15:26:24 +0000799void Heap::ClearNormalizedMapCaches() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000800 if (isolate_->bootstrapper()->IsActive() &&
801 !incremental_marking()->IsMarking()) {
802 return;
803 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000804
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000805 Object* context = native_contexts_list_;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000806 while (!context->IsUndefined()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000807 // GC can happen when the context is not fully initialized,
808 // so the cache can be undefined.
809 Object* cache =
810 Context::cast(context)->get(Context::NORMALIZED_MAP_CACHE_INDEX);
811 if (!cache->IsUndefined()) {
812 NormalizedMapCache::cast(cache)->Clear();
813 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000814 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
815 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000816}
817
818
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000819void Heap::UpdateSurvivalRateTrend(int start_new_space_size) {
820 double survival_rate =
821 (static_cast<double>(young_survivors_after_last_gc_) * 100) /
822 start_new_space_size;
823
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000824 if (survival_rate > kYoungSurvivalRateHighThreshold) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000825 high_survival_rate_period_length_++;
826 } else {
827 high_survival_rate_period_length_ = 0;
828 }
829
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000830 if (survival_rate < kYoungSurvivalRateLowThreshold) {
831 low_survival_rate_period_length_++;
832 } else {
833 low_survival_rate_period_length_ = 0;
834 }
835
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000836 double survival_rate_diff = survival_rate_ - survival_rate;
837
838 if (survival_rate_diff > kYoungSurvivalRateAllowedDeviation) {
839 set_survival_rate_trend(DECREASING);
840 } else if (survival_rate_diff < -kYoungSurvivalRateAllowedDeviation) {
841 set_survival_rate_trend(INCREASING);
842 } else {
843 set_survival_rate_trend(STABLE);
844 }
845
846 survival_rate_ = survival_rate;
847}
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000848
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000849bool Heap::PerformGarbageCollection(GarbageCollector collector,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000850 GCTracer* tracer) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000851 bool next_gc_likely_to_collect_more = false;
852
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000853 if (collector != SCAVENGER) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000854 PROFILE(isolate_, CodeMovingGCEvent());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000855 }
856
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000857#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000858 if (FLAG_verify_heap) {
859 VerifySymbolTable();
860 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000861#endif
862
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863 if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) {
864 ASSERT(!allocation_allowed_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000865 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000866 global_gc_prologue_callback_();
867 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000868
869 GCType gc_type =
870 collector == MARK_COMPACTOR ? kGCTypeMarkSweepCompact : kGCTypeScavenge;
871
872 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
873 if (gc_type & gc_prologue_callbacks_[i].gc_type) {
874 gc_prologue_callbacks_[i].callback(gc_type, kNoGCCallbackFlags);
875 }
876 }
877
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000878 EnsureFromSpaceIsCommitted();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000879
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000880 int start_new_space_size = Heap::new_space()->SizeAsInt();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000881
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000882 if (IsHighSurvivalRate()) {
883 // We speed up the incremental marker if it is running so that it
884 // does not fall behind the rate of promotion, which would cause a
885 // constantly growing old space.
886 incremental_marking()->NotifyOfHighPromotionRate();
887 }
888
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889 if (collector == MARK_COMPACTOR) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000890 // Perform mark-sweep with optional compaction.
kasper.lund7276f142008-07-30 08:49:36 +0000891 MarkCompact(tracer);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000892 sweep_generation_++;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000893 bool high_survival_rate_during_scavenges = IsHighSurvivalRate() &&
894 IsStableOrIncreasingSurvivalTrend();
895
896 UpdateSurvivalRateTrend(start_new_space_size);
897
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000898 size_of_old_gen_at_last_old_space_gc_ = PromotedSpaceSizeOfObjects();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000899
lrn@chromium.org303ada72010-10-27 09:33:13 +0000900 if (high_survival_rate_during_scavenges &&
901 IsStableOrIncreasingSurvivalTrend()) {
902 // Stable high survival rates of young objects both during partial and
903 // full collection indicate that mutator is either building or modifying
904 // a structure with a long lifetime.
905 // In this case we aggressively raise old generation memory limits to
906 // postpone subsequent mark-sweep collection and thus trade memory
907 // space for the mutation speed.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000908 old_gen_limit_factor_ = 2;
909 } else {
910 old_gen_limit_factor_ = 1;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000911 }
912
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000913 old_gen_promotion_limit_ =
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000914 OldGenPromotionLimit(size_of_old_gen_at_last_old_space_gc_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000915 old_gen_allocation_limit_ =
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000916 OldGenAllocationLimit(size_of_old_gen_at_last_old_space_gc_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000917
lrn@chromium.org303ada72010-10-27 09:33:13 +0000918 old_gen_exhausted_ = false;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000919 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000920 tracer_ = tracer;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000921 Scavenge();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000922 tracer_ = NULL;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000923
924 UpdateSurvivalRateTrend(start_new_space_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000925 }
ager@chromium.org439e85a2009-08-26 13:15:29 +0000926
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000927 if (!new_space_high_promotion_mode_active_ &&
928 new_space_.Capacity() == new_space_.MaximumCapacity() &&
929 IsStableOrIncreasingSurvivalTrend() &&
930 IsHighSurvivalRate()) {
931 // Stable high survival rates even though young generation is at
932 // maximum capacity indicates that most objects will be promoted.
933 // To decrease scavenger pauses and final mark-sweep pauses, we
934 // have to limit maximal capacity of the young generation.
935 new_space_high_promotion_mode_active_ = true;
936 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000937 PrintPID("Limited new space size due to high promotion rate: %d MB\n",
938 new_space_.InitialCapacity() / MB);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000939 }
940 } else if (new_space_high_promotion_mode_active_ &&
941 IsStableOrDecreasingSurvivalTrend() &&
942 IsLowSurvivalRate()) {
943 // Decreasing low survival rates might indicate that the above high
944 // promotion mode is over and we should allow the young generation
945 // to grow again.
946 new_space_high_promotion_mode_active_ = false;
947 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000948 PrintPID("Unlimited new space size due to low promotion rate: %d MB\n",
949 new_space_.MaximumCapacity() / MB);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000950 }
951 }
952
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000953 if (new_space_high_promotion_mode_active_ &&
954 new_space_.Capacity() > new_space_.InitialCapacity()) {
955 new_space_.Shrink();
956 }
957
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000958 isolate_->counters()->objs_since_last_young()->Set(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000959
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000960 // Callbacks that fire after this point might trigger nested GCs and
961 // restart incremental marking, the assertion can't be moved down.
962 ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped());
963
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000964 gc_post_processing_depth_++;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000965 { DisableAssertNoAllocation allow_allocation;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000966 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000967 next_gc_likely_to_collect_more =
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000968 isolate_->global_handles()->PostGarbageCollectionProcessing(collector);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000969 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000970 gc_post_processing_depth_--;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000971
ager@chromium.org3811b432009-10-28 14:53:37 +0000972 // Update relocatables.
973 Relocatable::PostGarbageCollectionProcessing();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000974
kasper.lund7276f142008-07-30 08:49:36 +0000975 if (collector == MARK_COMPACTOR) {
976 // Register the amount of external allocated memory.
977 amount_of_external_allocated_memory_at_last_global_gc_ =
978 amount_of_external_allocated_memory_;
979 }
980
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000981 GCCallbackFlags callback_flags = kNoGCCallbackFlags;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000982 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
983 if (gc_type & gc_epilogue_callbacks_[i].gc_type) {
984 gc_epilogue_callbacks_[i].callback(gc_type, callback_flags);
985 }
986 }
987
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) {
989 ASSERT(!allocation_allowed_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000990 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991 global_gc_epilogue_callback_();
992 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000993
994#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000995 if (FLAG_verify_heap) {
996 VerifySymbolTable();
997 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000998#endif
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000999
1000 return next_gc_likely_to_collect_more;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001001}
1002
1003
kasper.lund7276f142008-07-30 08:49:36 +00001004void Heap::MarkCompact(GCTracer* tracer) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001005 gc_state_ = MARK_COMPACT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001006 LOG(isolate_, ResourceEvent("markcompact", "begin"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001008 mark_compact_collector_.Prepare(tracer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001010 ms_count_++;
1011 tracer->set_full_gc_count(ms_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001013 MarkCompactPrologue();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001014
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001015 mark_compact_collector_.CollectGarbage();
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001016
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001017 LOG(isolate_, ResourceEvent("markcompact", "end"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018
1019 gc_state_ = NOT_IN_GC;
1020
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001021 isolate_->counters()->objs_since_last_full()->Set(0);
kasperl@chromium.org8b2bb262010-03-01 09:46:28 +00001022
1023 contexts_disposed_ = 0;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001024
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001025 flush_monomorphic_ics_ = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001026}
1027
1028
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001029void Heap::MarkCompactPrologue() {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001030 // At any old GC clear the keyed lookup cache to enable collection of unused
1031 // maps.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001032 isolate_->keyed_lookup_cache()->Clear();
1033 isolate_->context_slot_cache()->Clear();
1034 isolate_->descriptor_lookup_cache()->Clear();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001035 RegExpResultsCache::Clear(string_split_cache());
1036 RegExpResultsCache::Clear(regexp_multiple_cache());
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001037
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001038 isolate_->compilation_cache()->MarkCompactPrologue();
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001039
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001040 CompletelyClearInstanceofCache();
1041
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001042 FlushNumberStringCache();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001043 if (FLAG_cleanup_code_caches_at_gc) {
1044 polymorphic_code_cache()->set_cache(undefined_value());
1045 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001046
1047 ClearNormalizedMapCaches();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048}
1049
1050
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051Object* Heap::FindCodeObject(Address a) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001052 return isolate()->inner_pointer_to_code_cache()->
1053 GcSafeFindCodeForInnerPointer(a);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001054}
1055
1056
1057// Helper class for copying HeapObjects
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001058class ScavengeVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001059 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 explicit ScavengeVisitor(Heap* heap) : heap_(heap) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001061
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001062 void VisitPointer(Object** p) { ScavengePointer(p); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001063
1064 void VisitPointers(Object** start, Object** end) {
1065 // Copy all HeapObject pointers in [start, end)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001066 for (Object** p = start; p < end; p++) ScavengePointer(p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001067 }
1068
1069 private:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001070 void ScavengePointer(Object** p) {
1071 Object* object = *p;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001072 if (!heap_->InNewSpace(object)) return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001073 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
1074 reinterpret_cast<HeapObject*>(object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001076
1077 Heap* heap_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078};
1079
1080
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001081#ifdef VERIFY_HEAP
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001082// Visitor class to verify pointers in code or data space do not point into
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001083// new space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001084class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085 public:
1086 void VisitPointers(Object** start, Object**end) {
1087 for (Object** current = start; current < end; current++) {
1088 if ((*current)->IsHeapObject()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001089 CHECK(!HEAP->InNewSpace(HeapObject::cast(*current)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001090 }
1091 }
1092 }
1093};
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001094
1095
1096static void VerifyNonPointerSpacePointers() {
1097 // Verify that there are no pointers to new space in spaces where we
1098 // do not expect them.
1099 VerifyNonPointerSpacePointersVisitor v;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001100 HeapObjectIterator code_it(HEAP->code_space());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001101 for (HeapObject* object = code_it.Next();
1102 object != NULL; object = code_it.Next())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001103 object->Iterate(&v);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001104
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001105 // The old data space was normally swept conservatively so that the iterator
1106 // doesn't work, so we normally skip the next bit.
1107 if (!HEAP->old_data_space()->was_swept_conservatively()) {
1108 HeapObjectIterator data_it(HEAP->old_data_space());
1109 for (HeapObject* object = data_it.Next();
1110 object != NULL; object = data_it.Next())
1111 object->Iterate(&v);
1112 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001113}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001114#endif // VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001115
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001116
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001117void Heap::CheckNewSpaceExpansionCriteria() {
1118 if (new_space_.Capacity() < new_space_.MaximumCapacity() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001119 survived_since_last_expansion_ > new_space_.Capacity() &&
1120 !new_space_high_promotion_mode_active_) {
1121 // Grow the size of new space if there is room to grow, enough data
1122 // has survived scavenge since the last expansion and we are not in
1123 // high promotion mode.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001124 new_space_.Grow();
1125 survived_since_last_expansion_ = 0;
1126 }
1127}
1128
1129
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001130static bool IsUnscavengedHeapObject(Heap* heap, Object** p) {
1131 return heap->InNewSpace(*p) &&
1132 !HeapObject::cast(*p)->map_word().IsForwardingAddress();
1133}
1134
1135
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001136void Heap::ScavengeStoreBufferCallback(
1137 Heap* heap,
1138 MemoryChunk* page,
1139 StoreBufferEvent event) {
1140 heap->store_buffer_rebuilder_.Callback(page, event);
1141}
1142
1143
1144void StoreBufferRebuilder::Callback(MemoryChunk* page, StoreBufferEvent event) {
1145 if (event == kStoreBufferStartScanningPagesEvent) {
1146 start_of_current_page_ = NULL;
1147 current_page_ = NULL;
1148 } else if (event == kStoreBufferScanningPageEvent) {
1149 if (current_page_ != NULL) {
1150 // If this page already overflowed the store buffer during this iteration.
1151 if (current_page_->scan_on_scavenge()) {
1152 // Then we should wipe out the entries that have been added for it.
1153 store_buffer_->SetTop(start_of_current_page_);
1154 } else if (store_buffer_->Top() - start_of_current_page_ >=
1155 (store_buffer_->Limit() - store_buffer_->Top()) >> 2) {
1156 // Did we find too many pointers in the previous page? The heuristic is
1157 // that no page can take more then 1/5 the remaining slots in the store
1158 // buffer.
1159 current_page_->set_scan_on_scavenge(true);
1160 store_buffer_->SetTop(start_of_current_page_);
1161 } else {
1162 // In this case the page we scanned took a reasonable number of slots in
1163 // the store buffer. It has now been rehabilitated and is no longer
1164 // marked scan_on_scavenge.
1165 ASSERT(!current_page_->scan_on_scavenge());
1166 }
1167 }
1168 start_of_current_page_ = store_buffer_->Top();
1169 current_page_ = page;
1170 } else if (event == kStoreBufferFullEvent) {
1171 // The current page overflowed the store buffer again. Wipe out its entries
1172 // in the store buffer and mark it scan-on-scavenge again. This may happen
1173 // several times while scanning.
1174 if (current_page_ == NULL) {
1175 // Store Buffer overflowed while scanning promoted objects. These are not
1176 // in any particular page, though they are likely to be clustered by the
1177 // allocation routines.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001178 store_buffer_->EnsureSpace(StoreBuffer::kStoreBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001179 } else {
1180 // Store Buffer overflowed while scanning a particular old space page for
1181 // pointers to new space.
1182 ASSERT(current_page_ == page);
1183 ASSERT(page != NULL);
1184 current_page_->set_scan_on_scavenge(true);
1185 ASSERT(start_of_current_page_ != store_buffer_->Top());
1186 store_buffer_->SetTop(start_of_current_page_);
1187 }
1188 } else {
1189 UNREACHABLE();
1190 }
1191}
1192
1193
danno@chromium.orgc612e022011-11-10 11:38:15 +00001194void PromotionQueue::Initialize() {
1195 // Assumes that a NewSpacePage exactly fits a number of promotion queue
1196 // entries (where each is a pair of intptr_t). This allows us to simplify
1197 // the test fpr when to switch pages.
1198 ASSERT((Page::kPageSize - MemoryChunk::kBodyOffset) % (2 * kPointerSize)
1199 == 0);
1200 limit_ = reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceStart());
1201 front_ = rear_ =
1202 reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceEnd());
1203 emergency_stack_ = NULL;
1204 guard_ = false;
1205}
1206
1207
1208void PromotionQueue::RelocateQueueHead() {
1209 ASSERT(emergency_stack_ == NULL);
1210
1211 Page* p = Page::FromAllocationTop(reinterpret_cast<Address>(rear_));
1212 intptr_t* head_start = rear_;
1213 intptr_t* head_end =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001214 Min(front_, reinterpret_cast<intptr_t*>(p->area_end()));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001215
1216 int entries_count =
1217 static_cast<int>(head_end - head_start) / kEntrySizeInWords;
1218
1219 emergency_stack_ = new List<Entry>(2 * entries_count);
1220
1221 while (head_start != head_end) {
1222 int size = static_cast<int>(*(head_start++));
1223 HeapObject* obj = reinterpret_cast<HeapObject*>(*(head_start++));
1224 emergency_stack_->Add(Entry(obj, size));
1225 }
1226 rear_ = head_end;
1227}
1228
1229
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001230class ScavengeWeakObjectRetainer : public WeakObjectRetainer {
1231 public:
1232 explicit ScavengeWeakObjectRetainer(Heap* heap) : heap_(heap) { }
1233
1234 virtual Object* RetainAs(Object* object) {
1235 if (!heap_->InFromSpace(object)) {
1236 return object;
1237 }
1238
1239 MapWord map_word = HeapObject::cast(object)->map_word();
1240 if (map_word.IsForwardingAddress()) {
1241 return map_word.ToForwardingAddress();
1242 }
1243 return NULL;
1244 }
1245
1246 private:
1247 Heap* heap_;
1248};
1249
1250
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001251void Heap::Scavenge() {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001252 RelocationLock relocation_lock(this);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001253
1254#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001255 if (FLAG_verify_heap) VerifyNonPointerSpacePointers();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256#endif
1257
1258 gc_state_ = SCAVENGE;
1259
1260 // Implements Cheney's copying algorithm
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001261 LOG(isolate_, ResourceEvent("scavenge", "begin"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001262
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001263 // Clear descriptor cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001264 isolate_->descriptor_lookup_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001265
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001266 // Used for updating survived_since_last_expansion_ at function end.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001267 intptr_t survived_watermark = PromotedSpaceSizeOfObjects();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001268
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001269 CheckNewSpaceExpansionCriteria();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001271 SelectScavengingVisitorsTable();
1272
1273 incremental_marking()->PrepareForScavenge();
1274
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001275 AdvanceSweepers(static_cast<int>(new_space_.Size()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001276
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 // Flip the semispaces. After flipping, to space is empty, from space has
1278 // live objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001279 new_space_.Flip();
1280 new_space_.ResetAllocationInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001282 // We need to sweep newly copied objects which can be either in the
1283 // to space or promoted to the old generation. For to-space
1284 // objects, we treat the bottom of the to space as a queue. Newly
1285 // copied and unswept objects lie between a 'front' mark and the
1286 // allocation pointer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287 //
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001288 // Promoted objects can go into various old-generation spaces, and
1289 // can be allocated internally in the spaces (from the free list).
1290 // We treat the top of the to space as a queue of addresses of
1291 // promoted objects. The addresses of newly promoted and unswept
1292 // objects lie between a 'front' mark and a 'rear' mark that is
1293 // updated as a side effect of promoting an object.
1294 //
1295 // There is guaranteed to be enough room at the top of the to space
1296 // for the addresses of promoted objects: every object promoted
1297 // frees up its size in bytes from the top of the new space, and
1298 // objects are at least one pointer in size.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001299 Address new_space_front = new_space_.ToSpaceStart();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001300 promotion_queue_.Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001301
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001302#ifdef DEBUG
1303 store_buffer()->Clean();
1304#endif
1305
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001306 ScavengeVisitor scavenge_visitor(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307 // Copy roots.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001308 IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001309
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001310 // Copy objects reachable from the old generation.
1311 {
1312 StoreBufferRebuildScope scope(this,
1313 store_buffer(),
1314 &ScavengeStoreBufferCallback);
1315 store_buffer()->IteratePointersToNewSpace(&ScavengeObject);
1316 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001317
1318 // Copy objects reachable from cells by scavenging cell values directly.
1319 HeapObjectIterator cell_iterator(cell_space_);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001320 for (HeapObject* heap_object = cell_iterator.Next();
1321 heap_object != NULL;
1322 heap_object = cell_iterator.Next()) {
1323 if (heap_object->IsJSGlobalPropertyCell()) {
1324 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(heap_object);
1325 Address value_address = cell->ValueAddress();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001326 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address));
1327 }
1328 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001330 // Copy objects reachable from the code flushing candidates list.
1331 MarkCompactCollector* collector = mark_compact_collector();
1332 if (collector->is_code_flushing_enabled()) {
1333 collector->code_flusher()->IteratePointersToFromSpace(&scavenge_visitor);
1334 }
1335
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001336 // Scavenge object reachable from the native contexts list directly.
1337 scavenge_visitor.VisitPointer(BitCast<Object**>(&native_contexts_list_));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001338
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001339 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001340
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001341 while (isolate()->global_handles()->IterateObjectGroups(
1342 &scavenge_visitor, &IsUnscavengedHeapObject)) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001343 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
1344 }
1345 isolate()->global_handles()->RemoveObjectGroups();
1346
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001347 isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles(
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001348 &IsUnscavengedHeapObject);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001349 isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots(
1350 &scavenge_visitor);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001351 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
1352
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001353 UpdateNewSpaceReferencesInExternalStringTable(
1354 &UpdateNewSpaceReferenceInExternalStringTableEntry);
1355
danno@chromium.orgc612e022011-11-10 11:38:15 +00001356 promotion_queue_.Destroy();
1357
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001358 LiveObjectList::UpdateReferencesForScavengeGC();
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001359 if (!FLAG_watch_ic_patching) {
1360 isolate()->runtime_profiler()->UpdateSamplesAfterScavenge();
1361 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001362 incremental_marking()->UpdateMarkingDequeAfterScavenge();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001363
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001364 ScavengeWeakObjectRetainer weak_object_retainer(this);
1365 ProcessWeakReferences(&weak_object_retainer);
1366
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001367 ASSERT(new_space_front == new_space_.top());
1368
1369 // Set age mark.
1370 new_space_.set_age_mark(new_space_.top());
1371
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001372 new_space_.LowerInlineAllocationLimit(
1373 new_space_.inline_allocation_limit_step());
1374
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001375 // Update how much has survived scavenge.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001376 IncrementYoungSurvivorsCounter(static_cast<int>(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001377 (PromotedSpaceSizeOfObjects() - survived_watermark) + new_space_.Size()));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001378
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001379 LOG(isolate_, ResourceEvent("scavenge", "end"));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001380
1381 gc_state_ = NOT_IN_GC;
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001382
1383 scavenges_since_last_idle_round_++;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001384}
1385
1386
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001387String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
1388 Object** p) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001389 MapWord first_word = HeapObject::cast(*p)->map_word();
1390
1391 if (!first_word.IsForwardingAddress()) {
1392 // Unreachable external string can be finalized.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001393 heap->FinalizeExternalString(String::cast(*p));
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001394 return NULL;
1395 }
1396
1397 // String is still reachable.
1398 return String::cast(first_word.ToForwardingAddress());
1399}
1400
1401
1402void Heap::UpdateNewSpaceReferencesInExternalStringTable(
1403 ExternalStringTableUpdaterCallback updater_func) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001404#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001405 if (FLAG_verify_heap) {
1406 external_string_table_.Verify();
1407 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001408#endif
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001409
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001410 if (external_string_table_.new_space_strings_.is_empty()) return;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001411
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001412 Object** start = &external_string_table_.new_space_strings_[0];
1413 Object** end = start + external_string_table_.new_space_strings_.length();
1414 Object** last = start;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001415
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001416 for (Object** p = start; p < end; ++p) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001417 ASSERT(InFromSpace(*p));
1418 String* target = updater_func(this, p);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001419
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001420 if (target == NULL) continue;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001421
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001422 ASSERT(target->IsExternalString());
1423
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001424 if (InNewSpace(target)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001425 // String is still in new space. Update the table entry.
1426 *last = target;
1427 ++last;
1428 } else {
1429 // String got promoted. Move it to the old string list.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001430 external_string_table_.AddOldString(target);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001431 }
1432 }
1433
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001434 ASSERT(last <= end);
1435 external_string_table_.ShrinkNewStrings(static_cast<int>(last - start));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001436}
1437
1438
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001439void Heap::UpdateReferencesInExternalStringTable(
1440 ExternalStringTableUpdaterCallback updater_func) {
1441
1442 // Update old space string references.
1443 if (external_string_table_.old_space_strings_.length() > 0) {
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001444 Object** start = &external_string_table_.old_space_strings_[0];
1445 Object** end = start + external_string_table_.old_space_strings_.length();
1446 for (Object** p = start; p < end; ++p) *p = updater_func(this, p);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001447 }
1448
1449 UpdateNewSpaceReferencesInExternalStringTable(updater_func);
1450}
1451
1452
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001453static Object* ProcessFunctionWeakReferences(Heap* heap,
1454 Object* function,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001455 WeakObjectRetainer* retainer,
1456 bool record_slots) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001457 Object* undefined = heap->undefined_value();
1458 Object* head = undefined;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001459 JSFunction* tail = NULL;
1460 Object* candidate = function;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001461 while (candidate != undefined) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001462 // Check whether to keep the candidate in the list.
1463 JSFunction* candidate_function = reinterpret_cast<JSFunction*>(candidate);
1464 Object* retain = retainer->RetainAs(candidate);
1465 if (retain != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001466 if (head == undefined) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001467 // First element in the list.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001468 head = retain;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001469 } else {
1470 // Subsequent elements in the list.
1471 ASSERT(tail != NULL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001472 tail->set_next_function_link(retain);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001473 if (record_slots) {
1474 Object** next_function =
1475 HeapObject::RawField(tail, JSFunction::kNextFunctionLinkOffset);
1476 heap->mark_compact_collector()->RecordSlot(
1477 next_function, next_function, retain);
1478 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001479 }
1480 // Retained function is new tail.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001481 candidate_function = reinterpret_cast<JSFunction*>(retain);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001482 tail = candidate_function;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001483
1484 ASSERT(retain->IsUndefined() || retain->IsJSFunction());
1485
1486 if (retain == undefined) break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001487 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001488
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001489 // Move to next element in the list.
1490 candidate = candidate_function->next_function_link();
1491 }
1492
1493 // Terminate the list if there is one or more elements.
1494 if (tail != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001495 tail->set_next_function_link(undefined);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001496 }
1497
1498 return head;
1499}
1500
1501
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001502void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001503 Object* undefined = undefined_value();
1504 Object* head = undefined;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001505 Context* tail = NULL;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001506 Object* candidate = native_contexts_list_;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001507
1508 // We don't record weak slots during marking or scavenges.
1509 // Instead we do it once when we complete mark-compact cycle.
1510 // Note that write barrier has no effect if we are already in the middle of
1511 // compacting mark-sweep cycle and we have to record slots manually.
1512 bool record_slots =
1513 gc_state() == MARK_COMPACT &&
1514 mark_compact_collector()->is_compacting();
1515
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001516 while (candidate != undefined) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001517 // Check whether to keep the candidate in the list.
1518 Context* candidate_context = reinterpret_cast<Context*>(candidate);
1519 Object* retain = retainer->RetainAs(candidate);
1520 if (retain != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001521 if (head == undefined) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001522 // First element in the list.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001523 head = retain;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001524 } else {
1525 // Subsequent elements in the list.
1526 ASSERT(tail != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001527 tail->set_unchecked(this,
1528 Context::NEXT_CONTEXT_LINK,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001529 retain,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001530 UPDATE_WRITE_BARRIER);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001531
1532 if (record_slots) {
1533 Object** next_context =
1534 HeapObject::RawField(
1535 tail, FixedArray::SizeFor(Context::NEXT_CONTEXT_LINK));
1536 mark_compact_collector()->RecordSlot(
1537 next_context, next_context, retain);
1538 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001539 }
1540 // Retained context is new tail.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001541 candidate_context = reinterpret_cast<Context*>(retain);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001542 tail = candidate_context;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001543
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001544 if (retain == undefined) break;
1545
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001546 // Process the weak list of optimized functions for the context.
1547 Object* function_list_head =
1548 ProcessFunctionWeakReferences(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001549 this,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001550 candidate_context->get(Context::OPTIMIZED_FUNCTIONS_LIST),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001551 retainer,
1552 record_slots);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001553 candidate_context->set_unchecked(this,
1554 Context::OPTIMIZED_FUNCTIONS_LIST,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001555 function_list_head,
1556 UPDATE_WRITE_BARRIER);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001557 if (record_slots) {
1558 Object** optimized_functions =
1559 HeapObject::RawField(
1560 tail, FixedArray::SizeFor(Context::OPTIMIZED_FUNCTIONS_LIST));
1561 mark_compact_collector()->RecordSlot(
1562 optimized_functions, optimized_functions, function_list_head);
1563 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001564 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001565
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001566 // Move to next element in the list.
1567 candidate = candidate_context->get(Context::NEXT_CONTEXT_LINK);
1568 }
1569
1570 // Terminate the list if there is one or more elements.
1571 if (tail != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001572 tail->set_unchecked(this,
1573 Context::NEXT_CONTEXT_LINK,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001574 Heap::undefined_value(),
1575 UPDATE_WRITE_BARRIER);
1576 }
1577
1578 // Update the head of the list of contexts.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001579 native_contexts_list_ = head;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001580}
1581
1582
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001583void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) {
1584 AssertNoAllocation no_allocation;
1585
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001586 // Both the external string table and the symbol table may contain
1587 // external strings, but neither lists them exhaustively, nor is the
1588 // intersection set empty. Therefore we iterate over the external string
1589 // table first, ignoring symbols, and then over the symbol table.
1590
1591 class ExternalStringTableVisitorAdapter : public ObjectVisitor {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001592 public:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001593 explicit ExternalStringTableVisitorAdapter(
1594 v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001595 virtual void VisitPointers(Object** start, Object** end) {
1596 for (Object** p = start; p < end; p++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001597 // Visit non-symbol external strings,
1598 // since symbols are listed in the symbol table.
1599 if (!(*p)->IsSymbol()) {
1600 ASSERT((*p)->IsExternalString());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001601 visitor_->VisitExternalString(Utils::ToLocal(
1602 Handle<String>(String::cast(*p))));
1603 }
1604 }
1605 }
1606 private:
1607 v8::ExternalResourceVisitor* visitor_;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001608 } external_string_table_visitor(visitor);
1609
1610 external_string_table_.Iterate(&external_string_table_visitor);
1611
1612 class SymbolTableVisitorAdapter : public ObjectVisitor {
1613 public:
1614 explicit SymbolTableVisitorAdapter(
1615 v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
1616 virtual void VisitPointers(Object** start, Object** end) {
1617 for (Object** p = start; p < end; p++) {
1618 if ((*p)->IsExternalString()) {
1619 ASSERT((*p)->IsSymbol());
1620 visitor_->VisitExternalString(Utils::ToLocal(
1621 Handle<String>(String::cast(*p))));
1622 }
1623 }
1624 }
1625 private:
1626 v8::ExternalResourceVisitor* visitor_;
1627 } symbol_table_visitor(visitor);
1628
1629 symbol_table()->IterateElements(&symbol_table_visitor);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001630}
1631
1632
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001633class NewSpaceScavenger : public StaticNewSpaceVisitor<NewSpaceScavenger> {
1634 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001635 static inline void VisitPointer(Heap* heap, Object** p) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001636 Object* object = *p;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001637 if (!heap->InNewSpace(object)) return;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001638 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
1639 reinterpret_cast<HeapObject*>(object));
1640 }
1641};
1642
1643
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001644Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
1645 Address new_space_front) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001646 do {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001647 SemiSpace::AssertValidRange(new_space_front, new_space_.top());
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001648 // The addresses new_space_front and new_space_.top() define a
1649 // queue of unprocessed copied objects. Process them until the
1650 // queue is empty.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001651 while (new_space_front != new_space_.top()) {
1652 if (!NewSpacePage::IsAtEnd(new_space_front)) {
1653 HeapObject* object = HeapObject::FromAddress(new_space_front);
1654 new_space_front +=
1655 NewSpaceScavenger::IterateBody(object->map(), object);
1656 } else {
1657 new_space_front =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001658 NewSpacePage::FromLimit(new_space_front)->next_page()->area_start();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001659 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001660 }
1661
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001662 // Promote and process all the to-be-promoted objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001663 {
1664 StoreBufferRebuildScope scope(this,
1665 store_buffer(),
1666 &ScavengeStoreBufferCallback);
1667 while (!promotion_queue()->is_empty()) {
1668 HeapObject* target;
1669 int size;
1670 promotion_queue()->remove(&target, &size);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001671
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001672 // Promoted object might be already partially visited
1673 // during old space pointer iteration. Thus we search specificly
1674 // for pointers to from semispace instead of looking for pointers
1675 // to new space.
1676 ASSERT(!target->IsMap());
1677 IterateAndMarkPointersToFromSpace(target->address(),
1678 target->address() + size,
1679 &ScavengeObject);
1680 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001681 }
1682
1683 // Take another spin if there are now unswept objects in new space
1684 // (there are currently no more unswept promoted objects).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001685 } while (new_space_front != new_space_.top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001686
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001687 return new_space_front;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001688}
1689
1690
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001691STATIC_ASSERT((FixedDoubleArray::kHeaderSize & kDoubleAlignmentMask) == 0);
1692
1693
1694INLINE(static HeapObject* EnsureDoubleAligned(Heap* heap,
1695 HeapObject* object,
1696 int size));
1697
1698static HeapObject* EnsureDoubleAligned(Heap* heap,
1699 HeapObject* object,
1700 int size) {
1701 if ((OffsetFrom(object->address()) & kDoubleAlignmentMask) != 0) {
1702 heap->CreateFillerObjectAt(object->address(), kPointerSize);
1703 return HeapObject::FromAddress(object->address() + kPointerSize);
1704 } else {
1705 heap->CreateFillerObjectAt(object->address() + size - kPointerSize,
1706 kPointerSize);
1707 return object;
1708 }
1709}
1710
1711
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001712enum LoggingAndProfiling {
1713 LOGGING_AND_PROFILING_ENABLED,
1714 LOGGING_AND_PROFILING_DISABLED
1715};
1716
1717
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001718enum MarksHandling { TRANSFER_MARKS, IGNORE_MARKS };
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001719
1720
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001721template<MarksHandling marks_handling,
1722 LoggingAndProfiling logging_and_profiling_mode>
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001723class ScavengingVisitor : public StaticVisitorBase {
1724 public:
1725 static void Initialize() {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001726 table_.Register(kVisitSeqOneByteString, &EvacuateSeqOneByteString);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001727 table_.Register(kVisitSeqTwoByteString, &EvacuateSeqTwoByteString);
1728 table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate);
1729 table_.Register(kVisitByteArray, &EvacuateByteArray);
1730 table_.Register(kVisitFixedArray, &EvacuateFixedArray);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001731 table_.Register(kVisitFixedDoubleArray, &EvacuateFixedDoubleArray);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001732
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001733 table_.Register(kVisitNativeContext,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001734 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001735 template VisitSpecialized<Context::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001736
1737 table_.Register(kVisitConsString,
1738 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001739 template VisitSpecialized<ConsString::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001740
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001741 table_.Register(kVisitSlicedString,
1742 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1743 template VisitSpecialized<SlicedString::kSize>);
1744
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001745 table_.Register(kVisitSharedFunctionInfo,
1746 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001747 template VisitSpecialized<SharedFunctionInfo::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001748
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001749 table_.Register(kVisitJSWeakMap,
1750 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1751 Visit);
1752
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001753 table_.Register(kVisitJSRegExp,
1754 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1755 Visit);
1756
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001757 if (marks_handling == IGNORE_MARKS) {
1758 table_.Register(kVisitJSFunction,
1759 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1760 template VisitSpecialized<JSFunction::kSize>);
1761 } else {
1762 table_.Register(kVisitJSFunction, &EvacuateJSFunction);
1763 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001764
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001765 table_.RegisterSpecializations<ObjectEvacuationStrategy<DATA_OBJECT>,
1766 kVisitDataObject,
1767 kVisitDataObjectGeneric>();
1768
1769 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>,
1770 kVisitJSObject,
1771 kVisitJSObjectGeneric>();
1772
1773 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>,
1774 kVisitStruct,
1775 kVisitStructGeneric>();
1776 }
1777
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001778 static VisitorDispatchTable<ScavengingCallback>* GetTable() {
1779 return &table_;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001780 }
1781
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001782 private:
1783 enum ObjectContents { DATA_OBJECT, POINTER_OBJECT };
1784 enum SizeRestriction { SMALL, UNKNOWN_SIZE };
1785
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001786 static void RecordCopiedObject(Heap* heap, HeapObject* obj) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001787 bool should_record = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001788#ifdef DEBUG
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001789 should_record = FLAG_heap_stats;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001790#endif
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001791 should_record = should_record || FLAG_log_gc;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001792 if (should_record) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001793 if (heap->new_space()->Contains(obj)) {
1794 heap->new_space()->RecordAllocation(obj);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001795 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001796 heap->new_space()->RecordPromotion(obj);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001797 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001798 }
1799 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001800
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001801 // Helper function used by CopyObject to copy a source object to an
1802 // allocated target object and update the forwarding pointer in the source
1803 // object. Returns the target object.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001804 INLINE(static void MigrateObject(Heap* heap,
1805 HeapObject* source,
1806 HeapObject* target,
1807 int size)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001808 // Copy the content of source to target.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 heap->CopyBlock(target->address(), source->address(), size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001810
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001811 // Set the forwarding address.
1812 source->set_map_word(MapWord::FromForwardingAddress(target));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001814 if (logging_and_profiling_mode == LOGGING_AND_PROFILING_ENABLED) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001815 // Update NewSpace stats if necessary.
1816 RecordCopiedObject(heap, target);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001817 HEAP_PROFILE(heap, ObjectMoveEvent(source->address(), target->address()));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001818 Isolate* isolate = heap->isolate();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001819 if (isolate->logger()->is_logging_code_events() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001820 CpuProfiler::is_profiling(isolate)) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001821 if (target->IsSharedFunctionInfo()) {
1822 PROFILE(isolate, SharedFunctionInfoMoveEvent(
1823 source->address(), target->address()));
1824 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001825 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001826 }
1827
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001828 if (marks_handling == TRANSFER_MARKS) {
1829 if (Marking::TransferColor(source, target)) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001830 MemoryChunk::IncrementLiveBytesFromGC(target->address(), size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001831 }
1832 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001833 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001834
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001835
1836 template<ObjectContents object_contents,
1837 SizeRestriction size_restriction,
1838 int alignment>
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001839 static inline void EvacuateObject(Map* map,
1840 HeapObject** slot,
1841 HeapObject* object,
1842 int object_size) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001843 SLOW_ASSERT((size_restriction != SMALL) ||
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001844 (object_size <= Page::kMaxNonCodeHeapObjectSize));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001845 SLOW_ASSERT(object->Size() == object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001846
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001847 int allocation_size = object_size;
1848 if (alignment != kObjectAlignment) {
1849 ASSERT(alignment == kDoubleAlignment);
1850 allocation_size += kPointerSize;
1851 }
1852
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001853 Heap* heap = map->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001854 if (heap->ShouldBePromoted(object->address(), object_size)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001855 MaybeObject* maybe_result;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001856
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001857 if ((size_restriction != SMALL) &&
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001858 (allocation_size > Page::kMaxNonCodeHeapObjectSize)) {
1859 maybe_result = heap->lo_space()->AllocateRaw(allocation_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001860 NOT_EXECUTABLE);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001861 } else {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001862 if (object_contents == DATA_OBJECT) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001863 maybe_result = heap->old_data_space()->AllocateRaw(allocation_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001864 } else {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001865 maybe_result =
1866 heap->old_pointer_space()->AllocateRaw(allocation_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001867 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001868 }
1869
lrn@chromium.org303ada72010-10-27 09:33:13 +00001870 Object* result = NULL; // Initialization to please compiler.
1871 if (maybe_result->ToObject(&result)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001872 HeapObject* target = HeapObject::cast(result);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001873
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001874 if (alignment != kObjectAlignment) {
1875 target = EnsureDoubleAligned(heap, target, allocation_size);
1876 }
1877
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001878 // Order is important: slot might be inside of the target if target
1879 // was allocated over a dead object and slot comes from the store
1880 // buffer.
1881 *slot = target;
1882 MigrateObject(heap, object, target, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001883
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001884 if (object_contents == POINTER_OBJECT) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001885 if (map->instance_type() == JS_FUNCTION_TYPE) {
1886 heap->promotion_queue()->insert(
1887 target, JSFunction::kNonWeakFieldsEndOffset);
1888 } else {
1889 heap->promotion_queue()->insert(target, object_size);
1890 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001891 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001892
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001893 heap->tracer()->increment_promoted_objects_size(object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001894 return;
1895 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001896 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001897 MaybeObject* allocation = heap->new_space()->AllocateRaw(allocation_size);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001898 heap->promotion_queue()->SetNewLimit(heap->new_space()->top());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001899 Object* result = allocation->ToObjectUnchecked();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001900 HeapObject* target = HeapObject::cast(result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001901
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001902 if (alignment != kObjectAlignment) {
1903 target = EnsureDoubleAligned(heap, target, allocation_size);
1904 }
1905
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001906 // Order is important: slot might be inside of the target if target
1907 // was allocated over a dead object and slot comes from the store
1908 // buffer.
1909 *slot = target;
1910 MigrateObject(heap, object, target, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001911 return;
1912 }
1913
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001914
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001915 static inline void EvacuateJSFunction(Map* map,
1916 HeapObject** slot,
1917 HeapObject* object) {
1918 ObjectEvacuationStrategy<POINTER_OBJECT>::
1919 template VisitSpecialized<JSFunction::kSize>(map, slot, object);
1920
1921 HeapObject* target = *slot;
1922 MarkBit mark_bit = Marking::MarkBitFrom(target);
1923 if (Marking::IsBlack(mark_bit)) {
1924 // This object is black and it might not be rescanned by marker.
1925 // We should explicitly record code entry slot for compaction because
1926 // promotion queue processing (IterateAndMarkPointersToFromSpace) will
1927 // miss it as it is not HeapObject-tagged.
1928 Address code_entry_slot =
1929 target->address() + JSFunction::kCodeEntryOffset;
1930 Code* code = Code::cast(Code::GetObjectFromEntryAddress(code_entry_slot));
1931 map->GetHeap()->mark_compact_collector()->
1932 RecordCodeEntrySlot(code_entry_slot, code);
1933 }
1934 }
1935
1936
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001937 static inline void EvacuateFixedArray(Map* map,
1938 HeapObject** slot,
1939 HeapObject* object) {
1940 int object_size = FixedArray::BodyDescriptor::SizeOf(map, object);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001941 EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(map,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001942 slot,
1943 object,
1944 object_size);
1945 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001946
1947
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001948 static inline void EvacuateFixedDoubleArray(Map* map,
1949 HeapObject** slot,
1950 HeapObject* object) {
1951 int length = reinterpret_cast<FixedDoubleArray*>(object)->length();
1952 int object_size = FixedDoubleArray::SizeFor(length);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001953 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kDoubleAlignment>(
1954 map,
1955 slot,
1956 object,
1957 object_size);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001958 }
1959
1960
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001961 static inline void EvacuateByteArray(Map* map,
1962 HeapObject** slot,
1963 HeapObject* object) {
1964 int object_size = reinterpret_cast<ByteArray*>(object)->ByteArraySize();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001965 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
1966 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001967 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001968
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001969
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001970 static inline void EvacuateSeqOneByteString(Map* map,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001971 HeapObject** slot,
1972 HeapObject* object) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001973 int object_size = SeqOneByteString::cast(object)->
1974 SeqOneByteStringSize(map->instance_type());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001975 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
1976 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001977 }
1978
1979
1980 static inline void EvacuateSeqTwoByteString(Map* map,
1981 HeapObject** slot,
1982 HeapObject* object) {
1983 int object_size = SeqTwoByteString::cast(object)->
1984 SeqTwoByteStringSize(map->instance_type());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001985 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
1986 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001987 }
1988
1989
1990 static inline bool IsShortcutCandidate(int type) {
1991 return ((type & kShortcutTypeMask) == kShortcutTypeTag);
1992 }
1993
1994 static inline void EvacuateShortcutCandidate(Map* map,
1995 HeapObject** slot,
1996 HeapObject* object) {
1997 ASSERT(IsShortcutCandidate(map->instance_type()));
1998
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001999 Heap* heap = map->GetHeap();
2000
2001 if (marks_handling == IGNORE_MARKS &&
2002 ConsString::cast(object)->unchecked_second() ==
2003 heap->empty_string()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002004 HeapObject* first =
2005 HeapObject::cast(ConsString::cast(object)->unchecked_first());
2006
2007 *slot = first;
2008
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002009 if (!heap->InNewSpace(first)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002010 object->set_map_word(MapWord::FromForwardingAddress(first));
2011 return;
2012 }
2013
2014 MapWord first_word = first->map_word();
2015 if (first_word.IsForwardingAddress()) {
2016 HeapObject* target = first_word.ToForwardingAddress();
2017
2018 *slot = target;
2019 object->set_map_word(MapWord::FromForwardingAddress(target));
2020 return;
2021 }
2022
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002023 heap->DoScavengeObject(first->map(), slot, first);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002024 object->set_map_word(MapWord::FromForwardingAddress(*slot));
2025 return;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002026 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002027
2028 int object_size = ConsString::kSize;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002029 EvacuateObject<POINTER_OBJECT, SMALL, kObjectAlignment>(
2030 map, slot, object, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002031 }
2032
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002033 template<ObjectContents object_contents>
2034 class ObjectEvacuationStrategy {
2035 public:
2036 template<int object_size>
2037 static inline void VisitSpecialized(Map* map,
2038 HeapObject** slot,
2039 HeapObject* object) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002040 EvacuateObject<object_contents, SMALL, kObjectAlignment>(
2041 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002042 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002043
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002044 static inline void Visit(Map* map,
2045 HeapObject** slot,
2046 HeapObject* object) {
2047 int object_size = map->instance_size();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002048 EvacuateObject<object_contents, SMALL, kObjectAlignment>(
2049 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002050 }
2051 };
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002052
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002053 static VisitorDispatchTable<ScavengingCallback> table_;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002054};
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002055
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002056
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002057template<MarksHandling marks_handling,
2058 LoggingAndProfiling logging_and_profiling_mode>
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002059VisitorDispatchTable<ScavengingCallback>
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002060 ScavengingVisitor<marks_handling, logging_and_profiling_mode>::table_;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002061
2062
2063static void InitializeScavengingVisitorsTables() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002064 ScavengingVisitor<TRANSFER_MARKS,
2065 LOGGING_AND_PROFILING_DISABLED>::Initialize();
2066 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_DISABLED>::Initialize();
2067 ScavengingVisitor<TRANSFER_MARKS,
2068 LOGGING_AND_PROFILING_ENABLED>::Initialize();
2069 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_ENABLED>::Initialize();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002070}
2071
2072
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002073void Heap::SelectScavengingVisitorsTable() {
2074 bool logging_and_profiling =
2075 isolate()->logger()->is_logging() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002076 CpuProfiler::is_profiling(isolate()) ||
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002077 (isolate()->heap_profiler() != NULL &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002078 isolate()->heap_profiler()->is_profiling());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002079
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002080 if (!incremental_marking()->IsMarking()) {
2081 if (!logging_and_profiling) {
2082 scavenging_visitors_table_.CopyFrom(
2083 ScavengingVisitor<IGNORE_MARKS,
2084 LOGGING_AND_PROFILING_DISABLED>::GetTable());
2085 } else {
2086 scavenging_visitors_table_.CopyFrom(
2087 ScavengingVisitor<IGNORE_MARKS,
2088 LOGGING_AND_PROFILING_ENABLED>::GetTable());
2089 }
2090 } else {
2091 if (!logging_and_profiling) {
2092 scavenging_visitors_table_.CopyFrom(
2093 ScavengingVisitor<TRANSFER_MARKS,
2094 LOGGING_AND_PROFILING_DISABLED>::GetTable());
2095 } else {
2096 scavenging_visitors_table_.CopyFrom(
2097 ScavengingVisitor<TRANSFER_MARKS,
2098 LOGGING_AND_PROFILING_ENABLED>::GetTable());
2099 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002100
2101 if (incremental_marking()->IsCompacting()) {
2102 // When compacting forbid short-circuiting of cons-strings.
2103 // Scavenging code relies on the fact that new space object
2104 // can't be evacuated into evacuation candidate but
2105 // short-circuiting violates this assumption.
2106 scavenging_visitors_table_.Register(
2107 StaticVisitorBase::kVisitShortcutCandidate,
2108 scavenging_visitors_table_.GetVisitorById(
2109 StaticVisitorBase::kVisitConsString));
2110 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002111 }
2112}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002113
2114
2115void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002116 SLOW_ASSERT(HEAP->InFromSpace(object));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002117 MapWord first_word = object->map_word();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002118 SLOW_ASSERT(!first_word.IsForwardingAddress());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002119 Map* map = first_word.ToMap();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002120 map->GetHeap()->DoScavengeObject(map, p, object);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002121}
2122
2123
lrn@chromium.org303ada72010-10-27 09:33:13 +00002124MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type,
2125 int instance_size) {
2126 Object* result;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002127 MaybeObject* maybe_result = AllocateRawMap();
2128 if (!maybe_result->ToObject(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002129
2130 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002131 reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002132 reinterpret_cast<Map*>(result)->set_instance_type(instance_type);
2133 reinterpret_cast<Map*>(result)->set_instance_size(instance_size);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002134 reinterpret_cast<Map*>(result)->set_visitor_id(
2135 StaticVisitorBase::GetVisitorId(instance_type, instance_size));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002136 reinterpret_cast<Map*>(result)->set_inobject_properties(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002137 reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002138 reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002139 reinterpret_cast<Map*>(result)->set_bit_field(0);
2140 reinterpret_cast<Map*>(result)->set_bit_field2(0);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002141 int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) |
2142 Map::OwnsDescriptors::encode(true);
2143 reinterpret_cast<Map*>(result)->set_bit_field3(bit_field3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002144 return result;
2145}
2146
2147
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002148MaybeObject* Heap::AllocateMap(InstanceType instance_type,
2149 int instance_size,
2150 ElementsKind elements_kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002151 Object* result;
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002152 MaybeObject* maybe_result = AllocateRawMap();
2153 if (!maybe_result->To(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002154
2155 Map* map = reinterpret_cast<Map*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002156 map->set_map_no_write_barrier(meta_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002157 map->set_instance_type(instance_type);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002158 map->set_visitor_id(
2159 StaticVisitorBase::GetVisitorId(instance_type, instance_size));
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002160 map->set_prototype(null_value(), SKIP_WRITE_BARRIER);
2161 map->set_constructor(null_value(), SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002162 map->set_instance_size(instance_size);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002163 map->set_inobject_properties(0);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002164 map->set_pre_allocated_property_fields(0);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002165 map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002166 map->init_back_pointer(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002167 map->set_unused_property_fields(0);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002168 map->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002169 map->set_bit_field(0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002170 map->set_bit_field2(1 << Map::kIsExtensible);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002171 int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) |
2172 Map::OwnsDescriptors::encode(true);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002173 map->set_bit_field3(bit_field3);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002174 map->set_elements_kind(elements_kind);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002175
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002176 return map;
2177}
2178
2179
lrn@chromium.org303ada72010-10-27 09:33:13 +00002180MaybeObject* Heap::AllocateCodeCache() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002181 CodeCache* code_cache;
2182 { MaybeObject* maybe_code_cache = AllocateStruct(CODE_CACHE_TYPE);
2183 if (!maybe_code_cache->To(&code_cache)) return maybe_code_cache;
lrn@chromium.org303ada72010-10-27 09:33:13 +00002184 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002185 code_cache->set_default_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
2186 code_cache->set_normal_type_cache(undefined_value(), SKIP_WRITE_BARRIER);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002187 return code_cache;
2188}
2189
2190
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002191MaybeObject* Heap::AllocatePolymorphicCodeCache() {
2192 return AllocateStruct(POLYMORPHIC_CODE_CACHE_TYPE);
2193}
2194
2195
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002196MaybeObject* Heap::AllocateAccessorPair() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002197 AccessorPair* accessors;
2198 { MaybeObject* maybe_accessors = AllocateStruct(ACCESSOR_PAIR_TYPE);
2199 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002200 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002201 accessors->set_getter(the_hole_value(), SKIP_WRITE_BARRIER);
2202 accessors->set_setter(the_hole_value(), SKIP_WRITE_BARRIER);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002203 return accessors;
2204}
2205
2206
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002207MaybeObject* Heap::AllocateTypeFeedbackInfo() {
2208 TypeFeedbackInfo* info;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002209 { MaybeObject* maybe_info = AllocateStruct(TYPE_FEEDBACK_INFO_TYPE);
2210 if (!maybe_info->To(&info)) return maybe_info;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002211 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002212 info->initialize_storage();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002213 info->set_type_feedback_cells(TypeFeedbackCells::cast(empty_fixed_array()),
2214 SKIP_WRITE_BARRIER);
2215 return info;
2216}
2217
2218
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002219MaybeObject* Heap::AllocateAliasedArgumentsEntry(int aliased_context_slot) {
2220 AliasedArgumentsEntry* entry;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002221 { MaybeObject* maybe_entry = AllocateStruct(ALIASED_ARGUMENTS_ENTRY_TYPE);
2222 if (!maybe_entry->To(&entry)) return maybe_entry;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002223 }
2224 entry->set_aliased_context_slot(aliased_context_slot);
2225 return entry;
2226}
2227
2228
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002229const Heap::StringTypeTable Heap::string_type_table[] = {
2230#define STRING_TYPE_ELEMENT(type, size, name, camel_name) \
2231 {type, size, k##camel_name##MapRootIndex},
2232 STRING_TYPE_LIST(STRING_TYPE_ELEMENT)
2233#undef STRING_TYPE_ELEMENT
2234};
2235
2236
2237const Heap::ConstantSymbolTable Heap::constant_symbol_table[] = {
2238#define CONSTANT_SYMBOL_ELEMENT(name, contents) \
2239 {contents, k##name##RootIndex},
2240 SYMBOL_LIST(CONSTANT_SYMBOL_ELEMENT)
2241#undef CONSTANT_SYMBOL_ELEMENT
2242};
2243
2244
2245const Heap::StructTable Heap::struct_table[] = {
2246#define STRUCT_TABLE_ELEMENT(NAME, Name, name) \
2247 { NAME##_TYPE, Name::kSize, k##Name##MapRootIndex },
2248 STRUCT_LIST(STRUCT_TABLE_ELEMENT)
2249#undef STRUCT_TABLE_ELEMENT
2250};
2251
2252
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002253bool Heap::CreateInitialMaps() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002254 Object* obj;
2255 { MaybeObject* maybe_obj = AllocatePartialMap(MAP_TYPE, Map::kSize);
2256 if (!maybe_obj->ToObject(&obj)) return false;
2257 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002258 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002259 Map* new_meta_map = reinterpret_cast<Map*>(obj);
2260 set_meta_map(new_meta_map);
2261 new_meta_map->set_map(new_meta_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002262
lrn@chromium.org303ada72010-10-27 09:33:13 +00002263 { MaybeObject* maybe_obj =
2264 AllocatePartialMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2265 if (!maybe_obj->ToObject(&obj)) return false;
2266 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002267 set_fixed_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002268
lrn@chromium.org303ada72010-10-27 09:33:13 +00002269 { MaybeObject* maybe_obj = AllocatePartialMap(ODDBALL_TYPE, Oddball::kSize);
2270 if (!maybe_obj->ToObject(&obj)) return false;
2271 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002272 set_oddball_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002273
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002274 // Allocate the empty array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002275 { MaybeObject* maybe_obj = AllocateEmptyFixedArray();
2276 if (!maybe_obj->ToObject(&obj)) return false;
2277 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002278 set_empty_fixed_array(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002279
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002280 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002281 if (!maybe_obj->ToObject(&obj)) return false;
2282 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002283 set_null_value(Oddball::cast(obj));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002284 Oddball::cast(obj)->set_kind(Oddball::kNull);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002285
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002286 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE);
2287 if (!maybe_obj->ToObject(&obj)) return false;
2288 }
2289 set_undefined_value(Oddball::cast(obj));
2290 Oddball::cast(obj)->set_kind(Oddball::kUndefined);
2291 ASSERT(!InNewSpace(undefined_value()));
2292
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002293 // Allocate the empty descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002294 { MaybeObject* maybe_obj = AllocateEmptyFixedArray();
2295 if (!maybe_obj->ToObject(&obj)) return false;
2296 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002297 set_empty_descriptor_array(DescriptorArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002298
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002299 // Fix the instance_descriptors for the existing maps.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002300 meta_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002301 meta_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002302 meta_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002303
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002304 fixed_array_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002305 fixed_array_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002306 fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002307
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002308 oddball_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002309 oddball_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002310 oddball_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002311
2312 // Fix prototype object for existing maps.
2313 meta_map()->set_prototype(null_value());
2314 meta_map()->set_constructor(null_value());
2315
2316 fixed_array_map()->set_prototype(null_value());
2317 fixed_array_map()->set_constructor(null_value());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002318
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002319 oddball_map()->set_prototype(null_value());
2320 oddball_map()->set_constructor(null_value());
2321
lrn@chromium.org303ada72010-10-27 09:33:13 +00002322 { MaybeObject* maybe_obj =
2323 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2324 if (!maybe_obj->ToObject(&obj)) return false;
2325 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002326 set_fixed_cow_array_map(Map::cast(obj));
2327 ASSERT(fixed_array_map() != fixed_cow_array_map());
2328
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002329 { MaybeObject* maybe_obj =
2330 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2331 if (!maybe_obj->ToObject(&obj)) return false;
2332 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002333 set_scope_info_map(Map::cast(obj));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002334
lrn@chromium.org303ada72010-10-27 09:33:13 +00002335 { MaybeObject* maybe_obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
2336 if (!maybe_obj->ToObject(&obj)) return false;
2337 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002338 set_heap_number_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002339
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002340 { MaybeObject* maybe_obj = AllocateMap(FOREIGN_TYPE, Foreign::kSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002341 if (!maybe_obj->ToObject(&obj)) return false;
2342 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002343 set_foreign_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002344
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002345 for (unsigned i = 0; i < ARRAY_SIZE(string_type_table); i++) {
2346 const StringTypeTable& entry = string_type_table[i];
lrn@chromium.org303ada72010-10-27 09:33:13 +00002347 { MaybeObject* maybe_obj = AllocateMap(entry.type, entry.size);
2348 if (!maybe_obj->ToObject(&obj)) return false;
2349 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002350 roots_[entry.index] = Map::cast(obj);
2351 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002352
lrn@chromium.org303ada72010-10-27 09:33:13 +00002353 { MaybeObject* maybe_obj = AllocateMap(STRING_TYPE, kVariableSizeSentinel);
2354 if (!maybe_obj->ToObject(&obj)) return false;
2355 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002356 set_undetectable_string_map(Map::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002357 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002358
lrn@chromium.org303ada72010-10-27 09:33:13 +00002359 { MaybeObject* maybe_obj =
2360 AllocateMap(ASCII_STRING_TYPE, kVariableSizeSentinel);
2361 if (!maybe_obj->ToObject(&obj)) return false;
2362 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002363 set_undetectable_ascii_string_map(Map::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002364 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002365
lrn@chromium.org303ada72010-10-27 09:33:13 +00002366 { MaybeObject* maybe_obj =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002367 AllocateMap(FIXED_DOUBLE_ARRAY_TYPE, kVariableSizeSentinel);
2368 if (!maybe_obj->ToObject(&obj)) return false;
2369 }
2370 set_fixed_double_array_map(Map::cast(obj));
2371
2372 { MaybeObject* maybe_obj =
lrn@chromium.org303ada72010-10-27 09:33:13 +00002373 AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel);
2374 if (!maybe_obj->ToObject(&obj)) return false;
2375 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002376 set_byte_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002377
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002378 { MaybeObject* maybe_obj =
2379 AllocateMap(FREE_SPACE_TYPE, kVariableSizeSentinel);
2380 if (!maybe_obj->ToObject(&obj)) return false;
2381 }
2382 set_free_space_map(Map::cast(obj));
2383
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002384 { MaybeObject* maybe_obj = AllocateByteArray(0, TENURED);
2385 if (!maybe_obj->ToObject(&obj)) return false;
2386 }
2387 set_empty_byte_array(ByteArray::cast(obj));
2388
lrn@chromium.org303ada72010-10-27 09:33:13 +00002389 { MaybeObject* maybe_obj =
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002390 AllocateMap(EXTERNAL_PIXEL_ARRAY_TYPE, ExternalArray::kAlignedSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002391 if (!maybe_obj->ToObject(&obj)) return false;
2392 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002393 set_external_pixel_array_map(Map::cast(obj));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002394
lrn@chromium.org303ada72010-10-27 09:33:13 +00002395 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_BYTE_ARRAY_TYPE,
2396 ExternalArray::kAlignedSize);
2397 if (!maybe_obj->ToObject(&obj)) return false;
2398 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002399 set_external_byte_array_map(Map::cast(obj));
2400
lrn@chromium.org303ada72010-10-27 09:33:13 +00002401 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE,
2402 ExternalArray::kAlignedSize);
2403 if (!maybe_obj->ToObject(&obj)) return false;
2404 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002405 set_external_unsigned_byte_array_map(Map::cast(obj));
2406
lrn@chromium.org303ada72010-10-27 09:33:13 +00002407 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_SHORT_ARRAY_TYPE,
2408 ExternalArray::kAlignedSize);
2409 if (!maybe_obj->ToObject(&obj)) return false;
2410 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002411 set_external_short_array_map(Map::cast(obj));
2412
lrn@chromium.org303ada72010-10-27 09:33:13 +00002413 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE,
2414 ExternalArray::kAlignedSize);
2415 if (!maybe_obj->ToObject(&obj)) return false;
2416 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002417 set_external_unsigned_short_array_map(Map::cast(obj));
2418
lrn@chromium.org303ada72010-10-27 09:33:13 +00002419 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_INT_ARRAY_TYPE,
2420 ExternalArray::kAlignedSize);
2421 if (!maybe_obj->ToObject(&obj)) return false;
2422 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002423 set_external_int_array_map(Map::cast(obj));
2424
lrn@chromium.org303ada72010-10-27 09:33:13 +00002425 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE,
2426 ExternalArray::kAlignedSize);
2427 if (!maybe_obj->ToObject(&obj)) return false;
2428 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002429 set_external_unsigned_int_array_map(Map::cast(obj));
2430
lrn@chromium.org303ada72010-10-27 09:33:13 +00002431 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_FLOAT_ARRAY_TYPE,
2432 ExternalArray::kAlignedSize);
2433 if (!maybe_obj->ToObject(&obj)) return false;
2434 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002435 set_external_float_array_map(Map::cast(obj));
2436
whesse@chromium.org7b260152011-06-20 15:33:18 +00002437 { MaybeObject* maybe_obj =
2438 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2439 if (!maybe_obj->ToObject(&obj)) return false;
2440 }
2441 set_non_strict_arguments_elements_map(Map::cast(obj));
2442
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002443 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_DOUBLE_ARRAY_TYPE,
2444 ExternalArray::kAlignedSize);
2445 if (!maybe_obj->ToObject(&obj)) return false;
2446 }
2447 set_external_double_array_map(Map::cast(obj));
2448
lrn@chromium.org303ada72010-10-27 09:33:13 +00002449 { MaybeObject* maybe_obj = AllocateMap(CODE_TYPE, kVariableSizeSentinel);
2450 if (!maybe_obj->ToObject(&obj)) return false;
2451 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002452 set_code_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002453
lrn@chromium.org303ada72010-10-27 09:33:13 +00002454 { MaybeObject* maybe_obj = AllocateMap(JS_GLOBAL_PROPERTY_CELL_TYPE,
2455 JSGlobalPropertyCell::kSize);
2456 if (!maybe_obj->ToObject(&obj)) return false;
2457 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002458 set_global_property_cell_map(Map::cast(obj));
2459
lrn@chromium.org303ada72010-10-27 09:33:13 +00002460 { MaybeObject* maybe_obj = AllocateMap(FILLER_TYPE, kPointerSize);
2461 if (!maybe_obj->ToObject(&obj)) return false;
2462 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002463 set_one_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002464
lrn@chromium.org303ada72010-10-27 09:33:13 +00002465 { MaybeObject* maybe_obj = AllocateMap(FILLER_TYPE, 2 * kPointerSize);
2466 if (!maybe_obj->ToObject(&obj)) return false;
2467 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002468 set_two_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002469
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002470 for (unsigned i = 0; i < ARRAY_SIZE(struct_table); i++) {
2471 const StructTable& entry = struct_table[i];
lrn@chromium.org303ada72010-10-27 09:33:13 +00002472 { MaybeObject* maybe_obj = AllocateMap(entry.type, entry.size);
2473 if (!maybe_obj->ToObject(&obj)) return false;
2474 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002475 roots_[entry.index] = Map::cast(obj);
2476 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002477
lrn@chromium.org303ada72010-10-27 09:33:13 +00002478 { MaybeObject* maybe_obj =
2479 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2480 if (!maybe_obj->ToObject(&obj)) return false;
2481 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002482 set_hash_table_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002483
lrn@chromium.org303ada72010-10-27 09:33:13 +00002484 { MaybeObject* maybe_obj =
2485 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2486 if (!maybe_obj->ToObject(&obj)) return false;
2487 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002488 set_function_context_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002489
lrn@chromium.org303ada72010-10-27 09:33:13 +00002490 { MaybeObject* maybe_obj =
2491 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2492 if (!maybe_obj->ToObject(&obj)) return false;
2493 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002494 set_catch_context_map(Map::cast(obj));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002495
lrn@chromium.org303ada72010-10-27 09:33:13 +00002496 { MaybeObject* maybe_obj =
2497 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2498 if (!maybe_obj->ToObject(&obj)) return false;
2499 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002500 set_with_context_map(Map::cast(obj));
2501
2502 { MaybeObject* maybe_obj =
2503 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2504 if (!maybe_obj->ToObject(&obj)) return false;
2505 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002506 set_block_context_map(Map::cast(obj));
2507
2508 { MaybeObject* maybe_obj =
2509 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2510 if (!maybe_obj->ToObject(&obj)) return false;
2511 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002512 set_module_context_map(Map::cast(obj));
2513
2514 { MaybeObject* maybe_obj =
2515 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2516 if (!maybe_obj->ToObject(&obj)) return false;
2517 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002518 set_global_context_map(Map::cast(obj));
2519
2520 { MaybeObject* maybe_obj =
2521 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2522 if (!maybe_obj->ToObject(&obj)) return false;
2523 }
2524 Map* native_context_map = Map::cast(obj);
2525 native_context_map->set_dictionary_map(true);
2526 native_context_map->set_visitor_id(StaticVisitorBase::kVisitNativeContext);
2527 set_native_context_map(native_context_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002528
lrn@chromium.org303ada72010-10-27 09:33:13 +00002529 { MaybeObject* maybe_obj = AllocateMap(SHARED_FUNCTION_INFO_TYPE,
2530 SharedFunctionInfo::kAlignedSize);
2531 if (!maybe_obj->ToObject(&obj)) return false;
2532 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002533 set_shared_function_info_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002534
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002535 { MaybeObject* maybe_obj = AllocateMap(JS_MESSAGE_OBJECT_TYPE,
2536 JSMessageObject::kSize);
2537 if (!maybe_obj->ToObject(&obj)) return false;
2538 }
2539 set_message_object_map(Map::cast(obj));
2540
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002541 Map* external_map;
2542 { MaybeObject* maybe_obj =
2543 AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize + kPointerSize);
2544 if (!maybe_obj->To(&external_map)) return false;
2545 }
2546 external_map->set_is_extensible(false);
2547 set_external_map(external_map);
2548
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002549 ASSERT(!InNewSpace(empty_fixed_array()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002550 return true;
2551}
2552
2553
lrn@chromium.org303ada72010-10-27 09:33:13 +00002554MaybeObject* Heap::AllocateHeapNumber(double value, PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002555 // Statically ensure that it is safe to allocate heap numbers in paged
2556 // spaces.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002557 STATIC_ASSERT(HeapNumber::kSize <= Page::kNonCodeObjectAreaSize);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002558 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002559
lrn@chromium.org303ada72010-10-27 09:33:13 +00002560 Object* result;
2561 { MaybeObject* maybe_result =
2562 AllocateRaw(HeapNumber::kSize, space, OLD_DATA_SPACE);
2563 if (!maybe_result->ToObject(&result)) return maybe_result;
2564 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002565
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002566 HeapObject::cast(result)->set_map_no_write_barrier(heap_number_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002567 HeapNumber::cast(result)->set_value(value);
2568 return result;
2569}
2570
2571
lrn@chromium.org303ada72010-10-27 09:33:13 +00002572MaybeObject* Heap::AllocateHeapNumber(double value) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002573 // Use general version, if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002574 if (always_allocate()) return AllocateHeapNumber(value, TENURED);
2575
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002576 // This version of AllocateHeapNumber is optimized for
2577 // allocation in new space.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002578 STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxNonCodeHeapObjectSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002579 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002580 Object* result;
2581 { MaybeObject* maybe_result = new_space_.AllocateRaw(HeapNumber::kSize);
2582 if (!maybe_result->ToObject(&result)) return maybe_result;
2583 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002584 HeapObject::cast(result)->set_map_no_write_barrier(heap_number_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002585 HeapNumber::cast(result)->set_value(value);
2586 return result;
2587}
2588
2589
lrn@chromium.org303ada72010-10-27 09:33:13 +00002590MaybeObject* Heap::AllocateJSGlobalPropertyCell(Object* value) {
2591 Object* result;
2592 { MaybeObject* maybe_result = AllocateRawCell();
2593 if (!maybe_result->ToObject(&result)) return maybe_result;
2594 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002595 HeapObject::cast(result)->set_map_no_write_barrier(
2596 global_property_cell_map());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002597 JSGlobalPropertyCell::cast(result)->set_value(value);
2598 return result;
2599}
2600
2601
lrn@chromium.org303ada72010-10-27 09:33:13 +00002602MaybeObject* Heap::CreateOddball(const char* to_string,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002603 Object* to_number,
2604 byte kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002605 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002606 { MaybeObject* maybe_result = Allocate(oddball_map(), OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002607 if (!maybe_result->ToObject(&result)) return maybe_result;
2608 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002609 return Oddball::cast(result)->Initialize(to_string, to_number, kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002610}
2611
2612
2613bool Heap::CreateApiObjects() {
2614 Object* obj;
2615
lrn@chromium.org303ada72010-10-27 09:33:13 +00002616 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
2617 if (!maybe_obj->ToObject(&obj)) return false;
2618 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002619 // Don't use Smi-only elements optimizations for objects with the neander
2620 // map. There are too many cases where element values are set directly with a
2621 // bottleneck to trap the Smi-only -> fast elements transition, and there
2622 // appears to be no benefit for optimize this case.
2623 Map* new_neander_map = Map::cast(obj);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002624 new_neander_map->set_elements_kind(TERMINAL_FAST_ELEMENTS_KIND);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002625 set_neander_map(new_neander_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002626
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002627 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(neander_map());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002628 if (!maybe_obj->ToObject(&obj)) return false;
2629 }
2630 Object* elements;
2631 { MaybeObject* maybe_elements = AllocateFixedArray(2);
2632 if (!maybe_elements->ToObject(&elements)) return false;
2633 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002634 FixedArray::cast(elements)->set(0, Smi::FromInt(0));
2635 JSObject::cast(obj)->set_elements(FixedArray::cast(elements));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002636 set_message_listeners(JSObject::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002637
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002638 return true;
2639}
2640
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002641
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002642void Heap::CreateJSEntryStub() {
2643 JSEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002644 set_js_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002645}
2646
2647
2648void Heap::CreateJSConstructEntryStub() {
2649 JSConstructEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002650 set_js_construct_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002651}
2652
2653
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002654void Heap::CreateFixedStubs() {
2655 // Here we create roots for fixed stubs. They are needed at GC
2656 // for cooking and uncooking (check out frames.cc).
2657 // The eliminates the need for doing dictionary lookup in the
2658 // stub cache for these stubs.
2659 HandleScope scope;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002660 // gcc-4.4 has problem generating correct code of following snippet:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002661 // { JSEntryStub stub;
2662 // js_entry_code_ = *stub.GetCode();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002663 // }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002664 // { JSConstructEntryStub stub;
2665 // js_construct_entry_code_ = *stub.GetCode();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002666 // }
2667 // To workaround the problem, make separate functions without inlining.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002668 Heap::CreateJSEntryStub();
2669 Heap::CreateJSConstructEntryStub();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002670
2671 // Create stubs that should be there, so we don't unexpectedly have to
2672 // create them if we need them during the creation of another stub.
2673 // Stub creation mixes raw pointers and handles in an unsafe manner so
2674 // we cannot create stubs while we are creating stubs.
2675 CodeStub::GenerateStubsAheadOfTime();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002676}
2677
2678
2679bool Heap::CreateInitialObjects() {
2680 Object* obj;
2681
2682 // The -0 value must be set before NumberFromDouble works.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002683 { MaybeObject* maybe_obj = AllocateHeapNumber(-0.0, TENURED);
2684 if (!maybe_obj->ToObject(&obj)) return false;
2685 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002686 set_minus_zero_value(HeapNumber::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002687 ASSERT(signbit(minus_zero_value()->Number()) != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002688
lrn@chromium.org303ada72010-10-27 09:33:13 +00002689 { MaybeObject* maybe_obj = AllocateHeapNumber(OS::nan_value(), TENURED);
2690 if (!maybe_obj->ToObject(&obj)) return false;
2691 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002692 set_nan_value(HeapNumber::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002693
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002694 { MaybeObject* maybe_obj = AllocateHeapNumber(V8_INFINITY, TENURED);
2695 if (!maybe_obj->ToObject(&obj)) return false;
2696 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002697 set_infinity_value(HeapNumber::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002698
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00002699 // The hole has not been created yet, but we want to put something
2700 // predictable in the gaps in the symbol table, so lets make that Smi zero.
2701 set_the_hole_value(reinterpret_cast<Oddball*>(Smi::FromInt(0)));
2702
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002703 // Allocate initial symbol table.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002704 { MaybeObject* maybe_obj = SymbolTable::Allocate(kInitialSymbolTableSize);
2705 if (!maybe_obj->ToObject(&obj)) return false;
2706 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002707 // Don't use set_symbol_table() due to asserts.
2708 roots_[kSymbolTableRootIndex] = obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002709
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002710 // Finish initializing oddballs after creating symboltable.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002711 { MaybeObject* maybe_obj =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002712 undefined_value()->Initialize("undefined",
2713 nan_value(),
2714 Oddball::kUndefined);
2715 if (!maybe_obj->ToObject(&obj)) return false;
2716 }
2717
2718 // Initialize the null_value.
2719 { MaybeObject* maybe_obj =
2720 null_value()->Initialize("null", Smi::FromInt(0), Oddball::kNull);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002721 if (!maybe_obj->ToObject(&obj)) return false;
2722 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002723
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002724 { MaybeObject* maybe_obj = CreateOddball("true",
2725 Smi::FromInt(1),
2726 Oddball::kTrue);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002727 if (!maybe_obj->ToObject(&obj)) return false;
2728 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002729 set_true_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002730
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002731 { MaybeObject* maybe_obj = CreateOddball("false",
2732 Smi::FromInt(0),
2733 Oddball::kFalse);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002734 if (!maybe_obj->ToObject(&obj)) return false;
2735 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002736 set_false_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002737
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002738 { MaybeObject* maybe_obj = CreateOddball("hole",
2739 Smi::FromInt(-1),
2740 Oddball::kTheHole);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002741 if (!maybe_obj->ToObject(&obj)) return false;
2742 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002743 set_the_hole_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002744
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002745 { MaybeObject* maybe_obj = CreateOddball("arguments_marker",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002746 Smi::FromInt(-4),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002747 Oddball::kArgumentMarker);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002748 if (!maybe_obj->ToObject(&obj)) return false;
2749 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002750 set_arguments_marker(Oddball::cast(obj));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002751
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002752 { MaybeObject* maybe_obj = CreateOddball("no_interceptor_result_sentinel",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002753 Smi::FromInt(-2),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002754 Oddball::kOther);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002755 if (!maybe_obj->ToObject(&obj)) return false;
2756 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002757 set_no_interceptor_result_sentinel(obj);
2758
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002759 { MaybeObject* maybe_obj = CreateOddball("termination_exception",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002760 Smi::FromInt(-3),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002761 Oddball::kOther);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002762 if (!maybe_obj->ToObject(&obj)) return false;
2763 }
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00002764 set_termination_exception(obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002765
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002766 // Allocate the empty string.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002767 { MaybeObject* maybe_obj = AllocateRawOneByteString(0, TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002768 if (!maybe_obj->ToObject(&obj)) return false;
2769 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002770 set_empty_string(String::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002771
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002772 for (unsigned i = 0; i < ARRAY_SIZE(constant_symbol_table); i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002773 { MaybeObject* maybe_obj =
2774 LookupAsciiSymbol(constant_symbol_table[i].contents);
2775 if (!maybe_obj->ToObject(&obj)) return false;
2776 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002777 roots_[constant_symbol_table[i].index] = String::cast(obj);
2778 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002779
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002780 // Allocate the hidden symbol which is used to identify the hidden properties
2781 // in JSObjects. The hash code has a special value so that it will not match
2782 // the empty string when searching for the property. It cannot be part of the
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002783 // loop above because it needs to be allocated manually with the special
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002784 // hash code in place. The hash code for the hidden_symbol is zero to ensure
2785 // that it will always be at the first entry in property descriptors.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002786 { MaybeObject* maybe_obj =
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002787 AllocateSymbol(CStrVector(""), 0, String::kEmptyStringHash);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002788 if (!maybe_obj->ToObject(&obj)) return false;
2789 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002790 hidden_symbol_ = String::cast(obj);
2791
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002792 // Allocate the foreign for __proto__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002793 { MaybeObject* maybe_obj =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002794 AllocateForeign((Address) &Accessors::ObjectPrototype);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002795 if (!maybe_obj->ToObject(&obj)) return false;
2796 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002797 set_prototype_accessors(Foreign::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002798
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002799 // Allocate the code_stubs dictionary. The initial size is set to avoid
2800 // expanding the dictionary during bootstrapping.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002801 { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(128);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002802 if (!maybe_obj->ToObject(&obj)) return false;
2803 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002804 set_code_stubs(UnseededNumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002805
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002806
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002807 // Allocate the non_monomorphic_cache used in stub-cache.cc. The initial size
2808 // is set to avoid expanding the dictionary during bootstrapping.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002809 { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(64);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002810 if (!maybe_obj->ToObject(&obj)) return false;
2811 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002812 set_non_monomorphic_cache(UnseededNumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002813
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002814 { MaybeObject* maybe_obj = AllocatePolymorphicCodeCache();
2815 if (!maybe_obj->ToObject(&obj)) return false;
2816 }
2817 set_polymorphic_code_cache(PolymorphicCodeCache::cast(obj));
2818
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002819 set_instanceof_cache_function(Smi::FromInt(0));
2820 set_instanceof_cache_map(Smi::FromInt(0));
2821 set_instanceof_cache_answer(Smi::FromInt(0));
2822
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002823 CreateFixedStubs();
2824
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002825 // Allocate the dictionary of intrinsic function names.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002826 { MaybeObject* maybe_obj = StringDictionary::Allocate(Runtime::kNumFunctions);
2827 if (!maybe_obj->ToObject(&obj)) return false;
2828 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002829 { MaybeObject* maybe_obj = Runtime::InitializeIntrinsicFunctionNames(this,
2830 obj);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002831 if (!maybe_obj->ToObject(&obj)) return false;
2832 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002833 set_intrinsic_function_names(StringDictionary::cast(obj));
2834
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002835 { MaybeObject* maybe_obj = AllocateInitialNumberStringCache();
2836 if (!maybe_obj->ToObject(&obj)) return false;
2837 }
2838 set_number_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002839
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002840 // Allocate cache for single character ASCII strings.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002841 { MaybeObject* maybe_obj =
2842 AllocateFixedArray(String::kMaxAsciiCharCode + 1, TENURED);
2843 if (!maybe_obj->ToObject(&obj)) return false;
2844 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002845 set_single_character_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002846
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002847 // Allocate cache for string split.
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002848 { MaybeObject* maybe_obj = AllocateFixedArray(
2849 RegExpResultsCache::kRegExpResultsCacheSize, TENURED);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002850 if (!maybe_obj->ToObject(&obj)) return false;
2851 }
2852 set_string_split_cache(FixedArray::cast(obj));
2853
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002854 { MaybeObject* maybe_obj = AllocateFixedArray(
2855 RegExpResultsCache::kRegExpResultsCacheSize, TENURED);
2856 if (!maybe_obj->ToObject(&obj)) return false;
2857 }
2858 set_regexp_multiple_cache(FixedArray::cast(obj));
2859
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002860 // Allocate cache for external strings pointing to native source code.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002861 { MaybeObject* maybe_obj = AllocateFixedArray(Natives::GetBuiltinsCount());
2862 if (!maybe_obj->ToObject(&obj)) return false;
2863 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002864 set_natives_source_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002865
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002866 // Allocate object to hold object observation state.
2867 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
2868 if (!maybe_obj->ToObject(&obj)) return false;
2869 }
2870 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(Map::cast(obj));
2871 if (!maybe_obj->ToObject(&obj)) return false;
2872 }
2873 set_observation_state(JSObject::cast(obj));
2874
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002875 // Handling of script id generation is in FACTORY->NewScript.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002876 set_last_script_id(undefined_value());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002877
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002878 // Initialize keyed lookup cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002879 isolate_->keyed_lookup_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002880
2881 // Initialize context slot cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002882 isolate_->context_slot_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002883
2884 // Initialize descriptor cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002885 isolate_->descriptor_lookup_cache()->Clear();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002886
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002887 // Initialize compilation cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002888 isolate_->compilation_cache()->Clear();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002889
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002890 return true;
2891}
2892
2893
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002894bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) {
2895 RootListIndex writable_roots[] = {
2896 kStoreBufferTopRootIndex,
2897 kStackLimitRootIndex,
2898 kInstanceofCacheFunctionRootIndex,
2899 kInstanceofCacheMapRootIndex,
2900 kInstanceofCacheAnswerRootIndex,
2901 kCodeStubsRootIndex,
2902 kNonMonomorphicCacheRootIndex,
2903 kPolymorphicCodeCacheRootIndex,
2904 kLastScriptIdRootIndex,
2905 kEmptyScriptRootIndex,
2906 kRealStackLimitRootIndex,
2907 kArgumentsAdaptorDeoptPCOffsetRootIndex,
2908 kConstructStubDeoptPCOffsetRootIndex,
2909 kGetterStubDeoptPCOffsetRootIndex,
2910 kSetterStubDeoptPCOffsetRootIndex,
2911 kSymbolTableRootIndex,
2912 };
2913
2914 for (unsigned int i = 0; i < ARRAY_SIZE(writable_roots); i++) {
2915 if (root_index == writable_roots[i])
2916 return true;
2917 }
2918 return false;
2919}
2920
2921
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002922Object* RegExpResultsCache::Lookup(Heap* heap,
2923 String* key_string,
2924 Object* key_pattern,
2925 ResultsCacheType type) {
2926 FixedArray* cache;
2927 if (!key_string->IsSymbol()) return Smi::FromInt(0);
2928 if (type == STRING_SPLIT_SUBSTRINGS) {
2929 ASSERT(key_pattern->IsString());
2930 if (!key_pattern->IsSymbol()) return Smi::FromInt(0);
2931 cache = heap->string_split_cache();
2932 } else {
2933 ASSERT(type == REGEXP_MULTIPLE_INDICES);
2934 ASSERT(key_pattern->IsFixedArray());
2935 cache = heap->regexp_multiple_cache();
2936 }
2937
2938 uint32_t hash = key_string->Hash();
2939 uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) &
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002940 ~(kArrayEntriesPerCacheEntry - 1));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002941 if (cache->get(index + kStringOffset) == key_string &&
2942 cache->get(index + kPatternOffset) == key_pattern) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002943 return cache->get(index + kArrayOffset);
2944 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002945 index =
2946 ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1));
2947 if (cache->get(index + kStringOffset) == key_string &&
2948 cache->get(index + kPatternOffset) == key_pattern) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002949 return cache->get(index + kArrayOffset);
2950 }
2951 return Smi::FromInt(0);
2952}
2953
2954
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002955void RegExpResultsCache::Enter(Heap* heap,
2956 String* key_string,
2957 Object* key_pattern,
2958 FixedArray* value_array,
2959 ResultsCacheType type) {
2960 FixedArray* cache;
2961 if (!key_string->IsSymbol()) return;
2962 if (type == STRING_SPLIT_SUBSTRINGS) {
2963 ASSERT(key_pattern->IsString());
2964 if (!key_pattern->IsSymbol()) return;
2965 cache = heap->string_split_cache();
2966 } else {
2967 ASSERT(type == REGEXP_MULTIPLE_INDICES);
2968 ASSERT(key_pattern->IsFixedArray());
2969 cache = heap->regexp_multiple_cache();
2970 }
2971
2972 uint32_t hash = key_string->Hash();
2973 uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) &
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002974 ~(kArrayEntriesPerCacheEntry - 1));
2975 if (cache->get(index + kStringOffset) == Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002976 cache->set(index + kStringOffset, key_string);
2977 cache->set(index + kPatternOffset, key_pattern);
2978 cache->set(index + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002979 } else {
2980 uint32_t index2 =
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002981 ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1));
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002982 if (cache->get(index2 + kStringOffset) == Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002983 cache->set(index2 + kStringOffset, key_string);
2984 cache->set(index2 + kPatternOffset, key_pattern);
2985 cache->set(index2 + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002986 } else {
2987 cache->set(index2 + kStringOffset, Smi::FromInt(0));
2988 cache->set(index2 + kPatternOffset, Smi::FromInt(0));
2989 cache->set(index2 + kArrayOffset, Smi::FromInt(0));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002990 cache->set(index + kStringOffset, key_string);
2991 cache->set(index + kPatternOffset, key_pattern);
2992 cache->set(index + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002993 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002994 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002995 // If the array is a reasonably short list of substrings, convert it into a
2996 // list of symbols.
2997 if (type == STRING_SPLIT_SUBSTRINGS && value_array->length() < 100) {
2998 for (int i = 0; i < value_array->length(); i++) {
2999 String* str = String::cast(value_array->get(i));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003000 Object* symbol;
3001 MaybeObject* maybe_symbol = heap->LookupSymbol(str);
3002 if (maybe_symbol->ToObject(&symbol)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003003 value_array->set(i, symbol);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003004 }
3005 }
3006 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003007 // Convert backing store to a copy-on-write array.
3008 value_array->set_map_no_write_barrier(heap->fixed_cow_array_map());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003009}
3010
3011
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003012void RegExpResultsCache::Clear(FixedArray* cache) {
3013 for (int i = 0; i < kRegExpResultsCacheSize; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003014 cache->set(i, Smi::FromInt(0));
3015 }
3016}
3017
3018
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003019MaybeObject* Heap::AllocateInitialNumberStringCache() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003020 MaybeObject* maybe_obj =
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003021 AllocateFixedArray(kInitialNumberStringCacheSize * 2, TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003022 return maybe_obj;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003023}
3024
3025
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003026int Heap::FullSizeNumberStringCacheLength() {
3027 // Compute the size of the number string cache based on the max newspace size.
3028 // The number string cache has a minimum size based on twice the initial cache
3029 // size to ensure that it is bigger after being made 'full size'.
3030 int number_string_cache_size = max_semispace_size_ / 512;
3031 number_string_cache_size = Max(kInitialNumberStringCacheSize * 2,
3032 Min(0x4000, number_string_cache_size));
3033 // There is a string and a number per entry so the length is twice the number
3034 // of entries.
3035 return number_string_cache_size * 2;
3036}
3037
3038
3039void Heap::AllocateFullSizeNumberStringCache() {
3040 // The idea is to have a small number string cache in the snapshot to keep
3041 // boot-time memory usage down. If we expand the number string cache already
3042 // while creating the snapshot then that didn't work out.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003043 ASSERT(!Serializer::enabled() || FLAG_extra_code != NULL);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003044 MaybeObject* maybe_obj =
3045 AllocateFixedArray(FullSizeNumberStringCacheLength(), TENURED);
3046 Object* new_cache;
3047 if (maybe_obj->ToObject(&new_cache)) {
3048 // We don't bother to repopulate the cache with entries from the old cache.
3049 // It will be repopulated soon enough with new strings.
3050 set_number_string_cache(FixedArray::cast(new_cache));
3051 }
3052 // If allocation fails then we just return without doing anything. It is only
3053 // a cache, so best effort is OK here.
3054}
3055
3056
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003057void Heap::FlushNumberStringCache() {
3058 // Flush the number to string cache.
3059 int len = number_string_cache()->length();
3060 for (int i = 0; i < len; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003061 number_string_cache()->set_undefined(this, i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003062 }
3063}
3064
3065
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003066static inline int double_get_hash(double d) {
3067 DoubleRepresentation rep(d);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003068 return static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003069}
3070
3071
3072static inline int smi_get_hash(Smi* smi) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003073 return smi->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003074}
3075
3076
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003077Object* Heap::GetNumberStringCache(Object* number) {
3078 int hash;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003079 int mask = (number_string_cache()->length() >> 1) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003080 if (number->IsSmi()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003081 hash = smi_get_hash(Smi::cast(number)) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003082 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003083 hash = double_get_hash(number->Number()) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003084 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003085 Object* key = number_string_cache()->get(hash * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003086 if (key == number) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003087 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003088 } else if (key->IsHeapNumber() &&
3089 number->IsHeapNumber() &&
3090 key->Number() == number->Number()) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003091 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003092 }
3093 return undefined_value();
3094}
3095
3096
3097void Heap::SetNumberStringCache(Object* number, String* string) {
3098 int hash;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003099 int mask = (number_string_cache()->length() >> 1) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003100 if (number->IsSmi()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003101 hash = smi_get_hash(Smi::cast(number)) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003102 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003103 hash = double_get_hash(number->Number()) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003104 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003105 if (number_string_cache()->get(hash * 2) != undefined_value() &&
3106 number_string_cache()->length() != FullSizeNumberStringCacheLength()) {
3107 // The first time we have a hash collision, we move to the full sized
3108 // number string cache.
3109 AllocateFullSizeNumberStringCache();
3110 return;
3111 }
3112 number_string_cache()->set(hash * 2, number);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003113 number_string_cache()->set(hash * 2 + 1, string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003114}
3115
3116
lrn@chromium.org303ada72010-10-27 09:33:13 +00003117MaybeObject* Heap::NumberToString(Object* number,
3118 bool check_number_string_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003119 isolate_->counters()->number_to_string_runtime()->Increment();
ager@chromium.org357bf652010-04-12 11:30:10 +00003120 if (check_number_string_cache) {
3121 Object* cached = GetNumberStringCache(number);
3122 if (cached != undefined_value()) {
3123 return cached;
3124 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003125 }
3126
3127 char arr[100];
3128 Vector<char> buffer(arr, ARRAY_SIZE(arr));
3129 const char* str;
3130 if (number->IsSmi()) {
3131 int num = Smi::cast(number)->value();
3132 str = IntToCString(num, buffer);
3133 } else {
3134 double num = HeapNumber::cast(number)->value();
3135 str = DoubleToCString(num, buffer);
3136 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003137
lrn@chromium.org303ada72010-10-27 09:33:13 +00003138 Object* js_string;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003139 MaybeObject* maybe_js_string = AllocateStringFromOneByte(CStrVector(str));
lrn@chromium.org303ada72010-10-27 09:33:13 +00003140 if (maybe_js_string->ToObject(&js_string)) {
3141 SetNumberStringCache(number, String::cast(js_string));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003142 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00003143 return maybe_js_string;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003144}
3145
3146
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003147MaybeObject* Heap::Uint32ToString(uint32_t value,
3148 bool check_number_string_cache) {
3149 Object* number;
3150 MaybeObject* maybe = NumberFromUint32(value);
3151 if (!maybe->To<Object>(&number)) return maybe;
3152 return NumberToString(number, check_number_string_cache);
3153}
3154
3155
ager@chromium.org3811b432009-10-28 14:53:37 +00003156Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) {
3157 return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]);
3158}
3159
3160
3161Heap::RootListIndex Heap::RootIndexForExternalArrayType(
3162 ExternalArrayType array_type) {
3163 switch (array_type) {
3164 case kExternalByteArray:
3165 return kExternalByteArrayMapRootIndex;
3166 case kExternalUnsignedByteArray:
3167 return kExternalUnsignedByteArrayMapRootIndex;
3168 case kExternalShortArray:
3169 return kExternalShortArrayMapRootIndex;
3170 case kExternalUnsignedShortArray:
3171 return kExternalUnsignedShortArrayMapRootIndex;
3172 case kExternalIntArray:
3173 return kExternalIntArrayMapRootIndex;
3174 case kExternalUnsignedIntArray:
3175 return kExternalUnsignedIntArrayMapRootIndex;
3176 case kExternalFloatArray:
3177 return kExternalFloatArrayMapRootIndex;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003178 case kExternalDoubleArray:
3179 return kExternalDoubleArrayMapRootIndex;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003180 case kExternalPixelArray:
3181 return kExternalPixelArrayMapRootIndex;
ager@chromium.org3811b432009-10-28 14:53:37 +00003182 default:
3183 UNREACHABLE();
3184 return kUndefinedValueRootIndex;
3185 }
3186}
3187
3188
lrn@chromium.org303ada72010-10-27 09:33:13 +00003189MaybeObject* Heap::NumberFromDouble(double value, PretenureFlag pretenure) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003190 // We need to distinguish the minus zero value and this cannot be
3191 // done after conversion to int. Doing this by comparing bit
3192 // patterns is faster than using fpclassify() et al.
3193 static const DoubleRepresentation minus_zero(-0.0);
3194
3195 DoubleRepresentation rep(value);
3196 if (rep.bits == minus_zero.bits) {
3197 return AllocateHeapNumber(-0.0, pretenure);
3198 }
3199
3200 int int_value = FastD2I(value);
3201 if (value == int_value && Smi::IsValid(int_value)) {
3202 return Smi::FromInt(int_value);
3203 }
3204
3205 // Materialize the value in the heap.
3206 return AllocateHeapNumber(value, pretenure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003207}
3208
3209
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003210MaybeObject* Heap::AllocateForeign(Address address, PretenureFlag pretenure) {
3211 // Statically ensure that it is safe to allocate foreigns in paged spaces.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003212 STATIC_ASSERT(Foreign::kSize <= Page::kMaxNonCodeHeapObjectSize);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003213 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003214 Foreign* result;
3215 MaybeObject* maybe_result = Allocate(foreign_map(), space);
3216 if (!maybe_result->To(&result)) return maybe_result;
3217 result->set_foreign_address(address);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003218 return result;
3219}
3220
3221
lrn@chromium.org303ada72010-10-27 09:33:13 +00003222MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003223 SharedFunctionInfo* share;
3224 MaybeObject* maybe = Allocate(shared_function_info_map(), OLD_POINTER_SPACE);
3225 if (!maybe->To<SharedFunctionInfo>(&share)) return maybe;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003226
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003227 // Set pointer fields.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003228 share->set_name(name);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003229 Code* illegal = isolate_->builtins()->builtin(Builtins::kIllegal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003230 share->set_code(illegal);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003231 share->ClearOptimizedCodeMap();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003232 share->set_scope_info(ScopeInfo::Empty());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003233 Code* construct_stub =
3234 isolate_->builtins()->builtin(Builtins::kJSConstructStubGeneric);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003235 share->set_construct_stub(construct_stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003236 share->set_instance_class_name(Object_symbol());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003237 share->set_function_data(undefined_value(), SKIP_WRITE_BARRIER);
3238 share->set_script(undefined_value(), SKIP_WRITE_BARRIER);
3239 share->set_debug_info(undefined_value(), SKIP_WRITE_BARRIER);
3240 share->set_inferred_name(empty_string(), SKIP_WRITE_BARRIER);
3241 share->set_initial_map(undefined_value(), SKIP_WRITE_BARRIER);
3242 share->set_this_property_assignments(undefined_value(), SKIP_WRITE_BARRIER);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003243 share->set_ast_node_count(0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003244 share->set_stress_deopt_counter(FLAG_deopt_every_n_times);
3245 share->set_counters(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003246
3247 // Set integer fields (smi or int, depending on the architecture).
3248 share->set_length(0);
3249 share->set_formal_parameter_count(0);
3250 share->set_expected_nof_properties(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003251 share->set_num_literals(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003252 share->set_start_position_and_type(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003253 share->set_end_position(0);
3254 share->set_function_token_position(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003255 // All compiler hints default to false or 0.
3256 share->set_compiler_hints(0);
3257 share->set_this_property_assignments_count(0);
3258 share->set_opt_count(0);
3259
3260 return share;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003261}
3262
3263
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003264MaybeObject* Heap::AllocateJSMessageObject(String* type,
3265 JSArray* arguments,
3266 int start_position,
3267 int end_position,
3268 Object* script,
3269 Object* stack_trace,
3270 Object* stack_frames) {
3271 Object* result;
3272 { MaybeObject* maybe_result = Allocate(message_object_map(), NEW_SPACE);
3273 if (!maybe_result->ToObject(&result)) return maybe_result;
3274 }
3275 JSMessageObject* message = JSMessageObject::cast(result);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003276 message->set_properties(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003277 message->initialize_elements();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003278 message->set_elements(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003279 message->set_type(type);
3280 message->set_arguments(arguments);
3281 message->set_start_position(start_position);
3282 message->set_end_position(end_position);
3283 message->set_script(script);
3284 message->set_stack_trace(stack_trace);
3285 message->set_stack_frames(stack_frames);
3286 return result;
3287}
3288
3289
3290
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003291// Returns true for a character in a range. Both limits are inclusive.
3292static inline bool Between(uint32_t character, uint32_t from, uint32_t to) {
3293 // This makes uses of the the unsigned wraparound.
3294 return character - from <= to - from;
3295}
3296
3297
lrn@chromium.org303ada72010-10-27 09:33:13 +00003298MUST_USE_RESULT static inline MaybeObject* MakeOrFindTwoCharacterString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003299 Heap* heap,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003300 uint32_t c1,
3301 uint32_t c2) {
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003302 String* symbol;
3303 // Numeric strings have a different hash algorithm not known by
3304 // LookupTwoCharsSymbolIfExists, so we skip this step for such strings.
3305 if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003306 heap->symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) {
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003307 return symbol;
3308 // Now we know the length is 2, we might as well make use of that fact
3309 // when building the new string.
3310 } else if ((c1 | c2) <= String::kMaxAsciiCharCodeU) { // We can do this
3311 ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1)); // because of this.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003312 Object* result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003313 { MaybeObject* maybe_result = heap->AllocateRawOneByteString(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003314 if (!maybe_result->ToObject(&result)) return maybe_result;
3315 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003316 char* dest = SeqOneByteString::cast(result)->GetChars();
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003317 dest[0] = c1;
3318 dest[1] = c2;
3319 return result;
3320 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003321 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003322 { MaybeObject* maybe_result = heap->AllocateRawTwoByteString(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003323 if (!maybe_result->ToObject(&result)) return maybe_result;
3324 }
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003325 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
3326 dest[0] = c1;
3327 dest[1] = c2;
3328 return result;
3329 }
3330}
3331
3332
lrn@chromium.org303ada72010-10-27 09:33:13 +00003333MaybeObject* Heap::AllocateConsString(String* first, String* second) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003334 int first_length = first->length();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003335 if (first_length == 0) {
3336 return second;
3337 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003338
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003339 int second_length = second->length();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003340 if (second_length == 0) {
3341 return first;
3342 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003343
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003344 int length = first_length + second_length;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003345
3346 // Optimization for 2-byte strings often used as keys in a decompression
3347 // dictionary. Check whether we already have the string in the symbol
3348 // table to prevent creation of many unneccesary strings.
3349 if (length == 2) {
3350 unsigned c1 = first->Get(0);
3351 unsigned c2 = second->Get(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003352 return MakeOrFindTwoCharacterString(this, c1, c2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003353 }
3354
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003355 bool first_is_ascii = first->IsOneByteRepresentation();
3356 bool second_is_ascii = second->IsOneByteRepresentation();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003357 bool is_ascii = first_is_ascii && second_is_ascii;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003358
ager@chromium.org3e875802009-06-29 08:26:34 +00003359 // Make sure that an out of memory exception is thrown if the length
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003360 // of the new cons string is too large.
3361 if (length > String::kMaxLength || length < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003362 isolate()->context()->mark_out_of_memory();
ager@chromium.org3e875802009-06-29 08:26:34 +00003363 return Failure::OutOfMemoryException();
3364 }
3365
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003366 bool is_ascii_data_in_two_byte_string = false;
3367 if (!is_ascii) {
3368 // At least one of the strings uses two-byte representation so we
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003369 // can't use the fast case code for short ASCII strings below, but
3370 // we can try to save memory if all chars actually fit in ASCII.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003371 is_ascii_data_in_two_byte_string =
3372 first->HasOnlyAsciiChars() && second->HasOnlyAsciiChars();
3373 if (is_ascii_data_in_two_byte_string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003374 isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003375 }
3376 }
3377
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003378 // If the resulting string is small make a flat string.
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003379 if (length < ConsString::kMinLength) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003380 // Note that neither of the two inputs can be a slice because:
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003381 STATIC_ASSERT(ConsString::kMinLength <= SlicedString::kMinLength);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003382 ASSERT(first->IsFlat());
3383 ASSERT(second->IsFlat());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003384 if (is_ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003385 Object* result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003386 { MaybeObject* maybe_result = AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003387 if (!maybe_result->ToObject(&result)) return maybe_result;
3388 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003389 // Copy the characters into the new object.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003390 char* dest = SeqOneByteString::cast(result)->GetChars();
ager@chromium.org3e875802009-06-29 08:26:34 +00003391 // Copy first part.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003392 const char* src;
3393 if (first->IsExternalString()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003394 src = ExternalAsciiString::cast(first)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003395 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003396 src = SeqOneByteString::cast(first)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003397 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003398 for (int i = 0; i < first_length; i++) *dest++ = src[i];
3399 // Copy second part.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003400 if (second->IsExternalString()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003401 src = ExternalAsciiString::cast(second)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003402 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003403 src = SeqOneByteString::cast(second)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003404 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003405 for (int i = 0; i < second_length; i++) *dest++ = src[i];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003406 return result;
3407 } else {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003408 if (is_ascii_data_in_two_byte_string) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003409 Object* result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003410 { MaybeObject* maybe_result = AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003411 if (!maybe_result->ToObject(&result)) return maybe_result;
3412 }
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003413 // Copy the characters into the new object.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003414 char* dest = SeqOneByteString::cast(result)->GetChars();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003415 String::WriteToFlat(first, dest, 0, first_length);
3416 String::WriteToFlat(second, dest + first_length, 0, second_length);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003417 isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003418 return result;
3419 }
3420
lrn@chromium.org303ada72010-10-27 09:33:13 +00003421 Object* result;
3422 { MaybeObject* maybe_result = AllocateRawTwoByteString(length);
3423 if (!maybe_result->ToObject(&result)) return maybe_result;
3424 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003425 // Copy the characters into the new object.
3426 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003427 String::WriteToFlat(first, dest, 0, first_length);
3428 String::WriteToFlat(second, dest + first_length, 0, second_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003429 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003430 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003431 }
3432
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003433 Map* map = (is_ascii || is_ascii_data_in_two_byte_string) ?
3434 cons_ascii_string_map() : cons_string_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003435
lrn@chromium.org303ada72010-10-27 09:33:13 +00003436 Object* result;
3437 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3438 if (!maybe_result->ToObject(&result)) return maybe_result;
3439 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003440
3441 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003442 ConsString* cons_string = ConsString::cast(result);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003443 WriteBarrierMode mode = cons_string->GetWriteBarrierMode(no_gc);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003444 cons_string->set_length(length);
3445 cons_string->set_hash_field(String::kEmptyHashField);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003446 cons_string->set_first(first, mode);
3447 cons_string->set_second(second, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003448 return result;
3449}
3450
3451
lrn@chromium.org303ada72010-10-27 09:33:13 +00003452MaybeObject* Heap::AllocateSubString(String* buffer,
ager@chromium.org04921a82011-06-27 13:21:41 +00003453 int start,
3454 int end,
3455 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003456 int length = end - start;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003457 if (length <= 0) {
ager@chromium.org04921a82011-06-27 13:21:41 +00003458 return empty_string();
3459 } else if (length == 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003460 return LookupSingleCharacterStringFromCode(buffer->Get(start));
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003461 } else if (length == 2) {
3462 // Optimization for 2-byte strings often used as keys in a decompression
3463 // dictionary. Check whether we already have the string in the symbol
3464 // table to prevent creation of many unneccesary strings.
3465 unsigned c1 = buffer->Get(start);
3466 unsigned c2 = buffer->Get(start + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003467 return MakeOrFindTwoCharacterString(this, c1, c2);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003468 }
3469
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003470 // Make an attempt to flatten the buffer to reduce access time.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003471 buffer = buffer->TryFlattenGetString();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003472
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003473 if (!FLAG_string_slices ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003474 !buffer->IsFlat() ||
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003475 length < SlicedString::kMinLength ||
3476 pretenure == TENURED) {
3477 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003478 // WriteToFlat takes care of the case when an indirect string has a
3479 // different encoding from its underlying string. These encodings may
3480 // differ because of externalization.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003481 bool is_ascii = buffer->IsOneByteRepresentation();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003482 { MaybeObject* maybe_result = is_ascii
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003483 ? AllocateRawOneByteString(length, pretenure)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003484 : AllocateRawTwoByteString(length, pretenure);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003485 if (!maybe_result->ToObject(&result)) return maybe_result;
3486 }
3487 String* string_result = String::cast(result);
3488 // Copy the characters into the new object.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003489 if (is_ascii) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003490 ASSERT(string_result->IsOneByteRepresentation());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003491 char* dest = SeqOneByteString::cast(string_result)->GetChars();
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003492 String::WriteToFlat(buffer, dest, start, end);
3493 } else {
3494 ASSERT(string_result->IsTwoByteRepresentation());
3495 uc16* dest = SeqTwoByteString::cast(string_result)->GetChars();
3496 String::WriteToFlat(buffer, dest, start, end);
3497 }
3498 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003499 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003500
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003501 ASSERT(buffer->IsFlat());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003502#if VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003503 if (FLAG_verify_heap) {
3504 buffer->StringVerify();
3505 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003506#endif
3507
3508 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003509 // When slicing an indirect string we use its encoding for a newly created
3510 // slice and don't check the encoding of the underlying string. This is safe
3511 // even if the encodings are different because of externalization. If an
3512 // indirect ASCII string is pointing to a two-byte string, the two-byte char
3513 // codes of the underlying string must still fit into ASCII (because
3514 // externalization must not change char codes).
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003515 { Map* map = buffer->IsOneByteRepresentation()
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003516 ? sliced_ascii_string_map()
3517 : sliced_string_map();
3518 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3519 if (!maybe_result->ToObject(&result)) return maybe_result;
3520 }
3521
3522 AssertNoAllocation no_gc;
3523 SlicedString* sliced_string = SlicedString::cast(result);
3524 sliced_string->set_length(length);
3525 sliced_string->set_hash_field(String::kEmptyHashField);
3526 if (buffer->IsConsString()) {
3527 ConsString* cons = ConsString::cast(buffer);
3528 ASSERT(cons->second()->length() == 0);
3529 sliced_string->set_parent(cons->first());
3530 sliced_string->set_offset(start);
3531 } else if (buffer->IsSlicedString()) {
3532 // Prevent nesting sliced strings.
3533 SlicedString* parent_slice = SlicedString::cast(buffer);
3534 sliced_string->set_parent(parent_slice->parent());
3535 sliced_string->set_offset(start + parent_slice->offset());
3536 } else {
3537 sliced_string->set_parent(buffer);
3538 sliced_string->set_offset(start);
3539 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003540 ASSERT(sliced_string->parent()->IsSeqString() ||
3541 sliced_string->parent()->IsExternalString());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003542 return result;
3543}
3544
3545
lrn@chromium.org303ada72010-10-27 09:33:13 +00003546MaybeObject* Heap::AllocateExternalStringFromAscii(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003547 const ExternalAsciiString::Resource* resource) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003548 size_t length = resource->length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003549 if (length > static_cast<size_t>(String::kMaxLength)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003550 isolate()->context()->mark_out_of_memory();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003551 return Failure::OutOfMemoryException();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003552 }
3553
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00003554 ASSERT(String::IsAscii(resource->data(), static_cast<int>(length)));
3555
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003556 Map* map = external_ascii_string_map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003557 Object* result;
3558 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3559 if (!maybe_result->ToObject(&result)) return maybe_result;
3560 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003561
3562 ExternalAsciiString* external_string = ExternalAsciiString::cast(result);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003563 external_string->set_length(static_cast<int>(length));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003564 external_string->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003565 external_string->set_resource(resource);
3566
3567 return result;
3568}
3569
3570
lrn@chromium.org303ada72010-10-27 09:33:13 +00003571MaybeObject* Heap::AllocateExternalStringFromTwoByte(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003572 const ExternalTwoByteString::Resource* resource) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003573 size_t length = resource->length();
3574 if (length > static_cast<size_t>(String::kMaxLength)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003575 isolate()->context()->mark_out_of_memory();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003576 return Failure::OutOfMemoryException();
3577 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003578
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003579 // For small strings we check whether the resource contains only
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003580 // ASCII characters. If yes, we use a different string map.
3581 static const size_t kAsciiCheckLengthLimit = 32;
3582 bool is_ascii = length <= kAsciiCheckLengthLimit &&
3583 String::IsAscii(resource->data(), static_cast<int>(length));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003584 Map* map = is_ascii ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003585 external_string_with_ascii_data_map() : external_string_map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003586 Object* result;
3587 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3588 if (!maybe_result->ToObject(&result)) return maybe_result;
3589 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003590
3591 ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003592 external_string->set_length(static_cast<int>(length));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003593 external_string->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003594 external_string->set_resource(resource);
3595
3596 return result;
3597}
3598
3599
lrn@chromium.org303ada72010-10-27 09:33:13 +00003600MaybeObject* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003601 if (code <= String::kMaxAsciiCharCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003602 Object* value = single_character_string_cache()->get(code);
3603 if (value != undefined_value()) return value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003604
3605 char buffer[1];
3606 buffer[0] = static_cast<char>(code);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003607 Object* result;
3608 MaybeObject* maybe_result = LookupSymbol(Vector<const char>(buffer, 1));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003609
lrn@chromium.org303ada72010-10-27 09:33:13 +00003610 if (!maybe_result->ToObject(&result)) return maybe_result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003611 single_character_string_cache()->set(code, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003612 return result;
3613 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003614
lrn@chromium.org303ada72010-10-27 09:33:13 +00003615 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003616 { MaybeObject* maybe_result = AllocateRawTwoByteString(1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003617 if (!maybe_result->ToObject(&result)) return maybe_result;
3618 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00003619 String* answer = String::cast(result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003620 answer->Set(0, code);
ager@chromium.org870a0b62008-11-04 11:43:05 +00003621 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622}
3623
3624
lrn@chromium.org303ada72010-10-27 09:33:13 +00003625MaybeObject* Heap::AllocateByteArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003626 if (length < 0 || length > ByteArray::kMaxLength) {
3627 return Failure::OutOfMemoryException();
3628 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003629 if (pretenure == NOT_TENURED) {
3630 return AllocateByteArray(length);
3631 }
3632 int size = ByteArray::SizeFor(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003633 Object* result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003634 { MaybeObject* maybe_result = (size <= Page::kMaxNonCodeHeapObjectSize)
lrn@chromium.org303ada72010-10-27 09:33:13 +00003635 ? old_data_space_->AllocateRaw(size)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003636 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003637 if (!maybe_result->ToObject(&result)) return maybe_result;
3638 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003639
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003640 reinterpret_cast<ByteArray*>(result)->set_map_no_write_barrier(
3641 byte_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003642 reinterpret_cast<ByteArray*>(result)->set_length(length);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003643 return result;
3644}
3645
3646
lrn@chromium.org303ada72010-10-27 09:33:13 +00003647MaybeObject* Heap::AllocateByteArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003648 if (length < 0 || length > ByteArray::kMaxLength) {
3649 return Failure::OutOfMemoryException();
3650 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003651 int size = ByteArray::SizeFor(length);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003652 AllocationSpace space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003653 (size > Page::kMaxNonCodeHeapObjectSize) ? LO_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003654 Object* result;
3655 { MaybeObject* maybe_result = AllocateRaw(size, space, OLD_DATA_SPACE);
3656 if (!maybe_result->ToObject(&result)) return maybe_result;
3657 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003658
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003659 reinterpret_cast<ByteArray*>(result)->set_map_no_write_barrier(
3660 byte_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003661 reinterpret_cast<ByteArray*>(result)->set_length(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003662 return result;
3663}
3664
3665
ager@chromium.org6f10e412009-02-13 10:11:16 +00003666void Heap::CreateFillerObjectAt(Address addr, int size) {
3667 if (size == 0) return;
3668 HeapObject* filler = HeapObject::FromAddress(addr);
3669 if (size == kPointerSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003670 filler->set_map_no_write_barrier(one_pointer_filler_map());
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00003671 } else if (size == 2 * kPointerSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003672 filler->set_map_no_write_barrier(two_pointer_filler_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +00003673 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003674 filler->set_map_no_write_barrier(free_space_map());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003675 FreeSpace::cast(filler)->set_size(size);
ager@chromium.org6f10e412009-02-13 10:11:16 +00003676 }
3677}
3678
3679
lrn@chromium.org303ada72010-10-27 09:33:13 +00003680MaybeObject* Heap::AllocateExternalArray(int length,
3681 ExternalArrayType array_type,
3682 void* external_pointer,
3683 PretenureFlag pretenure) {
ager@chromium.org3811b432009-10-28 14:53:37 +00003684 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003685 Object* result;
3686 { MaybeObject* maybe_result = AllocateRaw(ExternalArray::kAlignedSize,
3687 space,
3688 OLD_DATA_SPACE);
3689 if (!maybe_result->ToObject(&result)) return maybe_result;
3690 }
ager@chromium.org3811b432009-10-28 14:53:37 +00003691
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003692 reinterpret_cast<ExternalArray*>(result)->set_map_no_write_barrier(
ager@chromium.org3811b432009-10-28 14:53:37 +00003693 MapForExternalArrayType(array_type));
3694 reinterpret_cast<ExternalArray*>(result)->set_length(length);
3695 reinterpret_cast<ExternalArray*>(result)->set_external_pointer(
3696 external_pointer);
3697
3698 return result;
3699}
3700
3701
lrn@chromium.org303ada72010-10-27 09:33:13 +00003702MaybeObject* Heap::CreateCode(const CodeDesc& desc,
3703 Code::Flags flags,
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003704 Handle<Object> self_reference,
3705 bool immovable) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003706 // Allocate ByteArray before the Code object, so that we do not risk
3707 // leaving uninitialized Code object (and breaking the heap).
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003708 ByteArray* reloc_info;
3709 MaybeObject* maybe_reloc_info = AllocateByteArray(desc.reloc_size, TENURED);
3710 if (!maybe_reloc_info->To(&reloc_info)) return maybe_reloc_info;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003711
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003712 // Compute size.
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003713 int body_size = RoundUp(desc.instr_size, kObjectAlignment);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003714 int obj_size = Code::SizeFor(body_size);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003715 ASSERT(IsAligned(static_cast<intptr_t>(obj_size), kCodeAlignment));
lrn@chromium.org303ada72010-10-27 09:33:13 +00003716 MaybeObject* maybe_result;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003717 // Large code objects and code objects which should stay at a fixed address
3718 // are allocated in large object space.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003719 HeapObject* result;
3720 bool force_lo_space = obj_size > code_space()->AreaSize();
3721 if (force_lo_space) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003722 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003723 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003724 maybe_result = code_space_->AllocateRaw(obj_size);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003725 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003726 if (!maybe_result->To<HeapObject>(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003727
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003728 if (immovable && !force_lo_space &&
3729 // Objects on the first page of each space are never moved.
3730 !code_space_->FirstPage()->Contains(result->address())) {
3731 // Discard the first code allocation, which was on a page where it could be
3732 // moved.
3733 CreateFillerObjectAt(result->address(), obj_size);
3734 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
3735 if (!maybe_result->To<HeapObject>(&result)) return maybe_result;
3736 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003737
3738 // Initialize the object
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003739 result->set_map_no_write_barrier(code_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003740 Code* code = Code::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003741 ASSERT(!isolate_->code_range()->exists() ||
3742 isolate_->code_range()->contains(code->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003743 code->set_instruction_size(desc.instr_size);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003744 code->set_relocation_info(reloc_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003745 code->set_flags(flags);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003746 if (code->is_call_stub() || code->is_keyed_call_stub()) {
3747 code->set_check_type(RECEIVER_MAP_CHECK);
3748 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003749 code->set_deoptimization_data(empty_fixed_array(), SKIP_WRITE_BARRIER);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003750 code->InitializeTypeFeedbackInfoNoWriteBarrier(undefined_value());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003751 code->set_handler_table(empty_fixed_array(), SKIP_WRITE_BARRIER);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00003752 code->set_gc_metadata(Smi::FromInt(0));
danno@chromium.org88aa0582012-03-23 15:11:57 +00003753 code->set_ic_age(global_ic_age_);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003754 code->set_prologue_offset(kPrologueOffsetNotSet);
kasperl@chromium.org061ef742009-02-27 12:16:20 +00003755 // Allow self references to created code object by patching the handle to
3756 // point to the newly allocated Code object.
3757 if (!self_reference.is_null()) {
3758 *(self_reference.location()) = code;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003759 }
3760 // Migrate generated code.
3761 // The generated code can contain Object** values (typically from handles)
3762 // that are dereferenced during the copy to point directly to the actual heap
3763 // objects. These pointers can include references to the code object itself,
3764 // through the self_reference parameter.
3765 code->CopyFrom(desc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003766
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003767#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003768 if (FLAG_verify_heap) {
3769 code->Verify();
3770 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003771#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003772 return code;
3773}
3774
3775
lrn@chromium.org303ada72010-10-27 09:33:13 +00003776MaybeObject* Heap::CopyCode(Code* code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003777 // Allocate an object the same size as the code object.
3778 int obj_size = code->Size();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003779 MaybeObject* maybe_result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003780 if (obj_size > code_space()->AreaSize()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003781 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003782 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003783 maybe_result = code_space_->AllocateRaw(obj_size);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003784 }
3785
lrn@chromium.org303ada72010-10-27 09:33:13 +00003786 Object* result;
3787 if (!maybe_result->ToObject(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003788
3789 // Copy code object.
3790 Address old_addr = code->address();
3791 Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003792 CopyBlock(new_addr, old_addr, obj_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003793 // Relocate the copy.
3794 Code* new_code = Code::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003795 ASSERT(!isolate_->code_range()->exists() ||
3796 isolate_->code_range()->contains(code->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003797 new_code->Relocate(new_addr - old_addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003798 return new_code;
3799}
3800
3801
lrn@chromium.org303ada72010-10-27 09:33:13 +00003802MaybeObject* Heap::CopyCode(Code* code, Vector<byte> reloc_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003803 // Allocate ByteArray before the Code object, so that we do not risk
3804 // leaving uninitialized Code object (and breaking the heap).
lrn@chromium.org303ada72010-10-27 09:33:13 +00003805 Object* reloc_info_array;
3806 { MaybeObject* maybe_reloc_info_array =
3807 AllocateByteArray(reloc_info.length(), TENURED);
3808 if (!maybe_reloc_info_array->ToObject(&reloc_info_array)) {
3809 return maybe_reloc_info_array;
3810 }
3811 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003812
3813 int new_body_size = RoundUp(code->instruction_size(), kObjectAlignment);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003814
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003815 int new_obj_size = Code::SizeFor(new_body_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003816
3817 Address old_addr = code->address();
3818
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00003819 size_t relocation_offset =
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003820 static_cast<size_t>(code->instruction_end() - old_addr);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003821
lrn@chromium.org303ada72010-10-27 09:33:13 +00003822 MaybeObject* maybe_result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003823 if (new_obj_size > code_space()->AreaSize()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003824 maybe_result = lo_space_->AllocateRaw(new_obj_size, EXECUTABLE);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003825 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003826 maybe_result = code_space_->AllocateRaw(new_obj_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003827 }
3828
lrn@chromium.org303ada72010-10-27 09:33:13 +00003829 Object* result;
3830 if (!maybe_result->ToObject(&result)) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003831
3832 // Copy code object.
3833 Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
3834
3835 // Copy header and instructions.
3836 memcpy(new_addr, old_addr, relocation_offset);
3837
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003838 Code* new_code = Code::cast(result);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003839 new_code->set_relocation_info(ByteArray::cast(reloc_info_array));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003840
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003841 // Copy patched rinfo.
3842 memcpy(new_code->relocation_start(), reloc_info.start(), reloc_info.length());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003843
3844 // Relocate the copy.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003845 ASSERT(!isolate_->code_range()->exists() ||
3846 isolate_->code_range()->contains(code->address()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003847 new_code->Relocate(new_addr - old_addr);
3848
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003849#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003850 if (FLAG_verify_heap) {
3851 code->Verify();
3852 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003853#endif
3854 return new_code;
3855}
3856
3857
lrn@chromium.org303ada72010-10-27 09:33:13 +00003858MaybeObject* Heap::Allocate(Map* map, AllocationSpace space) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003859 ASSERT(gc_state_ == NOT_IN_GC);
3860 ASSERT(map->instance_type() != MAP_TYPE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003861 // If allocation failures are disallowed, we may allocate in a different
3862 // space when new space is full and the object is not a large object.
3863 AllocationSpace retry_space =
3864 (space != NEW_SPACE) ? space : TargetSpaceId(map->instance_type());
lrn@chromium.org303ada72010-10-27 09:33:13 +00003865 Object* result;
3866 { MaybeObject* maybe_result =
3867 AllocateRaw(map->instance_size(), space, retry_space);
3868 if (!maybe_result->ToObject(&result)) return maybe_result;
3869 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003870 // No need for write barrier since object is white and map is in old space.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003871 HeapObject::cast(result)->set_map_no_write_barrier(map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003872 return result;
3873}
3874
3875
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003876void Heap::InitializeFunction(JSFunction* function,
3877 SharedFunctionInfo* shared,
3878 Object* prototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003879 ASSERT(!prototype->IsMap());
3880 function->initialize_properties();
3881 function->initialize_elements();
3882 function->set_shared(shared);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00003883 function->set_code(shared->code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003884 function->set_prototype_or_initial_map(prototype);
3885 function->set_context(undefined_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003886 function->set_literals_or_bindings(empty_fixed_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003887 function->set_next_function_link(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003888}
3889
3890
lrn@chromium.org303ada72010-10-27 09:33:13 +00003891MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00003892 // Allocate the prototype. Make sure to use the object function
3893 // from the function's context, since the function can be from a
3894 // different context.
3895 JSFunction* object_function =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003896 function->context()->native_context()->object_function();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003897
3898 // Each function prototype gets a copy of the object function map.
3899 // This avoid unwanted sharing of maps between prototypes of different
3900 // constructors.
3901 Map* new_map;
3902 ASSERT(object_function->has_initial_map());
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003903 MaybeObject* maybe_map = object_function->initial_map()->Copy();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003904 if (!maybe_map->To(&new_map)) return maybe_map;
3905
lrn@chromium.org303ada72010-10-27 09:33:13 +00003906 Object* prototype;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003907 MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map);
3908 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
3909
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003910 // When creating the prototype for the function we must set its
3911 // constructor to the function.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003912 MaybeObject* maybe_failure =
3913 JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
3914 constructor_symbol(), function, DONT_ENUM);
3915 if (maybe_failure->IsFailure()) return maybe_failure;
3916
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003917 return prototype;
3918}
3919
3920
lrn@chromium.org303ada72010-10-27 09:33:13 +00003921MaybeObject* Heap::AllocateFunction(Map* function_map,
3922 SharedFunctionInfo* shared,
3923 Object* prototype,
3924 PretenureFlag pretenure) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003925 AllocationSpace space =
3926 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003927 Object* result;
3928 { MaybeObject* maybe_result = Allocate(function_map, space);
3929 if (!maybe_result->ToObject(&result)) return maybe_result;
3930 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003931 InitializeFunction(JSFunction::cast(result), shared, prototype);
3932 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003933}
3934
3935
lrn@chromium.org303ada72010-10-27 09:33:13 +00003936MaybeObject* Heap::AllocateArgumentsObject(Object* callee, int length) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003937 // To get fast allocation and map sharing for arguments objects we
3938 // allocate them based on an arguments boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003939
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003940 JSObject* boilerplate;
3941 int arguments_object_size;
3942 bool strict_mode_callee = callee->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003943 !JSFunction::cast(callee)->shared()->is_classic_mode();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003944 if (strict_mode_callee) {
3945 boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003946 isolate()->context()->native_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003947 strict_mode_arguments_boilerplate();
3948 arguments_object_size = kArgumentsObjectSizeStrict;
3949 } else {
3950 boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003951 isolate()->context()->native_context()->arguments_boilerplate();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003952 arguments_object_size = kArgumentsObjectSize;
3953 }
3954
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003955 // This calls Copy directly rather than using Heap::AllocateRaw so we
3956 // duplicate the check here.
3957 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
3958
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003959 // Check that the size of the boilerplate matches our
3960 // expectations. The ArgumentsAccessStub::GenerateNewObject relies
3961 // on the size being a known constant.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003962 ASSERT(arguments_object_size == boilerplate->map()->instance_size());
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003963
3964 // Do the allocation.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003965 Object* result;
3966 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003967 AllocateRaw(arguments_object_size, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003968 if (!maybe_result->ToObject(&result)) return maybe_result;
3969 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003970
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00003971 // Copy the content. The arguments boilerplate doesn't have any
3972 // fields that point to new space so it's safe to skip the write
3973 // barrier here.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003974 CopyBlock(HeapObject::cast(result)->address(),
3975 boilerplate->address(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003976 JSObject::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003978 // Set the length property.
3979 JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsLengthIndex,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003980 Smi::FromInt(length),
3981 SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003982 // Set the callee property for non-strict mode arguments object only.
3983 if (!strict_mode_callee) {
3984 JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsCalleeIndex,
3985 callee);
3986 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003987
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003988 // Check the state of the object
3989 ASSERT(JSObject::cast(result)->HasFastProperties());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003990 ASSERT(JSObject::cast(result)->HasFastObjectElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003991
3992 return result;
3993}
3994
3995
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00003996static bool HasDuplicates(DescriptorArray* descriptors) {
3997 int count = descriptors->number_of_descriptors();
3998 if (count > 1) {
3999 String* prev_key = descriptors->GetKey(0);
4000 for (int i = 1; i != count; i++) {
4001 String* current_key = descriptors->GetKey(i);
4002 if (prev_key == current_key) return true;
4003 prev_key = current_key;
4004 }
4005 }
4006 return false;
4007}
4008
4009
lrn@chromium.org303ada72010-10-27 09:33:13 +00004010MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004011 ASSERT(!fun->has_initial_map());
4012
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004013 // First create a new map with the size and number of in-object properties
4014 // suggested by the function.
4015 int instance_size = fun->shared()->CalculateInstanceSize();
4016 int in_object_properties = fun->shared()->CalculateInObjectProperties();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004017 Map* map;
4018 MaybeObject* maybe_map = AllocateMap(JS_OBJECT_TYPE, instance_size);
4019 if (!maybe_map->To(&map)) return maybe_map;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004020
4021 // Fetch or allocate prototype.
4022 Object* prototype;
4023 if (fun->has_instance_prototype()) {
4024 prototype = fun->instance_prototype();
4025 } else {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004026 MaybeObject* maybe_prototype = AllocateFunctionPrototype(fun);
4027 if (!maybe_prototype->To(&prototype)) return maybe_prototype;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004028 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004029 map->set_inobject_properties(in_object_properties);
4030 map->set_unused_property_fields(in_object_properties);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004031 map->set_prototype(prototype);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004032 ASSERT(map->has_fast_object_elements());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004033
ager@chromium.org5c838252010-02-19 08:53:10 +00004034 // If the function has only simple this property assignments add
4035 // field descriptors for these to the initial map as the object
4036 // cannot be constructed without having these properties. Guard by
4037 // the inline_new flag so we only change the map if we generate a
4038 // specialized construct stub.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004039 ASSERT(in_object_properties <= Map::kMaxPreAllocatedPropertyFields);
ager@chromium.org5c838252010-02-19 08:53:10 +00004040 if (fun->shared()->CanGenerateInlineConstructor(prototype)) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004041 int count = fun->shared()->this_property_assignments_count();
4042 if (count > in_object_properties) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004043 // Inline constructor can only handle inobject properties.
4044 fun->shared()->ForbidInlineConstructor();
4045 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004046 DescriptorArray* descriptors;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00004047 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(count);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004048 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
4049
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004050 DescriptorArray::WhitenessWitness witness(descriptors);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004051 for (int i = 0; i < count; i++) {
4052 String* name = fun->shared()->GetThisPropertyAssignmentName(i);
4053 ASSERT(name->IsSymbol());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004054 FieldDescriptor field(name, i, NONE, i + 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004055 descriptors->Set(i, &field, witness);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004056 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004057 descriptors->Sort();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004058
4059 // The descriptors may contain duplicates because the compiler does not
4060 // guarantee the uniqueness of property names (it would have required
4061 // quadratic time). Once the descriptors are sorted we can check for
4062 // duplicates in linear time.
4063 if (HasDuplicates(descriptors)) {
4064 fun->shared()->ForbidInlineConstructor();
4065 } else {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004066 map->InitializeDescriptors(descriptors);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004067 map->set_pre_allocated_property_fields(count);
4068 map->set_unused_property_fields(in_object_properties - count);
4069 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004070 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004071 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004072
4073 fun->shared()->StartInobjectSlackTracking(map);
4074
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075 return map;
4076}
4077
4078
4079void Heap::InitializeJSObjectFromMap(JSObject* obj,
4080 FixedArray* properties,
4081 Map* map) {
4082 obj->set_properties(properties);
4083 obj->initialize_elements();
4084 // TODO(1240798): Initialize the object's body using valid initial values
4085 // according to the object's initial map. For example, if the map's
4086 // instance type is JS_ARRAY_TYPE, the length field should be initialized
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004087 // to a number (e.g. Smi::FromInt(0)) and the elements initialized to a
4088 // fixed array (e.g. Heap::empty_fixed_array()). Currently, the object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004089 // verification code has to cope with (temporarily) invalid objects. See
4090 // for example, JSArray::JSArrayVerify).
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004091 Object* filler;
4092 // We cannot always fill with one_pointer_filler_map because objects
4093 // created from API functions expect their internal fields to be initialized
4094 // with undefined_value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004095 // Pre-allocated fields need to be initialized with undefined_value as well
4096 // so that object accesses before the constructor completes (e.g. in the
4097 // debugger) will not cause a crash.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004098 if (map->constructor()->IsJSFunction() &&
4099 JSFunction::cast(map->constructor())->shared()->
4100 IsInobjectSlackTrackingInProgress()) {
4101 // We might want to shrink the object later.
4102 ASSERT(obj->GetInternalFieldCount() == 0);
4103 filler = Heap::one_pointer_filler_map();
4104 } else {
4105 filler = Heap::undefined_value();
4106 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004107 obj->InitializeBody(map, Heap::undefined_value(), filler);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004108}
4109
4110
lrn@chromium.org303ada72010-10-27 09:33:13 +00004111MaybeObject* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 // JSFunctions should be allocated using AllocateFunction to be
4113 // properly initialized.
4114 ASSERT(map->instance_type() != JS_FUNCTION_TYPE);
4115
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00004116 // Both types of global objects should be allocated using
4117 // AllocateGlobalObject to be properly initialized.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004118 ASSERT(map->instance_type() != JS_GLOBAL_OBJECT_TYPE);
4119 ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE);
4120
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004121 // Allocate the backing storage for the properties.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004122 int prop_size =
4123 map->pre_allocated_property_fields() +
4124 map->unused_property_fields() -
4125 map->inobject_properties();
4126 ASSERT(prop_size >= 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004127 Object* properties;
4128 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, pretenure);
4129 if (!maybe_properties->ToObject(&properties)) return maybe_properties;
4130 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004131
4132 // Allocate the JSObject.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004133 AllocationSpace space =
4134 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004135 if (map->instance_size() > Page::kMaxNonCodeHeapObjectSize) space = LO_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004136 Object* obj;
4137 { MaybeObject* maybe_obj = Allocate(map, space);
4138 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4139 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004140
4141 // Initialize the JSObject.
4142 InitializeJSObjectFromMap(JSObject::cast(obj),
4143 FixedArray::cast(properties),
4144 map);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004145 ASSERT(JSObject::cast(obj)->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004146 return obj;
4147}
4148
4149
lrn@chromium.org303ada72010-10-27 09:33:13 +00004150MaybeObject* Heap::AllocateJSObject(JSFunction* constructor,
4151 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004152 // Allocate the initial map if absent.
4153 if (!constructor->has_initial_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004154 Object* initial_map;
4155 { MaybeObject* maybe_initial_map = AllocateInitialMap(constructor);
4156 if (!maybe_initial_map->ToObject(&initial_map)) return maybe_initial_map;
4157 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004158 constructor->set_initial_map(Map::cast(initial_map));
4159 Map::cast(initial_map)->set_constructor(constructor);
4160 }
4161 // Allocate the object based on the constructors initial map.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004162 MaybeObject* result = AllocateJSObjectFromMap(
4163 constructor->initial_map(), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004164#ifdef DEBUG
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004165 // Make sure result is NOT a global object if valid.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004166 Object* non_failure;
4167 ASSERT(!result->ToObject(&non_failure) || !non_failure->IsGlobalObject());
4168#endif
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004169 return result;
4170}
4171
4172
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004173MaybeObject* Heap::AllocateJSModule(Context* context, ScopeInfo* scope_info) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004174 // Allocate a fresh map. Modules do not have a prototype.
4175 Map* map;
4176 MaybeObject* maybe_map = AllocateMap(JS_MODULE_TYPE, JSModule::kSize);
4177 if (!maybe_map->To(&map)) return maybe_map;
4178 // Allocate the object based on the map.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004179 JSModule* module;
4180 MaybeObject* maybe_module = AllocateJSObjectFromMap(map, TENURED);
4181 if (!maybe_module->To(&module)) return maybe_module;
4182 module->set_context(context);
4183 module->set_scope_info(scope_info);
4184 return module;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004185}
4186
4187
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004188MaybeObject* Heap::AllocateJSArrayAndStorage(
4189 ElementsKind elements_kind,
4190 int length,
4191 int capacity,
4192 ArrayStorageAllocationMode mode,
4193 PretenureFlag pretenure) {
4194 ASSERT(capacity >= length);
4195 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
4196 JSArray* array;
4197 if (!maybe_array->To(&array)) return maybe_array;
4198
4199 if (capacity == 0) {
4200 array->set_length(Smi::FromInt(0));
4201 array->set_elements(empty_fixed_array());
4202 return array;
4203 }
4204
4205 FixedArrayBase* elms;
4206 MaybeObject* maybe_elms = NULL;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004207 if (IsFastDoubleElementsKind(elements_kind)) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004208 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
4209 maybe_elms = AllocateUninitializedFixedDoubleArray(capacity);
4210 } else {
4211 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
4212 maybe_elms = AllocateFixedDoubleArrayWithHoles(capacity);
4213 }
4214 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004215 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004216 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
4217 maybe_elms = AllocateUninitializedFixedArray(capacity);
4218 } else {
4219 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
4220 maybe_elms = AllocateFixedArrayWithHoles(capacity);
4221 }
4222 }
4223 if (!maybe_elms->To(&elms)) return maybe_elms;
4224
4225 array->set_elements(elms);
4226 array->set_length(Smi::FromInt(length));
4227 return array;
4228}
4229
4230
4231MaybeObject* Heap::AllocateJSArrayWithElements(
4232 FixedArrayBase* elements,
4233 ElementsKind elements_kind,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004234 int length,
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004235 PretenureFlag pretenure) {
4236 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
4237 JSArray* array;
4238 if (!maybe_array->To(&array)) return maybe_array;
4239
4240 array->set_elements(elements);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004241 array->set_length(Smi::FromInt(length));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004242 array->ValidateElements();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004243 return array;
4244}
4245
4246
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004247MaybeObject* Heap::AllocateJSProxy(Object* handler, Object* prototype) {
4248 // Allocate map.
4249 // TODO(rossberg): Once we optimize proxies, think about a scheme to share
4250 // maps. Will probably depend on the identity of the handler object, too.
danno@chromium.org40cb8782011-05-25 07:58:50 +00004251 Map* map;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004252 MaybeObject* maybe_map_obj = AllocateMap(JS_PROXY_TYPE, JSProxy::kSize);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004253 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004254 map->set_prototype(prototype);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004255
4256 // Allocate the proxy object.
lrn@chromium.org34e60782011-09-15 07:25:40 +00004257 JSProxy* result;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004258 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004259 if (!maybe_result->To<JSProxy>(&result)) return maybe_result;
4260 result->InitializeBody(map->instance_size(), Smi::FromInt(0));
4261 result->set_handler(handler);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004262 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004263 return result;
4264}
4265
4266
4267MaybeObject* Heap::AllocateJSFunctionProxy(Object* handler,
4268 Object* call_trap,
4269 Object* construct_trap,
4270 Object* prototype) {
4271 // Allocate map.
4272 // TODO(rossberg): Once we optimize proxies, think about a scheme to share
4273 // maps. Will probably depend on the identity of the handler object, too.
4274 Map* map;
4275 MaybeObject* maybe_map_obj =
4276 AllocateMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize);
4277 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
4278 map->set_prototype(prototype);
4279
4280 // Allocate the proxy object.
4281 JSFunctionProxy* result;
4282 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
4283 if (!maybe_result->To<JSFunctionProxy>(&result)) return maybe_result;
4284 result->InitializeBody(map->instance_size(), Smi::FromInt(0));
4285 result->set_handler(handler);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004286 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004287 result->set_call_trap(call_trap);
4288 result->set_construct_trap(construct_trap);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004289 return result;
4290}
4291
4292
lrn@chromium.org303ada72010-10-27 09:33:13 +00004293MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004294 ASSERT(constructor->has_initial_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004295 Map* map = constructor->initial_map();
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004296 ASSERT(map->is_dictionary_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004297
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004298 // Make sure no field properties are described in the initial map.
4299 // This guarantees us that normalizing the properties does not
4300 // require us to change property values to JSGlobalPropertyCells.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004301 ASSERT(map->NextFreePropertyIndex() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004302
4303 // Make sure we don't have a ton of pre-allocated slots in the
4304 // global objects. They will be unused once we normalize the object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004305 ASSERT(map->unused_property_fields() == 0);
4306 ASSERT(map->inobject_properties() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004307
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004308 // Initial size of the backing store to avoid resize of the storage during
4309 // bootstrapping. The size differs between the JS global object ad the
4310 // builtins object.
4311 int initial_size = map->instance_type() == JS_GLOBAL_OBJECT_TYPE ? 64 : 512;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004312
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004313 // Allocate a dictionary object for backing storage.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004314 StringDictionary* dictionary;
4315 MaybeObject* maybe_dictionary =
4316 StringDictionary::Allocate(
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004317 map->NumberOfOwnDescriptors() * 2 + initial_size);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004318 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004319
4320 // The global object might be created from an object template with accessors.
4321 // Fill these accessors into the dictionary.
4322 DescriptorArray* descs = map->instance_descriptors();
4323 for (int i = 0; i < descs->number_of_descriptors(); i++) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004324 PropertyDetails details = descs->GetDetails(i);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004325 ASSERT(details.type() == CALLBACKS); // Only accessors are expected.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004326 PropertyDetails d = PropertyDetails(details.attributes(),
4327 CALLBACKS,
4328 details.descriptor_index());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004329 Object* value = descs->GetCallbacksObject(i);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004330 MaybeObject* maybe_value = AllocateJSGlobalPropertyCell(value);
4331 if (!maybe_value->ToObject(&value)) return maybe_value;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004332
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004333 MaybeObject* maybe_added = dictionary->Add(descs->GetKey(i), value, d);
4334 if (!maybe_added->To(&dictionary)) return maybe_added;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004335 }
4336
4337 // Allocate the global object and initialize it with the backing store.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004338 JSObject* global;
4339 MaybeObject* maybe_global = Allocate(map, OLD_POINTER_SPACE);
4340 if (!maybe_global->To(&global)) return maybe_global;
4341
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004342 InitializeJSObjectFromMap(global, dictionary, map);
4343
4344 // Create a new map for the global object.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004345 Map* new_map;
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004346 MaybeObject* maybe_map = map->CopyDropDescriptors();
4347 if (!maybe_map->To(&new_map)) return maybe_map;
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004348 new_map->set_dictionary_map(true);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004349
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004350 // Set up the global object as a normalized object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004351 global->set_map(new_map);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004352 global->set_properties(dictionary);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004353
4354 // Make sure result is a global object with properties in dictionary.
4355 ASSERT(global->IsGlobalObject());
4356 ASSERT(!global->HasFastProperties());
4357 return global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004358}
4359
4360
lrn@chromium.org303ada72010-10-27 09:33:13 +00004361MaybeObject* Heap::CopyJSObject(JSObject* source) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004362 // Never used to copy functions. If functions need to be copied we
4363 // have to be careful to clear the literals array.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004364 SLOW_ASSERT(!source->IsJSFunction());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004365
4366 // Make the clone.
4367 Map* map = source->map();
4368 int object_size = map->instance_size();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004369 Object* clone;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004370
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004371 WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER;
4372
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004373 // If we're forced to always allocate, we use the general allocation
4374 // functions which may leave us with an object in old space.
4375 if (always_allocate()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004376 { MaybeObject* maybe_clone =
4377 AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE);
4378 if (!maybe_clone->ToObject(&clone)) return maybe_clone;
4379 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004380 Address clone_address = HeapObject::cast(clone)->address();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004381 CopyBlock(clone_address,
4382 source->address(),
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004383 object_size);
4384 // Update write barrier for all fields that lie beyond the header.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004385 RecordWrites(clone_address,
4386 JSObject::kHeaderSize,
antonm@chromium.org8e5e3382010-03-24 09:56:30 +00004387 (object_size - JSObject::kHeaderSize) / kPointerSize);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004388 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004389 wb_mode = SKIP_WRITE_BARRIER;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004390 { MaybeObject* maybe_clone = new_space_.AllocateRaw(object_size);
4391 if (!maybe_clone->ToObject(&clone)) return maybe_clone;
4392 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004393 SLOW_ASSERT(InNewSpace(clone));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004394 // Since we know the clone is allocated in new space, we can copy
ager@chromium.org32912102009-01-16 10:38:43 +00004395 // the contents without worrying about updating the write barrier.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004396 CopyBlock(HeapObject::cast(clone)->address(),
4397 source->address(),
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004398 object_size);
4399 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004400
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004401 SLOW_ASSERT(
4402 JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004403 FixedArrayBase* elements = FixedArrayBase::cast(source->elements());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004404 FixedArray* properties = FixedArray::cast(source->properties());
4405 // Update elements if necessary.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00004406 if (elements->length() > 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004407 Object* elem;
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004408 { MaybeObject* maybe_elem;
4409 if (elements->map() == fixed_cow_array_map()) {
4410 maybe_elem = FixedArray::cast(elements);
4411 } else if (source->HasFastDoubleElements()) {
4412 maybe_elem = CopyFixedDoubleArray(FixedDoubleArray::cast(elements));
4413 } else {
4414 maybe_elem = CopyFixedArray(FixedArray::cast(elements));
4415 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004416 if (!maybe_elem->ToObject(&elem)) return maybe_elem;
4417 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004418 JSObject::cast(clone)->set_elements(FixedArrayBase::cast(elem), wb_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004419 }
4420 // Update properties if necessary.
4421 if (properties->length() > 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004422 Object* prop;
4423 { MaybeObject* maybe_prop = CopyFixedArray(properties);
4424 if (!maybe_prop->ToObject(&prop)) return maybe_prop;
4425 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004426 JSObject::cast(clone)->set_properties(FixedArray::cast(prop), wb_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004427 }
4428 // Return the new clone.
4429 return clone;
4430}
4431
4432
lrn@chromium.org34e60782011-09-15 07:25:40 +00004433MaybeObject* Heap::ReinitializeJSReceiver(
4434 JSReceiver* object, InstanceType type, int size) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004435 ASSERT(type >= FIRST_JS_OBJECT_TYPE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004436
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004437 // Allocate fresh map.
4438 // TODO(rossberg): Once we optimize proxies, cache these maps.
4439 Map* map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004440 MaybeObject* maybe = AllocateMap(type, size);
4441 if (!maybe->To<Map>(&map)) return maybe;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004442
lrn@chromium.org34e60782011-09-15 07:25:40 +00004443 // Check that the receiver has at least the size of the fresh object.
4444 int size_difference = object->map()->instance_size() - map->instance_size();
4445 ASSERT(size_difference >= 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004446
4447 map->set_prototype(object->map()->prototype());
4448
4449 // Allocate the backing storage for the properties.
4450 int prop_size = map->unused_property_fields() - map->inobject_properties();
4451 Object* properties;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004452 maybe = AllocateFixedArray(prop_size, TENURED);
4453 if (!maybe->ToObject(&properties)) return maybe;
4454
4455 // Functions require some allocation, which might fail here.
4456 SharedFunctionInfo* shared = NULL;
4457 if (type == JS_FUNCTION_TYPE) {
4458 String* name;
4459 maybe = LookupAsciiSymbol("<freezing call trap>");
4460 if (!maybe->To<String>(&name)) return maybe;
4461 maybe = AllocateSharedFunctionInfo(name);
4462 if (!maybe->To<SharedFunctionInfo>(&shared)) return maybe;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004463 }
4464
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004465 // Because of possible retries of this function after failure,
4466 // we must NOT fail after this point, where we have changed the type!
4467
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004468 // Reset the map for the object.
4469 object->set_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004470 JSObject* jsobj = JSObject::cast(object);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004471
4472 // Reinitialize the object from the constructor map.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004473 InitializeJSObjectFromMap(jsobj, FixedArray::cast(properties), map);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004474
4475 // Functions require some minimal initialization.
4476 if (type == JS_FUNCTION_TYPE) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004477 map->set_function_with_prototype(true);
4478 InitializeFunction(JSFunction::cast(object), shared, the_hole_value());
4479 JSFunction::cast(object)->set_context(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004480 isolate()->context()->native_context());
lrn@chromium.org34e60782011-09-15 07:25:40 +00004481 }
4482
4483 // Put in filler if the new object is smaller than the old.
4484 if (size_difference > 0) {
4485 CreateFillerObjectAt(
4486 object->address() + map->instance_size(), size_difference);
4487 }
4488
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004489 return object;
4490}
4491
4492
lrn@chromium.org303ada72010-10-27 09:33:13 +00004493MaybeObject* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor,
4494 JSGlobalProxy* object) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004495 ASSERT(constructor->has_initial_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004496 Map* map = constructor->initial_map();
4497
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004498 // Check that the already allocated object has the same size and type as
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004499 // objects allocated using the constructor.
4500 ASSERT(map->instance_size() == object->map()->instance_size());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004501 ASSERT(map->instance_type() == object->map()->instance_type());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004502
4503 // Allocate the backing storage for the properties.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004504 int prop_size = map->unused_property_fields() - map->inobject_properties();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004505 Object* properties;
4506 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, TENURED);
4507 if (!maybe_properties->ToObject(&properties)) return maybe_properties;
4508 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004509
4510 // Reset the map for the object.
4511 object->set_map(constructor->initial_map());
4512
4513 // Reinitialize the object from the constructor map.
4514 InitializeJSObjectFromMap(object, FixedArray::cast(properties), map);
4515 return object;
4516}
4517
4518
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004519MaybeObject* Heap::AllocateStringFromOneByte(Vector<const char> string,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004520 PretenureFlag pretenure) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004521 int length = string.length();
4522 if (length == 1) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004523 return Heap::LookupSingleCharacterStringFromCode(string[0]);
4524 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004525 Object* result;
4526 { MaybeObject* maybe_result =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004527 AllocateRawOneByteString(string.length(), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004528 if (!maybe_result->ToObject(&result)) return maybe_result;
4529 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004530
4531 // Copy the characters into the new object.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004532 CopyChars(SeqOneByteString::cast(result)->GetChars(), string.start(), length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004533 return result;
4534}
4535
4536
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004537MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector<const char> string,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004538 int non_ascii_start,
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004539 PretenureFlag pretenure) {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004540 // Continue counting the number of characters in the UTF-8 string, starting
4541 // from the first non-ascii character or word.
4542 int chars = non_ascii_start;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004543 Access<UnicodeCache::Utf8Decoder>
4544 decoder(isolate_->unicode_cache()->utf8_decoder());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004545 decoder->Reset(string.start() + non_ascii_start, string.length() - chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004546 while (decoder->has_more()) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004547 uint32_t r = decoder->GetNext();
4548 if (r <= unibrow::Utf16::kMaxNonSurrogateCharCode) {
4549 chars++;
4550 } else {
4551 chars += 2;
4552 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004553 }
4554
lrn@chromium.org303ada72010-10-27 09:33:13 +00004555 Object* result;
4556 { MaybeObject* maybe_result = AllocateRawTwoByteString(chars, pretenure);
4557 if (!maybe_result->ToObject(&result)) return maybe_result;
4558 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004559
4560 // Convert and copy the characters into the new object.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004561 SeqTwoByteString* twobyte = SeqTwoByteString::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004562 decoder->Reset(string.start(), string.length());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004563 int i = 0;
4564 while (i < chars) {
4565 uint32_t r = decoder->GetNext();
4566 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004567 twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::LeadSurrogate(r));
4568 twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::TrailSurrogate(r));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004569 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004570 twobyte->SeqTwoByteStringSet(i++, r);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004571 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004572 }
4573 return result;
4574}
4575
4576
lrn@chromium.org303ada72010-10-27 09:33:13 +00004577MaybeObject* Heap::AllocateStringFromTwoByte(Vector<const uc16> string,
4578 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004579 // Check if the string is an ASCII string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004580 Object* result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004581 int length = string.length();
4582 const uc16* start = string.start();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004583
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004584 if (String::IsAscii(start, length)) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004585 MaybeObject* maybe_result = AllocateRawOneByteString(length, pretenure);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004586 if (!maybe_result->ToObject(&result)) return maybe_result;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004587 CopyChars(SeqOneByteString::cast(result)->GetChars(), start, length);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004588 } else { // It's not an ASCII string.
4589 MaybeObject* maybe_result = AllocateRawTwoByteString(length, pretenure);
4590 if (!maybe_result->ToObject(&result)) return maybe_result;
4591 CopyChars(SeqTwoByteString::cast(result)->GetChars(), start, length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004592 }
4593 return result;
4594}
4595
4596
4597Map* Heap::SymbolMapForString(String* string) {
4598 // If the string is in new space it cannot be used as a symbol.
4599 if (InNewSpace(string)) return NULL;
4600
4601 // Find the corresponding symbol map for strings.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004602 switch (string->map()->instance_type()) {
4603 case STRING_TYPE: return symbol_map();
4604 case ASCII_STRING_TYPE: return ascii_symbol_map();
4605 case CONS_STRING_TYPE: return cons_symbol_map();
4606 case CONS_ASCII_STRING_TYPE: return cons_ascii_symbol_map();
4607 case EXTERNAL_STRING_TYPE: return external_symbol_map();
4608 case EXTERNAL_ASCII_STRING_TYPE: return external_ascii_symbol_map();
4609 case EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
4610 return external_symbol_with_ascii_data_map();
4611 case SHORT_EXTERNAL_STRING_TYPE: return short_external_symbol_map();
4612 case SHORT_EXTERNAL_ASCII_STRING_TYPE:
4613 return short_external_ascii_symbol_map();
4614 case SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
4615 return short_external_symbol_with_ascii_data_map();
4616 default: return NULL; // No match found.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004617 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004618}
4619
4620
lrn@chromium.org303ada72010-10-27 09:33:13 +00004621MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
4622 int chars,
4623 uint32_t hash_field) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004624 ASSERT(chars >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004625 // Ensure the chars matches the number of characters in the buffer.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004626 ASSERT(static_cast<unsigned>(chars) == buffer->Utf16Length());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004627 // Determine whether the string is ASCII.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004628 bool is_ascii = true;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004629 while (buffer->has_more()) {
4630 if (buffer->GetNext() > unibrow::Utf8::kMaxOneByteChar) {
4631 is_ascii = false;
4632 break;
4633 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004634 }
4635 buffer->Rewind();
4636
4637 // Compute map and object size.
4638 int size;
4639 Map* map;
4640
4641 if (is_ascii) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004642 if (chars > SeqOneByteString::kMaxLength) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004643 return Failure::OutOfMemoryException();
4644 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004645 map = ascii_symbol_map();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004646 size = SeqOneByteString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004647 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004648 if (chars > SeqTwoByteString::kMaxLength) {
4649 return Failure::OutOfMemoryException();
4650 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004651 map = symbol_map();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004652 size = SeqTwoByteString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004653 }
4654
4655 // Allocate string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004656 Object* result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004657 { MaybeObject* maybe_result = (size > Page::kMaxNonCodeHeapObjectSize)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004658 ? lo_space_->AllocateRaw(size, NOT_EXECUTABLE)
lrn@chromium.org303ada72010-10-27 09:33:13 +00004659 : old_data_space_->AllocateRaw(size);
4660 if (!maybe_result->ToObject(&result)) return maybe_result;
4661 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004662
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004663 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(map);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004664 // Set length and hash fields of the allocated string.
ager@chromium.org870a0b62008-11-04 11:43:05 +00004665 String* answer = String::cast(result);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004666 answer->set_length(chars);
4667 answer->set_hash_field(hash_field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004668
ager@chromium.org870a0b62008-11-04 11:43:05 +00004669 ASSERT_EQ(size, answer->Size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004670
4671 // Fill in the characters.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004672 int i = 0;
4673 while (i < chars) {
4674 uint32_t character = buffer->GetNext();
4675 if (character > unibrow::Utf16::kMaxNonSurrogateCharCode) {
4676 answer->Set(i++, unibrow::Utf16::LeadSurrogate(character));
4677 answer->Set(i++, unibrow::Utf16::TrailSurrogate(character));
4678 } else {
4679 answer->Set(i++, character);
4680 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004681 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00004682 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004683}
4684
4685
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004686MaybeObject* Heap::AllocateRawOneByteString(int length,
4687 PretenureFlag pretenure) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004688 if (length < 0 || length > SeqOneByteString::kMaxLength) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004689 return Failure::OutOfMemoryException();
4690 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004691
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004692 int size = SeqOneByteString::SizeFor(length);
4693 ASSERT(size <= SeqOneByteString::kMaxSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004694
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004695 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
4696 AllocationSpace retry_space = OLD_DATA_SPACE;
4697
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004698 if (space == NEW_SPACE) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004699 if (size > kMaxObjectSizeInNewSpace) {
4700 // Allocate in large object space, retry space will be ignored.
4701 space = LO_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004702 } else if (size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004703 // Allocate in new space, retry in large object space.
4704 retry_space = LO_SPACE;
4705 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004706 } else if (space == OLD_DATA_SPACE &&
4707 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004708 space = LO_SPACE;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004709 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004710 Object* result;
4711 { MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
4712 if (!maybe_result->ToObject(&result)) return maybe_result;
4713 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004714
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004715 // Partially initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004716 HeapObject::cast(result)->set_map_no_write_barrier(ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004717 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004718 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004719 ASSERT_EQ(size, HeapObject::cast(result)->Size());
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004720
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004721#ifdef VERIFY_HEAP
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004722 if (FLAG_verify_heap) {
4723 // Initialize string's content to ensure ASCII-ness (character range 0-127)
4724 // as required when verifying the heap.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004725 char* dest = SeqOneByteString::cast(result)->GetChars();
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004726 memset(dest, 0x0F, length * kCharSize);
4727 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004728#endif
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004729
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004730 return result;
4731}
4732
4733
lrn@chromium.org303ada72010-10-27 09:33:13 +00004734MaybeObject* Heap::AllocateRawTwoByteString(int length,
4735 PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004736 if (length < 0 || length > SeqTwoByteString::kMaxLength) {
4737 return Failure::OutOfMemoryException();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004738 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004739 int size = SeqTwoByteString::SizeFor(length);
4740 ASSERT(size <= SeqTwoByteString::kMaxSize);
4741 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
4742 AllocationSpace retry_space = OLD_DATA_SPACE;
4743
4744 if (space == NEW_SPACE) {
4745 if (size > kMaxObjectSizeInNewSpace) {
4746 // Allocate in large object space, retry space will be ignored.
4747 space = LO_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004748 } else if (size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004749 // Allocate in new space, retry in large object space.
4750 retry_space = LO_SPACE;
4751 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004752 } else if (space == OLD_DATA_SPACE &&
4753 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004754 space = LO_SPACE;
4755 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004756 Object* result;
4757 { MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
4758 if (!maybe_result->ToObject(&result)) return maybe_result;
4759 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004760
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004761 // Partially initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004762 HeapObject::cast(result)->set_map_no_write_barrier(string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004763 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004764 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004765 ASSERT_EQ(size, HeapObject::cast(result)->Size());
4766 return result;
4767}
4768
4769
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004770MaybeObject* Heap::AllocateJSArray(
4771 ElementsKind elements_kind,
4772 PretenureFlag pretenure) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004773 Context* native_context = isolate()->context()->native_context();
4774 JSFunction* array_function = native_context->array_function();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004775 Map* map = array_function->initial_map();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004776 Object* maybe_map_array = native_context->js_array_maps();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004777 if (!maybe_map_array->IsUndefined()) {
4778 Object* maybe_transitioned_map =
4779 FixedArray::cast(maybe_map_array)->get(elements_kind);
4780 if (!maybe_transitioned_map->IsUndefined()) {
4781 map = Map::cast(maybe_transitioned_map);
4782 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004783 }
4784
4785 return AllocateJSObjectFromMap(map, pretenure);
4786}
4787
4788
lrn@chromium.org303ada72010-10-27 09:33:13 +00004789MaybeObject* Heap::AllocateEmptyFixedArray() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004790 int size = FixedArray::SizeFor(0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004791 Object* result;
4792 { MaybeObject* maybe_result =
4793 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
4794 if (!maybe_result->ToObject(&result)) return maybe_result;
4795 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004796 // Initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004797 reinterpret_cast<FixedArray*>(result)->set_map_no_write_barrier(
4798 fixed_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004799 reinterpret_cast<FixedArray*>(result)->set_length(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004800 return result;
4801}
4802
4803
lrn@chromium.org303ada72010-10-27 09:33:13 +00004804MaybeObject* Heap::AllocateRawFixedArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004805 if (length < 0 || length > FixedArray::kMaxLength) {
4806 return Failure::OutOfMemoryException();
4807 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004808 ASSERT(length > 0);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004809 // Use the general function if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004810 if (always_allocate()) return AllocateFixedArray(length, TENURED);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004811 // Allocate the raw data for a fixed array.
4812 int size = FixedArray::SizeFor(length);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004813 return size <= kMaxObjectSizeInNewSpace
4814 ? new_space_.AllocateRaw(size)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004815 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004816}
4817
4818
lrn@chromium.org303ada72010-10-27 09:33:13 +00004819MaybeObject* Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004820 int len = src->length();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004821 Object* obj;
4822 { MaybeObject* maybe_obj = AllocateRawFixedArray(len);
4823 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4824 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004825 if (InNewSpace(obj)) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004826 HeapObject* dst = HeapObject::cast(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004827 dst->set_map_no_write_barrier(map);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004828 CopyBlock(dst->address() + kPointerSize,
4829 src->address() + kPointerSize,
4830 FixedArray::SizeFor(len) - kPointerSize);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004831 return obj;
4832 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004833 HeapObject::cast(obj)->set_map_no_write_barrier(map);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004834 FixedArray* result = FixedArray::cast(obj);
4835 result->set_length(len);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004836
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004837 // Copy the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004838 AssertNoAllocation no_gc;
4839 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004840 for (int i = 0; i < len; i++) result->set(i, src->get(i), mode);
4841 return result;
4842}
4843
4844
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004845MaybeObject* Heap::CopyFixedDoubleArrayWithMap(FixedDoubleArray* src,
4846 Map* map) {
4847 int len = src->length();
4848 Object* obj;
4849 { MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(len, NOT_TENURED);
4850 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4851 }
4852 HeapObject* dst = HeapObject::cast(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004853 dst->set_map_no_write_barrier(map);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004854 CopyBlock(
4855 dst->address() + FixedDoubleArray::kLengthOffset,
4856 src->address() + FixedDoubleArray::kLengthOffset,
4857 FixedDoubleArray::SizeFor(len) - FixedDoubleArray::kLengthOffset);
4858 return obj;
4859}
4860
4861
lrn@chromium.org303ada72010-10-27 09:33:13 +00004862MaybeObject* Heap::AllocateFixedArray(int length) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004863 ASSERT(length >= 0);
ager@chromium.org32912102009-01-16 10:38:43 +00004864 if (length == 0) return empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004865 Object* result;
4866 { MaybeObject* maybe_result = AllocateRawFixedArray(length);
4867 if (!maybe_result->ToObject(&result)) return maybe_result;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004868 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004869 // Initialize header.
4870 FixedArray* array = reinterpret_cast<FixedArray*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004871 array->set_map_no_write_barrier(fixed_array_map());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004872 array->set_length(length);
4873 // Initialize body.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004874 ASSERT(!InNewSpace(undefined_value()));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004875 MemsetPointer(array->data_start(), undefined_value(), length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004876 return result;
4877}
4878
4879
lrn@chromium.org303ada72010-10-27 09:33:13 +00004880MaybeObject* Heap::AllocateRawFixedArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004881 if (length < 0 || length > FixedArray::kMaxLength) {
4882 return Failure::OutOfMemoryException();
4883 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004884
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004885 AllocationSpace space =
4886 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004887 int size = FixedArray::SizeFor(length);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004888 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
4889 // Too big for new space.
4890 space = LO_SPACE;
4891 } else if (space == OLD_POINTER_SPACE &&
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004892 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004893 // Too big for old pointer space.
4894 space = LO_SPACE;
4895 }
4896
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004897 AllocationSpace retry_space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004898 (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_POINTER_SPACE : LO_SPACE;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004899
4900 return AllocateRaw(size, space, retry_space);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004901}
4902
4903
lrn@chromium.org303ada72010-10-27 09:33:13 +00004904MUST_USE_RESULT static MaybeObject* AllocateFixedArrayWithFiller(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004905 Heap* heap,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004906 int length,
4907 PretenureFlag pretenure,
4908 Object* filler) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004909 ASSERT(length >= 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004910 ASSERT(heap->empty_fixed_array()->IsFixedArray());
4911 if (length == 0) return heap->empty_fixed_array();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004912
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004913 ASSERT(!heap->InNewSpace(filler));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004914 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004915 { MaybeObject* maybe_result = heap->AllocateRawFixedArray(length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004916 if (!maybe_result->ToObject(&result)) return maybe_result;
4917 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004918
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004919 HeapObject::cast(result)->set_map_no_write_barrier(heap->fixed_array_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004920 FixedArray* array = FixedArray::cast(result);
4921 array->set_length(length);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004922 MemsetPointer(array->data_start(), filler, length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004923 return array;
4924}
4925
4926
lrn@chromium.org303ada72010-10-27 09:33:13 +00004927MaybeObject* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004928 return AllocateFixedArrayWithFiller(this,
4929 length,
4930 pretenure,
4931 undefined_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004932}
4933
4934
lrn@chromium.org303ada72010-10-27 09:33:13 +00004935MaybeObject* Heap::AllocateFixedArrayWithHoles(int length,
4936 PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004937 return AllocateFixedArrayWithFiller(this,
4938 length,
4939 pretenure,
4940 the_hole_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004941}
4942
4943
lrn@chromium.org303ada72010-10-27 09:33:13 +00004944MaybeObject* Heap::AllocateUninitializedFixedArray(int length) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004945 if (length == 0) return empty_fixed_array();
4946
lrn@chromium.org303ada72010-10-27 09:33:13 +00004947 Object* obj;
4948 { MaybeObject* maybe_obj = AllocateRawFixedArray(length);
4949 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4950 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004951
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004952 reinterpret_cast<FixedArray*>(obj)->set_map_no_write_barrier(
4953 fixed_array_map());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004954 FixedArray::cast(obj)->set_length(length);
4955 return obj;
4956}
4957
4958
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004959MaybeObject* Heap::AllocateEmptyFixedDoubleArray() {
4960 int size = FixedDoubleArray::SizeFor(0);
4961 Object* result;
4962 { MaybeObject* maybe_result =
4963 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
4964 if (!maybe_result->ToObject(&result)) return maybe_result;
4965 }
4966 // Initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004967 reinterpret_cast<FixedDoubleArray*>(result)->set_map_no_write_barrier(
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004968 fixed_double_array_map());
4969 reinterpret_cast<FixedDoubleArray*>(result)->set_length(0);
4970 return result;
4971}
4972
4973
4974MaybeObject* Heap::AllocateUninitializedFixedDoubleArray(
4975 int length,
4976 PretenureFlag pretenure) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004977 if (length == 0) return empty_fixed_array();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004978
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004979 Object* elements_object;
4980 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
4981 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj;
4982 FixedDoubleArray* elements =
4983 reinterpret_cast<FixedDoubleArray*>(elements_object);
4984
4985 elements->set_map_no_write_barrier(fixed_double_array_map());
4986 elements->set_length(length);
4987 return elements;
4988}
4989
4990
4991MaybeObject* Heap::AllocateFixedDoubleArrayWithHoles(
4992 int length,
4993 PretenureFlag pretenure) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004994 if (length == 0) return empty_fixed_array();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004995
4996 Object* elements_object;
4997 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
4998 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj;
4999 FixedDoubleArray* elements =
5000 reinterpret_cast<FixedDoubleArray*>(elements_object);
5001
5002 for (int i = 0; i < length; ++i) {
5003 elements->set_the_hole(i);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005004 }
5005
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005006 elements->set_map_no_write_barrier(fixed_double_array_map());
5007 elements->set_length(length);
5008 return elements;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005009}
5010
5011
5012MaybeObject* Heap::AllocateRawFixedDoubleArray(int length,
5013 PretenureFlag pretenure) {
5014 if (length < 0 || length > FixedDoubleArray::kMaxLength) {
5015 return Failure::OutOfMemoryException();
5016 }
5017
5018 AllocationSpace space =
5019 (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
5020 int size = FixedDoubleArray::SizeFor(length);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005021
5022#ifndef V8_HOST_ARCH_64_BIT
5023 size += kPointerSize;
5024#endif
5025
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005026 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
5027 // Too big for new space.
5028 space = LO_SPACE;
5029 } else if (space == OLD_DATA_SPACE &&
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005030 size > Page::kMaxNonCodeHeapObjectSize) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005031 // Too big for old data space.
5032 space = LO_SPACE;
5033 }
5034
5035 AllocationSpace retry_space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005036 (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_DATA_SPACE : LO_SPACE;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005037
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005038 HeapObject* object;
5039 { MaybeObject* maybe_object = AllocateRaw(size, space, retry_space);
5040 if (!maybe_object->To<HeapObject>(&object)) return maybe_object;
5041 }
5042
5043 return EnsureDoubleAligned(this, object, size);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005044}
5045
5046
lrn@chromium.org303ada72010-10-27 09:33:13 +00005047MaybeObject* Heap::AllocateHashTable(int length, PretenureFlag pretenure) {
5048 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005049 { MaybeObject* maybe_result = AllocateFixedArray(length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005050 if (!maybe_result->ToObject(&result)) return maybe_result;
5051 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005052 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(
5053 hash_table_map());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005054 ASSERT(result->IsHashTable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005055 return result;
5056}
5057
5058
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005059MaybeObject* Heap::AllocateNativeContext() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005060 Object* result;
5061 { MaybeObject* maybe_result =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005062 AllocateFixedArray(Context::NATIVE_CONTEXT_SLOTS);
5063 if (!maybe_result->ToObject(&result)) return maybe_result;
5064 }
5065 Context* context = reinterpret_cast<Context*>(result);
5066 context->set_map_no_write_barrier(native_context_map());
5067 context->set_js_array_maps(undefined_value());
5068 ASSERT(context->IsNativeContext());
5069 ASSERT(result->IsContext());
5070 return result;
5071}
5072
5073
5074MaybeObject* Heap::AllocateGlobalContext(JSFunction* function,
5075 ScopeInfo* scope_info) {
5076 Object* result;
5077 { MaybeObject* maybe_result =
5078 AllocateFixedArray(scope_info->ContextLength(), TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005079 if (!maybe_result->ToObject(&result)) return maybe_result;
5080 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005081 Context* context = reinterpret_cast<Context*>(result);
danno@chromium.orgeb831462012-08-24 11:57:08 +00005082 context->set_map_no_write_barrier(global_context_map());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005083 context->set_closure(function);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005084 context->set_previous(function->context());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005085 context->set_extension(scope_info);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005086 context->set_global_object(function->context()->global_object());
danno@chromium.orgeb831462012-08-24 11:57:08 +00005087 ASSERT(context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005088 ASSERT(result->IsContext());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005089 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005090}
5091
5092
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005093MaybeObject* Heap::AllocateModuleContext(ScopeInfo* scope_info) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005094 Object* result;
5095 { MaybeObject* maybe_result =
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005096 AllocateFixedArray(scope_info->ContextLength(), TENURED);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005097 if (!maybe_result->ToObject(&result)) return maybe_result;
5098 }
5099 Context* context = reinterpret_cast<Context*>(result);
5100 context->set_map_no_write_barrier(module_context_map());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005101 // Instance link will be set later.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005102 context->set_extension(Smi::FromInt(0));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005103 return context;
5104}
5105
5106
lrn@chromium.org303ada72010-10-27 09:33:13 +00005107MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005108 ASSERT(length >= Context::MIN_CONTEXT_SLOTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005109 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005110 { MaybeObject* maybe_result = AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005111 if (!maybe_result->ToObject(&result)) return maybe_result;
5112 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005113 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005114 context->set_map_no_write_barrier(function_context_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005115 context->set_closure(function);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005116 context->set_previous(function->context());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005117 context->set_extension(Smi::FromInt(0));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005118 context->set_global_object(function->context()->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005119 return context;
5120}
5121
5122
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005123MaybeObject* Heap::AllocateCatchContext(JSFunction* function,
5124 Context* previous,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005125 String* name,
5126 Object* thrown_object) {
5127 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == Context::THROWN_OBJECT_INDEX);
5128 Object* result;
5129 { MaybeObject* maybe_result =
5130 AllocateFixedArray(Context::MIN_CONTEXT_SLOTS + 1);
5131 if (!maybe_result->ToObject(&result)) return maybe_result;
5132 }
5133 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005134 context->set_map_no_write_barrier(catch_context_map());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005135 context->set_closure(function);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005136 context->set_previous(previous);
5137 context->set_extension(name);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005138 context->set_global_object(previous->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005139 context->set(Context::THROWN_OBJECT_INDEX, thrown_object);
5140 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005141}
5142
5143
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005144MaybeObject* Heap::AllocateWithContext(JSFunction* function,
5145 Context* previous,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005146 JSObject* extension) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005147 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005148 { MaybeObject* maybe_result = AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005149 if (!maybe_result->ToObject(&result)) return maybe_result;
5150 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005151 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005152 context->set_map_no_write_barrier(with_context_map());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005153 context->set_closure(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005154 context->set_previous(previous);
5155 context->set_extension(extension);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005156 context->set_global_object(previous->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005157 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005158}
5159
5160
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005161MaybeObject* Heap::AllocateBlockContext(JSFunction* function,
5162 Context* previous,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005163 ScopeInfo* scope_info) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005164 Object* result;
5165 { MaybeObject* maybe_result =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005166 AllocateFixedArrayWithHoles(scope_info->ContextLength());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005167 if (!maybe_result->ToObject(&result)) return maybe_result;
5168 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005169 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005170 context->set_map_no_write_barrier(block_context_map());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005171 context->set_closure(function);
5172 context->set_previous(previous);
5173 context->set_extension(scope_info);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005174 context->set_global_object(previous->global_object());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005175 return context;
5176}
5177
5178
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005179MaybeObject* Heap::AllocateScopeInfo(int length) {
5180 FixedArray* scope_info;
5181 MaybeObject* maybe_scope_info = AllocateFixedArray(length, TENURED);
5182 if (!maybe_scope_info->To(&scope_info)) return maybe_scope_info;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005183 scope_info->set_map_no_write_barrier(scope_info_map());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005184 return scope_info;
5185}
5186
5187
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00005188MaybeObject* Heap::AllocateExternal(void* value) {
5189 Foreign* foreign;
5190 { MaybeObject* maybe_result = AllocateForeign(static_cast<Address>(value));
5191 if (!maybe_result->To(&foreign)) return maybe_result;
5192 }
5193 JSObject* external;
5194 { MaybeObject* maybe_result = AllocateJSObjectFromMap(external_map());
5195 if (!maybe_result->To(&external)) return maybe_result;
5196 }
5197 external->SetInternalField(0, foreign);
5198 return external;
5199}
5200
5201
lrn@chromium.org303ada72010-10-27 09:33:13 +00005202MaybeObject* Heap::AllocateStruct(InstanceType type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005203 Map* map;
5204 switch (type) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005205#define MAKE_CASE(NAME, Name, name) \
5206 case NAME##_TYPE: map = name##_map(); break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005207STRUCT_LIST(MAKE_CASE)
5208#undef MAKE_CASE
5209 default:
5210 UNREACHABLE();
5211 return Failure::InternalError();
5212 }
5213 int size = map->instance_size();
5214 AllocationSpace space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005215 (size > Page::kMaxNonCodeHeapObjectSize) ? LO_SPACE : OLD_POINTER_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005216 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005217 { MaybeObject* maybe_result = Allocate(map, space);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005218 if (!maybe_result->ToObject(&result)) return maybe_result;
5219 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005220 Struct::cast(result)->InitializeBody(size);
5221 return result;
5222}
5223
5224
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005225bool Heap::IsHeapIterable() {
5226 return (!old_pointer_space()->was_swept_conservatively() &&
5227 !old_data_space()->was_swept_conservatively());
5228}
5229
5230
5231void Heap::EnsureHeapIsIterable() {
5232 ASSERT(IsAllocationAllowed());
5233 if (!IsHeapIterable()) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005234 CollectAllGarbage(kMakeHeapIterableMask, "Heap::EnsureHeapIsIterable");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005235 }
5236 ASSERT(IsHeapIterable());
5237}
5238
5239
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005240void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005241 incremental_marking()->Step(step_size,
5242 IncrementalMarking::NO_GC_VIA_STACK_GUARD);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005243
5244 if (incremental_marking()->IsComplete()) {
5245 bool uncommit = false;
5246 if (gc_count_at_last_idle_gc_ == gc_count_) {
5247 // No GC since the last full GC, the mutator is probably not active.
5248 isolate_->compilation_cache()->Clear();
5249 uncommit = true;
5250 }
5251 CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental");
5252 gc_count_at_last_idle_gc_ = gc_count_;
5253 if (uncommit) {
5254 new_space_.Shrink();
5255 UncommitFromSpace();
5256 }
5257 }
5258}
5259
5260
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005261bool Heap::IdleNotification(int hint) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005262 // Hints greater than this value indicate that
5263 // the embedder is requesting a lot of GC work.
danno@chromium.org88aa0582012-03-23 15:11:57 +00005264 const int kMaxHint = 1000;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005265 // Minimal hint that allows to do full GC.
5266 const int kMinHintForFullGC = 100;
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005267 intptr_t size_factor = Min(Max(hint, 20), kMaxHint) / 4;
5268 // The size factor is in range [5..250]. The numbers here are chosen from
5269 // experiments. If you changes them, make sure to test with
5270 // chrome/performance_ui_tests --gtest_filter="GeneralMixMemoryTest.*
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00005271 intptr_t step_size =
5272 size_factor * IncrementalMarking::kAllocatedThreshold;
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005273
5274 if (contexts_disposed_ > 0) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005275 if (hint >= kMaxHint) {
5276 // The embedder is requesting a lot of GC work after context disposal,
5277 // we age inline caches so that they don't keep objects from
5278 // the old context alive.
5279 AgeInlineCaches();
5280 }
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005281 int mark_sweep_time = Min(TimeMarkSweepWouldTakeInMs(), 1000);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005282 if (hint >= mark_sweep_time && !FLAG_expose_gc &&
5283 incremental_marking()->IsStopped()) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005284 HistogramTimerScope scope(isolate_->counters()->gc_context());
5285 CollectAllGarbage(kReduceMemoryFootprintMask,
5286 "idle notification: contexts disposed");
5287 } else {
5288 AdvanceIdleIncrementalMarking(step_size);
5289 contexts_disposed_ = 0;
5290 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005291 // After context disposal there is likely a lot of garbage remaining, reset
5292 // the idle notification counters in order to trigger more incremental GCs
5293 // on subsequent idle notifications.
5294 StartIdleRound();
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005295 return false;
5296 }
5297
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005298 if (!FLAG_incremental_marking || FLAG_expose_gc || Serializer::enabled()) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005299 return IdleGlobalGC();
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005300 }
5301
5302 // By doing small chunks of GC work in each IdleNotification,
5303 // perform a round of incremental GCs and after that wait until
5304 // the mutator creates enough garbage to justify a new round.
5305 // An incremental GC progresses as follows:
5306 // 1. many incremental marking steps,
5307 // 2. one old space mark-sweep-compact,
5308 // 3. many lazy sweep steps.
5309 // Use mark-sweep-compact events to count incremental GCs in a round.
5310
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005311
5312 if (incremental_marking()->IsStopped()) {
5313 if (!IsSweepingComplete() &&
5314 !AdvanceSweepers(static_cast<int>(step_size))) {
5315 return false;
5316 }
5317 }
5318
5319 if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) {
5320 if (EnoughGarbageSinceLastIdleRound()) {
5321 StartIdleRound();
5322 } else {
5323 return true;
5324 }
5325 }
5326
5327 int new_mark_sweeps = ms_count_ - ms_count_at_last_idle_notification_;
5328 mark_sweeps_since_idle_round_started_ += new_mark_sweeps;
5329 ms_count_at_last_idle_notification_ = ms_count_;
5330
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005331 int remaining_mark_sweeps = kMaxMarkSweepsInIdleRound -
5332 mark_sweeps_since_idle_round_started_;
5333
5334 if (remaining_mark_sweeps <= 0) {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005335 FinishIdleRound();
5336 return true;
5337 }
5338
5339 if (incremental_marking()->IsStopped()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005340 // If there are no more than two GCs left in this idle round and we are
5341 // allowed to do a full GC, then make those GCs full in order to compact
5342 // the code space.
5343 // TODO(ulan): Once we enable code compaction for incremental marking,
5344 // we can get rid of this special case and always start incremental marking.
5345 if (remaining_mark_sweeps <= 2 && hint >= kMinHintForFullGC) {
5346 CollectAllGarbage(kReduceMemoryFootprintMask,
5347 "idle notification: finalize idle round");
5348 } else {
5349 incremental_marking()->Start();
5350 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005351 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005352 if (!incremental_marking()->IsStopped()) {
5353 AdvanceIdleIncrementalMarking(step_size);
5354 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005355 return false;
5356}
5357
5358
5359bool Heap::IdleGlobalGC() {
ager@chromium.orga1645e22009-09-09 19:27:10 +00005360 static const int kIdlesBeforeScavenge = 4;
5361 static const int kIdlesBeforeMarkSweep = 7;
5362 static const int kIdlesBeforeMarkCompact = 8;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005363 static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005364 static const unsigned int kGCsBetweenCleanup = 4;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005365
5366 if (!last_idle_notification_gc_count_init_) {
5367 last_idle_notification_gc_count_ = gc_count_;
5368 last_idle_notification_gc_count_init_ = true;
5369 }
ager@chromium.org96c75b52009-08-26 09:13:16 +00005370
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005371 bool uncommit = true;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005372 bool finished = false;
5373
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005374 // Reset the number of idle notifications received when a number of
5375 // GCs have taken place. This allows another round of cleanup based
5376 // on idle notifications if enough work has been carried out to
5377 // provoke a number of garbage collections.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005378 if (gc_count_ - last_idle_notification_gc_count_ < kGCsBetweenCleanup) {
5379 number_idle_notifications_ =
5380 Min(number_idle_notifications_ + 1, kMaxIdleCount);
ager@chromium.org96c75b52009-08-26 09:13:16 +00005381 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005382 number_idle_notifications_ = 0;
5383 last_idle_notification_gc_count_ = gc_count_;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005384 }
5385
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005386 if (number_idle_notifications_ == kIdlesBeforeScavenge) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005387 CollectGarbage(NEW_SPACE, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005388 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005389 last_idle_notification_gc_count_ = gc_count_;
5390 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005391 // Before doing the mark-sweep collections we clear the
5392 // compilation cache to avoid hanging on to source code and
5393 // generated code for cached functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005394 isolate_->compilation_cache()->Clear();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005395
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005396 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005397 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005398 last_idle_notification_gc_count_ = gc_count_;
ager@chromium.orga1645e22009-09-09 19:27:10 +00005399
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005400 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005401 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005402 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005403 last_idle_notification_gc_count_ = gc_count_;
5404 number_idle_notifications_ = 0;
ager@chromium.orga1645e22009-09-09 19:27:10 +00005405 finished = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005406 } else if (number_idle_notifications_ > kIdlesBeforeMarkCompact) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005407 // If we have received more than kIdlesBeforeMarkCompact idle
5408 // notifications we do not perform any cleanup because we don't
5409 // expect to gain much by doing so.
5410 finished = true;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005411 }
5412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005413 if (uncommit) UncommitFromSpace();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005414
ager@chromium.org96c75b52009-08-26 09:13:16 +00005415 return finished;
5416}
5417
5418
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005419#ifdef DEBUG
5420
5421void Heap::Print() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005422 if (!HasBeenSetUp()) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005423 isolate()->PrintStack();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005424 AllSpaces spaces;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005425 for (Space* space = spaces.next(); space != NULL; space = spaces.next())
5426 space->Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005427}
5428
5429
5430void Heap::ReportCodeStatistics(const char* title) {
5431 PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title);
5432 PagedSpace::ResetCodeStatistics();
5433 // We do not look for code in new space, map space, or old space. If code
5434 // somehow ends up in those spaces, we would miss it here.
5435 code_space_->CollectCodeStatistics();
5436 lo_space_->CollectCodeStatistics();
5437 PagedSpace::ReportCodeStatistics();
5438}
5439
5440
5441// This function expects that NewSpace's allocated objects histogram is
5442// populated (via a call to CollectStatistics or else as a side effect of a
5443// just-completed scavenge collection).
5444void Heap::ReportHeapStatistics(const char* title) {
5445 USE(title);
5446 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n",
5447 title, gc_count_);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005448 PrintF("old_gen_promotion_limit_ %" V8_PTR_PREFIX "d\n",
5449 old_gen_promotion_limit_);
5450 PrintF("old_gen_allocation_limit_ %" V8_PTR_PREFIX "d\n",
5451 old_gen_allocation_limit_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005452 PrintF("old_gen_limit_factor_ %d\n", old_gen_limit_factor_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005453
5454 PrintF("\n");
5455 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005456 isolate_->global_handles()->PrintStats();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005457 PrintF("\n");
5458
5459 PrintF("Heap statistics : ");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005460 isolate_->memory_allocator()->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005461 PrintF("To space : ");
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005462 new_space_.ReportStatistics();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005463 PrintF("Old pointer space : ");
5464 old_pointer_space_->ReportStatistics();
5465 PrintF("Old data space : ");
5466 old_data_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005467 PrintF("Code space : ");
5468 code_space_->ReportStatistics();
5469 PrintF("Map space : ");
5470 map_space_->ReportStatistics();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005471 PrintF("Cell space : ");
5472 cell_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005473 PrintF("Large object space : ");
5474 lo_space_->ReportStatistics();
5475 PrintF(">>>>>> ========================================= >>>>>>\n");
5476}
5477
5478#endif // DEBUG
5479
5480bool Heap::Contains(HeapObject* value) {
5481 return Contains(value->address());
5482}
5483
5484
5485bool Heap::Contains(Address addr) {
5486 if (OS::IsOutsideAllocatedSpace(addr)) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005487 return HasBeenSetUp() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005488 (new_space_.ToSpaceContains(addr) ||
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005489 old_pointer_space_->Contains(addr) ||
5490 old_data_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005491 code_space_->Contains(addr) ||
5492 map_space_->Contains(addr) ||
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005493 cell_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005494 lo_space_->SlowContains(addr));
5495}
5496
5497
5498bool Heap::InSpace(HeapObject* value, AllocationSpace space) {
5499 return InSpace(value->address(), space);
5500}
5501
5502
5503bool Heap::InSpace(Address addr, AllocationSpace space) {
5504 if (OS::IsOutsideAllocatedSpace(addr)) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005505 if (!HasBeenSetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005506
5507 switch (space) {
5508 case NEW_SPACE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005509 return new_space_.ToSpaceContains(addr);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005510 case OLD_POINTER_SPACE:
5511 return old_pointer_space_->Contains(addr);
5512 case OLD_DATA_SPACE:
5513 return old_data_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005514 case CODE_SPACE:
5515 return code_space_->Contains(addr);
5516 case MAP_SPACE:
5517 return map_space_->Contains(addr);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005518 case CELL_SPACE:
5519 return cell_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005520 case LO_SPACE:
5521 return lo_space_->SlowContains(addr);
5522 }
5523
5524 return false;
5525}
5526
5527
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005528#ifdef VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005529void Heap::Verify() {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005530 CHECK(HasBeenSetUp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005531
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005532 store_buffer()->Verify();
5533
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005534 VerifyPointersVisitor visitor;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005535 IterateRoots(&visitor, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005536
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005537 new_space_.Verify();
5538
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005539 old_pointer_space_->Verify(&visitor);
5540 map_space_->Verify(&visitor);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005541
5542 VerifyPointersVisitor no_dirty_regions_visitor;
5543 old_data_space_->Verify(&no_dirty_regions_visitor);
5544 code_space_->Verify(&no_dirty_regions_visitor);
5545 cell_space_->Verify(&no_dirty_regions_visitor);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005546
5547 lo_space_->Verify();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005548}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005549#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005550
5551
lrn@chromium.org303ada72010-10-27 09:33:13 +00005552MaybeObject* Heap::LookupSymbol(Vector<const char> string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005553 Object* symbol = NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005554 Object* new_table;
5555 { MaybeObject* maybe_new_table =
5556 symbol_table()->LookupSymbol(string, &symbol);
5557 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5558 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005559 // Can't use set_symbol_table because SymbolTable::cast knows that
5560 // SymbolTable is a singleton and checks for identity.
5561 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005562 ASSERT(symbol != NULL);
5563 return symbol;
5564}
5565
5566
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005567MaybeObject* Heap::LookupAsciiSymbol(Vector<const char> string) {
5568 Object* symbol = NULL;
5569 Object* new_table;
5570 { MaybeObject* maybe_new_table =
5571 symbol_table()->LookupAsciiSymbol(string, &symbol);
5572 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5573 }
5574 // Can't use set_symbol_table because SymbolTable::cast knows that
5575 // SymbolTable is a singleton and checks for identity.
5576 roots_[kSymbolTableRootIndex] = new_table;
5577 ASSERT(symbol != NULL);
5578 return symbol;
5579}
5580
5581
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005582MaybeObject* Heap::LookupAsciiSymbol(Handle<SeqOneByteString> string,
danno@chromium.org40cb8782011-05-25 07:58:50 +00005583 int from,
5584 int length) {
5585 Object* symbol = NULL;
5586 Object* new_table;
5587 { MaybeObject* maybe_new_table =
5588 symbol_table()->LookupSubStringAsciiSymbol(string,
5589 from,
5590 length,
5591 &symbol);
5592 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5593 }
5594 // Can't use set_symbol_table because SymbolTable::cast knows that
5595 // SymbolTable is a singleton and checks for identity.
5596 roots_[kSymbolTableRootIndex] = new_table;
5597 ASSERT(symbol != NULL);
5598 return symbol;
5599}
5600
5601
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005602MaybeObject* Heap::LookupTwoByteSymbol(Vector<const uc16> string) {
5603 Object* symbol = NULL;
5604 Object* new_table;
5605 { MaybeObject* maybe_new_table =
5606 symbol_table()->LookupTwoByteSymbol(string, &symbol);
5607 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5608 }
5609 // Can't use set_symbol_table because SymbolTable::cast knows that
5610 // SymbolTable is a singleton and checks for identity.
5611 roots_[kSymbolTableRootIndex] = new_table;
5612 ASSERT(symbol != NULL);
5613 return symbol;
5614}
5615
5616
lrn@chromium.org303ada72010-10-27 09:33:13 +00005617MaybeObject* Heap::LookupSymbol(String* string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005618 if (string->IsSymbol()) return string;
5619 Object* symbol = NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005620 Object* new_table;
5621 { MaybeObject* maybe_new_table =
5622 symbol_table()->LookupString(string, &symbol);
5623 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5624 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005625 // Can't use set_symbol_table because SymbolTable::cast knows that
5626 // SymbolTable is a singleton and checks for identity.
5627 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005628 ASSERT(symbol != NULL);
5629 return symbol;
5630}
5631
5632
ager@chromium.org7c537e22008-10-16 08:43:32 +00005633bool Heap::LookupSymbolIfExists(String* string, String** symbol) {
5634 if (string->IsSymbol()) {
5635 *symbol = string;
5636 return true;
5637 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005638 return symbol_table()->LookupSymbolIfExists(string, symbol);
ager@chromium.org7c537e22008-10-16 08:43:32 +00005639}
5640
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005641
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005642void Heap::ZapFromSpace() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005643 NewSpacePageIterator it(new_space_.FromSpaceStart(),
5644 new_space_.FromSpaceEnd());
5645 while (it.has_next()) {
5646 NewSpacePage* page = it.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005647 for (Address cursor = page->area_start(), limit = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005648 cursor < limit;
5649 cursor += kPointerSize) {
5650 Memory::Address_at(cursor) = kFromSpaceZapValue;
5651 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005652 }
5653}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005654
5655
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005656void Heap::IterateAndMarkPointersToFromSpace(Address start,
5657 Address end,
5658 ObjectSlotCallback callback) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005659 Address slot_address = start;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005660
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005661 // We are not collecting slots on new space objects during mutation
5662 // thus we have to scan for pointers to evacuation candidates when we
5663 // promote objects. But we should not record any slots in non-black
5664 // objects. Grey object's slots would be rescanned.
5665 // White object might not survive until the end of collection
5666 // it would be a violation of the invariant to record it's slots.
5667 bool record_slots = false;
5668 if (incremental_marking()->IsCompacting()) {
5669 MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::FromAddress(start));
5670 record_slots = Marking::IsBlack(mark_bit);
5671 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005672
5673 while (slot_address < end) {
5674 Object** slot = reinterpret_cast<Object**>(slot_address);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005675 Object* object = *slot;
5676 // If the store buffer becomes overfull we mark pages as being exempt from
5677 // the store buffer. These pages are scanned to find pointers that point
5678 // to the new space. In that case we may hit newly promoted objects and
5679 // fix the pointers before the promotion queue gets to them. Thus the 'if'.
5680 if (object->IsHeapObject()) {
5681 if (Heap::InFromSpace(object)) {
5682 callback(reinterpret_cast<HeapObject**>(slot),
5683 HeapObject::cast(object));
5684 Object* new_object = *slot;
5685 if (InNewSpace(new_object)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005686 SLOW_ASSERT(Heap::InToSpace(new_object));
5687 SLOW_ASSERT(new_object->IsHeapObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005688 store_buffer_.EnterDirectlyIntoStoreBuffer(
5689 reinterpret_cast<Address>(slot));
5690 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005691 SLOW_ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_object));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005692 } else if (record_slots &&
5693 MarkCompactCollector::IsOnEvacuationCandidate(object)) {
5694 mark_compact_collector()->RecordSlot(slot, slot, object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005695 }
5696 }
5697 slot_address += kPointerSize;
5698 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005699}
5700
5701
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005702#ifdef DEBUG
5703typedef bool (*CheckStoreBufferFilter)(Object** addr);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005704
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005705
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005706bool IsAMapPointerAddress(Object** addr) {
5707 uintptr_t a = reinterpret_cast<uintptr_t>(addr);
5708 int mod = a % Map::kSize;
5709 return mod >= Map::kPointerFieldsBeginOffset &&
5710 mod < Map::kPointerFieldsEndOffset;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005711}
5712
5713
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005714bool EverythingsAPointer(Object** addr) {
5715 return true;
5716}
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005717
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005718
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005719static void CheckStoreBuffer(Heap* heap,
5720 Object** current,
5721 Object** limit,
5722 Object**** store_buffer_position,
5723 Object*** store_buffer_top,
5724 CheckStoreBufferFilter filter,
5725 Address special_garbage_start,
5726 Address special_garbage_end) {
5727 Map* free_space_map = heap->free_space_map();
5728 for ( ; current < limit; current++) {
5729 Object* o = *current;
5730 Address current_address = reinterpret_cast<Address>(current);
5731 // Skip free space.
5732 if (o == free_space_map) {
5733 Address current_address = reinterpret_cast<Address>(current);
5734 FreeSpace* free_space =
5735 FreeSpace::cast(HeapObject::FromAddress(current_address));
5736 int skip = free_space->Size();
5737 ASSERT(current_address + skip <= reinterpret_cast<Address>(limit));
5738 ASSERT(skip > 0);
5739 current_address += skip - kPointerSize;
5740 current = reinterpret_cast<Object**>(current_address);
5741 continue;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005742 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005743 // Skip the current linear allocation space between top and limit which is
5744 // unmarked with the free space map, but can contain junk.
5745 if (current_address == special_garbage_start &&
5746 special_garbage_end != special_garbage_start) {
5747 current_address = special_garbage_end - kPointerSize;
5748 current = reinterpret_cast<Object**>(current_address);
5749 continue;
5750 }
5751 if (!(*filter)(current)) continue;
5752 ASSERT(current_address < special_garbage_start ||
5753 current_address >= special_garbage_end);
5754 ASSERT(reinterpret_cast<uintptr_t>(o) != kFreeListZapValue);
5755 // We have to check that the pointer does not point into new space
5756 // without trying to cast it to a heap object since the hash field of
5757 // a string can contain values like 1 and 3 which are tagged null
5758 // pointers.
5759 if (!heap->InNewSpace(o)) continue;
5760 while (**store_buffer_position < current &&
5761 *store_buffer_position < store_buffer_top) {
5762 (*store_buffer_position)++;
5763 }
5764 if (**store_buffer_position != current ||
5765 *store_buffer_position == store_buffer_top) {
5766 Object** obj_start = current;
5767 while (!(*obj_start)->IsMap()) obj_start--;
5768 UNREACHABLE();
5769 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005770 }
5771}
5772
5773
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005774// Check that the store buffer contains all intergenerational pointers by
5775// scanning a page and ensuring that all pointers to young space are in the
5776// store buffer.
5777void Heap::OldPointerSpaceCheckStoreBuffer() {
5778 OldSpace* space = old_pointer_space();
5779 PageIterator pages(space);
5780
5781 store_buffer()->SortUniq();
5782
5783 while (pages.has_next()) {
5784 Page* page = pages.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005785 Object** current = reinterpret_cast<Object**>(page->area_start());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005786
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005787 Address end = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005788
5789 Object*** store_buffer_position = store_buffer()->Start();
5790 Object*** store_buffer_top = store_buffer()->Top();
5791
5792 Object** limit = reinterpret_cast<Object**>(end);
5793 CheckStoreBuffer(this,
5794 current,
5795 limit,
5796 &store_buffer_position,
5797 store_buffer_top,
5798 &EverythingsAPointer,
5799 space->top(),
5800 space->limit());
5801 }
5802}
5803
5804
5805void Heap::MapSpaceCheckStoreBuffer() {
5806 MapSpace* space = map_space();
5807 PageIterator pages(space);
5808
5809 store_buffer()->SortUniq();
5810
5811 while (pages.has_next()) {
5812 Page* page = pages.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005813 Object** current = reinterpret_cast<Object**>(page->area_start());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005814
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005815 Address end = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005816
5817 Object*** store_buffer_position = store_buffer()->Start();
5818 Object*** store_buffer_top = store_buffer()->Top();
5819
5820 Object** limit = reinterpret_cast<Object**>(end);
5821 CheckStoreBuffer(this,
5822 current,
5823 limit,
5824 &store_buffer_position,
5825 store_buffer_top,
5826 &IsAMapPointerAddress,
5827 space->top(),
5828 space->limit());
5829 }
5830}
5831
5832
5833void Heap::LargeObjectSpaceCheckStoreBuffer() {
5834 LargeObjectIterator it(lo_space());
5835 for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) {
5836 // We only have code, sequential strings, or fixed arrays in large
5837 // object space, and only fixed arrays can possibly contain pointers to
5838 // the young generation.
5839 if (object->IsFixedArray()) {
5840 Object*** store_buffer_position = store_buffer()->Start();
5841 Object*** store_buffer_top = store_buffer()->Top();
5842 Object** current = reinterpret_cast<Object**>(object->address());
5843 Object** limit =
5844 reinterpret_cast<Object**>(object->address() + object->Size());
5845 CheckStoreBuffer(this,
5846 current,
5847 limit,
5848 &store_buffer_position,
5849 store_buffer_top,
5850 &EverythingsAPointer,
5851 NULL,
5852 NULL);
5853 }
5854 }
5855}
5856#endif
5857
5858
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005859void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) {
5860 IterateStrongRoots(v, mode);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005861 IterateWeakRoots(v, mode);
5862}
5863
5864
5865void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005866 v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex]));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005867 v->Synchronize(VisitorSynchronization::kSymbolTable);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005868 if (mode != VISIT_ALL_IN_SCAVENGE &&
5869 mode != VISIT_ALL_IN_SWEEP_NEWSPACE) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005870 // Scavenge collections have special processing for this.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005871 external_string_table_.Iterate(v);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005872 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005873 v->Synchronize(VisitorSynchronization::kExternalStringsTable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005874}
5875
5876
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005877void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005878 v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005879 v->Synchronize(VisitorSynchronization::kStrongRootList);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005880
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00005881 v->VisitPointer(BitCast<Object**>(&hidden_symbol_));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005882 v->Synchronize(VisitorSynchronization::kSymbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005883
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005884 isolate_->bootstrapper()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005885 v->Synchronize(VisitorSynchronization::kBootstrapper);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005886 isolate_->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005887 v->Synchronize(VisitorSynchronization::kTop);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005888 Relocatable::Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005889 v->Synchronize(VisitorSynchronization::kRelocatable);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005890
5891#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005892 isolate_->debug()->Iterate(v);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005893 if (isolate_->deoptimizer_data() != NULL) {
5894 isolate_->deoptimizer_data()->Iterate(v);
5895 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005896#endif
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005897 v->Synchronize(VisitorSynchronization::kDebug);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005898 isolate_->compilation_cache()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005899 v->Synchronize(VisitorSynchronization::kCompilationCache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005900
5901 // Iterate over local handles in handle scopes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005902 isolate_->handle_scope_implementer()->Iterate(v);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005903 isolate_->IterateDeferredHandles(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005904 v->Synchronize(VisitorSynchronization::kHandleScope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005905
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005906 // Iterate over the builtin code objects and code stubs in the
5907 // heap. Note that it is not necessary to iterate over code objects
5908 // on scavenge collections.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005909 if (mode != VISIT_ALL_IN_SCAVENGE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005910 isolate_->builtins()->IterateBuiltins(v);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005911 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005912 v->Synchronize(VisitorSynchronization::kBuiltins);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005913
5914 // Iterate over global handles.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005915 switch (mode) {
5916 case VISIT_ONLY_STRONG:
5917 isolate_->global_handles()->IterateStrongRoots(v);
5918 break;
5919 case VISIT_ALL_IN_SCAVENGE:
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005920 isolate_->global_handles()->IterateNewSpaceStrongAndDependentRoots(v);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005921 break;
5922 case VISIT_ALL_IN_SWEEP_NEWSPACE:
5923 case VISIT_ALL:
5924 isolate_->global_handles()->IterateAllRoots(v);
5925 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005926 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005927 v->Synchronize(VisitorSynchronization::kGlobalHandles);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005928
5929 // Iterate over pointers being held by inactive threads.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005930 isolate_->thread_manager()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005931 v->Synchronize(VisitorSynchronization::kThreadManager);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005932
5933 // Iterate over the pointers the Serialization/Deserialization code is
5934 // holding.
5935 // During garbage collection this keeps the partial snapshot cache alive.
5936 // During deserialization of the startup snapshot this creates the partial
5937 // snapshot cache and deserializes the objects it refers to. During
5938 // serialization this does nothing, since the partial snapshot cache is
5939 // empty. However the next thing we do is create the partial snapshot,
5940 // filling up the partial snapshot cache with objects it needs as we go.
5941 SerializerDeserializer::Iterate(v);
5942 // We don't do a v->Synchronize call here, because in debug mode that will
5943 // output a flag to the snapshot. However at this point the serializer and
5944 // deserializer are deliberately a little unsynchronized (see above) so the
5945 // checking of the sync flag in the snapshot would fail.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005946}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005947
5948
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005949// TODO(1236194): Since the heap size is configurable on the command line
5950// and through the API, we should gracefully handle the case that the heap
5951// size is not big enough to fit all the initial objects.
ager@chromium.org01fe7df2010-11-10 11:59:11 +00005952bool Heap::ConfigureHeap(int max_semispace_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005953 intptr_t max_old_gen_size,
5954 intptr_t max_executable_size) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005955 if (HasBeenSetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005956
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00005957 if (FLAG_stress_compaction) {
5958 // This will cause more frequent GCs when stressing.
5959 max_semispace_size_ = Page::kPageSize;
5960 }
5961
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005962 if (max_semispace_size > 0) {
5963 if (max_semispace_size < Page::kPageSize) {
5964 max_semispace_size = Page::kPageSize;
5965 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00005966 PrintPID("Max semispace size cannot be less than %dkbytes\n",
5967 Page::kPageSize >> 10);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005968 }
5969 }
5970 max_semispace_size_ = max_semispace_size;
5971 }
ager@chromium.org3811b432009-10-28 14:53:37 +00005972
5973 if (Snapshot::IsEnabled()) {
5974 // If we are using a snapshot we always reserve the default amount
5975 // of memory for each semispace because code in the snapshot has
5976 // write-barrier code that relies on the size and alignment of new
5977 // space. We therefore cannot use a larger max semispace size
5978 // than the default reserved semispace size.
5979 if (max_semispace_size_ > reserved_semispace_size_) {
5980 max_semispace_size_ = reserved_semispace_size_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005981 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00005982 PrintPID("Max semispace size cannot be more than %dkbytes\n",
5983 reserved_semispace_size_ >> 10);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005984 }
ager@chromium.org3811b432009-10-28 14:53:37 +00005985 }
5986 } else {
5987 // If we are not using snapshots we reserve space for the actual
5988 // max semispace size.
5989 reserved_semispace_size_ = max_semispace_size_;
5990 }
5991
5992 if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size;
ager@chromium.org01fe7df2010-11-10 11:59:11 +00005993 if (max_executable_size > 0) {
5994 max_executable_size_ = RoundUp(max_executable_size, Page::kPageSize);
5995 }
5996
5997 // The max executable size must be less than or equal to the max old
5998 // generation size.
5999 if (max_executable_size_ > max_old_generation_size_) {
6000 max_executable_size_ = max_old_generation_size_;
6001 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006002
6003 // The new space size must be a power of two to support single-bit testing
6004 // for containment.
ager@chromium.org3811b432009-10-28 14:53:37 +00006005 max_semispace_size_ = RoundUpToPowerOf2(max_semispace_size_);
6006 reserved_semispace_size_ = RoundUpToPowerOf2(reserved_semispace_size_);
6007 initial_semispace_size_ = Min(initial_semispace_size_, max_semispace_size_);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006008 external_allocation_limit_ = 16 * max_semispace_size_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006009
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006010 // The old generation is paged and needs at least one page for each space.
6011 int paged_space_count = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1;
6012 max_old_generation_size_ = Max(static_cast<intptr_t>(paged_space_count *
6013 Page::kPageSize),
6014 RoundUp(max_old_generation_size_,
6015 Page::kPageSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006016
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006017 configured_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006018 return true;
6019}
6020
6021
kasper.lund7276f142008-07-30 08:49:36 +00006022bool Heap::ConfigureHeapDefault() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006023 return ConfigureHeap(static_cast<intptr_t>(FLAG_max_new_space_size / 2) * KB,
6024 static_cast<intptr_t>(FLAG_max_old_space_size) * MB,
6025 static_cast<intptr_t>(FLAG_max_executable_size) * MB);
kasper.lund7276f142008-07-30 08:49:36 +00006026}
6027
6028
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006029void Heap::RecordStats(HeapStats* stats, bool take_snapshot) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006030 *stats->start_marker = HeapStats::kStartMarker;
6031 *stats->end_marker = HeapStats::kEndMarker;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006032 *stats->new_space_size = new_space_.SizeAsInt();
6033 *stats->new_space_capacity = static_cast<int>(new_space_.Capacity());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006034 *stats->old_pointer_space_size = old_pointer_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006035 *stats->old_pointer_space_capacity = old_pointer_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006036 *stats->old_data_space_size = old_data_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006037 *stats->old_data_space_capacity = old_data_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006038 *stats->code_space_size = code_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006039 *stats->code_space_capacity = code_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006040 *stats->map_space_size = map_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006041 *stats->map_space_capacity = map_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006042 *stats->cell_space_size = cell_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006043 *stats->cell_space_capacity = cell_space_->Capacity();
6044 *stats->lo_space_size = lo_space_->Size();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006045 isolate_->global_handles()->RecordStats(stats);
6046 *stats->memory_allocator_size = isolate()->memory_allocator()->Size();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006047 *stats->memory_allocator_capacity =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006048 isolate()->memory_allocator()->Size() +
6049 isolate()->memory_allocator()->Available();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006050 *stats->os_error = OS::GetLastError();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006051 isolate()->memory_allocator()->Available();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006052 if (take_snapshot) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006053 HeapIterator iterator;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006054 for (HeapObject* obj = iterator.next();
6055 obj != NULL;
6056 obj = iterator.next()) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006057 InstanceType type = obj->map()->instance_type();
6058 ASSERT(0 <= type && type <= LAST_TYPE);
6059 stats->objects_per_type[type]++;
6060 stats->size_per_type[type] += obj->Size();
6061 }
6062 }
ager@chromium.org60121232009-12-03 11:25:37 +00006063}
6064
6065
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00006066intptr_t Heap::PromotedSpaceSizeOfObjects() {
6067 return old_pointer_space_->SizeOfObjects()
6068 + old_data_space_->SizeOfObjects()
6069 + code_space_->SizeOfObjects()
6070 + map_space_->SizeOfObjects()
6071 + cell_space_->SizeOfObjects()
6072 + lo_space_->SizeOfObjects();
6073}
6074
6075
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00006076intptr_t Heap::PromotedExternalMemorySize() {
kasper.lund7276f142008-07-30 08:49:36 +00006077 if (amount_of_external_allocated_memory_
6078 <= amount_of_external_allocated_memory_at_last_global_gc_) return 0;
6079 return amount_of_external_allocated_memory_
6080 - amount_of_external_allocated_memory_at_last_global_gc_;
6081}
6082
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00006083
6084V8_DECLARE_ONCE(initialize_gc_once);
6085
6086static void InitializeGCOnce() {
6087 InitializeScavengingVisitorsTables();
6088 NewSpaceScavenger::Initialize();
6089 MarkCompactCollector::Initialize();
6090}
6091
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006092bool Heap::SetUp(bool create_heap_objects) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006093#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006094 allocation_timeout_ = FLAG_gc_interval;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006095#endif
6096
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006097 // Initialize heap spaces and initial maps and objects. Whenever something
6098 // goes wrong, just return false. The caller should check the results and
6099 // call Heap::TearDown() to release allocated memory.
6100 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006101 // If the heap is not yet configured (e.g. through the API), configure it.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006102 // Configuration is based on the flags new-space-size (really the semispace
6103 // size) and old-space-size if set or the initial values of semispace_size_
6104 // and old_generation_size_ otherwise.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006105 if (!configured_) {
kasper.lund7276f142008-07-30 08:49:36 +00006106 if (!ConfigureHeapDefault()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006107 }
6108
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00006109 CallOnce(&initialize_gc_once, &InitializeGCOnce);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006110
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006111 MarkMapPointersAsEncoded(false);
6112
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006113 // Set up memory allocator.
6114 if (!isolate_->memory_allocator()->SetUp(MaxReserved(), MaxExecutableSize()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006115 return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006116
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006117 // Set up new space.
6118 if (!new_space_.SetUp(reserved_semispace_size_, max_semispace_size_)) {
ager@chromium.org3811b432009-10-28 14:53:37 +00006119 return false;
6120 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006121
ager@chromium.orga1645e22009-09-09 19:27:10 +00006122 // Initialize old pointer space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006123 old_pointer_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006124 new OldSpace(this,
6125 max_old_generation_size_,
6126 OLD_POINTER_SPACE,
6127 NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006128 if (old_pointer_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006129 if (!old_pointer_space_->SetUp()) return false;
ager@chromium.orga1645e22009-09-09 19:27:10 +00006130
6131 // Initialize old data space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006132 old_data_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006133 new OldSpace(this,
6134 max_old_generation_size_,
6135 OLD_DATA_SPACE,
6136 NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006137 if (old_data_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006138 if (!old_data_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006139
6140 // Initialize the code space, set its maximum capacity to the old
kasper.lund7276f142008-07-30 08:49:36 +00006141 // generation size. It needs executable memory.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006142 // On 64-bit platform(s), we put all code objects in a 2 GB range of
6143 // virtual address space, so that they can call each other with near calls.
6144 if (code_range_size_ > 0) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006145 if (!isolate_->code_range()->SetUp(code_range_size_)) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006146 return false;
6147 }
6148 }
6149
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006150 code_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006151 new OldSpace(this, max_old_generation_size_, CODE_SPACE, EXECUTABLE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006152 if (code_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006153 if (!code_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006154
6155 // Initialize map space.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00006156 map_space_ = new MapSpace(this, max_old_generation_size_, MAP_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006157 if (map_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006158 if (!map_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006159
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006160 // Initialize global property cell space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006161 cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006162 if (cell_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006163 if (!cell_space_->SetUp()) return false;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006164
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006165 // The large object code space may contain code or data. We set the memory
6166 // to be non-executable here for safety, but this means we need to enable it
6167 // explicitly when allocating large code objects.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006168 lo_space_ = new LargeObjectSpace(this, max_old_generation_size_, LO_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006169 if (lo_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006170 if (!lo_space_->SetUp()) return false;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006171
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006172 // Set up the seed that is used to randomize the string hash function.
6173 ASSERT(hash_seed() == 0);
6174 if (FLAG_randomize_hashes) {
6175 if (FLAG_hash_seed == 0) {
6176 set_hash_seed(
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006177 Smi::FromInt(V8::RandomPrivate(isolate()) & 0x3fffffff));
6178 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006179 set_hash_seed(Smi::FromInt(FLAG_hash_seed));
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006180 }
6181 }
6182
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006183 if (create_heap_objects) {
6184 // Create initial maps.
6185 if (!CreateInitialMaps()) return false;
6186 if (!CreateApiObjects()) return false;
6187
6188 // Create initial objects
6189 if (!CreateInitialObjects()) return false;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00006190
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006191 native_contexts_list_ = undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006192 }
6193
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006194 LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity()));
6195 LOG(isolate_, IntPtrTEvent("heap-available", Available()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006196
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006197 store_buffer()->SetUp();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006198
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006199 if (FLAG_parallel_recompilation) relocation_mutex_ = OS::CreateMutex();
6200
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006201 return true;
6202}
6203
6204
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006205void Heap::SetStackLimits() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006206 ASSERT(isolate_ != NULL);
6207 ASSERT(isolate_ == isolate());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006208 // On 64 bit machines, pointers are generally out of range of Smis. We write
6209 // something that looks like an out of range Smi to the GC.
6210
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006211 // Set up the special root array entries containing the stack limits.
6212 // These are actually addresses, but the tag makes the GC ignore it.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006213 roots_[kStackLimitRootIndex] =
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006214 reinterpret_cast<Object*>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006215 (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006216 roots_[kRealStackLimitRootIndex] =
6217 reinterpret_cast<Object*>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006218 (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006219}
6220
6221
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006222void Heap::TearDown() {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006223#ifdef VERIFY_HEAP
danno@chromium.org1044a4d2012-04-30 12:34:39 +00006224 if (FLAG_verify_heap) {
6225 Verify();
6226 }
6227#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006228
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006229 if (FLAG_print_cumulative_gc_stat) {
6230 PrintF("\n\n");
6231 PrintF("gc_count=%d ", gc_count_);
6232 PrintF("mark_sweep_count=%d ", ms_count_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006233 PrintF("max_gc_pause=%d ", get_max_gc_pause());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006234 PrintF("total_gc_time=%d ", total_gc_time_ms_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006235 PrintF("min_in_mutator=%d ", get_min_in_mutator());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006236 PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ",
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006237 get_max_alive_after_gc());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006238 PrintF("\n\n");
6239 }
6240
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006241 isolate_->global_handles()->TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006242
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006243 external_string_table_.TearDown();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00006244
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006245 new_space_.TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006246
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006247 if (old_pointer_space_ != NULL) {
6248 old_pointer_space_->TearDown();
6249 delete old_pointer_space_;
6250 old_pointer_space_ = NULL;
6251 }
6252
6253 if (old_data_space_ != NULL) {
6254 old_data_space_->TearDown();
6255 delete old_data_space_;
6256 old_data_space_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006257 }
6258
6259 if (code_space_ != NULL) {
6260 code_space_->TearDown();
6261 delete code_space_;
6262 code_space_ = NULL;
6263 }
6264
6265 if (map_space_ != NULL) {
6266 map_space_->TearDown();
6267 delete map_space_;
6268 map_space_ = NULL;
6269 }
6270
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006271 if (cell_space_ != NULL) {
6272 cell_space_->TearDown();
6273 delete cell_space_;
6274 cell_space_ = NULL;
6275 }
6276
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006277 if (lo_space_ != NULL) {
6278 lo_space_->TearDown();
6279 delete lo_space_;
6280 lo_space_ = NULL;
6281 }
6282
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006283 store_buffer()->TearDown();
6284 incremental_marking()->TearDown();
6285
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006286 isolate_->memory_allocator()->TearDown();
6287
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006288 delete relocation_mutex_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006289}
6290
6291
6292void Heap::Shrink() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006293 // Try to shrink all paged spaces.
6294 PagedSpaces spaces;
danno@chromium.org2c456792011-11-11 12:00:53 +00006295 for (PagedSpace* space = spaces.next();
6296 space != NULL;
6297 space = spaces.next()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006298 space->ReleaseAllUnusedPages();
danno@chromium.org2c456792011-11-11 12:00:53 +00006299 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006300}
6301
6302
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006303void Heap::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) {
6304 ASSERT(callback != NULL);
6305 GCPrologueCallbackPair pair(callback, gc_type);
6306 ASSERT(!gc_prologue_callbacks_.Contains(pair));
6307 return gc_prologue_callbacks_.Add(pair);
6308}
6309
6310
6311void Heap::RemoveGCPrologueCallback(GCPrologueCallback callback) {
6312 ASSERT(callback != NULL);
6313 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
6314 if (gc_prologue_callbacks_[i].callback == callback) {
6315 gc_prologue_callbacks_.Remove(i);
6316 return;
6317 }
6318 }
6319 UNREACHABLE();
6320}
6321
6322
6323void Heap::AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type) {
6324 ASSERT(callback != NULL);
6325 GCEpilogueCallbackPair pair(callback, gc_type);
6326 ASSERT(!gc_epilogue_callbacks_.Contains(pair));
6327 return gc_epilogue_callbacks_.Add(pair);
6328}
6329
6330
6331void Heap::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
6332 ASSERT(callback != NULL);
6333 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
6334 if (gc_epilogue_callbacks_[i].callback == callback) {
6335 gc_epilogue_callbacks_.Remove(i);
6336 return;
6337 }
6338 }
6339 UNREACHABLE();
6340}
6341
6342
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006343#ifdef DEBUG
6344
6345class PrintHandleVisitor: public ObjectVisitor {
6346 public:
6347 void VisitPointers(Object** start, Object** end) {
6348 for (Object** p = start; p < end; p++)
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006349 PrintF(" handle %p to %p\n",
6350 reinterpret_cast<void*>(p),
6351 reinterpret_cast<void*>(*p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006352 }
6353};
6354
6355void Heap::PrintHandles() {
6356 PrintF("Handles:\n");
6357 PrintHandleVisitor v;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006358 isolate_->handle_scope_implementer()->Iterate(&v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006359}
6360
6361#endif
6362
6363
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006364Space* AllSpaces::next() {
6365 switch (counter_++) {
6366 case NEW_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006367 return HEAP->new_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006368 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006369 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006370 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006371 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006372 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006373 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006374 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006375 return HEAP->map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006376 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006377 return HEAP->cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006378 case LO_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006379 return HEAP->lo_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006380 default:
6381 return NULL;
6382 }
6383}
6384
6385
6386PagedSpace* PagedSpaces::next() {
6387 switch (counter_++) {
6388 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006389 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006390 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006391 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006392 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006393 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006394 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006395 return HEAP->map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006396 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006397 return HEAP->cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006398 default:
6399 return NULL;
6400 }
6401}
6402
6403
6404
6405OldSpace* OldSpaces::next() {
6406 switch (counter_++) {
6407 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006408 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006409 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006410 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006411 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006412 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006413 default:
6414 return NULL;
6415 }
6416}
6417
6418
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006419SpaceIterator::SpaceIterator()
6420 : current_space_(FIRST_SPACE),
6421 iterator_(NULL),
6422 size_func_(NULL) {
6423}
6424
6425
6426SpaceIterator::SpaceIterator(HeapObjectCallback size_func)
6427 : current_space_(FIRST_SPACE),
6428 iterator_(NULL),
6429 size_func_(size_func) {
kasper.lund7276f142008-07-30 08:49:36 +00006430}
6431
6432
6433SpaceIterator::~SpaceIterator() {
6434 // Delete active iterator if any.
6435 delete iterator_;
6436}
6437
6438
6439bool SpaceIterator::has_next() {
6440 // Iterate until no more spaces.
6441 return current_space_ != LAST_SPACE;
6442}
6443
6444
6445ObjectIterator* SpaceIterator::next() {
6446 if (iterator_ != NULL) {
6447 delete iterator_;
6448 iterator_ = NULL;
6449 // Move to the next space
6450 current_space_++;
6451 if (current_space_ > LAST_SPACE) {
6452 return NULL;
6453 }
6454 }
6455
6456 // Return iterator for the new current space.
6457 return CreateIterator();
6458}
6459
6460
6461// Create an iterator for the space to iterate.
6462ObjectIterator* SpaceIterator::CreateIterator() {
6463 ASSERT(iterator_ == NULL);
6464
6465 switch (current_space_) {
6466 case NEW_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006467 iterator_ = new SemiSpaceIterator(HEAP->new_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006468 break;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006469 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006470 iterator_ = new HeapObjectIterator(HEAP->old_pointer_space(), size_func_);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006471 break;
6472 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006473 iterator_ = new HeapObjectIterator(HEAP->old_data_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006474 break;
6475 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006476 iterator_ = new HeapObjectIterator(HEAP->code_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006477 break;
6478 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006479 iterator_ = new HeapObjectIterator(HEAP->map_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006480 break;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006481 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006482 iterator_ = new HeapObjectIterator(HEAP->cell_space(), size_func_);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006483 break;
kasper.lund7276f142008-07-30 08:49:36 +00006484 case LO_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006485 iterator_ = new LargeObjectIterator(HEAP->lo_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006486 break;
6487 }
6488
6489 // Return the newly allocated iterator;
6490 ASSERT(iterator_ != NULL);
6491 return iterator_;
6492}
6493
6494
whesse@chromium.org023421e2010-12-21 12:19:12 +00006495class HeapObjectsFilter {
6496 public:
6497 virtual ~HeapObjectsFilter() {}
6498 virtual bool SkipObject(HeapObject* object) = 0;
6499};
6500
6501
whesse@chromium.org023421e2010-12-21 12:19:12 +00006502class UnreachableObjectsFilter : public HeapObjectsFilter {
6503 public:
6504 UnreachableObjectsFilter() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006505 MarkReachableObjects();
6506 }
6507
6508 ~UnreachableObjectsFilter() {
6509 Isolate::Current()->heap()->mark_compact_collector()->ClearMarkbits();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006510 }
6511
6512 bool SkipObject(HeapObject* object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006513 MarkBit mark_bit = Marking::MarkBitFrom(object);
6514 return !mark_bit.Get();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006515 }
6516
6517 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006518 class MarkingVisitor : public ObjectVisitor {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006519 public:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006520 MarkingVisitor() : marking_stack_(10) {}
whesse@chromium.org023421e2010-12-21 12:19:12 +00006521
6522 void VisitPointers(Object** start, Object** end) {
6523 for (Object** p = start; p < end; p++) {
6524 if (!(*p)->IsHeapObject()) continue;
6525 HeapObject* obj = HeapObject::cast(*p);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006526 MarkBit mark_bit = Marking::MarkBitFrom(obj);
6527 if (!mark_bit.Get()) {
6528 mark_bit.Set();
6529 marking_stack_.Add(obj);
whesse@chromium.org023421e2010-12-21 12:19:12 +00006530 }
6531 }
6532 }
6533
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006534 void TransitiveClosure() {
6535 while (!marking_stack_.is_empty()) {
6536 HeapObject* obj = marking_stack_.RemoveLast();
6537 obj->Iterate(this);
6538 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00006539 }
6540
6541 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006542 List<HeapObject*> marking_stack_;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006543 };
6544
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006545 void MarkReachableObjects() {
6546 Heap* heap = Isolate::Current()->heap();
6547 MarkingVisitor visitor;
6548 heap->IterateRoots(&visitor, VISIT_ALL);
6549 visitor.TransitiveClosure();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006550 }
6551
6552 AssertNoAllocation no_alloc;
6553};
6554
6555
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006556HeapIterator::HeapIterator()
6557 : filtering_(HeapIterator::kNoFiltering),
6558 filter_(NULL) {
6559 Init();
6560}
6561
6562
whesse@chromium.org023421e2010-12-21 12:19:12 +00006563HeapIterator::HeapIterator(HeapIterator::HeapObjectsFiltering filtering)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006564 : filtering_(filtering),
6565 filter_(NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006566 Init();
6567}
6568
6569
6570HeapIterator::~HeapIterator() {
6571 Shutdown();
6572}
6573
6574
6575void HeapIterator::Init() {
6576 // Start the iteration.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006577 space_iterator_ = new SpaceIterator;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006578 switch (filtering_) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006579 case kFilterUnreachable:
6580 filter_ = new UnreachableObjectsFilter;
6581 break;
6582 default:
6583 break;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006585 object_iterator_ = space_iterator_->next();
6586}
6587
6588
6589void HeapIterator::Shutdown() {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006590#ifdef DEBUG
whesse@chromium.org023421e2010-12-21 12:19:12 +00006591 // Assert that in filtering mode we have iterated through all
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006592 // objects. Otherwise, heap will be left in an inconsistent state.
whesse@chromium.org023421e2010-12-21 12:19:12 +00006593 if (filtering_ != kNoFiltering) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006594 ASSERT(object_iterator_ == NULL);
6595 }
6596#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006597 // Make sure the last iterator is deallocated.
6598 delete space_iterator_;
6599 space_iterator_ = NULL;
6600 object_iterator_ = NULL;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006601 delete filter_;
6602 filter_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006603}
6604
6605
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006606HeapObject* HeapIterator::next() {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006607 if (filter_ == NULL) return NextObject();
6608
6609 HeapObject* obj = NextObject();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006610 while (obj != NULL && filter_->SkipObject(obj)) obj = NextObject();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006611 return obj;
6612}
6613
6614
6615HeapObject* HeapIterator::NextObject() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006616 // No iterator means we are done.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006617 if (object_iterator_ == NULL) return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006618
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006619 if (HeapObject* obj = object_iterator_->next_object()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006620 // If the current iterator has more objects we are fine.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006621 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006622 } else {
6623 // Go though the spaces looking for one that has objects.
6624 while (space_iterator_->has_next()) {
6625 object_iterator_ = space_iterator_->next();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006626 if (HeapObject* obj = object_iterator_->next_object()) {
6627 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006628 }
6629 }
6630 }
6631 // Done with the last space.
6632 object_iterator_ = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006633 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006634}
6635
6636
6637void HeapIterator::reset() {
6638 // Restart the iterator.
6639 Shutdown();
6640 Init();
6641}
6642
6643
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006644#if defined(DEBUG) || defined(LIVE_OBJECT_LIST)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006645
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006646Object* const PathTracer::kAnyGlobalObject = reinterpret_cast<Object*>(NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006647
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006648class PathTracer::MarkVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006649 public:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006650 explicit MarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006651 void VisitPointers(Object** start, Object** end) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006652 // Scan all HeapObject pointers in [start, end)
6653 for (Object** p = start; !tracer_->found() && (p < end); p++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006654 if ((*p)->IsHeapObject())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006655 tracer_->MarkRecursively(p, this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006656 }
6657 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006658
6659 private:
6660 PathTracer* tracer_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006661};
6662
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006663
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006664class PathTracer::UnmarkVisitor: public ObjectVisitor {
6665 public:
6666 explicit UnmarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
6667 void VisitPointers(Object** start, Object** end) {
6668 // Scan all HeapObject pointers in [start, end)
6669 for (Object** p = start; p < end; p++) {
6670 if ((*p)->IsHeapObject())
6671 tracer_->UnmarkRecursively(p, this);
6672 }
6673 }
6674
6675 private:
6676 PathTracer* tracer_;
6677};
6678
6679
6680void PathTracer::VisitPointers(Object** start, Object** end) {
6681 bool done = ((what_to_find_ == FIND_FIRST) && found_target_);
6682 // Visit all HeapObject pointers in [start, end)
6683 for (Object** p = start; !done && (p < end); p++) {
6684 if ((*p)->IsHeapObject()) {
6685 TracePathFrom(p);
6686 done = ((what_to_find_ == FIND_FIRST) && found_target_);
6687 }
6688 }
6689}
6690
6691
6692void PathTracer::Reset() {
6693 found_target_ = false;
6694 object_stack_.Clear();
6695}
6696
6697
6698void PathTracer::TracePathFrom(Object** root) {
6699 ASSERT((search_target_ == kAnyGlobalObject) ||
6700 search_target_->IsHeapObject());
6701 found_target_in_trace_ = false;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00006702 Reset();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006703
6704 MarkVisitor mark_visitor(this);
6705 MarkRecursively(root, &mark_visitor);
6706
6707 UnmarkVisitor unmark_visitor(this);
6708 UnmarkRecursively(root, &unmark_visitor);
6709
6710 ProcessResults();
6711}
6712
6713
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006714static bool SafeIsNativeContext(HeapObject* obj) {
6715 return obj->map() == obj->GetHeap()->raw_unchecked_native_context_map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006716}
6717
6718
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006719void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006720 if (!(*p)->IsHeapObject()) return;
6721
6722 HeapObject* obj = HeapObject::cast(*p);
6723
6724 Object* map = obj->map();
6725
6726 if (!map->IsHeapObject()) return; // visited before
6727
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006728 if (found_target_in_trace_) return; // stop if target found
6729 object_stack_.Add(obj);
6730 if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) ||
6731 (obj == search_target_)) {
6732 found_target_in_trace_ = true;
6733 found_target_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006734 return;
6735 }
6736
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006737 bool is_native_context = SafeIsNativeContext(obj);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006738
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006739 // not visited yet
6740 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
6741
6742 Address map_addr = map_p->address();
6743
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006744 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_addr + kMarkTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006745
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006746 // Scan the object body.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006747 if (is_native_context && (visit_mode_ == VISIT_ONLY_STRONG)) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006748 // This is specialized to scan Context's properly.
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00006749 Object** start = reinterpret_cast<Object**>(obj->address() +
6750 Context::kHeaderSize);
6751 Object** end = reinterpret_cast<Object**>(obj->address() +
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006752 Context::kHeaderSize + Context::FIRST_WEAK_SLOT * kPointerSize);
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00006753 mark_visitor->VisitPointers(start, end);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006754 } else {
6755 obj->IterateBody(map_p->instance_type(),
6756 obj->SizeFromMap(map_p),
6757 mark_visitor);
6758 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006759
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006760 // Scan the map after the body because the body is a lot more interesting
6761 // when doing leak detection.
6762 MarkRecursively(&map, mark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006763
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006764 if (!found_target_in_trace_) // don't pop if found the target
6765 object_stack_.RemoveLast();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006766}
6767
6768
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006769void PathTracer::UnmarkRecursively(Object** p, UnmarkVisitor* unmark_visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006770 if (!(*p)->IsHeapObject()) return;
6771
6772 HeapObject* obj = HeapObject::cast(*p);
6773
6774 Object* map = obj->map();
6775
6776 if (map->IsHeapObject()) return; // unmarked already
6777
6778 Address map_addr = reinterpret_cast<Address>(map);
6779
6780 map_addr -= kMarkTag;
6781
6782 ASSERT_TAG_ALIGNED(map_addr);
6783
6784 HeapObject* map_p = HeapObject::FromAddress(map_addr);
6785
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006786 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006787
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006788 UnmarkRecursively(reinterpret_cast<Object**>(&map_p), unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006789
6790 obj->IterateBody(Map::cast(map_p)->instance_type(),
6791 obj->SizeFromMap(Map::cast(map_p)),
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006792 unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006793}
6794
6795
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006796void PathTracer::ProcessResults() {
6797 if (found_target_) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006798 PrintF("=====================================\n");
6799 PrintF("==== Path to object ====\n");
6800 PrintF("=====================================\n\n");
6801
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006802 ASSERT(!object_stack_.is_empty());
6803 for (int i = 0; i < object_stack_.length(); i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006804 if (i > 0) PrintF("\n |\n |\n V\n\n");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006805 Object* obj = object_stack_[i];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006806 obj->Print();
6807 }
6808 PrintF("=====================================\n");
6809 }
6810}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006811#endif // DEBUG || LIVE_OBJECT_LIST
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006812
6813
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006814#ifdef DEBUG
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00006815// Triggers a depth-first traversal of reachable objects from one
6816// given root object and finds a path to a specific heap object and
6817// prints it.
6818void Heap::TracePathToObjectFrom(Object* target, Object* root) {
6819 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
6820 tracer.VisitPointer(&root);
6821}
6822
6823
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006824// Triggers a depth-first traversal of reachable objects from roots
6825// and finds a path to a specific heap object and prints it.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00006826void Heap::TracePathToObject(Object* target) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006827 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
6828 IterateRoots(&tracer, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006829}
6830
6831
6832// Triggers a depth-first traversal of reachable objects from roots
6833// and finds a path to any global object and prints it. Useful for
6834// determining the source for leaks of global objects.
6835void Heap::TracePathToGlobal() {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006836 PathTracer tracer(PathTracer::kAnyGlobalObject,
6837 PathTracer::FIND_ALL,
6838 VISIT_ALL);
6839 IterateRoots(&tracer, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006840}
6841#endif
6842
6843
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006844static intptr_t CountTotalHolesSize() {
6845 intptr_t holes_size = 0;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006846 OldSpaces spaces;
6847 for (OldSpace* space = spaces.next();
6848 space != NULL;
6849 space = spaces.next()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006850 holes_size += space->Waste() + space->Available();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006851 }
6852 return holes_size;
6853}
6854
6855
rossberg@chromium.org994edf62012-02-06 10:12:55 +00006856GCTracer::GCTracer(Heap* heap,
6857 const char* gc_reason,
6858 const char* collector_reason)
kasper.lund7276f142008-07-30 08:49:36 +00006859 : start_time_(0.0),
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00006860 start_object_size_(0),
6861 start_memory_size_(0),
kasper.lund7276f142008-07-30 08:49:36 +00006862 gc_count_(0),
6863 full_gc_count_(0),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006864 allocated_since_last_gc_(0),
6865 spent_in_mutator_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006866 promoted_objects_size_(0),
rossberg@chromium.org994edf62012-02-06 10:12:55 +00006867 heap_(heap),
6868 gc_reason_(gc_reason),
6869 collector_reason_(collector_reason) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006870 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
kasper.lund7276f142008-07-30 08:49:36 +00006871 start_time_ = OS::TimeCurrentMillis();
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00006872 start_object_size_ = heap_->SizeOfObjects();
6873 start_memory_size_ = heap_->isolate()->memory_allocator()->Size();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006874
6875 for (int i = 0; i < Scope::kNumberOfScopes; i++) {
6876 scopes_[i] = 0;
6877 }
6878
6879 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize();
6880
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006881 allocated_since_last_gc_ =
6882 heap_->SizeOfObjects() - heap_->alive_after_last_gc_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006883
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006884 if (heap_->last_gc_end_timestamp_ > 0) {
6885 spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006886 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006887
6888 steps_count_ = heap_->incremental_marking()->steps_count();
6889 steps_took_ = heap_->incremental_marking()->steps_took();
6890 longest_step_ = heap_->incremental_marking()->longest_step();
6891 steps_count_since_last_gc_ =
6892 heap_->incremental_marking()->steps_count_since_last_gc();
6893 steps_took_since_last_gc_ =
6894 heap_->incremental_marking()->steps_took_since_last_gc();
kasper.lund7276f142008-07-30 08:49:36 +00006895}
6896
6897
6898GCTracer::~GCTracer() {
kasper.lund7276f142008-07-30 08:49:36 +00006899 // Printf ONE line iff flag is set.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006900 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
6901
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006902 bool first_gc = (heap_->last_gc_end_timestamp_ == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006903
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006904 heap_->alive_after_last_gc_ = heap_->SizeOfObjects();
6905 heap_->last_gc_end_timestamp_ = OS::TimeCurrentMillis();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006906
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006907 int time = static_cast<int>(heap_->last_gc_end_timestamp_ - start_time_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006908
6909 // Update cumulative GC statistics if required.
6910 if (FLAG_print_cumulative_gc_stat) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006911 heap_->total_gc_time_ms_ += time;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006912 heap_->max_gc_pause_ = Max(heap_->max_gc_pause_, time);
6913 heap_->max_alive_after_gc_ = Max(heap_->max_alive_after_gc_,
6914 heap_->alive_after_last_gc_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006915 if (!first_gc) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006916 heap_->min_in_mutator_ = Min(heap_->min_in_mutator_,
6917 static_cast<int>(spent_in_mutator_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006918 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006919 } else if (FLAG_trace_gc_verbose) {
6920 heap_->total_gc_time_ms_ += time;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006921 }
6922
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006923 if (collector_ == SCAVENGER && FLAG_trace_gc_ignore_scavenger) return;
6924
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006925 PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init());
rossberg@chromium.org994edf62012-02-06 10:12:55 +00006926
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006927 if (!FLAG_trace_gc_nvp) {
6928 int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]);
6929
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00006930 double end_memory_size_mb =
6931 static_cast<double>(heap_->isolate()->memory_allocator()->Size()) / MB;
6932
6933 PrintF("%s %.1f (%.1f) -> %.1f (%.1f) MB, ",
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006934 CollectorString(),
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00006935 static_cast<double>(start_object_size_) / MB,
6936 static_cast<double>(start_memory_size_) / MB,
6937 SizeOfHeapObjects(),
6938 end_memory_size_mb);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006939
6940 if (external_time > 0) PrintF("%d / ", external_time);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006941 PrintF("%d ms", time);
6942 if (steps_count_ > 0) {
6943 if (collector_ == SCAVENGER) {
6944 PrintF(" (+ %d ms in %d steps since last GC)",
6945 static_cast<int>(steps_took_since_last_gc_),
6946 steps_count_since_last_gc_);
6947 } else {
6948 PrintF(" (+ %d ms in %d steps since start of marking, "
6949 "biggest step %f ms)",
6950 static_cast<int>(steps_took_),
6951 steps_count_,
6952 longest_step_);
6953 }
6954 }
rossberg@chromium.org994edf62012-02-06 10:12:55 +00006955
6956 if (gc_reason_ != NULL) {
6957 PrintF(" [%s]", gc_reason_);
6958 }
6959
6960 if (collector_reason_ != NULL) {
6961 PrintF(" [%s]", collector_reason_);
6962 }
6963
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006964 PrintF(".\n");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006965 } else {
6966 PrintF("pause=%d ", time);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006967 PrintF("mutator=%d ", static_cast<int>(spent_in_mutator_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006968 PrintF("gc=");
6969 switch (collector_) {
6970 case SCAVENGER:
6971 PrintF("s");
6972 break;
6973 case MARK_COMPACTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006974 PrintF("ms");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006975 break;
6976 default:
6977 UNREACHABLE();
6978 }
6979 PrintF(" ");
6980
6981 PrintF("external=%d ", static_cast<int>(scopes_[Scope::EXTERNAL]));
6982 PrintF("mark=%d ", static_cast<int>(scopes_[Scope::MC_MARK]));
6983 PrintF("sweep=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP]));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006984 PrintF("sweepns=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP_NEWSPACE]));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00006985 PrintF("evacuate=%d ", static_cast<int>(scopes_[Scope::MC_EVACUATE_PAGES]));
6986 PrintF("new_new=%d ",
6987 static_cast<int>(scopes_[Scope::MC_UPDATE_NEW_TO_NEW_POINTERS]));
6988 PrintF("root_new=%d ",
6989 static_cast<int>(scopes_[Scope::MC_UPDATE_ROOT_TO_NEW_POINTERS]));
6990 PrintF("old_new=%d ",
6991 static_cast<int>(scopes_[Scope::MC_UPDATE_OLD_TO_NEW_POINTERS]));
6992 PrintF("compaction_ptrs=%d ",
6993 static_cast<int>(scopes_[Scope::MC_UPDATE_POINTERS_TO_EVACUATED]));
6994 PrintF("intracompaction_ptrs=%d ", static_cast<int>(scopes_[
6995 Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED]));
6996 PrintF("misc_compaction=%d ",
6997 static_cast<int>(scopes_[Scope::MC_UPDATE_MISC_POINTERS]));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006998
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00006999 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_object_size_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007000 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007001 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ",
7002 in_free_list_or_wasted_before_gc_);
7003 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007004
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007005 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_);
7006 PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007007
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007008 if (collector_ == SCAVENGER) {
7009 PrintF("stepscount=%d ", steps_count_since_last_gc_);
7010 PrintF("stepstook=%d ", static_cast<int>(steps_took_since_last_gc_));
7011 } else {
7012 PrintF("stepscount=%d ", steps_count_);
7013 PrintF("stepstook=%d ", static_cast<int>(steps_took_));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007014 PrintF("longeststep=%.f ", longest_step_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007015 }
7016
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007017 PrintF("\n");
7018 }
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007019
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007020 heap_->PrintShortHeapStatistics();
kasper.lund7276f142008-07-30 08:49:36 +00007021}
7022
7023
7024const char* GCTracer::CollectorString() {
7025 switch (collector_) {
7026 case SCAVENGER:
7027 return "Scavenge";
7028 case MARK_COMPACTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007029 return "Mark-sweep";
kasper.lund7276f142008-07-30 08:49:36 +00007030 }
7031 return "Unknown GC";
7032}
7033
7034
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007035int KeyedLookupCache::Hash(Map* map, String* name) {
7036 // Uses only lower 32 bits if pointers are larger.
7037 uintptr_t addr_hash =
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007038 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00007039 return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007040}
7041
7042
7043int KeyedLookupCache::Lookup(Map* map, String* name) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007044 int index = (Hash(map, name) & kHashMask);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007045 for (int i = 0; i < kEntriesPerBucket; i++) {
7046 Key& key = keys_[index + i];
7047 if ((key.map == map) && key.name->Equals(name)) {
7048 return field_offsets_[index + i];
7049 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007050 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007051 return kNotFound;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007052}
7053
7054
7055void KeyedLookupCache::Update(Map* map, String* name, int field_offset) {
7056 String* symbol;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007057 if (HEAP->LookupSymbolIfExists(name, &symbol)) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007058 int index = (Hash(map, symbol) & kHashMask);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007059 // After a GC there will be free slots, so we use them in order (this may
7060 // help to get the most frequently used one in position 0).
7061 for (int i = 0; i< kEntriesPerBucket; i++) {
7062 Key& key = keys_[index];
7063 Object* free_entry_indicator = NULL;
7064 if (key.map == free_entry_indicator) {
7065 key.map = map;
7066 key.name = symbol;
7067 field_offsets_[index + i] = field_offset;
7068 return;
7069 }
7070 }
7071 // No free entry found in this bucket, so we move them all down one and
7072 // put the new entry at position zero.
7073 for (int i = kEntriesPerBucket - 1; i > 0; i--) {
7074 Key& key = keys_[index + i];
7075 Key& key2 = keys_[index + i - 1];
7076 key = key2;
7077 field_offsets_[index + i] = field_offsets_[index + i - 1];
7078 }
7079
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007080 // Write the new first entry.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007081 Key& key = keys_[index];
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007082 key.map = map;
7083 key.name = symbol;
7084 field_offsets_[index] = field_offset;
7085 }
7086}
7087
7088
7089void KeyedLookupCache::Clear() {
7090 for (int index = 0; index < kLength; index++) keys_[index].map = NULL;
7091}
7092
7093
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007094void DescriptorLookupCache::Clear() {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007095 for (int index = 0; index < kLength; index++) keys_[index].source = NULL;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007096}
7097
7098
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007099#ifdef DEBUG
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007100void Heap::GarbageCollectionGreedyCheck() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007101 ASSERT(FLAG_gc_greedy);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007102 if (isolate_->bootstrapper()->IsActive()) return;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007103 if (disallow_allocation_failure()) return;
7104 CollectGarbage(NEW_SPACE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007105}
7106#endif
7107
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007108
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007109TranscendentalCache::SubCache::SubCache(Type t)
7110 : type_(t),
7111 isolate_(Isolate::Current()) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007112 uint32_t in0 = 0xffffffffu; // Bit-pattern for a NaN that isn't
7113 uint32_t in1 = 0xffffffffu; // generated by the FPU.
7114 for (int i = 0; i < kCacheSize; i++) {
7115 elements_[i].in[0] = in0;
7116 elements_[i].in[1] = in1;
7117 elements_[i].output = NULL;
7118 }
7119}
7120
7121
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007122void TranscendentalCache::Clear() {
7123 for (int i = 0; i < kNumberOfCaches; i++) {
7124 if (caches_[i] != NULL) {
7125 delete caches_[i];
7126 caches_[i] = NULL;
7127 }
7128 }
7129}
7130
7131
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007132void ExternalStringTable::CleanUp() {
7133 int last = 0;
7134 for (int i = 0; i < new_space_strings_.length(); ++i) {
danno@chromium.org72204d52012-10-31 10:02:10 +00007135 if (new_space_strings_[i] == heap_->the_hole_value()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007136 continue;
7137 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007138 if (heap_->InNewSpace(new_space_strings_[i])) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007139 new_space_strings_[last++] = new_space_strings_[i];
7140 } else {
7141 old_space_strings_.Add(new_space_strings_[i]);
7142 }
7143 }
7144 new_space_strings_.Rewind(last);
7145 last = 0;
7146 for (int i = 0; i < old_space_strings_.length(); ++i) {
danno@chromium.org72204d52012-10-31 10:02:10 +00007147 if (old_space_strings_[i] == heap_->the_hole_value()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007148 continue;
7149 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007150 ASSERT(!heap_->InNewSpace(old_space_strings_[i]));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007151 old_space_strings_[last++] = old_space_strings_[i];
7152 }
7153 old_space_strings_.Rewind(last);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007154#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007155 if (FLAG_verify_heap) {
7156 Verify();
7157 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007158#endif
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007159}
7160
7161
7162void ExternalStringTable::TearDown() {
7163 new_space_strings_.Free();
7164 old_space_strings_.Free();
7165}
7166
7167
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007168void Heap::QueueMemoryChunkForFree(MemoryChunk* chunk) {
7169 chunk->set_next_chunk(chunks_queued_for_free_);
7170 chunks_queued_for_free_ = chunk;
7171}
7172
7173
7174void Heap::FreeQueuedChunks() {
7175 if (chunks_queued_for_free_ == NULL) return;
7176 MemoryChunk* next;
7177 MemoryChunk* chunk;
7178 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
7179 next = chunk->next_chunk();
7180 chunk->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
7181
7182 if (chunk->owner()->identity() == LO_SPACE) {
7183 // StoreBuffer::Filter relies on MemoryChunk::FromAnyPointerAddress.
7184 // If FromAnyPointerAddress encounters a slot that belongs to a large
7185 // chunk queued for deletion it will fail to find the chunk because
7186 // it try to perform a search in the list of pages owned by of the large
7187 // object space and queued chunks were detached from that list.
7188 // To work around this we split large chunk into normal kPageSize aligned
danno@chromium.org2c456792011-11-11 12:00:53 +00007189 // pieces and initialize size, owner and flags field of every piece.
7190 // If FromAnyPointerAddress encounters a slot that belongs to one of
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007191 // these smaller pieces it will treat it as a slot on a normal Page.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007192 Address chunk_end = chunk->address() + chunk->size();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007193 MemoryChunk* inner = MemoryChunk::FromAddress(
7194 chunk->address() + Page::kPageSize);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007195 MemoryChunk* inner_last = MemoryChunk::FromAddress(chunk_end - 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007196 while (inner <= inner_last) {
7197 // Size of a large chunk is always a multiple of
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007198 // OS::AllocateAlignment() so there is always
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007199 // enough space for a fake MemoryChunk header.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007200 Address area_end = Min(inner->address() + Page::kPageSize, chunk_end);
7201 // Guard against overflow.
7202 if (area_end < inner->address()) area_end = chunk_end;
7203 inner->SetArea(inner->address(), area_end);
danno@chromium.org2c456792011-11-11 12:00:53 +00007204 inner->set_size(Page::kPageSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007205 inner->set_owner(lo_space());
7206 inner->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
7207 inner = MemoryChunk::FromAddress(
7208 inner->address() + Page::kPageSize);
7209 }
7210 }
7211 }
7212 isolate_->heap()->store_buffer()->Compact();
7213 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED);
7214 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
7215 next = chunk->next_chunk();
7216 isolate_->memory_allocator()->Free(chunk);
7217 }
7218 chunks_queued_for_free_ = NULL;
7219}
7220
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00007221
7222void Heap::RememberUnmappedPage(Address page, bool compacted) {
7223 uintptr_t p = reinterpret_cast<uintptr_t>(page);
7224 // Tag the page pointer to make it findable in the dump file.
7225 if (compacted) {
7226 p ^= 0xc1ead & (Page::kPageSize - 1); // Cleared.
7227 } else {
7228 p ^= 0x1d1ed & (Page::kPageSize - 1); // I died.
7229 }
7230 remembered_unmapped_pages_[remembered_unmapped_pages_index_] =
7231 reinterpret_cast<Address>(p);
7232 remembered_unmapped_pages_index_++;
7233 remembered_unmapped_pages_index_ %= kRememberedUnmappedPages;
7234}
7235
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00007236
7237void Heap::ClearObjectStats(bool clear_last_time_stats) {
7238 memset(object_counts_, 0, sizeof(object_counts_));
7239 memset(object_sizes_, 0, sizeof(object_sizes_));
7240 if (clear_last_time_stats) {
7241 memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_));
7242 memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_));
7243 }
7244}
7245
7246
7247static LazyMutex checkpoint_object_stats_mutex = LAZY_MUTEX_INITIALIZER;
7248
7249
7250void Heap::CheckpointObjectStats() {
7251 ScopedLock lock(checkpoint_object_stats_mutex.Pointer());
7252 Counters* counters = isolate()->counters();
7253#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7254 counters->count_of_##name()->Increment( \
7255 static_cast<int>(object_counts_[name])); \
7256 counters->count_of_##name()->Decrement( \
7257 static_cast<int>(object_counts_last_time_[name])); \
7258 counters->size_of_##name()->Increment( \
7259 static_cast<int>(object_sizes_[name])); \
7260 counters->size_of_##name()->Decrement( \
7261 static_cast<int>(object_sizes_last_time_[name]));
7262 INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7263#undef ADJUST_LAST_TIME_OBJECT_COUNT
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007264 int index;
7265#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7266 index = FIRST_CODE_KIND_SUB_TYPE + Code::name; \
7267 counters->count_of_CODE_TYPE_##name()->Increment( \
7268 static_cast<int>(object_counts_[index])); \
7269 counters->count_of_CODE_TYPE_##name()->Decrement( \
7270 static_cast<int>(object_counts_last_time_[index])); \
7271 counters->size_of_CODE_TYPE_##name()->Increment( \
7272 static_cast<int>(object_sizes_[index])); \
7273 counters->size_of_CODE_TYPE_##name()->Decrement( \
7274 static_cast<int>(object_sizes_last_time_[index]));
7275 CODE_KIND_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7276#undef ADJUST_LAST_TIME_OBJECT_COUNT
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007277#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7278 index = FIRST_FIXED_ARRAY_SUB_TYPE + name; \
7279 counters->count_of_FIXED_ARRAY_##name()->Increment( \
7280 static_cast<int>(object_counts_[index])); \
7281 counters->count_of_FIXED_ARRAY_##name()->Decrement( \
7282 static_cast<int>(object_counts_last_time_[index])); \
7283 counters->size_of_FIXED_ARRAY_##name()->Increment( \
7284 static_cast<int>(object_sizes_[index])); \
7285 counters->size_of_FIXED_ARRAY_##name()->Decrement( \
7286 static_cast<int>(object_sizes_last_time_[index]));
7287 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7288#undef ADJUST_LAST_TIME_OBJECT_COUNT
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007289
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00007290 memcpy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
7291 memcpy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
7292 ClearObjectStats();
7293}
7294
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007295} } // namespace v8::internal