blob: 746c9b6d6faaf2676e3ddc7419f072f084007403 [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 =
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000968 isolate_->global_handles()->PostGarbageCollectionProcessing(
969 collector, tracer);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000970 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000971 gc_post_processing_depth_--;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000972
ager@chromium.org3811b432009-10-28 14:53:37 +0000973 // Update relocatables.
974 Relocatable::PostGarbageCollectionProcessing();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000975
kasper.lund7276f142008-07-30 08:49:36 +0000976 if (collector == MARK_COMPACTOR) {
977 // Register the amount of external allocated memory.
978 amount_of_external_allocated_memory_at_last_global_gc_ =
979 amount_of_external_allocated_memory_;
980 }
981
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000982 GCCallbackFlags callback_flags = kNoGCCallbackFlags;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000983 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
984 if (gc_type & gc_epilogue_callbacks_[i].gc_type) {
985 gc_epilogue_callbacks_[i].callback(gc_type, callback_flags);
986 }
987 }
988
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000989 if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) {
990 ASSERT(!allocation_allowed_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000991 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992 global_gc_epilogue_callback_();
993 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000994
995#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000996 if (FLAG_verify_heap) {
997 VerifySymbolTable();
998 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000999#endif
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001000
1001 return next_gc_likely_to_collect_more;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002}
1003
1004
kasper.lund7276f142008-07-30 08:49:36 +00001005void Heap::MarkCompact(GCTracer* tracer) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006 gc_state_ = MARK_COMPACT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001007 LOG(isolate_, ResourceEvent("markcompact", "begin"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001008
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001009 mark_compact_collector_.Prepare(tracer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001011 ms_count_++;
1012 tracer->set_full_gc_count(ms_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001013
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001014 MarkCompactPrologue();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001015
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001016 mark_compact_collector_.CollectGarbage();
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001018 LOG(isolate_, ResourceEvent("markcompact", "end"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019
1020 gc_state_ = NOT_IN_GC;
1021
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001022 isolate_->counters()->objs_since_last_full()->Set(0);
kasperl@chromium.org8b2bb262010-03-01 09:46:28 +00001023
1024 contexts_disposed_ = 0;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001025
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001026 flush_monomorphic_ics_ = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001027}
1028
1029
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001030void Heap::MarkCompactPrologue() {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001031 // At any old GC clear the keyed lookup cache to enable collection of unused
1032 // maps.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001033 isolate_->keyed_lookup_cache()->Clear();
1034 isolate_->context_slot_cache()->Clear();
1035 isolate_->descriptor_lookup_cache()->Clear();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001036 RegExpResultsCache::Clear(string_split_cache());
1037 RegExpResultsCache::Clear(regexp_multiple_cache());
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001038
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001039 isolate_->compilation_cache()->MarkCompactPrologue();
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001040
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001041 CompletelyClearInstanceofCache();
1042
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001043 FlushNumberStringCache();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001044 if (FLAG_cleanup_code_caches_at_gc) {
1045 polymorphic_code_cache()->set_cache(undefined_value());
1046 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001047
1048 ClearNormalizedMapCaches();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001049}
1050
1051
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001052Object* Heap::FindCodeObject(Address a) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001053 return isolate()->inner_pointer_to_code_cache()->
1054 GcSafeFindCodeForInnerPointer(a);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001055}
1056
1057
1058// Helper class for copying HeapObjects
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001059class ScavengeVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001060 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001061 explicit ScavengeVisitor(Heap* heap) : heap_(heap) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001063 void VisitPointer(Object** p) { ScavengePointer(p); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064
1065 void VisitPointers(Object** start, Object** end) {
1066 // Copy all HeapObject pointers in [start, end)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001067 for (Object** p = start; p < end; p++) ScavengePointer(p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001068 }
1069
1070 private:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001071 void ScavengePointer(Object** p) {
1072 Object* object = *p;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001073 if (!heap_->InNewSpace(object)) return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001074 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
1075 reinterpret_cast<HeapObject*>(object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001076 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001077
1078 Heap* heap_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001079};
1080
1081
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001082#ifdef VERIFY_HEAP
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001083// Visitor class to verify pointers in code or data space do not point into
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084// new space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001085class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001086 public:
1087 void VisitPointers(Object** start, Object**end) {
1088 for (Object** current = start; current < end; current++) {
1089 if ((*current)->IsHeapObject()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001090 CHECK(!HEAP->InNewSpace(HeapObject::cast(*current)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091 }
1092 }
1093 }
1094};
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001095
1096
1097static void VerifyNonPointerSpacePointers() {
1098 // Verify that there are no pointers to new space in spaces where we
1099 // do not expect them.
1100 VerifyNonPointerSpacePointersVisitor v;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001101 HeapObjectIterator code_it(HEAP->code_space());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001102 for (HeapObject* object = code_it.Next();
1103 object != NULL; object = code_it.Next())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001104 object->Iterate(&v);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001105
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001106 // The old data space was normally swept conservatively so that the iterator
1107 // doesn't work, so we normally skip the next bit.
1108 if (!HEAP->old_data_space()->was_swept_conservatively()) {
1109 HeapObjectIterator data_it(HEAP->old_data_space());
1110 for (HeapObject* object = data_it.Next();
1111 object != NULL; object = data_it.Next())
1112 object->Iterate(&v);
1113 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001114}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001115#endif // VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001116
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001117
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001118void Heap::CheckNewSpaceExpansionCriteria() {
1119 if (new_space_.Capacity() < new_space_.MaximumCapacity() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001120 survived_since_last_expansion_ > new_space_.Capacity() &&
1121 !new_space_high_promotion_mode_active_) {
1122 // Grow the size of new space if there is room to grow, enough data
1123 // has survived scavenge since the last expansion and we are not in
1124 // high promotion mode.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001125 new_space_.Grow();
1126 survived_since_last_expansion_ = 0;
1127 }
1128}
1129
1130
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001131static bool IsUnscavengedHeapObject(Heap* heap, Object** p) {
1132 return heap->InNewSpace(*p) &&
1133 !HeapObject::cast(*p)->map_word().IsForwardingAddress();
1134}
1135
1136
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001137void Heap::ScavengeStoreBufferCallback(
1138 Heap* heap,
1139 MemoryChunk* page,
1140 StoreBufferEvent event) {
1141 heap->store_buffer_rebuilder_.Callback(page, event);
1142}
1143
1144
1145void StoreBufferRebuilder::Callback(MemoryChunk* page, StoreBufferEvent event) {
1146 if (event == kStoreBufferStartScanningPagesEvent) {
1147 start_of_current_page_ = NULL;
1148 current_page_ = NULL;
1149 } else if (event == kStoreBufferScanningPageEvent) {
1150 if (current_page_ != NULL) {
1151 // If this page already overflowed the store buffer during this iteration.
1152 if (current_page_->scan_on_scavenge()) {
1153 // Then we should wipe out the entries that have been added for it.
1154 store_buffer_->SetTop(start_of_current_page_);
1155 } else if (store_buffer_->Top() - start_of_current_page_ >=
1156 (store_buffer_->Limit() - store_buffer_->Top()) >> 2) {
1157 // Did we find too many pointers in the previous page? The heuristic is
1158 // that no page can take more then 1/5 the remaining slots in the store
1159 // buffer.
1160 current_page_->set_scan_on_scavenge(true);
1161 store_buffer_->SetTop(start_of_current_page_);
1162 } else {
1163 // In this case the page we scanned took a reasonable number of slots in
1164 // the store buffer. It has now been rehabilitated and is no longer
1165 // marked scan_on_scavenge.
1166 ASSERT(!current_page_->scan_on_scavenge());
1167 }
1168 }
1169 start_of_current_page_ = store_buffer_->Top();
1170 current_page_ = page;
1171 } else if (event == kStoreBufferFullEvent) {
1172 // The current page overflowed the store buffer again. Wipe out its entries
1173 // in the store buffer and mark it scan-on-scavenge again. This may happen
1174 // several times while scanning.
1175 if (current_page_ == NULL) {
1176 // Store Buffer overflowed while scanning promoted objects. These are not
1177 // in any particular page, though they are likely to be clustered by the
1178 // allocation routines.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001179 store_buffer_->EnsureSpace(StoreBuffer::kStoreBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001180 } else {
1181 // Store Buffer overflowed while scanning a particular old space page for
1182 // pointers to new space.
1183 ASSERT(current_page_ == page);
1184 ASSERT(page != NULL);
1185 current_page_->set_scan_on_scavenge(true);
1186 ASSERT(start_of_current_page_ != store_buffer_->Top());
1187 store_buffer_->SetTop(start_of_current_page_);
1188 }
1189 } else {
1190 UNREACHABLE();
1191 }
1192}
1193
1194
danno@chromium.orgc612e022011-11-10 11:38:15 +00001195void PromotionQueue::Initialize() {
1196 // Assumes that a NewSpacePage exactly fits a number of promotion queue
1197 // entries (where each is a pair of intptr_t). This allows us to simplify
1198 // the test fpr when to switch pages.
1199 ASSERT((Page::kPageSize - MemoryChunk::kBodyOffset) % (2 * kPointerSize)
1200 == 0);
1201 limit_ = reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceStart());
1202 front_ = rear_ =
1203 reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceEnd());
1204 emergency_stack_ = NULL;
1205 guard_ = false;
1206}
1207
1208
1209void PromotionQueue::RelocateQueueHead() {
1210 ASSERT(emergency_stack_ == NULL);
1211
1212 Page* p = Page::FromAllocationTop(reinterpret_cast<Address>(rear_));
1213 intptr_t* head_start = rear_;
1214 intptr_t* head_end =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001215 Min(front_, reinterpret_cast<intptr_t*>(p->area_end()));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001216
1217 int entries_count =
1218 static_cast<int>(head_end - head_start) / kEntrySizeInWords;
1219
1220 emergency_stack_ = new List<Entry>(2 * entries_count);
1221
1222 while (head_start != head_end) {
1223 int size = static_cast<int>(*(head_start++));
1224 HeapObject* obj = reinterpret_cast<HeapObject*>(*(head_start++));
1225 emergency_stack_->Add(Entry(obj, size));
1226 }
1227 rear_ = head_end;
1228}
1229
1230
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001231class ScavengeWeakObjectRetainer : public WeakObjectRetainer {
1232 public:
1233 explicit ScavengeWeakObjectRetainer(Heap* heap) : heap_(heap) { }
1234
1235 virtual Object* RetainAs(Object* object) {
1236 if (!heap_->InFromSpace(object)) {
1237 return object;
1238 }
1239
1240 MapWord map_word = HeapObject::cast(object)->map_word();
1241 if (map_word.IsForwardingAddress()) {
1242 return map_word.ToForwardingAddress();
1243 }
1244 return NULL;
1245 }
1246
1247 private:
1248 Heap* heap_;
1249};
1250
1251
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001252void Heap::Scavenge() {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001253 RelocationLock relocation_lock(this);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001254
1255#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001256 if (FLAG_verify_heap) VerifyNonPointerSpacePointers();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257#endif
1258
1259 gc_state_ = SCAVENGE;
1260
1261 // Implements Cheney's copying algorithm
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001262 LOG(isolate_, ResourceEvent("scavenge", "begin"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001263
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001264 // Clear descriptor cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001265 isolate_->descriptor_lookup_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001266
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001267 // Used for updating survived_since_last_expansion_ at function end.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001268 intptr_t survived_watermark = PromotedSpaceSizeOfObjects();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001269
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001270 CheckNewSpaceExpansionCriteria();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001271
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001272 SelectScavengingVisitorsTable();
1273
1274 incremental_marking()->PrepareForScavenge();
1275
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001276 AdvanceSweepers(static_cast<int>(new_space_.Size()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001277
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 // Flip the semispaces. After flipping, to space is empty, from space has
1279 // live objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001280 new_space_.Flip();
1281 new_space_.ResetAllocationInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001283 // We need to sweep newly copied objects which can be either in the
1284 // to space or promoted to the old generation. For to-space
1285 // objects, we treat the bottom of the to space as a queue. Newly
1286 // copied and unswept objects lie between a 'front' mark and the
1287 // allocation pointer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288 //
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001289 // Promoted objects can go into various old-generation spaces, and
1290 // can be allocated internally in the spaces (from the free list).
1291 // We treat the top of the to space as a queue of addresses of
1292 // promoted objects. The addresses of newly promoted and unswept
1293 // objects lie between a 'front' mark and a 'rear' mark that is
1294 // updated as a side effect of promoting an object.
1295 //
1296 // There is guaranteed to be enough room at the top of the to space
1297 // for the addresses of promoted objects: every object promoted
1298 // frees up its size in bytes from the top of the new space, and
1299 // objects are at least one pointer in size.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 Address new_space_front = new_space_.ToSpaceStart();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001301 promotion_queue_.Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001302
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001303#ifdef DEBUG
1304 store_buffer()->Clean();
1305#endif
1306
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001307 ScavengeVisitor scavenge_visitor(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001308 // Copy roots.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001309 IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001310
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001311 // Copy objects reachable from the old generation.
1312 {
1313 StoreBufferRebuildScope scope(this,
1314 store_buffer(),
1315 &ScavengeStoreBufferCallback);
1316 store_buffer()->IteratePointersToNewSpace(&ScavengeObject);
1317 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001318
1319 // Copy objects reachable from cells by scavenging cell values directly.
1320 HeapObjectIterator cell_iterator(cell_space_);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001321 for (HeapObject* heap_object = cell_iterator.Next();
1322 heap_object != NULL;
1323 heap_object = cell_iterator.Next()) {
1324 if (heap_object->IsJSGlobalPropertyCell()) {
1325 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(heap_object);
1326 Address value_address = cell->ValueAddress();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001327 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address));
1328 }
1329 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001330
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001331 // Copy objects reachable from the code flushing candidates list.
1332 MarkCompactCollector* collector = mark_compact_collector();
1333 if (collector->is_code_flushing_enabled()) {
1334 collector->code_flusher()->IteratePointersToFromSpace(&scavenge_visitor);
1335 }
1336
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001337 // Scavenge object reachable from the native contexts list directly.
1338 scavenge_visitor.VisitPointer(BitCast<Object**>(&native_contexts_list_));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001339
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001340 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001341
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001342 while (isolate()->global_handles()->IterateObjectGroups(
1343 &scavenge_visitor, &IsUnscavengedHeapObject)) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001344 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
1345 }
1346 isolate()->global_handles()->RemoveObjectGroups();
1347
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001348 isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles(
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001349 &IsUnscavengedHeapObject);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001350 isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots(
1351 &scavenge_visitor);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001352 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
1353
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001354 UpdateNewSpaceReferencesInExternalStringTable(
1355 &UpdateNewSpaceReferenceInExternalStringTableEntry);
1356
danno@chromium.orgc612e022011-11-10 11:38:15 +00001357 promotion_queue_.Destroy();
1358
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001359 LiveObjectList::UpdateReferencesForScavengeGC();
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001360 if (!FLAG_watch_ic_patching) {
1361 isolate()->runtime_profiler()->UpdateSamplesAfterScavenge();
1362 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001363 incremental_marking()->UpdateMarkingDequeAfterScavenge();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001364
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001365 ScavengeWeakObjectRetainer weak_object_retainer(this);
1366 ProcessWeakReferences(&weak_object_retainer);
1367
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001368 ASSERT(new_space_front == new_space_.top());
1369
1370 // Set age mark.
1371 new_space_.set_age_mark(new_space_.top());
1372
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001373 new_space_.LowerInlineAllocationLimit(
1374 new_space_.inline_allocation_limit_step());
1375
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001376 // Update how much has survived scavenge.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001377 IncrementYoungSurvivorsCounter(static_cast<int>(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001378 (PromotedSpaceSizeOfObjects() - survived_watermark) + new_space_.Size()));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001379
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001380 LOG(isolate_, ResourceEvent("scavenge", "end"));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001381
1382 gc_state_ = NOT_IN_GC;
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001383
1384 scavenges_since_last_idle_round_++;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001385}
1386
1387
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001388String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
1389 Object** p) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001390 MapWord first_word = HeapObject::cast(*p)->map_word();
1391
1392 if (!first_word.IsForwardingAddress()) {
1393 // Unreachable external string can be finalized.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001394 heap->FinalizeExternalString(String::cast(*p));
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001395 return NULL;
1396 }
1397
1398 // String is still reachable.
1399 return String::cast(first_word.ToForwardingAddress());
1400}
1401
1402
1403void Heap::UpdateNewSpaceReferencesInExternalStringTable(
1404 ExternalStringTableUpdaterCallback updater_func) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001405#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001406 if (FLAG_verify_heap) {
1407 external_string_table_.Verify();
1408 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001409#endif
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001410
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001411 if (external_string_table_.new_space_strings_.is_empty()) return;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001412
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001413 Object** start = &external_string_table_.new_space_strings_[0];
1414 Object** end = start + external_string_table_.new_space_strings_.length();
1415 Object** last = start;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001416
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001417 for (Object** p = start; p < end; ++p) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001418 ASSERT(InFromSpace(*p));
1419 String* target = updater_func(this, p);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001420
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001421 if (target == NULL) continue;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001422
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001423 ASSERT(target->IsExternalString());
1424
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001425 if (InNewSpace(target)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001426 // String is still in new space. Update the table entry.
1427 *last = target;
1428 ++last;
1429 } else {
1430 // String got promoted. Move it to the old string list.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001431 external_string_table_.AddOldString(target);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001432 }
1433 }
1434
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001435 ASSERT(last <= end);
1436 external_string_table_.ShrinkNewStrings(static_cast<int>(last - start));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001437}
1438
1439
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001440void Heap::UpdateReferencesInExternalStringTable(
1441 ExternalStringTableUpdaterCallback updater_func) {
1442
1443 // Update old space string references.
1444 if (external_string_table_.old_space_strings_.length() > 0) {
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001445 Object** start = &external_string_table_.old_space_strings_[0];
1446 Object** end = start + external_string_table_.old_space_strings_.length();
1447 for (Object** p = start; p < end; ++p) *p = updater_func(this, p);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001448 }
1449
1450 UpdateNewSpaceReferencesInExternalStringTable(updater_func);
1451}
1452
1453
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001454static Object* ProcessFunctionWeakReferences(Heap* heap,
1455 Object* function,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001456 WeakObjectRetainer* retainer,
1457 bool record_slots) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001458 Object* undefined = heap->undefined_value();
1459 Object* head = undefined;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001460 JSFunction* tail = NULL;
1461 Object* candidate = function;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001462 while (candidate != undefined) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001463 // Check whether to keep the candidate in the list.
1464 JSFunction* candidate_function = reinterpret_cast<JSFunction*>(candidate);
1465 Object* retain = retainer->RetainAs(candidate);
1466 if (retain != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001467 if (head == undefined) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001468 // First element in the list.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001469 head = retain;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001470 } else {
1471 // Subsequent elements in the list.
1472 ASSERT(tail != NULL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001473 tail->set_next_function_link(retain);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001474 if (record_slots) {
1475 Object** next_function =
1476 HeapObject::RawField(tail, JSFunction::kNextFunctionLinkOffset);
1477 heap->mark_compact_collector()->RecordSlot(
1478 next_function, next_function, retain);
1479 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001480 }
1481 // Retained function is new tail.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001482 candidate_function = reinterpret_cast<JSFunction*>(retain);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001483 tail = candidate_function;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001484
1485 ASSERT(retain->IsUndefined() || retain->IsJSFunction());
1486
1487 if (retain == undefined) break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001488 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001489
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001490 // Move to next element in the list.
1491 candidate = candidate_function->next_function_link();
1492 }
1493
1494 // Terminate the list if there is one or more elements.
1495 if (tail != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001496 tail->set_next_function_link(undefined);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001497 }
1498
1499 return head;
1500}
1501
1502
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001503void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001504 Object* undefined = undefined_value();
1505 Object* head = undefined;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001506 Context* tail = NULL;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001507 Object* candidate = native_contexts_list_;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001508
1509 // We don't record weak slots during marking or scavenges.
1510 // Instead we do it once when we complete mark-compact cycle.
1511 // Note that write barrier has no effect if we are already in the middle of
1512 // compacting mark-sweep cycle and we have to record slots manually.
1513 bool record_slots =
1514 gc_state() == MARK_COMPACT &&
1515 mark_compact_collector()->is_compacting();
1516
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001517 while (candidate != undefined) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001518 // Check whether to keep the candidate in the list.
1519 Context* candidate_context = reinterpret_cast<Context*>(candidate);
1520 Object* retain = retainer->RetainAs(candidate);
1521 if (retain != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001522 if (head == undefined) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001523 // First element in the list.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001524 head = retain;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001525 } else {
1526 // Subsequent elements in the list.
1527 ASSERT(tail != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001528 tail->set_unchecked(this,
1529 Context::NEXT_CONTEXT_LINK,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001530 retain,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001531 UPDATE_WRITE_BARRIER);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001532
1533 if (record_slots) {
1534 Object** next_context =
1535 HeapObject::RawField(
1536 tail, FixedArray::SizeFor(Context::NEXT_CONTEXT_LINK));
1537 mark_compact_collector()->RecordSlot(
1538 next_context, next_context, retain);
1539 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001540 }
1541 // Retained context is new tail.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001542 candidate_context = reinterpret_cast<Context*>(retain);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001543 tail = candidate_context;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001544
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001545 if (retain == undefined) break;
1546
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001547 // Process the weak list of optimized functions for the context.
1548 Object* function_list_head =
1549 ProcessFunctionWeakReferences(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001550 this,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001551 candidate_context->get(Context::OPTIMIZED_FUNCTIONS_LIST),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001552 retainer,
1553 record_slots);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001554 candidate_context->set_unchecked(this,
1555 Context::OPTIMIZED_FUNCTIONS_LIST,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001556 function_list_head,
1557 UPDATE_WRITE_BARRIER);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001558 if (record_slots) {
1559 Object** optimized_functions =
1560 HeapObject::RawField(
1561 tail, FixedArray::SizeFor(Context::OPTIMIZED_FUNCTIONS_LIST));
1562 mark_compact_collector()->RecordSlot(
1563 optimized_functions, optimized_functions, function_list_head);
1564 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001565 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001566
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001567 // Move to next element in the list.
1568 candidate = candidate_context->get(Context::NEXT_CONTEXT_LINK);
1569 }
1570
1571 // Terminate the list if there is one or more elements.
1572 if (tail != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001573 tail->set_unchecked(this,
1574 Context::NEXT_CONTEXT_LINK,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001575 Heap::undefined_value(),
1576 UPDATE_WRITE_BARRIER);
1577 }
1578
1579 // Update the head of the list of contexts.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001580 native_contexts_list_ = head;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001581}
1582
1583
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001584void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) {
1585 AssertNoAllocation no_allocation;
1586
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001587 // Both the external string table and the symbol table may contain
1588 // external strings, but neither lists them exhaustively, nor is the
1589 // intersection set empty. Therefore we iterate over the external string
1590 // table first, ignoring symbols, and then over the symbol table.
1591
1592 class ExternalStringTableVisitorAdapter : public ObjectVisitor {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001593 public:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001594 explicit ExternalStringTableVisitorAdapter(
1595 v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001596 virtual void VisitPointers(Object** start, Object** end) {
1597 for (Object** p = start; p < end; p++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001598 // Visit non-symbol external strings,
1599 // since symbols are listed in the symbol table.
1600 if (!(*p)->IsSymbol()) {
1601 ASSERT((*p)->IsExternalString());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001602 visitor_->VisitExternalString(Utils::ToLocal(
1603 Handle<String>(String::cast(*p))));
1604 }
1605 }
1606 }
1607 private:
1608 v8::ExternalResourceVisitor* visitor_;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001609 } external_string_table_visitor(visitor);
1610
1611 external_string_table_.Iterate(&external_string_table_visitor);
1612
1613 class SymbolTableVisitorAdapter : public ObjectVisitor {
1614 public:
1615 explicit SymbolTableVisitorAdapter(
1616 v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
1617 virtual void VisitPointers(Object** start, Object** end) {
1618 for (Object** p = start; p < end; p++) {
1619 if ((*p)->IsExternalString()) {
1620 ASSERT((*p)->IsSymbol());
1621 visitor_->VisitExternalString(Utils::ToLocal(
1622 Handle<String>(String::cast(*p))));
1623 }
1624 }
1625 }
1626 private:
1627 v8::ExternalResourceVisitor* visitor_;
1628 } symbol_table_visitor(visitor);
1629
1630 symbol_table()->IterateElements(&symbol_table_visitor);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001631}
1632
1633
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001634class NewSpaceScavenger : public StaticNewSpaceVisitor<NewSpaceScavenger> {
1635 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001636 static inline void VisitPointer(Heap* heap, Object** p) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001637 Object* object = *p;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001638 if (!heap->InNewSpace(object)) return;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001639 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
1640 reinterpret_cast<HeapObject*>(object));
1641 }
1642};
1643
1644
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001645Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
1646 Address new_space_front) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001647 do {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001648 SemiSpace::AssertValidRange(new_space_front, new_space_.top());
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001649 // The addresses new_space_front and new_space_.top() define a
1650 // queue of unprocessed copied objects. Process them until the
1651 // queue is empty.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001652 while (new_space_front != new_space_.top()) {
1653 if (!NewSpacePage::IsAtEnd(new_space_front)) {
1654 HeapObject* object = HeapObject::FromAddress(new_space_front);
1655 new_space_front +=
1656 NewSpaceScavenger::IterateBody(object->map(), object);
1657 } else {
1658 new_space_front =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001659 NewSpacePage::FromLimit(new_space_front)->next_page()->area_start();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001660 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001661 }
1662
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001663 // Promote and process all the to-be-promoted objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001664 {
1665 StoreBufferRebuildScope scope(this,
1666 store_buffer(),
1667 &ScavengeStoreBufferCallback);
1668 while (!promotion_queue()->is_empty()) {
1669 HeapObject* target;
1670 int size;
1671 promotion_queue()->remove(&target, &size);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001672
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001673 // Promoted object might be already partially visited
1674 // during old space pointer iteration. Thus we search specificly
1675 // for pointers to from semispace instead of looking for pointers
1676 // to new space.
1677 ASSERT(!target->IsMap());
1678 IterateAndMarkPointersToFromSpace(target->address(),
1679 target->address() + size,
1680 &ScavengeObject);
1681 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001682 }
1683
1684 // Take another spin if there are now unswept objects in new space
1685 // (there are currently no more unswept promoted objects).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001686 } while (new_space_front != new_space_.top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001687
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001688 return new_space_front;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689}
1690
1691
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001692STATIC_ASSERT((FixedDoubleArray::kHeaderSize & kDoubleAlignmentMask) == 0);
1693
1694
1695INLINE(static HeapObject* EnsureDoubleAligned(Heap* heap,
1696 HeapObject* object,
1697 int size));
1698
1699static HeapObject* EnsureDoubleAligned(Heap* heap,
1700 HeapObject* object,
1701 int size) {
1702 if ((OffsetFrom(object->address()) & kDoubleAlignmentMask) != 0) {
1703 heap->CreateFillerObjectAt(object->address(), kPointerSize);
1704 return HeapObject::FromAddress(object->address() + kPointerSize);
1705 } else {
1706 heap->CreateFillerObjectAt(object->address() + size - kPointerSize,
1707 kPointerSize);
1708 return object;
1709 }
1710}
1711
1712
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001713enum LoggingAndProfiling {
1714 LOGGING_AND_PROFILING_ENABLED,
1715 LOGGING_AND_PROFILING_DISABLED
1716};
1717
1718
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001719enum MarksHandling { TRANSFER_MARKS, IGNORE_MARKS };
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001720
1721
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001722template<MarksHandling marks_handling,
1723 LoggingAndProfiling logging_and_profiling_mode>
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001724class ScavengingVisitor : public StaticVisitorBase {
1725 public:
1726 static void Initialize() {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001727 table_.Register(kVisitSeqOneByteString, &EvacuateSeqOneByteString);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001728 table_.Register(kVisitSeqTwoByteString, &EvacuateSeqTwoByteString);
1729 table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate);
1730 table_.Register(kVisitByteArray, &EvacuateByteArray);
1731 table_.Register(kVisitFixedArray, &EvacuateFixedArray);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001732 table_.Register(kVisitFixedDoubleArray, &EvacuateFixedDoubleArray);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001733
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001734 table_.Register(kVisitNativeContext,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001735 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001736 template VisitSpecialized<Context::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001737
1738 table_.Register(kVisitConsString,
1739 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001740 template VisitSpecialized<ConsString::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001741
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001742 table_.Register(kVisitSlicedString,
1743 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1744 template VisitSpecialized<SlicedString::kSize>);
1745
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001746 table_.Register(kVisitSharedFunctionInfo,
1747 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001748 template VisitSpecialized<SharedFunctionInfo::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001749
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001750 table_.Register(kVisitJSWeakMap,
1751 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1752 Visit);
1753
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001754 table_.Register(kVisitJSRegExp,
1755 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1756 Visit);
1757
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001758 if (marks_handling == IGNORE_MARKS) {
1759 table_.Register(kVisitJSFunction,
1760 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1761 template VisitSpecialized<JSFunction::kSize>);
1762 } else {
1763 table_.Register(kVisitJSFunction, &EvacuateJSFunction);
1764 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001765
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001766 table_.RegisterSpecializations<ObjectEvacuationStrategy<DATA_OBJECT>,
1767 kVisitDataObject,
1768 kVisitDataObjectGeneric>();
1769
1770 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>,
1771 kVisitJSObject,
1772 kVisitJSObjectGeneric>();
1773
1774 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>,
1775 kVisitStruct,
1776 kVisitStructGeneric>();
1777 }
1778
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001779 static VisitorDispatchTable<ScavengingCallback>* GetTable() {
1780 return &table_;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001781 }
1782
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001783 private:
1784 enum ObjectContents { DATA_OBJECT, POINTER_OBJECT };
1785 enum SizeRestriction { SMALL, UNKNOWN_SIZE };
1786
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001787 static void RecordCopiedObject(Heap* heap, HeapObject* obj) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001788 bool should_record = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001789#ifdef DEBUG
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001790 should_record = FLAG_heap_stats;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001791#endif
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001792 should_record = should_record || FLAG_log_gc;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001793 if (should_record) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001794 if (heap->new_space()->Contains(obj)) {
1795 heap->new_space()->RecordAllocation(obj);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001796 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001797 heap->new_space()->RecordPromotion(obj);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001798 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001799 }
1800 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001801
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001802 // Helper function used by CopyObject to copy a source object to an
1803 // allocated target object and update the forwarding pointer in the source
1804 // object. Returns the target object.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001805 INLINE(static void MigrateObject(Heap* heap,
1806 HeapObject* source,
1807 HeapObject* target,
1808 int size)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001809 // Copy the content of source to target.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001810 heap->CopyBlock(target->address(), source->address(), size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001811
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001812 // Set the forwarding address.
1813 source->set_map_word(MapWord::FromForwardingAddress(target));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001814
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001815 if (logging_and_profiling_mode == LOGGING_AND_PROFILING_ENABLED) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001816 // Update NewSpace stats if necessary.
1817 RecordCopiedObject(heap, target);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001818 HEAP_PROFILE(heap, ObjectMoveEvent(source->address(), target->address()));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001819 Isolate* isolate = heap->isolate();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001820 if (isolate->logger()->is_logging_code_events() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001821 CpuProfiler::is_profiling(isolate)) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001822 if (target->IsSharedFunctionInfo()) {
1823 PROFILE(isolate, SharedFunctionInfoMoveEvent(
1824 source->address(), target->address()));
1825 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001826 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001827 }
1828
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001829 if (marks_handling == TRANSFER_MARKS) {
1830 if (Marking::TransferColor(source, target)) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001831 MemoryChunk::IncrementLiveBytesFromGC(target->address(), size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001832 }
1833 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001834 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001835
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001836
1837 template<ObjectContents object_contents,
1838 SizeRestriction size_restriction,
1839 int alignment>
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001840 static inline void EvacuateObject(Map* map,
1841 HeapObject** slot,
1842 HeapObject* object,
1843 int object_size) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001844 SLOW_ASSERT((size_restriction != SMALL) ||
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001845 (object_size <= Page::kMaxNonCodeHeapObjectSize));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001846 SLOW_ASSERT(object->Size() == object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001847
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001848 int allocation_size = object_size;
1849 if (alignment != kObjectAlignment) {
1850 ASSERT(alignment == kDoubleAlignment);
1851 allocation_size += kPointerSize;
1852 }
1853
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001854 Heap* heap = map->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001855 if (heap->ShouldBePromoted(object->address(), object_size)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001856 MaybeObject* maybe_result;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001857
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001858 if ((size_restriction != SMALL) &&
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001859 (allocation_size > Page::kMaxNonCodeHeapObjectSize)) {
1860 maybe_result = heap->lo_space()->AllocateRaw(allocation_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001861 NOT_EXECUTABLE);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001862 } else {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001863 if (object_contents == DATA_OBJECT) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001864 maybe_result = heap->old_data_space()->AllocateRaw(allocation_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001865 } else {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001866 maybe_result =
1867 heap->old_pointer_space()->AllocateRaw(allocation_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001868 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001869 }
1870
lrn@chromium.org303ada72010-10-27 09:33:13 +00001871 Object* result = NULL; // Initialization to please compiler.
1872 if (maybe_result->ToObject(&result)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001873 HeapObject* target = HeapObject::cast(result);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001874
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001875 if (alignment != kObjectAlignment) {
1876 target = EnsureDoubleAligned(heap, target, allocation_size);
1877 }
1878
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001879 // Order is important: slot might be inside of the target if target
1880 // was allocated over a dead object and slot comes from the store
1881 // buffer.
1882 *slot = target;
1883 MigrateObject(heap, object, target, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001884
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001885 if (object_contents == POINTER_OBJECT) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001886 if (map->instance_type() == JS_FUNCTION_TYPE) {
1887 heap->promotion_queue()->insert(
1888 target, JSFunction::kNonWeakFieldsEndOffset);
1889 } else {
1890 heap->promotion_queue()->insert(target, object_size);
1891 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001892 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001893
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001894 heap->tracer()->increment_promoted_objects_size(object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001895 return;
1896 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001897 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001898 MaybeObject* allocation = heap->new_space()->AllocateRaw(allocation_size);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001899 heap->promotion_queue()->SetNewLimit(heap->new_space()->top());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001900 Object* result = allocation->ToObjectUnchecked();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001901 HeapObject* target = HeapObject::cast(result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001902
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001903 if (alignment != kObjectAlignment) {
1904 target = EnsureDoubleAligned(heap, target, allocation_size);
1905 }
1906
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001907 // Order is important: slot might be inside of the target if target
1908 // was allocated over a dead object and slot comes from the store
1909 // buffer.
1910 *slot = target;
1911 MigrateObject(heap, object, target, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001912 return;
1913 }
1914
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001915
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001916 static inline void EvacuateJSFunction(Map* map,
1917 HeapObject** slot,
1918 HeapObject* object) {
1919 ObjectEvacuationStrategy<POINTER_OBJECT>::
1920 template VisitSpecialized<JSFunction::kSize>(map, slot, object);
1921
1922 HeapObject* target = *slot;
1923 MarkBit mark_bit = Marking::MarkBitFrom(target);
1924 if (Marking::IsBlack(mark_bit)) {
1925 // This object is black and it might not be rescanned by marker.
1926 // We should explicitly record code entry slot for compaction because
1927 // promotion queue processing (IterateAndMarkPointersToFromSpace) will
1928 // miss it as it is not HeapObject-tagged.
1929 Address code_entry_slot =
1930 target->address() + JSFunction::kCodeEntryOffset;
1931 Code* code = Code::cast(Code::GetObjectFromEntryAddress(code_entry_slot));
1932 map->GetHeap()->mark_compact_collector()->
1933 RecordCodeEntrySlot(code_entry_slot, code);
1934 }
1935 }
1936
1937
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001938 static inline void EvacuateFixedArray(Map* map,
1939 HeapObject** slot,
1940 HeapObject* object) {
1941 int object_size = FixedArray::BodyDescriptor::SizeOf(map, object);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001942 EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(map,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001943 slot,
1944 object,
1945 object_size);
1946 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001947
1948
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001949 static inline void EvacuateFixedDoubleArray(Map* map,
1950 HeapObject** slot,
1951 HeapObject* object) {
1952 int length = reinterpret_cast<FixedDoubleArray*>(object)->length();
1953 int object_size = FixedDoubleArray::SizeFor(length);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001954 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kDoubleAlignment>(
1955 map,
1956 slot,
1957 object,
1958 object_size);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001959 }
1960
1961
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001962 static inline void EvacuateByteArray(Map* map,
1963 HeapObject** slot,
1964 HeapObject* object) {
1965 int object_size = reinterpret_cast<ByteArray*>(object)->ByteArraySize();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001966 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
1967 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001968 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001969
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001970
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001971 static inline void EvacuateSeqOneByteString(Map* map,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001972 HeapObject** slot,
1973 HeapObject* object) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001974 int object_size = SeqOneByteString::cast(object)->
1975 SeqOneByteStringSize(map->instance_type());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001976 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
1977 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001978 }
1979
1980
1981 static inline void EvacuateSeqTwoByteString(Map* map,
1982 HeapObject** slot,
1983 HeapObject* object) {
1984 int object_size = SeqTwoByteString::cast(object)->
1985 SeqTwoByteStringSize(map->instance_type());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001986 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
1987 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001988 }
1989
1990
1991 static inline bool IsShortcutCandidate(int type) {
1992 return ((type & kShortcutTypeMask) == kShortcutTypeTag);
1993 }
1994
1995 static inline void EvacuateShortcutCandidate(Map* map,
1996 HeapObject** slot,
1997 HeapObject* object) {
1998 ASSERT(IsShortcutCandidate(map->instance_type()));
1999
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002000 Heap* heap = map->GetHeap();
2001
2002 if (marks_handling == IGNORE_MARKS &&
2003 ConsString::cast(object)->unchecked_second() ==
2004 heap->empty_string()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002005 HeapObject* first =
2006 HeapObject::cast(ConsString::cast(object)->unchecked_first());
2007
2008 *slot = first;
2009
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002010 if (!heap->InNewSpace(first)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002011 object->set_map_word(MapWord::FromForwardingAddress(first));
2012 return;
2013 }
2014
2015 MapWord first_word = first->map_word();
2016 if (first_word.IsForwardingAddress()) {
2017 HeapObject* target = first_word.ToForwardingAddress();
2018
2019 *slot = target;
2020 object->set_map_word(MapWord::FromForwardingAddress(target));
2021 return;
2022 }
2023
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002024 heap->DoScavengeObject(first->map(), slot, first);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002025 object->set_map_word(MapWord::FromForwardingAddress(*slot));
2026 return;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002027 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002028
2029 int object_size = ConsString::kSize;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002030 EvacuateObject<POINTER_OBJECT, SMALL, kObjectAlignment>(
2031 map, slot, object, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002032 }
2033
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002034 template<ObjectContents object_contents>
2035 class ObjectEvacuationStrategy {
2036 public:
2037 template<int object_size>
2038 static inline void VisitSpecialized(Map* map,
2039 HeapObject** slot,
2040 HeapObject* object) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002041 EvacuateObject<object_contents, SMALL, kObjectAlignment>(
2042 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002043 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002044
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002045 static inline void Visit(Map* map,
2046 HeapObject** slot,
2047 HeapObject* object) {
2048 int object_size = map->instance_size();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002049 EvacuateObject<object_contents, SMALL, kObjectAlignment>(
2050 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002051 }
2052 };
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002054 static VisitorDispatchTable<ScavengingCallback> table_;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002055};
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002056
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002057
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002058template<MarksHandling marks_handling,
2059 LoggingAndProfiling logging_and_profiling_mode>
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002060VisitorDispatchTable<ScavengingCallback>
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002061 ScavengingVisitor<marks_handling, logging_and_profiling_mode>::table_;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002062
2063
2064static void InitializeScavengingVisitorsTables() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002065 ScavengingVisitor<TRANSFER_MARKS,
2066 LOGGING_AND_PROFILING_DISABLED>::Initialize();
2067 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_DISABLED>::Initialize();
2068 ScavengingVisitor<TRANSFER_MARKS,
2069 LOGGING_AND_PROFILING_ENABLED>::Initialize();
2070 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_ENABLED>::Initialize();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002071}
2072
2073
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002074void Heap::SelectScavengingVisitorsTable() {
2075 bool logging_and_profiling =
2076 isolate()->logger()->is_logging() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002077 CpuProfiler::is_profiling(isolate()) ||
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002078 (isolate()->heap_profiler() != NULL &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002079 isolate()->heap_profiler()->is_profiling());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002080
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002081 if (!incremental_marking()->IsMarking()) {
2082 if (!logging_and_profiling) {
2083 scavenging_visitors_table_.CopyFrom(
2084 ScavengingVisitor<IGNORE_MARKS,
2085 LOGGING_AND_PROFILING_DISABLED>::GetTable());
2086 } else {
2087 scavenging_visitors_table_.CopyFrom(
2088 ScavengingVisitor<IGNORE_MARKS,
2089 LOGGING_AND_PROFILING_ENABLED>::GetTable());
2090 }
2091 } else {
2092 if (!logging_and_profiling) {
2093 scavenging_visitors_table_.CopyFrom(
2094 ScavengingVisitor<TRANSFER_MARKS,
2095 LOGGING_AND_PROFILING_DISABLED>::GetTable());
2096 } else {
2097 scavenging_visitors_table_.CopyFrom(
2098 ScavengingVisitor<TRANSFER_MARKS,
2099 LOGGING_AND_PROFILING_ENABLED>::GetTable());
2100 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002101
2102 if (incremental_marking()->IsCompacting()) {
2103 // When compacting forbid short-circuiting of cons-strings.
2104 // Scavenging code relies on the fact that new space object
2105 // can't be evacuated into evacuation candidate but
2106 // short-circuiting violates this assumption.
2107 scavenging_visitors_table_.Register(
2108 StaticVisitorBase::kVisitShortcutCandidate,
2109 scavenging_visitors_table_.GetVisitorById(
2110 StaticVisitorBase::kVisitConsString));
2111 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002112 }
2113}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002114
2115
2116void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002117 SLOW_ASSERT(HEAP->InFromSpace(object));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002118 MapWord first_word = object->map_word();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002119 SLOW_ASSERT(!first_word.IsForwardingAddress());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002120 Map* map = first_word.ToMap();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002121 map->GetHeap()->DoScavengeObject(map, p, object);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002122}
2123
2124
lrn@chromium.org303ada72010-10-27 09:33:13 +00002125MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type,
2126 int instance_size) {
2127 Object* result;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002128 MaybeObject* maybe_result = AllocateRawMap();
2129 if (!maybe_result->ToObject(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002130
2131 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002132 reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002133 reinterpret_cast<Map*>(result)->set_instance_type(instance_type);
2134 reinterpret_cast<Map*>(result)->set_instance_size(instance_size);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002135 reinterpret_cast<Map*>(result)->set_visitor_id(
2136 StaticVisitorBase::GetVisitorId(instance_type, instance_size));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002137 reinterpret_cast<Map*>(result)->set_inobject_properties(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002138 reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002139 reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002140 reinterpret_cast<Map*>(result)->set_bit_field(0);
2141 reinterpret_cast<Map*>(result)->set_bit_field2(0);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002142 int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) |
2143 Map::OwnsDescriptors::encode(true);
2144 reinterpret_cast<Map*>(result)->set_bit_field3(bit_field3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002145 return result;
2146}
2147
2148
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002149MaybeObject* Heap::AllocateMap(InstanceType instance_type,
2150 int instance_size,
2151 ElementsKind elements_kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002152 Object* result;
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002153 MaybeObject* maybe_result = AllocateRawMap();
2154 if (!maybe_result->To(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002155
2156 Map* map = reinterpret_cast<Map*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002157 map->set_map_no_write_barrier(meta_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002158 map->set_instance_type(instance_type);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002159 map->set_visitor_id(
2160 StaticVisitorBase::GetVisitorId(instance_type, instance_size));
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002161 map->set_prototype(null_value(), SKIP_WRITE_BARRIER);
2162 map->set_constructor(null_value(), SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002163 map->set_instance_size(instance_size);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002164 map->set_inobject_properties(0);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002165 map->set_pre_allocated_property_fields(0);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002166 map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002167 map->init_back_pointer(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002168 map->set_unused_property_fields(0);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002169 map->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002170 map->set_bit_field(0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002171 map->set_bit_field2(1 << Map::kIsExtensible);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002172 int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) |
2173 Map::OwnsDescriptors::encode(true);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002174 map->set_bit_field3(bit_field3);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002175 map->set_elements_kind(elements_kind);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002176
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002177 return map;
2178}
2179
2180
lrn@chromium.org303ada72010-10-27 09:33:13 +00002181MaybeObject* Heap::AllocateCodeCache() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002182 CodeCache* code_cache;
2183 { MaybeObject* maybe_code_cache = AllocateStruct(CODE_CACHE_TYPE);
2184 if (!maybe_code_cache->To(&code_cache)) return maybe_code_cache;
lrn@chromium.org303ada72010-10-27 09:33:13 +00002185 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002186 code_cache->set_default_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
2187 code_cache->set_normal_type_cache(undefined_value(), SKIP_WRITE_BARRIER);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002188 return code_cache;
2189}
2190
2191
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002192MaybeObject* Heap::AllocatePolymorphicCodeCache() {
2193 return AllocateStruct(POLYMORPHIC_CODE_CACHE_TYPE);
2194}
2195
2196
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002197MaybeObject* Heap::AllocateAccessorPair() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002198 AccessorPair* accessors;
2199 { MaybeObject* maybe_accessors = AllocateStruct(ACCESSOR_PAIR_TYPE);
2200 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002201 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002202 accessors->set_getter(the_hole_value(), SKIP_WRITE_BARRIER);
2203 accessors->set_setter(the_hole_value(), SKIP_WRITE_BARRIER);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002204 return accessors;
2205}
2206
2207
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002208MaybeObject* Heap::AllocateTypeFeedbackInfo() {
2209 TypeFeedbackInfo* info;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002210 { MaybeObject* maybe_info = AllocateStruct(TYPE_FEEDBACK_INFO_TYPE);
2211 if (!maybe_info->To(&info)) return maybe_info;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002212 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002213 info->initialize_storage();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002214 info->set_type_feedback_cells(TypeFeedbackCells::cast(empty_fixed_array()),
2215 SKIP_WRITE_BARRIER);
2216 return info;
2217}
2218
2219
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002220MaybeObject* Heap::AllocateAliasedArgumentsEntry(int aliased_context_slot) {
2221 AliasedArgumentsEntry* entry;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002222 { MaybeObject* maybe_entry = AllocateStruct(ALIASED_ARGUMENTS_ENTRY_TYPE);
2223 if (!maybe_entry->To(&entry)) return maybe_entry;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002224 }
2225 entry->set_aliased_context_slot(aliased_context_slot);
2226 return entry;
2227}
2228
2229
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002230const Heap::StringTypeTable Heap::string_type_table[] = {
2231#define STRING_TYPE_ELEMENT(type, size, name, camel_name) \
2232 {type, size, k##camel_name##MapRootIndex},
2233 STRING_TYPE_LIST(STRING_TYPE_ELEMENT)
2234#undef STRING_TYPE_ELEMENT
2235};
2236
2237
2238const Heap::ConstantSymbolTable Heap::constant_symbol_table[] = {
2239#define CONSTANT_SYMBOL_ELEMENT(name, contents) \
2240 {contents, k##name##RootIndex},
2241 SYMBOL_LIST(CONSTANT_SYMBOL_ELEMENT)
2242#undef CONSTANT_SYMBOL_ELEMENT
2243};
2244
2245
2246const Heap::StructTable Heap::struct_table[] = {
2247#define STRUCT_TABLE_ELEMENT(NAME, Name, name) \
2248 { NAME##_TYPE, Name::kSize, k##Name##MapRootIndex },
2249 STRUCT_LIST(STRUCT_TABLE_ELEMENT)
2250#undef STRUCT_TABLE_ELEMENT
2251};
2252
2253
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002254bool Heap::CreateInitialMaps() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002255 Object* obj;
2256 { MaybeObject* maybe_obj = AllocatePartialMap(MAP_TYPE, Map::kSize);
2257 if (!maybe_obj->ToObject(&obj)) return false;
2258 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002259 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002260 Map* new_meta_map = reinterpret_cast<Map*>(obj);
2261 set_meta_map(new_meta_map);
2262 new_meta_map->set_map(new_meta_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002263
lrn@chromium.org303ada72010-10-27 09:33:13 +00002264 { MaybeObject* maybe_obj =
2265 AllocatePartialMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2266 if (!maybe_obj->ToObject(&obj)) return false;
2267 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002268 set_fixed_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002269
lrn@chromium.org303ada72010-10-27 09:33:13 +00002270 { MaybeObject* maybe_obj = AllocatePartialMap(ODDBALL_TYPE, Oddball::kSize);
2271 if (!maybe_obj->ToObject(&obj)) return false;
2272 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002273 set_oddball_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002274
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002275 // Allocate the empty array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002276 { MaybeObject* maybe_obj = AllocateEmptyFixedArray();
2277 if (!maybe_obj->ToObject(&obj)) return false;
2278 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002279 set_empty_fixed_array(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002280
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002281 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002282 if (!maybe_obj->ToObject(&obj)) return false;
2283 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002284 set_null_value(Oddball::cast(obj));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002285 Oddball::cast(obj)->set_kind(Oddball::kNull);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002286
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002287 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE);
2288 if (!maybe_obj->ToObject(&obj)) return false;
2289 }
2290 set_undefined_value(Oddball::cast(obj));
2291 Oddball::cast(obj)->set_kind(Oddball::kUndefined);
2292 ASSERT(!InNewSpace(undefined_value()));
2293
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002294 // Allocate the empty descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002295 { MaybeObject* maybe_obj = AllocateEmptyFixedArray();
2296 if (!maybe_obj->ToObject(&obj)) return false;
2297 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002298 set_empty_descriptor_array(DescriptorArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002299
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002300 // Fix the instance_descriptors for the existing maps.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002301 meta_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002302 meta_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002303 meta_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002304
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002305 fixed_array_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002306 fixed_array_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002307 fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002308
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002309 oddball_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002310 oddball_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002311 oddball_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002312
2313 // Fix prototype object for existing maps.
2314 meta_map()->set_prototype(null_value());
2315 meta_map()->set_constructor(null_value());
2316
2317 fixed_array_map()->set_prototype(null_value());
2318 fixed_array_map()->set_constructor(null_value());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002319
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002320 oddball_map()->set_prototype(null_value());
2321 oddball_map()->set_constructor(null_value());
2322
lrn@chromium.org303ada72010-10-27 09:33:13 +00002323 { MaybeObject* maybe_obj =
2324 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2325 if (!maybe_obj->ToObject(&obj)) return false;
2326 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002327 set_fixed_cow_array_map(Map::cast(obj));
2328 ASSERT(fixed_array_map() != fixed_cow_array_map());
2329
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002330 { MaybeObject* maybe_obj =
2331 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2332 if (!maybe_obj->ToObject(&obj)) return false;
2333 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002334 set_scope_info_map(Map::cast(obj));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002335
lrn@chromium.org303ada72010-10-27 09:33:13 +00002336 { MaybeObject* maybe_obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
2337 if (!maybe_obj->ToObject(&obj)) return false;
2338 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002339 set_heap_number_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002340
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002341 { MaybeObject* maybe_obj = AllocateMap(FOREIGN_TYPE, Foreign::kSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002342 if (!maybe_obj->ToObject(&obj)) return false;
2343 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002344 set_foreign_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002345
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002346 for (unsigned i = 0; i < ARRAY_SIZE(string_type_table); i++) {
2347 const StringTypeTable& entry = string_type_table[i];
lrn@chromium.org303ada72010-10-27 09:33:13 +00002348 { MaybeObject* maybe_obj = AllocateMap(entry.type, entry.size);
2349 if (!maybe_obj->ToObject(&obj)) return false;
2350 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002351 roots_[entry.index] = Map::cast(obj);
2352 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002353
lrn@chromium.org303ada72010-10-27 09:33:13 +00002354 { MaybeObject* maybe_obj = AllocateMap(STRING_TYPE, kVariableSizeSentinel);
2355 if (!maybe_obj->ToObject(&obj)) return false;
2356 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002357 set_undetectable_string_map(Map::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002358 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002359
lrn@chromium.org303ada72010-10-27 09:33:13 +00002360 { MaybeObject* maybe_obj =
2361 AllocateMap(ASCII_STRING_TYPE, kVariableSizeSentinel);
2362 if (!maybe_obj->ToObject(&obj)) return false;
2363 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002364 set_undetectable_ascii_string_map(Map::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002365 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002366
lrn@chromium.org303ada72010-10-27 09:33:13 +00002367 { MaybeObject* maybe_obj =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002368 AllocateMap(FIXED_DOUBLE_ARRAY_TYPE, kVariableSizeSentinel);
2369 if (!maybe_obj->ToObject(&obj)) return false;
2370 }
2371 set_fixed_double_array_map(Map::cast(obj));
2372
2373 { MaybeObject* maybe_obj =
lrn@chromium.org303ada72010-10-27 09:33:13 +00002374 AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel);
2375 if (!maybe_obj->ToObject(&obj)) return false;
2376 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002377 set_byte_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002378
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002379 { MaybeObject* maybe_obj =
2380 AllocateMap(FREE_SPACE_TYPE, kVariableSizeSentinel);
2381 if (!maybe_obj->ToObject(&obj)) return false;
2382 }
2383 set_free_space_map(Map::cast(obj));
2384
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002385 { MaybeObject* maybe_obj = AllocateByteArray(0, TENURED);
2386 if (!maybe_obj->ToObject(&obj)) return false;
2387 }
2388 set_empty_byte_array(ByteArray::cast(obj));
2389
lrn@chromium.org303ada72010-10-27 09:33:13 +00002390 { MaybeObject* maybe_obj =
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002391 AllocateMap(EXTERNAL_PIXEL_ARRAY_TYPE, ExternalArray::kAlignedSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002392 if (!maybe_obj->ToObject(&obj)) return false;
2393 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002394 set_external_pixel_array_map(Map::cast(obj));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002395
lrn@chromium.org303ada72010-10-27 09:33:13 +00002396 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_BYTE_ARRAY_TYPE,
2397 ExternalArray::kAlignedSize);
2398 if (!maybe_obj->ToObject(&obj)) return false;
2399 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002400 set_external_byte_array_map(Map::cast(obj));
2401
lrn@chromium.org303ada72010-10-27 09:33:13 +00002402 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE,
2403 ExternalArray::kAlignedSize);
2404 if (!maybe_obj->ToObject(&obj)) return false;
2405 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002406 set_external_unsigned_byte_array_map(Map::cast(obj));
2407
lrn@chromium.org303ada72010-10-27 09:33:13 +00002408 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_SHORT_ARRAY_TYPE,
2409 ExternalArray::kAlignedSize);
2410 if (!maybe_obj->ToObject(&obj)) return false;
2411 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002412 set_external_short_array_map(Map::cast(obj));
2413
lrn@chromium.org303ada72010-10-27 09:33:13 +00002414 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE,
2415 ExternalArray::kAlignedSize);
2416 if (!maybe_obj->ToObject(&obj)) return false;
2417 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002418 set_external_unsigned_short_array_map(Map::cast(obj));
2419
lrn@chromium.org303ada72010-10-27 09:33:13 +00002420 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_INT_ARRAY_TYPE,
2421 ExternalArray::kAlignedSize);
2422 if (!maybe_obj->ToObject(&obj)) return false;
2423 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002424 set_external_int_array_map(Map::cast(obj));
2425
lrn@chromium.org303ada72010-10-27 09:33:13 +00002426 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE,
2427 ExternalArray::kAlignedSize);
2428 if (!maybe_obj->ToObject(&obj)) return false;
2429 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002430 set_external_unsigned_int_array_map(Map::cast(obj));
2431
lrn@chromium.org303ada72010-10-27 09:33:13 +00002432 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_FLOAT_ARRAY_TYPE,
2433 ExternalArray::kAlignedSize);
2434 if (!maybe_obj->ToObject(&obj)) return false;
2435 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002436 set_external_float_array_map(Map::cast(obj));
2437
whesse@chromium.org7b260152011-06-20 15:33:18 +00002438 { MaybeObject* maybe_obj =
2439 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2440 if (!maybe_obj->ToObject(&obj)) return false;
2441 }
2442 set_non_strict_arguments_elements_map(Map::cast(obj));
2443
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002444 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_DOUBLE_ARRAY_TYPE,
2445 ExternalArray::kAlignedSize);
2446 if (!maybe_obj->ToObject(&obj)) return false;
2447 }
2448 set_external_double_array_map(Map::cast(obj));
2449
lrn@chromium.org303ada72010-10-27 09:33:13 +00002450 { MaybeObject* maybe_obj = AllocateMap(CODE_TYPE, kVariableSizeSentinel);
2451 if (!maybe_obj->ToObject(&obj)) return false;
2452 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002453 set_code_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002454
lrn@chromium.org303ada72010-10-27 09:33:13 +00002455 { MaybeObject* maybe_obj = AllocateMap(JS_GLOBAL_PROPERTY_CELL_TYPE,
2456 JSGlobalPropertyCell::kSize);
2457 if (!maybe_obj->ToObject(&obj)) return false;
2458 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002459 set_global_property_cell_map(Map::cast(obj));
2460
lrn@chromium.org303ada72010-10-27 09:33:13 +00002461 { MaybeObject* maybe_obj = AllocateMap(FILLER_TYPE, kPointerSize);
2462 if (!maybe_obj->ToObject(&obj)) return false;
2463 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002464 set_one_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002465
lrn@chromium.org303ada72010-10-27 09:33:13 +00002466 { MaybeObject* maybe_obj = AllocateMap(FILLER_TYPE, 2 * kPointerSize);
2467 if (!maybe_obj->ToObject(&obj)) return false;
2468 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002469 set_two_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002470
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002471 for (unsigned i = 0; i < ARRAY_SIZE(struct_table); i++) {
2472 const StructTable& entry = struct_table[i];
lrn@chromium.org303ada72010-10-27 09:33:13 +00002473 { MaybeObject* maybe_obj = AllocateMap(entry.type, entry.size);
2474 if (!maybe_obj->ToObject(&obj)) return false;
2475 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002476 roots_[entry.index] = Map::cast(obj);
2477 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002478
lrn@chromium.org303ada72010-10-27 09:33:13 +00002479 { MaybeObject* maybe_obj =
2480 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2481 if (!maybe_obj->ToObject(&obj)) return false;
2482 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002483 set_hash_table_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002484
lrn@chromium.org303ada72010-10-27 09:33:13 +00002485 { MaybeObject* maybe_obj =
2486 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2487 if (!maybe_obj->ToObject(&obj)) return false;
2488 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002489 set_function_context_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002490
lrn@chromium.org303ada72010-10-27 09:33:13 +00002491 { MaybeObject* maybe_obj =
2492 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2493 if (!maybe_obj->ToObject(&obj)) return false;
2494 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002495 set_catch_context_map(Map::cast(obj));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002496
lrn@chromium.org303ada72010-10-27 09:33:13 +00002497 { MaybeObject* maybe_obj =
2498 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2499 if (!maybe_obj->ToObject(&obj)) return false;
2500 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002501 set_with_context_map(Map::cast(obj));
2502
2503 { MaybeObject* maybe_obj =
2504 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2505 if (!maybe_obj->ToObject(&obj)) return false;
2506 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002507 set_block_context_map(Map::cast(obj));
2508
2509 { MaybeObject* maybe_obj =
2510 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2511 if (!maybe_obj->ToObject(&obj)) return false;
2512 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002513 set_module_context_map(Map::cast(obj));
2514
2515 { MaybeObject* maybe_obj =
2516 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2517 if (!maybe_obj->ToObject(&obj)) return false;
2518 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002519 set_global_context_map(Map::cast(obj));
2520
2521 { MaybeObject* maybe_obj =
2522 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2523 if (!maybe_obj->ToObject(&obj)) return false;
2524 }
2525 Map* native_context_map = Map::cast(obj);
2526 native_context_map->set_dictionary_map(true);
2527 native_context_map->set_visitor_id(StaticVisitorBase::kVisitNativeContext);
2528 set_native_context_map(native_context_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002529
lrn@chromium.org303ada72010-10-27 09:33:13 +00002530 { MaybeObject* maybe_obj = AllocateMap(SHARED_FUNCTION_INFO_TYPE,
2531 SharedFunctionInfo::kAlignedSize);
2532 if (!maybe_obj->ToObject(&obj)) return false;
2533 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002534 set_shared_function_info_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002535
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002536 { MaybeObject* maybe_obj = AllocateMap(JS_MESSAGE_OBJECT_TYPE,
2537 JSMessageObject::kSize);
2538 if (!maybe_obj->ToObject(&obj)) return false;
2539 }
2540 set_message_object_map(Map::cast(obj));
2541
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002542 Map* external_map;
2543 { MaybeObject* maybe_obj =
2544 AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize + kPointerSize);
2545 if (!maybe_obj->To(&external_map)) return false;
2546 }
2547 external_map->set_is_extensible(false);
2548 set_external_map(external_map);
2549
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002550 ASSERT(!InNewSpace(empty_fixed_array()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002551 return true;
2552}
2553
2554
lrn@chromium.org303ada72010-10-27 09:33:13 +00002555MaybeObject* Heap::AllocateHeapNumber(double value, PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002556 // Statically ensure that it is safe to allocate heap numbers in paged
2557 // spaces.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002558 STATIC_ASSERT(HeapNumber::kSize <= Page::kNonCodeObjectAreaSize);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002559 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002560
lrn@chromium.org303ada72010-10-27 09:33:13 +00002561 Object* result;
2562 { MaybeObject* maybe_result =
2563 AllocateRaw(HeapNumber::kSize, space, OLD_DATA_SPACE);
2564 if (!maybe_result->ToObject(&result)) return maybe_result;
2565 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002566
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002567 HeapObject::cast(result)->set_map_no_write_barrier(heap_number_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002568 HeapNumber::cast(result)->set_value(value);
2569 return result;
2570}
2571
2572
lrn@chromium.org303ada72010-10-27 09:33:13 +00002573MaybeObject* Heap::AllocateHeapNumber(double value) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002574 // Use general version, if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002575 if (always_allocate()) return AllocateHeapNumber(value, TENURED);
2576
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002577 // This version of AllocateHeapNumber is optimized for
2578 // allocation in new space.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002579 STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxNonCodeHeapObjectSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002580 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002581 Object* result;
2582 { MaybeObject* maybe_result = new_space_.AllocateRaw(HeapNumber::kSize);
2583 if (!maybe_result->ToObject(&result)) return maybe_result;
2584 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002585 HeapObject::cast(result)->set_map_no_write_barrier(heap_number_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002586 HeapNumber::cast(result)->set_value(value);
2587 return result;
2588}
2589
2590
lrn@chromium.org303ada72010-10-27 09:33:13 +00002591MaybeObject* Heap::AllocateJSGlobalPropertyCell(Object* value) {
2592 Object* result;
2593 { MaybeObject* maybe_result = AllocateRawCell();
2594 if (!maybe_result->ToObject(&result)) return maybe_result;
2595 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002596 HeapObject::cast(result)->set_map_no_write_barrier(
2597 global_property_cell_map());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002598 JSGlobalPropertyCell::cast(result)->set_value(value);
2599 return result;
2600}
2601
2602
lrn@chromium.org303ada72010-10-27 09:33:13 +00002603MaybeObject* Heap::CreateOddball(const char* to_string,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002604 Object* to_number,
2605 byte kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002606 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002607 { MaybeObject* maybe_result = Allocate(oddball_map(), OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002608 if (!maybe_result->ToObject(&result)) return maybe_result;
2609 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002610 return Oddball::cast(result)->Initialize(to_string, to_number, kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002611}
2612
2613
2614bool Heap::CreateApiObjects() {
2615 Object* obj;
2616
lrn@chromium.org303ada72010-10-27 09:33:13 +00002617 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
2618 if (!maybe_obj->ToObject(&obj)) return false;
2619 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002620 // Don't use Smi-only elements optimizations for objects with the neander
2621 // map. There are too many cases where element values are set directly with a
2622 // bottleneck to trap the Smi-only -> fast elements transition, and there
2623 // appears to be no benefit for optimize this case.
2624 Map* new_neander_map = Map::cast(obj);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002625 new_neander_map->set_elements_kind(TERMINAL_FAST_ELEMENTS_KIND);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002626 set_neander_map(new_neander_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002627
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002628 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(neander_map());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002629 if (!maybe_obj->ToObject(&obj)) return false;
2630 }
2631 Object* elements;
2632 { MaybeObject* maybe_elements = AllocateFixedArray(2);
2633 if (!maybe_elements->ToObject(&elements)) return false;
2634 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002635 FixedArray::cast(elements)->set(0, Smi::FromInt(0));
2636 JSObject::cast(obj)->set_elements(FixedArray::cast(elements));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002637 set_message_listeners(JSObject::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002638
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002639 return true;
2640}
2641
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002642
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002643void Heap::CreateJSEntryStub() {
2644 JSEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002645 set_js_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002646}
2647
2648
2649void Heap::CreateJSConstructEntryStub() {
2650 JSConstructEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002651 set_js_construct_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002652}
2653
2654
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002655void Heap::CreateFixedStubs() {
2656 // Here we create roots for fixed stubs. They are needed at GC
2657 // for cooking and uncooking (check out frames.cc).
2658 // The eliminates the need for doing dictionary lookup in the
2659 // stub cache for these stubs.
2660 HandleScope scope;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002661 // gcc-4.4 has problem generating correct code of following snippet:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002662 // { JSEntryStub stub;
2663 // js_entry_code_ = *stub.GetCode();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002664 // }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002665 // { JSConstructEntryStub stub;
2666 // js_construct_entry_code_ = *stub.GetCode();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002667 // }
2668 // To workaround the problem, make separate functions without inlining.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002669 Heap::CreateJSEntryStub();
2670 Heap::CreateJSConstructEntryStub();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002671
2672 // Create stubs that should be there, so we don't unexpectedly have to
2673 // create them if we need them during the creation of another stub.
2674 // Stub creation mixes raw pointers and handles in an unsafe manner so
2675 // we cannot create stubs while we are creating stubs.
2676 CodeStub::GenerateStubsAheadOfTime();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002677}
2678
2679
2680bool Heap::CreateInitialObjects() {
2681 Object* obj;
2682
2683 // The -0 value must be set before NumberFromDouble works.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002684 { MaybeObject* maybe_obj = AllocateHeapNumber(-0.0, TENURED);
2685 if (!maybe_obj->ToObject(&obj)) return false;
2686 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002687 set_minus_zero_value(HeapNumber::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002688 ASSERT(signbit(minus_zero_value()->Number()) != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002689
lrn@chromium.org303ada72010-10-27 09:33:13 +00002690 { MaybeObject* maybe_obj = AllocateHeapNumber(OS::nan_value(), TENURED);
2691 if (!maybe_obj->ToObject(&obj)) return false;
2692 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002693 set_nan_value(HeapNumber::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002694
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002695 { MaybeObject* maybe_obj = AllocateHeapNumber(V8_INFINITY, TENURED);
2696 if (!maybe_obj->ToObject(&obj)) return false;
2697 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002698 set_infinity_value(HeapNumber::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002699
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00002700 // The hole has not been created yet, but we want to put something
2701 // predictable in the gaps in the symbol table, so lets make that Smi zero.
2702 set_the_hole_value(reinterpret_cast<Oddball*>(Smi::FromInt(0)));
2703
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002704 // Allocate initial symbol table.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002705 { MaybeObject* maybe_obj = SymbolTable::Allocate(kInitialSymbolTableSize);
2706 if (!maybe_obj->ToObject(&obj)) return false;
2707 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002708 // Don't use set_symbol_table() due to asserts.
2709 roots_[kSymbolTableRootIndex] = obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002710
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002711 // Finish initializing oddballs after creating symboltable.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002712 { MaybeObject* maybe_obj =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002713 undefined_value()->Initialize("undefined",
2714 nan_value(),
2715 Oddball::kUndefined);
2716 if (!maybe_obj->ToObject(&obj)) return false;
2717 }
2718
2719 // Initialize the null_value.
2720 { MaybeObject* maybe_obj =
2721 null_value()->Initialize("null", Smi::FromInt(0), Oddball::kNull);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002722 if (!maybe_obj->ToObject(&obj)) return false;
2723 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002724
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002725 { MaybeObject* maybe_obj = CreateOddball("true",
2726 Smi::FromInt(1),
2727 Oddball::kTrue);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002728 if (!maybe_obj->ToObject(&obj)) return false;
2729 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002730 set_true_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002731
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002732 { MaybeObject* maybe_obj = CreateOddball("false",
2733 Smi::FromInt(0),
2734 Oddball::kFalse);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002735 if (!maybe_obj->ToObject(&obj)) return false;
2736 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002737 set_false_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002738
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002739 { MaybeObject* maybe_obj = CreateOddball("hole",
2740 Smi::FromInt(-1),
2741 Oddball::kTheHole);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002742 if (!maybe_obj->ToObject(&obj)) return false;
2743 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002744 set_the_hole_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002745
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002746 { MaybeObject* maybe_obj = CreateOddball("arguments_marker",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002747 Smi::FromInt(-4),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002748 Oddball::kArgumentMarker);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002749 if (!maybe_obj->ToObject(&obj)) return false;
2750 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002751 set_arguments_marker(Oddball::cast(obj));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002752
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002753 { MaybeObject* maybe_obj = CreateOddball("no_interceptor_result_sentinel",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002754 Smi::FromInt(-2),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002755 Oddball::kOther);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002756 if (!maybe_obj->ToObject(&obj)) return false;
2757 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002758 set_no_interceptor_result_sentinel(obj);
2759
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002760 { MaybeObject* maybe_obj = CreateOddball("termination_exception",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002761 Smi::FromInt(-3),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002762 Oddball::kOther);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002763 if (!maybe_obj->ToObject(&obj)) return false;
2764 }
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00002765 set_termination_exception(obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002766
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002767 // Allocate the empty string.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002768 { MaybeObject* maybe_obj = AllocateRawOneByteString(0, TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002769 if (!maybe_obj->ToObject(&obj)) return false;
2770 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002771 set_empty_string(String::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002772
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002773 for (unsigned i = 0; i < ARRAY_SIZE(constant_symbol_table); i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002774 { MaybeObject* maybe_obj =
2775 LookupAsciiSymbol(constant_symbol_table[i].contents);
2776 if (!maybe_obj->ToObject(&obj)) return false;
2777 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002778 roots_[constant_symbol_table[i].index] = String::cast(obj);
2779 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002780
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002781 // Allocate the hidden symbol which is used to identify the hidden properties
2782 // in JSObjects. The hash code has a special value so that it will not match
2783 // the empty string when searching for the property. It cannot be part of the
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002784 // loop above because it needs to be allocated manually with the special
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002785 // hash code in place. The hash code for the hidden_symbol is zero to ensure
2786 // that it will always be at the first entry in property descriptors.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002787 { MaybeObject* maybe_obj =
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002788 AllocateSymbol(CStrVector(""), 0, String::kEmptyStringHash);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002789 if (!maybe_obj->ToObject(&obj)) return false;
2790 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002791 hidden_symbol_ = String::cast(obj);
2792
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002793 // Allocate the foreign for __proto__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002794 { MaybeObject* maybe_obj =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002795 AllocateForeign((Address) &Accessors::ObjectPrototype);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002796 if (!maybe_obj->ToObject(&obj)) return false;
2797 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002798 set_prototype_accessors(Foreign::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002799
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002800 // Allocate the code_stubs dictionary. The initial size is set to avoid
2801 // expanding the dictionary during bootstrapping.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002802 { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(128);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002803 if (!maybe_obj->ToObject(&obj)) return false;
2804 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002805 set_code_stubs(UnseededNumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002806
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002807
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002808 // Allocate the non_monomorphic_cache used in stub-cache.cc. The initial size
2809 // is set to avoid expanding the dictionary during bootstrapping.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002810 { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(64);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002811 if (!maybe_obj->ToObject(&obj)) return false;
2812 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002813 set_non_monomorphic_cache(UnseededNumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002814
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002815 { MaybeObject* maybe_obj = AllocatePolymorphicCodeCache();
2816 if (!maybe_obj->ToObject(&obj)) return false;
2817 }
2818 set_polymorphic_code_cache(PolymorphicCodeCache::cast(obj));
2819
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002820 set_instanceof_cache_function(Smi::FromInt(0));
2821 set_instanceof_cache_map(Smi::FromInt(0));
2822 set_instanceof_cache_answer(Smi::FromInt(0));
2823
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002824 CreateFixedStubs();
2825
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002826 // Allocate the dictionary of intrinsic function names.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002827 { MaybeObject* maybe_obj = StringDictionary::Allocate(Runtime::kNumFunctions);
2828 if (!maybe_obj->ToObject(&obj)) return false;
2829 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002830 { MaybeObject* maybe_obj = Runtime::InitializeIntrinsicFunctionNames(this,
2831 obj);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002832 if (!maybe_obj->ToObject(&obj)) return false;
2833 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002834 set_intrinsic_function_names(StringDictionary::cast(obj));
2835
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002836 { MaybeObject* maybe_obj = AllocateInitialNumberStringCache();
2837 if (!maybe_obj->ToObject(&obj)) return false;
2838 }
2839 set_number_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002840
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002841 // Allocate cache for single character ASCII strings.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002842 { MaybeObject* maybe_obj =
2843 AllocateFixedArray(String::kMaxAsciiCharCode + 1, TENURED);
2844 if (!maybe_obj->ToObject(&obj)) return false;
2845 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002846 set_single_character_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002847
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002848 // Allocate cache for string split.
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002849 { MaybeObject* maybe_obj = AllocateFixedArray(
2850 RegExpResultsCache::kRegExpResultsCacheSize, TENURED);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002851 if (!maybe_obj->ToObject(&obj)) return false;
2852 }
2853 set_string_split_cache(FixedArray::cast(obj));
2854
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002855 { MaybeObject* maybe_obj = AllocateFixedArray(
2856 RegExpResultsCache::kRegExpResultsCacheSize, TENURED);
2857 if (!maybe_obj->ToObject(&obj)) return false;
2858 }
2859 set_regexp_multiple_cache(FixedArray::cast(obj));
2860
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002861 // Allocate cache for external strings pointing to native source code.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002862 { MaybeObject* maybe_obj = AllocateFixedArray(Natives::GetBuiltinsCount());
2863 if (!maybe_obj->ToObject(&obj)) return false;
2864 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002865 set_natives_source_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002866
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002867 // Allocate object to hold object observation state.
2868 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
2869 if (!maybe_obj->ToObject(&obj)) return false;
2870 }
2871 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(Map::cast(obj));
2872 if (!maybe_obj->ToObject(&obj)) return false;
2873 }
2874 set_observation_state(JSObject::cast(obj));
2875
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002876 // Handling of script id generation is in FACTORY->NewScript.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002877 set_last_script_id(undefined_value());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002878
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002879 // Initialize keyed lookup cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002880 isolate_->keyed_lookup_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002881
2882 // Initialize context slot cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002883 isolate_->context_slot_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002884
2885 // Initialize descriptor cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002886 isolate_->descriptor_lookup_cache()->Clear();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002887
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002888 // Initialize compilation cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002889 isolate_->compilation_cache()->Clear();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002890
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002891 return true;
2892}
2893
2894
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002895bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) {
2896 RootListIndex writable_roots[] = {
2897 kStoreBufferTopRootIndex,
2898 kStackLimitRootIndex,
2899 kInstanceofCacheFunctionRootIndex,
2900 kInstanceofCacheMapRootIndex,
2901 kInstanceofCacheAnswerRootIndex,
2902 kCodeStubsRootIndex,
2903 kNonMonomorphicCacheRootIndex,
2904 kPolymorphicCodeCacheRootIndex,
2905 kLastScriptIdRootIndex,
2906 kEmptyScriptRootIndex,
2907 kRealStackLimitRootIndex,
2908 kArgumentsAdaptorDeoptPCOffsetRootIndex,
2909 kConstructStubDeoptPCOffsetRootIndex,
2910 kGetterStubDeoptPCOffsetRootIndex,
2911 kSetterStubDeoptPCOffsetRootIndex,
2912 kSymbolTableRootIndex,
2913 };
2914
2915 for (unsigned int i = 0; i < ARRAY_SIZE(writable_roots); i++) {
2916 if (root_index == writable_roots[i])
2917 return true;
2918 }
2919 return false;
2920}
2921
2922
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002923Object* RegExpResultsCache::Lookup(Heap* heap,
2924 String* key_string,
2925 Object* key_pattern,
2926 ResultsCacheType type) {
2927 FixedArray* cache;
2928 if (!key_string->IsSymbol()) return Smi::FromInt(0);
2929 if (type == STRING_SPLIT_SUBSTRINGS) {
2930 ASSERT(key_pattern->IsString());
2931 if (!key_pattern->IsSymbol()) return Smi::FromInt(0);
2932 cache = heap->string_split_cache();
2933 } else {
2934 ASSERT(type == REGEXP_MULTIPLE_INDICES);
2935 ASSERT(key_pattern->IsFixedArray());
2936 cache = heap->regexp_multiple_cache();
2937 }
2938
2939 uint32_t hash = key_string->Hash();
2940 uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) &
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002941 ~(kArrayEntriesPerCacheEntry - 1));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002942 if (cache->get(index + kStringOffset) == key_string &&
2943 cache->get(index + kPatternOffset) == key_pattern) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002944 return cache->get(index + kArrayOffset);
2945 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002946 index =
2947 ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1));
2948 if (cache->get(index + kStringOffset) == key_string &&
2949 cache->get(index + kPatternOffset) == key_pattern) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002950 return cache->get(index + kArrayOffset);
2951 }
2952 return Smi::FromInt(0);
2953}
2954
2955
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002956void RegExpResultsCache::Enter(Heap* heap,
2957 String* key_string,
2958 Object* key_pattern,
2959 FixedArray* value_array,
2960 ResultsCacheType type) {
2961 FixedArray* cache;
2962 if (!key_string->IsSymbol()) return;
2963 if (type == STRING_SPLIT_SUBSTRINGS) {
2964 ASSERT(key_pattern->IsString());
2965 if (!key_pattern->IsSymbol()) return;
2966 cache = heap->string_split_cache();
2967 } else {
2968 ASSERT(type == REGEXP_MULTIPLE_INDICES);
2969 ASSERT(key_pattern->IsFixedArray());
2970 cache = heap->regexp_multiple_cache();
2971 }
2972
2973 uint32_t hash = key_string->Hash();
2974 uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) &
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002975 ~(kArrayEntriesPerCacheEntry - 1));
2976 if (cache->get(index + kStringOffset) == Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002977 cache->set(index + kStringOffset, key_string);
2978 cache->set(index + kPatternOffset, key_pattern);
2979 cache->set(index + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002980 } else {
2981 uint32_t index2 =
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002982 ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1));
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002983 if (cache->get(index2 + kStringOffset) == Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002984 cache->set(index2 + kStringOffset, key_string);
2985 cache->set(index2 + kPatternOffset, key_pattern);
2986 cache->set(index2 + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002987 } else {
2988 cache->set(index2 + kStringOffset, Smi::FromInt(0));
2989 cache->set(index2 + kPatternOffset, Smi::FromInt(0));
2990 cache->set(index2 + kArrayOffset, Smi::FromInt(0));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002991 cache->set(index + kStringOffset, key_string);
2992 cache->set(index + kPatternOffset, key_pattern);
2993 cache->set(index + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002994 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002995 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002996 // If the array is a reasonably short list of substrings, convert it into a
2997 // list of symbols.
2998 if (type == STRING_SPLIT_SUBSTRINGS && value_array->length() < 100) {
2999 for (int i = 0; i < value_array->length(); i++) {
3000 String* str = String::cast(value_array->get(i));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003001 Object* symbol;
3002 MaybeObject* maybe_symbol = heap->LookupSymbol(str);
3003 if (maybe_symbol->ToObject(&symbol)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003004 value_array->set(i, symbol);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003005 }
3006 }
3007 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003008 // Convert backing store to a copy-on-write array.
3009 value_array->set_map_no_write_barrier(heap->fixed_cow_array_map());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003010}
3011
3012
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003013void RegExpResultsCache::Clear(FixedArray* cache) {
3014 for (int i = 0; i < kRegExpResultsCacheSize; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003015 cache->set(i, Smi::FromInt(0));
3016 }
3017}
3018
3019
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003020MaybeObject* Heap::AllocateInitialNumberStringCache() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003021 MaybeObject* maybe_obj =
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003022 AllocateFixedArray(kInitialNumberStringCacheSize * 2, TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003023 return maybe_obj;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003024}
3025
3026
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003027int Heap::FullSizeNumberStringCacheLength() {
3028 // Compute the size of the number string cache based on the max newspace size.
3029 // The number string cache has a minimum size based on twice the initial cache
3030 // size to ensure that it is bigger after being made 'full size'.
3031 int number_string_cache_size = max_semispace_size_ / 512;
3032 number_string_cache_size = Max(kInitialNumberStringCacheSize * 2,
3033 Min(0x4000, number_string_cache_size));
3034 // There is a string and a number per entry so the length is twice the number
3035 // of entries.
3036 return number_string_cache_size * 2;
3037}
3038
3039
3040void Heap::AllocateFullSizeNumberStringCache() {
3041 // The idea is to have a small number string cache in the snapshot to keep
3042 // boot-time memory usage down. If we expand the number string cache already
3043 // while creating the snapshot then that didn't work out.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003044 ASSERT(!Serializer::enabled() || FLAG_extra_code != NULL);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003045 MaybeObject* maybe_obj =
3046 AllocateFixedArray(FullSizeNumberStringCacheLength(), TENURED);
3047 Object* new_cache;
3048 if (maybe_obj->ToObject(&new_cache)) {
3049 // We don't bother to repopulate the cache with entries from the old cache.
3050 // It will be repopulated soon enough with new strings.
3051 set_number_string_cache(FixedArray::cast(new_cache));
3052 }
3053 // If allocation fails then we just return without doing anything. It is only
3054 // a cache, so best effort is OK here.
3055}
3056
3057
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003058void Heap::FlushNumberStringCache() {
3059 // Flush the number to string cache.
3060 int len = number_string_cache()->length();
3061 for (int i = 0; i < len; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003062 number_string_cache()->set_undefined(this, i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003063 }
3064}
3065
3066
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003067static inline int double_get_hash(double d) {
3068 DoubleRepresentation rep(d);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003069 return static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003070}
3071
3072
3073static inline int smi_get_hash(Smi* smi) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003074 return smi->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003075}
3076
3077
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003078Object* Heap::GetNumberStringCache(Object* number) {
3079 int hash;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003080 int mask = (number_string_cache()->length() >> 1) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003081 if (number->IsSmi()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003082 hash = smi_get_hash(Smi::cast(number)) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003083 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003084 hash = double_get_hash(number->Number()) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003085 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003086 Object* key = number_string_cache()->get(hash * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003087 if (key == number) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003088 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003089 } else if (key->IsHeapNumber() &&
3090 number->IsHeapNumber() &&
3091 key->Number() == number->Number()) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003092 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003093 }
3094 return undefined_value();
3095}
3096
3097
3098void Heap::SetNumberStringCache(Object* number, String* string) {
3099 int hash;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003100 int mask = (number_string_cache()->length() >> 1) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003101 if (number->IsSmi()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003102 hash = smi_get_hash(Smi::cast(number)) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003103 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003104 hash = double_get_hash(number->Number()) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003105 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003106 if (number_string_cache()->get(hash * 2) != undefined_value() &&
3107 number_string_cache()->length() != FullSizeNumberStringCacheLength()) {
3108 // The first time we have a hash collision, we move to the full sized
3109 // number string cache.
3110 AllocateFullSizeNumberStringCache();
3111 return;
3112 }
3113 number_string_cache()->set(hash * 2, number);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003114 number_string_cache()->set(hash * 2 + 1, string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003115}
3116
3117
lrn@chromium.org303ada72010-10-27 09:33:13 +00003118MaybeObject* Heap::NumberToString(Object* number,
3119 bool check_number_string_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003120 isolate_->counters()->number_to_string_runtime()->Increment();
ager@chromium.org357bf652010-04-12 11:30:10 +00003121 if (check_number_string_cache) {
3122 Object* cached = GetNumberStringCache(number);
3123 if (cached != undefined_value()) {
3124 return cached;
3125 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003126 }
3127
3128 char arr[100];
3129 Vector<char> buffer(arr, ARRAY_SIZE(arr));
3130 const char* str;
3131 if (number->IsSmi()) {
3132 int num = Smi::cast(number)->value();
3133 str = IntToCString(num, buffer);
3134 } else {
3135 double num = HeapNumber::cast(number)->value();
3136 str = DoubleToCString(num, buffer);
3137 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003138
lrn@chromium.org303ada72010-10-27 09:33:13 +00003139 Object* js_string;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003140 MaybeObject* maybe_js_string = AllocateStringFromOneByte(CStrVector(str));
lrn@chromium.org303ada72010-10-27 09:33:13 +00003141 if (maybe_js_string->ToObject(&js_string)) {
3142 SetNumberStringCache(number, String::cast(js_string));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003143 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00003144 return maybe_js_string;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003145}
3146
3147
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003148MaybeObject* Heap::Uint32ToString(uint32_t value,
3149 bool check_number_string_cache) {
3150 Object* number;
3151 MaybeObject* maybe = NumberFromUint32(value);
3152 if (!maybe->To<Object>(&number)) return maybe;
3153 return NumberToString(number, check_number_string_cache);
3154}
3155
3156
ager@chromium.org3811b432009-10-28 14:53:37 +00003157Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) {
3158 return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]);
3159}
3160
3161
3162Heap::RootListIndex Heap::RootIndexForExternalArrayType(
3163 ExternalArrayType array_type) {
3164 switch (array_type) {
3165 case kExternalByteArray:
3166 return kExternalByteArrayMapRootIndex;
3167 case kExternalUnsignedByteArray:
3168 return kExternalUnsignedByteArrayMapRootIndex;
3169 case kExternalShortArray:
3170 return kExternalShortArrayMapRootIndex;
3171 case kExternalUnsignedShortArray:
3172 return kExternalUnsignedShortArrayMapRootIndex;
3173 case kExternalIntArray:
3174 return kExternalIntArrayMapRootIndex;
3175 case kExternalUnsignedIntArray:
3176 return kExternalUnsignedIntArrayMapRootIndex;
3177 case kExternalFloatArray:
3178 return kExternalFloatArrayMapRootIndex;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003179 case kExternalDoubleArray:
3180 return kExternalDoubleArrayMapRootIndex;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003181 case kExternalPixelArray:
3182 return kExternalPixelArrayMapRootIndex;
ager@chromium.org3811b432009-10-28 14:53:37 +00003183 default:
3184 UNREACHABLE();
3185 return kUndefinedValueRootIndex;
3186 }
3187}
3188
3189
lrn@chromium.org303ada72010-10-27 09:33:13 +00003190MaybeObject* Heap::NumberFromDouble(double value, PretenureFlag pretenure) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003191 // We need to distinguish the minus zero value and this cannot be
3192 // done after conversion to int. Doing this by comparing bit
3193 // patterns is faster than using fpclassify() et al.
3194 static const DoubleRepresentation minus_zero(-0.0);
3195
3196 DoubleRepresentation rep(value);
3197 if (rep.bits == minus_zero.bits) {
3198 return AllocateHeapNumber(-0.0, pretenure);
3199 }
3200
3201 int int_value = FastD2I(value);
3202 if (value == int_value && Smi::IsValid(int_value)) {
3203 return Smi::FromInt(int_value);
3204 }
3205
3206 // Materialize the value in the heap.
3207 return AllocateHeapNumber(value, pretenure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003208}
3209
3210
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003211MaybeObject* Heap::AllocateForeign(Address address, PretenureFlag pretenure) {
3212 // Statically ensure that it is safe to allocate foreigns in paged spaces.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003213 STATIC_ASSERT(Foreign::kSize <= Page::kMaxNonCodeHeapObjectSize);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003214 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003215 Foreign* result;
3216 MaybeObject* maybe_result = Allocate(foreign_map(), space);
3217 if (!maybe_result->To(&result)) return maybe_result;
3218 result->set_foreign_address(address);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003219 return result;
3220}
3221
3222
lrn@chromium.org303ada72010-10-27 09:33:13 +00003223MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003224 SharedFunctionInfo* share;
3225 MaybeObject* maybe = Allocate(shared_function_info_map(), OLD_POINTER_SPACE);
3226 if (!maybe->To<SharedFunctionInfo>(&share)) return maybe;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003227
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003228 // Set pointer fields.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003229 share->set_name(name);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003230 Code* illegal = isolate_->builtins()->builtin(Builtins::kIllegal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003231 share->set_code(illegal);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003232 share->ClearOptimizedCodeMap();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003233 share->set_scope_info(ScopeInfo::Empty());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003234 Code* construct_stub =
3235 isolate_->builtins()->builtin(Builtins::kJSConstructStubGeneric);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003236 share->set_construct_stub(construct_stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003237 share->set_instance_class_name(Object_symbol());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003238 share->set_function_data(undefined_value(), SKIP_WRITE_BARRIER);
3239 share->set_script(undefined_value(), SKIP_WRITE_BARRIER);
3240 share->set_debug_info(undefined_value(), SKIP_WRITE_BARRIER);
3241 share->set_inferred_name(empty_string(), SKIP_WRITE_BARRIER);
3242 share->set_initial_map(undefined_value(), SKIP_WRITE_BARRIER);
3243 share->set_this_property_assignments(undefined_value(), SKIP_WRITE_BARRIER);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003244 share->set_ast_node_count(0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003245 share->set_stress_deopt_counter(FLAG_deopt_every_n_times);
3246 share->set_counters(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003247
3248 // Set integer fields (smi or int, depending on the architecture).
3249 share->set_length(0);
3250 share->set_formal_parameter_count(0);
3251 share->set_expected_nof_properties(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003252 share->set_num_literals(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003253 share->set_start_position_and_type(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003254 share->set_end_position(0);
3255 share->set_function_token_position(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003256 // All compiler hints default to false or 0.
3257 share->set_compiler_hints(0);
3258 share->set_this_property_assignments_count(0);
3259 share->set_opt_count(0);
3260
3261 return share;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003262}
3263
3264
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003265MaybeObject* Heap::AllocateJSMessageObject(String* type,
3266 JSArray* arguments,
3267 int start_position,
3268 int end_position,
3269 Object* script,
3270 Object* stack_trace,
3271 Object* stack_frames) {
3272 Object* result;
3273 { MaybeObject* maybe_result = Allocate(message_object_map(), NEW_SPACE);
3274 if (!maybe_result->ToObject(&result)) return maybe_result;
3275 }
3276 JSMessageObject* message = JSMessageObject::cast(result);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003277 message->set_properties(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003278 message->initialize_elements();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003279 message->set_elements(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003280 message->set_type(type);
3281 message->set_arguments(arguments);
3282 message->set_start_position(start_position);
3283 message->set_end_position(end_position);
3284 message->set_script(script);
3285 message->set_stack_trace(stack_trace);
3286 message->set_stack_frames(stack_frames);
3287 return result;
3288}
3289
3290
3291
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003292// Returns true for a character in a range. Both limits are inclusive.
3293static inline bool Between(uint32_t character, uint32_t from, uint32_t to) {
3294 // This makes uses of the the unsigned wraparound.
3295 return character - from <= to - from;
3296}
3297
3298
lrn@chromium.org303ada72010-10-27 09:33:13 +00003299MUST_USE_RESULT static inline MaybeObject* MakeOrFindTwoCharacterString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003300 Heap* heap,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003301 uint32_t c1,
3302 uint32_t c2) {
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003303 String* symbol;
3304 // Numeric strings have a different hash algorithm not known by
3305 // LookupTwoCharsSymbolIfExists, so we skip this step for such strings.
3306 if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003307 heap->symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) {
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003308 return symbol;
3309 // Now we know the length is 2, we might as well make use of that fact
3310 // when building the new string.
3311 } else if ((c1 | c2) <= String::kMaxAsciiCharCodeU) { // We can do this
3312 ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1)); // because of this.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003313 Object* result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003314 { MaybeObject* maybe_result = heap->AllocateRawOneByteString(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003315 if (!maybe_result->ToObject(&result)) return maybe_result;
3316 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003317 char* dest = SeqOneByteString::cast(result)->GetChars();
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003318 dest[0] = c1;
3319 dest[1] = c2;
3320 return result;
3321 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003322 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003323 { MaybeObject* maybe_result = heap->AllocateRawTwoByteString(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003324 if (!maybe_result->ToObject(&result)) return maybe_result;
3325 }
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003326 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
3327 dest[0] = c1;
3328 dest[1] = c2;
3329 return result;
3330 }
3331}
3332
3333
lrn@chromium.org303ada72010-10-27 09:33:13 +00003334MaybeObject* Heap::AllocateConsString(String* first, String* second) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003335 int first_length = first->length();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003336 if (first_length == 0) {
3337 return second;
3338 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003339
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003340 int second_length = second->length();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003341 if (second_length == 0) {
3342 return first;
3343 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003344
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003345 int length = first_length + second_length;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003346
3347 // Optimization for 2-byte strings often used as keys in a decompression
3348 // dictionary. Check whether we already have the string in the symbol
3349 // table to prevent creation of many unneccesary strings.
3350 if (length == 2) {
3351 unsigned c1 = first->Get(0);
3352 unsigned c2 = second->Get(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003353 return MakeOrFindTwoCharacterString(this, c1, c2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003354 }
3355
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003356 bool first_is_ascii = first->IsOneByteRepresentation();
3357 bool second_is_ascii = second->IsOneByteRepresentation();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003358 bool is_ascii = first_is_ascii && second_is_ascii;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003359
ager@chromium.org3e875802009-06-29 08:26:34 +00003360 // Make sure that an out of memory exception is thrown if the length
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003361 // of the new cons string is too large.
3362 if (length > String::kMaxLength || length < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003363 isolate()->context()->mark_out_of_memory();
ager@chromium.org3e875802009-06-29 08:26:34 +00003364 return Failure::OutOfMemoryException();
3365 }
3366
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003367 bool is_ascii_data_in_two_byte_string = false;
3368 if (!is_ascii) {
3369 // At least one of the strings uses two-byte representation so we
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003370 // can't use the fast case code for short ASCII strings below, but
3371 // we can try to save memory if all chars actually fit in ASCII.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003372 is_ascii_data_in_two_byte_string =
3373 first->HasOnlyAsciiChars() && second->HasOnlyAsciiChars();
3374 if (is_ascii_data_in_two_byte_string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003375 isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003376 }
3377 }
3378
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003379 // If the resulting string is small make a flat string.
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003380 if (length < ConsString::kMinLength) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003381 // Note that neither of the two inputs can be a slice because:
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003382 STATIC_ASSERT(ConsString::kMinLength <= SlicedString::kMinLength);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003383 ASSERT(first->IsFlat());
3384 ASSERT(second->IsFlat());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003385 if (is_ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003386 Object* result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003387 { MaybeObject* maybe_result = AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003388 if (!maybe_result->ToObject(&result)) return maybe_result;
3389 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003390 // Copy the characters into the new object.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003391 char* dest = SeqOneByteString::cast(result)->GetChars();
ager@chromium.org3e875802009-06-29 08:26:34 +00003392 // Copy first part.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003393 const char* src;
3394 if (first->IsExternalString()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003395 src = ExternalAsciiString::cast(first)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003396 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003397 src = SeqOneByteString::cast(first)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003398 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003399 for (int i = 0; i < first_length; i++) *dest++ = src[i];
3400 // Copy second part.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003401 if (second->IsExternalString()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003402 src = ExternalAsciiString::cast(second)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003403 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003404 src = SeqOneByteString::cast(second)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003405 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003406 for (int i = 0; i < second_length; i++) *dest++ = src[i];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003407 return result;
3408 } else {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003409 if (is_ascii_data_in_two_byte_string) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003410 Object* result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003411 { MaybeObject* maybe_result = AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003412 if (!maybe_result->ToObject(&result)) return maybe_result;
3413 }
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003414 // Copy the characters into the new object.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003415 char* dest = SeqOneByteString::cast(result)->GetChars();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003416 String::WriteToFlat(first, dest, 0, first_length);
3417 String::WriteToFlat(second, dest + first_length, 0, second_length);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003418 isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003419 return result;
3420 }
3421
lrn@chromium.org303ada72010-10-27 09:33:13 +00003422 Object* result;
3423 { MaybeObject* maybe_result = AllocateRawTwoByteString(length);
3424 if (!maybe_result->ToObject(&result)) return maybe_result;
3425 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003426 // Copy the characters into the new object.
3427 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003428 String::WriteToFlat(first, dest, 0, first_length);
3429 String::WriteToFlat(second, dest + first_length, 0, second_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003430 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003431 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003432 }
3433
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003434 Map* map = (is_ascii || is_ascii_data_in_two_byte_string) ?
3435 cons_ascii_string_map() : cons_string_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003436
lrn@chromium.org303ada72010-10-27 09:33:13 +00003437 Object* result;
3438 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3439 if (!maybe_result->ToObject(&result)) return maybe_result;
3440 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003441
3442 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003443 ConsString* cons_string = ConsString::cast(result);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003444 WriteBarrierMode mode = cons_string->GetWriteBarrierMode(no_gc);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003445 cons_string->set_length(length);
3446 cons_string->set_hash_field(String::kEmptyHashField);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003447 cons_string->set_first(first, mode);
3448 cons_string->set_second(second, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003449 return result;
3450}
3451
3452
lrn@chromium.org303ada72010-10-27 09:33:13 +00003453MaybeObject* Heap::AllocateSubString(String* buffer,
ager@chromium.org04921a82011-06-27 13:21:41 +00003454 int start,
3455 int end,
3456 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003457 int length = end - start;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003458 if (length <= 0) {
ager@chromium.org04921a82011-06-27 13:21:41 +00003459 return empty_string();
3460 } else if (length == 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003461 return LookupSingleCharacterStringFromCode(buffer->Get(start));
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003462 } else if (length == 2) {
3463 // Optimization for 2-byte strings often used as keys in a decompression
3464 // dictionary. Check whether we already have the string in the symbol
3465 // table to prevent creation of many unneccesary strings.
3466 unsigned c1 = buffer->Get(start);
3467 unsigned c2 = buffer->Get(start + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003468 return MakeOrFindTwoCharacterString(this, c1, c2);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003469 }
3470
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003471 // Make an attempt to flatten the buffer to reduce access time.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003472 buffer = buffer->TryFlattenGetString();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003473
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003474 if (!FLAG_string_slices ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003475 !buffer->IsFlat() ||
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003476 length < SlicedString::kMinLength ||
3477 pretenure == TENURED) {
3478 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003479 // WriteToFlat takes care of the case when an indirect string has a
3480 // different encoding from its underlying string. These encodings may
3481 // differ because of externalization.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003482 bool is_ascii = buffer->IsOneByteRepresentation();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003483 { MaybeObject* maybe_result = is_ascii
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003484 ? AllocateRawOneByteString(length, pretenure)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003485 : AllocateRawTwoByteString(length, pretenure);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003486 if (!maybe_result->ToObject(&result)) return maybe_result;
3487 }
3488 String* string_result = String::cast(result);
3489 // Copy the characters into the new object.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003490 if (is_ascii) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003491 ASSERT(string_result->IsOneByteRepresentation());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003492 char* dest = SeqOneByteString::cast(string_result)->GetChars();
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003493 String::WriteToFlat(buffer, dest, start, end);
3494 } else {
3495 ASSERT(string_result->IsTwoByteRepresentation());
3496 uc16* dest = SeqTwoByteString::cast(string_result)->GetChars();
3497 String::WriteToFlat(buffer, dest, start, end);
3498 }
3499 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003500 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003501
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003502 ASSERT(buffer->IsFlat());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003503#if VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003504 if (FLAG_verify_heap) {
3505 buffer->StringVerify();
3506 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003507#endif
3508
3509 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003510 // When slicing an indirect string we use its encoding for a newly created
3511 // slice and don't check the encoding of the underlying string. This is safe
3512 // even if the encodings are different because of externalization. If an
3513 // indirect ASCII string is pointing to a two-byte string, the two-byte char
3514 // codes of the underlying string must still fit into ASCII (because
3515 // externalization must not change char codes).
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003516 { Map* map = buffer->IsOneByteRepresentation()
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003517 ? sliced_ascii_string_map()
3518 : sliced_string_map();
3519 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3520 if (!maybe_result->ToObject(&result)) return maybe_result;
3521 }
3522
3523 AssertNoAllocation no_gc;
3524 SlicedString* sliced_string = SlicedString::cast(result);
3525 sliced_string->set_length(length);
3526 sliced_string->set_hash_field(String::kEmptyHashField);
3527 if (buffer->IsConsString()) {
3528 ConsString* cons = ConsString::cast(buffer);
3529 ASSERT(cons->second()->length() == 0);
3530 sliced_string->set_parent(cons->first());
3531 sliced_string->set_offset(start);
3532 } else if (buffer->IsSlicedString()) {
3533 // Prevent nesting sliced strings.
3534 SlicedString* parent_slice = SlicedString::cast(buffer);
3535 sliced_string->set_parent(parent_slice->parent());
3536 sliced_string->set_offset(start + parent_slice->offset());
3537 } else {
3538 sliced_string->set_parent(buffer);
3539 sliced_string->set_offset(start);
3540 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003541 ASSERT(sliced_string->parent()->IsSeqString() ||
3542 sliced_string->parent()->IsExternalString());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003543 return result;
3544}
3545
3546
lrn@chromium.org303ada72010-10-27 09:33:13 +00003547MaybeObject* Heap::AllocateExternalStringFromAscii(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003548 const ExternalAsciiString::Resource* resource) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003549 size_t length = resource->length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003550 if (length > static_cast<size_t>(String::kMaxLength)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003551 isolate()->context()->mark_out_of_memory();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003552 return Failure::OutOfMemoryException();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003553 }
3554
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00003555 ASSERT(String::IsAscii(resource->data(), static_cast<int>(length)));
3556
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003557 Map* map = external_ascii_string_map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003558 Object* result;
3559 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3560 if (!maybe_result->ToObject(&result)) return maybe_result;
3561 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003562
3563 ExternalAsciiString* external_string = ExternalAsciiString::cast(result);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003564 external_string->set_length(static_cast<int>(length));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003565 external_string->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003566 external_string->set_resource(resource);
3567
3568 return result;
3569}
3570
3571
lrn@chromium.org303ada72010-10-27 09:33:13 +00003572MaybeObject* Heap::AllocateExternalStringFromTwoByte(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003573 const ExternalTwoByteString::Resource* resource) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003574 size_t length = resource->length();
3575 if (length > static_cast<size_t>(String::kMaxLength)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003576 isolate()->context()->mark_out_of_memory();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003577 return Failure::OutOfMemoryException();
3578 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003579
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003580 // For small strings we check whether the resource contains only
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003581 // ASCII characters. If yes, we use a different string map.
3582 static const size_t kAsciiCheckLengthLimit = 32;
3583 bool is_ascii = length <= kAsciiCheckLengthLimit &&
3584 String::IsAscii(resource->data(), static_cast<int>(length));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003585 Map* map = is_ascii ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003586 external_string_with_ascii_data_map() : external_string_map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003587 Object* result;
3588 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3589 if (!maybe_result->ToObject(&result)) return maybe_result;
3590 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003591
3592 ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003593 external_string->set_length(static_cast<int>(length));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003594 external_string->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595 external_string->set_resource(resource);
3596
3597 return result;
3598}
3599
3600
lrn@chromium.org303ada72010-10-27 09:33:13 +00003601MaybeObject* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003602 if (code <= String::kMaxAsciiCharCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003603 Object* value = single_character_string_cache()->get(code);
3604 if (value != undefined_value()) return value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003605
3606 char buffer[1];
3607 buffer[0] = static_cast<char>(code);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003608 Object* result;
3609 MaybeObject* maybe_result = LookupSymbol(Vector<const char>(buffer, 1));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003610
lrn@chromium.org303ada72010-10-27 09:33:13 +00003611 if (!maybe_result->ToObject(&result)) return maybe_result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003612 single_character_string_cache()->set(code, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003613 return result;
3614 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003615
lrn@chromium.org303ada72010-10-27 09:33:13 +00003616 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003617 { MaybeObject* maybe_result = AllocateRawTwoByteString(1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003618 if (!maybe_result->ToObject(&result)) return maybe_result;
3619 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00003620 String* answer = String::cast(result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003621 answer->Set(0, code);
ager@chromium.org870a0b62008-11-04 11:43:05 +00003622 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003623}
3624
3625
lrn@chromium.org303ada72010-10-27 09:33:13 +00003626MaybeObject* Heap::AllocateByteArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003627 if (length < 0 || length > ByteArray::kMaxLength) {
3628 return Failure::OutOfMemoryException();
3629 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003630 if (pretenure == NOT_TENURED) {
3631 return AllocateByteArray(length);
3632 }
3633 int size = ByteArray::SizeFor(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003634 Object* result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003635 { MaybeObject* maybe_result = (size <= Page::kMaxNonCodeHeapObjectSize)
lrn@chromium.org303ada72010-10-27 09:33:13 +00003636 ? old_data_space_->AllocateRaw(size)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003637 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003638 if (!maybe_result->ToObject(&result)) return maybe_result;
3639 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003640
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003641 reinterpret_cast<ByteArray*>(result)->set_map_no_write_barrier(
3642 byte_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003643 reinterpret_cast<ByteArray*>(result)->set_length(length);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003644 return result;
3645}
3646
3647
lrn@chromium.org303ada72010-10-27 09:33:13 +00003648MaybeObject* Heap::AllocateByteArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003649 if (length < 0 || length > ByteArray::kMaxLength) {
3650 return Failure::OutOfMemoryException();
3651 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003652 int size = ByteArray::SizeFor(length);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003653 AllocationSpace space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003654 (size > Page::kMaxNonCodeHeapObjectSize) ? LO_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003655 Object* result;
3656 { MaybeObject* maybe_result = AllocateRaw(size, space, OLD_DATA_SPACE);
3657 if (!maybe_result->ToObject(&result)) return maybe_result;
3658 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003659
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003660 reinterpret_cast<ByteArray*>(result)->set_map_no_write_barrier(
3661 byte_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003662 reinterpret_cast<ByteArray*>(result)->set_length(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003663 return result;
3664}
3665
3666
ager@chromium.org6f10e412009-02-13 10:11:16 +00003667void Heap::CreateFillerObjectAt(Address addr, int size) {
3668 if (size == 0) return;
3669 HeapObject* filler = HeapObject::FromAddress(addr);
3670 if (size == kPointerSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003671 filler->set_map_no_write_barrier(one_pointer_filler_map());
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00003672 } else if (size == 2 * kPointerSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003673 filler->set_map_no_write_barrier(two_pointer_filler_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +00003674 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003675 filler->set_map_no_write_barrier(free_space_map());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003676 FreeSpace::cast(filler)->set_size(size);
ager@chromium.org6f10e412009-02-13 10:11:16 +00003677 }
3678}
3679
3680
lrn@chromium.org303ada72010-10-27 09:33:13 +00003681MaybeObject* Heap::AllocateExternalArray(int length,
3682 ExternalArrayType array_type,
3683 void* external_pointer,
3684 PretenureFlag pretenure) {
ager@chromium.org3811b432009-10-28 14:53:37 +00003685 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003686 Object* result;
3687 { MaybeObject* maybe_result = AllocateRaw(ExternalArray::kAlignedSize,
3688 space,
3689 OLD_DATA_SPACE);
3690 if (!maybe_result->ToObject(&result)) return maybe_result;
3691 }
ager@chromium.org3811b432009-10-28 14:53:37 +00003692
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003693 reinterpret_cast<ExternalArray*>(result)->set_map_no_write_barrier(
ager@chromium.org3811b432009-10-28 14:53:37 +00003694 MapForExternalArrayType(array_type));
3695 reinterpret_cast<ExternalArray*>(result)->set_length(length);
3696 reinterpret_cast<ExternalArray*>(result)->set_external_pointer(
3697 external_pointer);
3698
3699 return result;
3700}
3701
3702
lrn@chromium.org303ada72010-10-27 09:33:13 +00003703MaybeObject* Heap::CreateCode(const CodeDesc& desc,
3704 Code::Flags flags,
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003705 Handle<Object> self_reference,
3706 bool immovable) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003707 // Allocate ByteArray before the Code object, so that we do not risk
3708 // leaving uninitialized Code object (and breaking the heap).
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003709 ByteArray* reloc_info;
3710 MaybeObject* maybe_reloc_info = AllocateByteArray(desc.reloc_size, TENURED);
3711 if (!maybe_reloc_info->To(&reloc_info)) return maybe_reloc_info;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003712
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003713 // Compute size.
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003714 int body_size = RoundUp(desc.instr_size, kObjectAlignment);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003715 int obj_size = Code::SizeFor(body_size);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003716 ASSERT(IsAligned(static_cast<intptr_t>(obj_size), kCodeAlignment));
lrn@chromium.org303ada72010-10-27 09:33:13 +00003717 MaybeObject* maybe_result;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003718 // Large code objects and code objects which should stay at a fixed address
3719 // are allocated in large object space.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003720 HeapObject* result;
3721 bool force_lo_space = obj_size > code_space()->AreaSize();
3722 if (force_lo_space) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003723 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003724 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003725 maybe_result = code_space_->AllocateRaw(obj_size);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003726 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003727 if (!maybe_result->To<HeapObject>(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003728
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003729 if (immovable && !force_lo_space &&
3730 // Objects on the first page of each space are never moved.
3731 !code_space_->FirstPage()->Contains(result->address())) {
3732 // Discard the first code allocation, which was on a page where it could be
3733 // moved.
3734 CreateFillerObjectAt(result->address(), obj_size);
3735 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
3736 if (!maybe_result->To<HeapObject>(&result)) return maybe_result;
3737 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003738
3739 // Initialize the object
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003740 result->set_map_no_write_barrier(code_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003741 Code* code = Code::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003742 ASSERT(!isolate_->code_range()->exists() ||
3743 isolate_->code_range()->contains(code->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003744 code->set_instruction_size(desc.instr_size);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003745 code->set_relocation_info(reloc_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003746 code->set_flags(flags);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003747 if (code->is_call_stub() || code->is_keyed_call_stub()) {
3748 code->set_check_type(RECEIVER_MAP_CHECK);
3749 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003750 code->set_deoptimization_data(empty_fixed_array(), SKIP_WRITE_BARRIER);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003751 code->InitializeTypeFeedbackInfoNoWriteBarrier(undefined_value());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003752 code->set_handler_table(empty_fixed_array(), SKIP_WRITE_BARRIER);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00003753 code->set_gc_metadata(Smi::FromInt(0));
danno@chromium.org88aa0582012-03-23 15:11:57 +00003754 code->set_ic_age(global_ic_age_);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003755 code->set_prologue_offset(kPrologueOffsetNotSet);
kasperl@chromium.org061ef742009-02-27 12:16:20 +00003756 // Allow self references to created code object by patching the handle to
3757 // point to the newly allocated Code object.
3758 if (!self_reference.is_null()) {
3759 *(self_reference.location()) = code;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003760 }
3761 // Migrate generated code.
3762 // The generated code can contain Object** values (typically from handles)
3763 // that are dereferenced during the copy to point directly to the actual heap
3764 // objects. These pointers can include references to the code object itself,
3765 // through the self_reference parameter.
3766 code->CopyFrom(desc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003768#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003769 if (FLAG_verify_heap) {
3770 code->Verify();
3771 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003772#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003773 return code;
3774}
3775
3776
lrn@chromium.org303ada72010-10-27 09:33:13 +00003777MaybeObject* Heap::CopyCode(Code* code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003778 // Allocate an object the same size as the code object.
3779 int obj_size = code->Size();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003780 MaybeObject* maybe_result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003781 if (obj_size > code_space()->AreaSize()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003782 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003783 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003784 maybe_result = code_space_->AllocateRaw(obj_size);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003785 }
3786
lrn@chromium.org303ada72010-10-27 09:33:13 +00003787 Object* result;
3788 if (!maybe_result->ToObject(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003789
3790 // Copy code object.
3791 Address old_addr = code->address();
3792 Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003793 CopyBlock(new_addr, old_addr, obj_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003794 // Relocate the copy.
3795 Code* new_code = Code::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003796 ASSERT(!isolate_->code_range()->exists() ||
3797 isolate_->code_range()->contains(code->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003798 new_code->Relocate(new_addr - old_addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003799 return new_code;
3800}
3801
3802
lrn@chromium.org303ada72010-10-27 09:33:13 +00003803MaybeObject* Heap::CopyCode(Code* code, Vector<byte> reloc_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003804 // Allocate ByteArray before the Code object, so that we do not risk
3805 // leaving uninitialized Code object (and breaking the heap).
lrn@chromium.org303ada72010-10-27 09:33:13 +00003806 Object* reloc_info_array;
3807 { MaybeObject* maybe_reloc_info_array =
3808 AllocateByteArray(reloc_info.length(), TENURED);
3809 if (!maybe_reloc_info_array->ToObject(&reloc_info_array)) {
3810 return maybe_reloc_info_array;
3811 }
3812 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003813
3814 int new_body_size = RoundUp(code->instruction_size(), kObjectAlignment);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003815
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003816 int new_obj_size = Code::SizeFor(new_body_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003817
3818 Address old_addr = code->address();
3819
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00003820 size_t relocation_offset =
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003821 static_cast<size_t>(code->instruction_end() - old_addr);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003822
lrn@chromium.org303ada72010-10-27 09:33:13 +00003823 MaybeObject* maybe_result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003824 if (new_obj_size > code_space()->AreaSize()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003825 maybe_result = lo_space_->AllocateRaw(new_obj_size, EXECUTABLE);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003826 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003827 maybe_result = code_space_->AllocateRaw(new_obj_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003828 }
3829
lrn@chromium.org303ada72010-10-27 09:33:13 +00003830 Object* result;
3831 if (!maybe_result->ToObject(&result)) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003832
3833 // Copy code object.
3834 Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
3835
3836 // Copy header and instructions.
3837 memcpy(new_addr, old_addr, relocation_offset);
3838
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003839 Code* new_code = Code::cast(result);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003840 new_code->set_relocation_info(ByteArray::cast(reloc_info_array));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003841
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003842 // Copy patched rinfo.
3843 memcpy(new_code->relocation_start(), reloc_info.start(), reloc_info.length());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003844
3845 // Relocate the copy.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003846 ASSERT(!isolate_->code_range()->exists() ||
3847 isolate_->code_range()->contains(code->address()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003848 new_code->Relocate(new_addr - old_addr);
3849
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003850#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003851 if (FLAG_verify_heap) {
3852 code->Verify();
3853 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003854#endif
3855 return new_code;
3856}
3857
3858
lrn@chromium.org303ada72010-10-27 09:33:13 +00003859MaybeObject* Heap::Allocate(Map* map, AllocationSpace space) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003860 ASSERT(gc_state_ == NOT_IN_GC);
3861 ASSERT(map->instance_type() != MAP_TYPE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003862 // If allocation failures are disallowed, we may allocate in a different
3863 // space when new space is full and the object is not a large object.
3864 AllocationSpace retry_space =
3865 (space != NEW_SPACE) ? space : TargetSpaceId(map->instance_type());
lrn@chromium.org303ada72010-10-27 09:33:13 +00003866 Object* result;
3867 { MaybeObject* maybe_result =
3868 AllocateRaw(map->instance_size(), space, retry_space);
3869 if (!maybe_result->ToObject(&result)) return maybe_result;
3870 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003871 // No need for write barrier since object is white and map is in old space.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003872 HeapObject::cast(result)->set_map_no_write_barrier(map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003873 return result;
3874}
3875
3876
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003877void Heap::InitializeFunction(JSFunction* function,
3878 SharedFunctionInfo* shared,
3879 Object* prototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003880 ASSERT(!prototype->IsMap());
3881 function->initialize_properties();
3882 function->initialize_elements();
3883 function->set_shared(shared);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00003884 function->set_code(shared->code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003885 function->set_prototype_or_initial_map(prototype);
3886 function->set_context(undefined_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003887 function->set_literals_or_bindings(empty_fixed_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003888 function->set_next_function_link(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003889}
3890
3891
lrn@chromium.org303ada72010-10-27 09:33:13 +00003892MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00003893 // Allocate the prototype. Make sure to use the object function
3894 // from the function's context, since the function can be from a
3895 // different context.
3896 JSFunction* object_function =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003897 function->context()->native_context()->object_function();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003898
3899 // Each function prototype gets a copy of the object function map.
3900 // This avoid unwanted sharing of maps between prototypes of different
3901 // constructors.
3902 Map* new_map;
3903 ASSERT(object_function->has_initial_map());
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003904 MaybeObject* maybe_map = object_function->initial_map()->Copy();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003905 if (!maybe_map->To(&new_map)) return maybe_map;
3906
lrn@chromium.org303ada72010-10-27 09:33:13 +00003907 Object* prototype;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003908 MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map);
3909 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
3910
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003911 // When creating the prototype for the function we must set its
3912 // constructor to the function.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003913 MaybeObject* maybe_failure =
3914 JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
3915 constructor_symbol(), function, DONT_ENUM);
3916 if (maybe_failure->IsFailure()) return maybe_failure;
3917
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003918 return prototype;
3919}
3920
3921
lrn@chromium.org303ada72010-10-27 09:33:13 +00003922MaybeObject* Heap::AllocateFunction(Map* function_map,
3923 SharedFunctionInfo* shared,
3924 Object* prototype,
3925 PretenureFlag pretenure) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003926 AllocationSpace space =
3927 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003928 Object* result;
3929 { MaybeObject* maybe_result = Allocate(function_map, space);
3930 if (!maybe_result->ToObject(&result)) return maybe_result;
3931 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003932 InitializeFunction(JSFunction::cast(result), shared, prototype);
3933 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003934}
3935
3936
lrn@chromium.org303ada72010-10-27 09:33:13 +00003937MaybeObject* Heap::AllocateArgumentsObject(Object* callee, int length) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003938 // To get fast allocation and map sharing for arguments objects we
3939 // allocate them based on an arguments boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003940
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003941 JSObject* boilerplate;
3942 int arguments_object_size;
3943 bool strict_mode_callee = callee->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003944 !JSFunction::cast(callee)->shared()->is_classic_mode();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003945 if (strict_mode_callee) {
3946 boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003947 isolate()->context()->native_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003948 strict_mode_arguments_boilerplate();
3949 arguments_object_size = kArgumentsObjectSizeStrict;
3950 } else {
3951 boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003952 isolate()->context()->native_context()->arguments_boilerplate();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003953 arguments_object_size = kArgumentsObjectSize;
3954 }
3955
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003956 // This calls Copy directly rather than using Heap::AllocateRaw so we
3957 // duplicate the check here.
3958 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
3959
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003960 // Check that the size of the boilerplate matches our
3961 // expectations. The ArgumentsAccessStub::GenerateNewObject relies
3962 // on the size being a known constant.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003963 ASSERT(arguments_object_size == boilerplate->map()->instance_size());
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003964
3965 // Do the allocation.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003966 Object* result;
3967 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003968 AllocateRaw(arguments_object_size, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003969 if (!maybe_result->ToObject(&result)) return maybe_result;
3970 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003971
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00003972 // Copy the content. The arguments boilerplate doesn't have any
3973 // fields that point to new space so it's safe to skip the write
3974 // barrier here.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003975 CopyBlock(HeapObject::cast(result)->address(),
3976 boilerplate->address(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003977 JSObject::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003979 // Set the length property.
3980 JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsLengthIndex,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003981 Smi::FromInt(length),
3982 SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003983 // Set the callee property for non-strict mode arguments object only.
3984 if (!strict_mode_callee) {
3985 JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsCalleeIndex,
3986 callee);
3987 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003988
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003989 // Check the state of the object
3990 ASSERT(JSObject::cast(result)->HasFastProperties());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003991 ASSERT(JSObject::cast(result)->HasFastObjectElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003992
3993 return result;
3994}
3995
3996
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00003997static bool HasDuplicates(DescriptorArray* descriptors) {
3998 int count = descriptors->number_of_descriptors();
3999 if (count > 1) {
4000 String* prev_key = descriptors->GetKey(0);
4001 for (int i = 1; i != count; i++) {
4002 String* current_key = descriptors->GetKey(i);
4003 if (prev_key == current_key) return true;
4004 prev_key = current_key;
4005 }
4006 }
4007 return false;
4008}
4009
4010
lrn@chromium.org303ada72010-10-27 09:33:13 +00004011MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004012 ASSERT(!fun->has_initial_map());
4013
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004014 // First create a new map with the size and number of in-object properties
4015 // suggested by the function.
4016 int instance_size = fun->shared()->CalculateInstanceSize();
4017 int in_object_properties = fun->shared()->CalculateInObjectProperties();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004018 Map* map;
4019 MaybeObject* maybe_map = AllocateMap(JS_OBJECT_TYPE, instance_size);
4020 if (!maybe_map->To(&map)) return maybe_map;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021
4022 // Fetch or allocate prototype.
4023 Object* prototype;
4024 if (fun->has_instance_prototype()) {
4025 prototype = fun->instance_prototype();
4026 } else {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004027 MaybeObject* maybe_prototype = AllocateFunctionPrototype(fun);
4028 if (!maybe_prototype->To(&prototype)) return maybe_prototype;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004030 map->set_inobject_properties(in_object_properties);
4031 map->set_unused_property_fields(in_object_properties);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 map->set_prototype(prototype);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004033 ASSERT(map->has_fast_object_elements());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004034
ager@chromium.org5c838252010-02-19 08:53:10 +00004035 // If the function has only simple this property assignments add
4036 // field descriptors for these to the initial map as the object
4037 // cannot be constructed without having these properties. Guard by
4038 // the inline_new flag so we only change the map if we generate a
4039 // specialized construct stub.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004040 ASSERT(in_object_properties <= Map::kMaxPreAllocatedPropertyFields);
ager@chromium.org5c838252010-02-19 08:53:10 +00004041 if (fun->shared()->CanGenerateInlineConstructor(prototype)) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004042 int count = fun->shared()->this_property_assignments_count();
4043 if (count > in_object_properties) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004044 // Inline constructor can only handle inobject properties.
4045 fun->shared()->ForbidInlineConstructor();
4046 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004047 DescriptorArray* descriptors;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00004048 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(count);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004049 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
4050
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004051 DescriptorArray::WhitenessWitness witness(descriptors);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004052 for (int i = 0; i < count; i++) {
4053 String* name = fun->shared()->GetThisPropertyAssignmentName(i);
4054 ASSERT(name->IsSymbol());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004055 FieldDescriptor field(name, i, NONE, i + 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004056 descriptors->Set(i, &field, witness);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004057 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004058 descriptors->Sort();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004059
4060 // The descriptors may contain duplicates because the compiler does not
4061 // guarantee the uniqueness of property names (it would have required
4062 // quadratic time). Once the descriptors are sorted we can check for
4063 // duplicates in linear time.
4064 if (HasDuplicates(descriptors)) {
4065 fun->shared()->ForbidInlineConstructor();
4066 } else {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004067 map->InitializeDescriptors(descriptors);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004068 map->set_pre_allocated_property_fields(count);
4069 map->set_unused_property_fields(in_object_properties - count);
4070 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004071 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004072 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004073
4074 fun->shared()->StartInobjectSlackTracking(map);
4075
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004076 return map;
4077}
4078
4079
4080void Heap::InitializeJSObjectFromMap(JSObject* obj,
4081 FixedArray* properties,
4082 Map* map) {
4083 obj->set_properties(properties);
4084 obj->initialize_elements();
4085 // TODO(1240798): Initialize the object's body using valid initial values
4086 // according to the object's initial map. For example, if the map's
4087 // instance type is JS_ARRAY_TYPE, the length field should be initialized
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004088 // to a number (e.g. Smi::FromInt(0)) and the elements initialized to a
4089 // fixed array (e.g. Heap::empty_fixed_array()). Currently, the object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004090 // verification code has to cope with (temporarily) invalid objects. See
4091 // for example, JSArray::JSArrayVerify).
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004092 Object* filler;
4093 // We cannot always fill with one_pointer_filler_map because objects
4094 // created from API functions expect their internal fields to be initialized
4095 // with undefined_value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004096 // Pre-allocated fields need to be initialized with undefined_value as well
4097 // so that object accesses before the constructor completes (e.g. in the
4098 // debugger) will not cause a crash.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004099 if (map->constructor()->IsJSFunction() &&
4100 JSFunction::cast(map->constructor())->shared()->
4101 IsInobjectSlackTrackingInProgress()) {
4102 // We might want to shrink the object later.
4103 ASSERT(obj->GetInternalFieldCount() == 0);
4104 filler = Heap::one_pointer_filler_map();
4105 } else {
4106 filler = Heap::undefined_value();
4107 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004108 obj->InitializeBody(map, Heap::undefined_value(), filler);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109}
4110
4111
lrn@chromium.org303ada72010-10-27 09:33:13 +00004112MaybeObject* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004113 // JSFunctions should be allocated using AllocateFunction to be
4114 // properly initialized.
4115 ASSERT(map->instance_type() != JS_FUNCTION_TYPE);
4116
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00004117 // Both types of global objects should be allocated using
4118 // AllocateGlobalObject to be properly initialized.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004119 ASSERT(map->instance_type() != JS_GLOBAL_OBJECT_TYPE);
4120 ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE);
4121
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004122 // Allocate the backing storage for the properties.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004123 int prop_size =
4124 map->pre_allocated_property_fields() +
4125 map->unused_property_fields() -
4126 map->inobject_properties();
4127 ASSERT(prop_size >= 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004128 Object* properties;
4129 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, pretenure);
4130 if (!maybe_properties->ToObject(&properties)) return maybe_properties;
4131 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004132
4133 // Allocate the JSObject.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004134 AllocationSpace space =
4135 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004136 if (map->instance_size() > Page::kMaxNonCodeHeapObjectSize) space = LO_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004137 Object* obj;
4138 { MaybeObject* maybe_obj = Allocate(map, space);
4139 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4140 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004141
4142 // Initialize the JSObject.
4143 InitializeJSObjectFromMap(JSObject::cast(obj),
4144 FixedArray::cast(properties),
4145 map);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004146 ASSERT(JSObject::cast(obj)->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004147 return obj;
4148}
4149
4150
lrn@chromium.org303ada72010-10-27 09:33:13 +00004151MaybeObject* Heap::AllocateJSObject(JSFunction* constructor,
4152 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004153 // Allocate the initial map if absent.
4154 if (!constructor->has_initial_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004155 Object* initial_map;
4156 { MaybeObject* maybe_initial_map = AllocateInitialMap(constructor);
4157 if (!maybe_initial_map->ToObject(&initial_map)) return maybe_initial_map;
4158 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004159 constructor->set_initial_map(Map::cast(initial_map));
4160 Map::cast(initial_map)->set_constructor(constructor);
4161 }
4162 // Allocate the object based on the constructors initial map.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004163 MaybeObject* result = AllocateJSObjectFromMap(
4164 constructor->initial_map(), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004165#ifdef DEBUG
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004166 // Make sure result is NOT a global object if valid.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004167 Object* non_failure;
4168 ASSERT(!result->ToObject(&non_failure) || !non_failure->IsGlobalObject());
4169#endif
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004170 return result;
4171}
4172
4173
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004174MaybeObject* Heap::AllocateJSModule(Context* context, ScopeInfo* scope_info) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004175 // Allocate a fresh map. Modules do not have a prototype.
4176 Map* map;
4177 MaybeObject* maybe_map = AllocateMap(JS_MODULE_TYPE, JSModule::kSize);
4178 if (!maybe_map->To(&map)) return maybe_map;
4179 // Allocate the object based on the map.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004180 JSModule* module;
4181 MaybeObject* maybe_module = AllocateJSObjectFromMap(map, TENURED);
4182 if (!maybe_module->To(&module)) return maybe_module;
4183 module->set_context(context);
4184 module->set_scope_info(scope_info);
4185 return module;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004186}
4187
4188
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004189MaybeObject* Heap::AllocateJSArrayAndStorage(
4190 ElementsKind elements_kind,
4191 int length,
4192 int capacity,
4193 ArrayStorageAllocationMode mode,
4194 PretenureFlag pretenure) {
4195 ASSERT(capacity >= length);
4196 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
4197 JSArray* array;
4198 if (!maybe_array->To(&array)) return maybe_array;
4199
4200 if (capacity == 0) {
4201 array->set_length(Smi::FromInt(0));
4202 array->set_elements(empty_fixed_array());
4203 return array;
4204 }
4205
4206 FixedArrayBase* elms;
4207 MaybeObject* maybe_elms = NULL;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004208 if (IsFastDoubleElementsKind(elements_kind)) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004209 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
4210 maybe_elms = AllocateUninitializedFixedDoubleArray(capacity);
4211 } else {
4212 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
4213 maybe_elms = AllocateFixedDoubleArrayWithHoles(capacity);
4214 }
4215 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004216 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004217 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
4218 maybe_elms = AllocateUninitializedFixedArray(capacity);
4219 } else {
4220 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
4221 maybe_elms = AllocateFixedArrayWithHoles(capacity);
4222 }
4223 }
4224 if (!maybe_elms->To(&elms)) return maybe_elms;
4225
4226 array->set_elements(elms);
4227 array->set_length(Smi::FromInt(length));
4228 return array;
4229}
4230
4231
4232MaybeObject* Heap::AllocateJSArrayWithElements(
4233 FixedArrayBase* elements,
4234 ElementsKind elements_kind,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004235 int length,
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004236 PretenureFlag pretenure) {
4237 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
4238 JSArray* array;
4239 if (!maybe_array->To(&array)) return maybe_array;
4240
4241 array->set_elements(elements);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004242 array->set_length(Smi::FromInt(length));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004243 array->ValidateElements();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004244 return array;
4245}
4246
4247
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004248MaybeObject* Heap::AllocateJSProxy(Object* handler, Object* prototype) {
4249 // Allocate map.
4250 // TODO(rossberg): Once we optimize proxies, think about a scheme to share
4251 // maps. Will probably depend on the identity of the handler object, too.
danno@chromium.org40cb8782011-05-25 07:58:50 +00004252 Map* map;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004253 MaybeObject* maybe_map_obj = AllocateMap(JS_PROXY_TYPE, JSProxy::kSize);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004254 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004255 map->set_prototype(prototype);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004256
4257 // Allocate the proxy object.
lrn@chromium.org34e60782011-09-15 07:25:40 +00004258 JSProxy* result;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004259 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004260 if (!maybe_result->To<JSProxy>(&result)) return maybe_result;
4261 result->InitializeBody(map->instance_size(), Smi::FromInt(0));
4262 result->set_handler(handler);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004263 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004264 return result;
4265}
4266
4267
4268MaybeObject* Heap::AllocateJSFunctionProxy(Object* handler,
4269 Object* call_trap,
4270 Object* construct_trap,
4271 Object* prototype) {
4272 // Allocate map.
4273 // TODO(rossberg): Once we optimize proxies, think about a scheme to share
4274 // maps. Will probably depend on the identity of the handler object, too.
4275 Map* map;
4276 MaybeObject* maybe_map_obj =
4277 AllocateMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize);
4278 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
4279 map->set_prototype(prototype);
4280
4281 // Allocate the proxy object.
4282 JSFunctionProxy* result;
4283 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
4284 if (!maybe_result->To<JSFunctionProxy>(&result)) return maybe_result;
4285 result->InitializeBody(map->instance_size(), Smi::FromInt(0));
4286 result->set_handler(handler);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004287 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004288 result->set_call_trap(call_trap);
4289 result->set_construct_trap(construct_trap);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004290 return result;
4291}
4292
4293
lrn@chromium.org303ada72010-10-27 09:33:13 +00004294MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004295 ASSERT(constructor->has_initial_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004296 Map* map = constructor->initial_map();
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004297 ASSERT(map->is_dictionary_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004298
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004299 // Make sure no field properties are described in the initial map.
4300 // This guarantees us that normalizing the properties does not
4301 // require us to change property values to JSGlobalPropertyCells.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004302 ASSERT(map->NextFreePropertyIndex() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004303
4304 // Make sure we don't have a ton of pre-allocated slots in the
4305 // global objects. They will be unused once we normalize the object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004306 ASSERT(map->unused_property_fields() == 0);
4307 ASSERT(map->inobject_properties() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004308
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004309 // Initial size of the backing store to avoid resize of the storage during
4310 // bootstrapping. The size differs between the JS global object ad the
4311 // builtins object.
4312 int initial_size = map->instance_type() == JS_GLOBAL_OBJECT_TYPE ? 64 : 512;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004313
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004314 // Allocate a dictionary object for backing storage.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004315 StringDictionary* dictionary;
4316 MaybeObject* maybe_dictionary =
4317 StringDictionary::Allocate(
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004318 map->NumberOfOwnDescriptors() * 2 + initial_size);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004319 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004320
4321 // The global object might be created from an object template with accessors.
4322 // Fill these accessors into the dictionary.
4323 DescriptorArray* descs = map->instance_descriptors();
4324 for (int i = 0; i < descs->number_of_descriptors(); i++) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004325 PropertyDetails details = descs->GetDetails(i);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004326 ASSERT(details.type() == CALLBACKS); // Only accessors are expected.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004327 PropertyDetails d = PropertyDetails(details.attributes(),
4328 CALLBACKS,
4329 details.descriptor_index());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004330 Object* value = descs->GetCallbacksObject(i);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004331 MaybeObject* maybe_value = AllocateJSGlobalPropertyCell(value);
4332 if (!maybe_value->ToObject(&value)) return maybe_value;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004333
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004334 MaybeObject* maybe_added = dictionary->Add(descs->GetKey(i), value, d);
4335 if (!maybe_added->To(&dictionary)) return maybe_added;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004336 }
4337
4338 // Allocate the global object and initialize it with the backing store.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004339 JSObject* global;
4340 MaybeObject* maybe_global = Allocate(map, OLD_POINTER_SPACE);
4341 if (!maybe_global->To(&global)) return maybe_global;
4342
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004343 InitializeJSObjectFromMap(global, dictionary, map);
4344
4345 // Create a new map for the global object.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004346 Map* new_map;
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004347 MaybeObject* maybe_map = map->CopyDropDescriptors();
4348 if (!maybe_map->To(&new_map)) return maybe_map;
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004349 new_map->set_dictionary_map(true);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004350
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004351 // Set up the global object as a normalized object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004352 global->set_map(new_map);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004353 global->set_properties(dictionary);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004354
4355 // Make sure result is a global object with properties in dictionary.
4356 ASSERT(global->IsGlobalObject());
4357 ASSERT(!global->HasFastProperties());
4358 return global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004359}
4360
4361
lrn@chromium.org303ada72010-10-27 09:33:13 +00004362MaybeObject* Heap::CopyJSObject(JSObject* source) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004363 // Never used to copy functions. If functions need to be copied we
4364 // have to be careful to clear the literals array.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004365 SLOW_ASSERT(!source->IsJSFunction());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004366
4367 // Make the clone.
4368 Map* map = source->map();
4369 int object_size = map->instance_size();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004370 Object* clone;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004371
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004372 WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER;
4373
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004374 // If we're forced to always allocate, we use the general allocation
4375 // functions which may leave us with an object in old space.
4376 if (always_allocate()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004377 { MaybeObject* maybe_clone =
4378 AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE);
4379 if (!maybe_clone->ToObject(&clone)) return maybe_clone;
4380 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004381 Address clone_address = HeapObject::cast(clone)->address();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004382 CopyBlock(clone_address,
4383 source->address(),
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004384 object_size);
4385 // Update write barrier for all fields that lie beyond the header.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004386 RecordWrites(clone_address,
4387 JSObject::kHeaderSize,
antonm@chromium.org8e5e3382010-03-24 09:56:30 +00004388 (object_size - JSObject::kHeaderSize) / kPointerSize);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004389 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004390 wb_mode = SKIP_WRITE_BARRIER;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004391 { MaybeObject* maybe_clone = new_space_.AllocateRaw(object_size);
4392 if (!maybe_clone->ToObject(&clone)) return maybe_clone;
4393 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004394 SLOW_ASSERT(InNewSpace(clone));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004395 // Since we know the clone is allocated in new space, we can copy
ager@chromium.org32912102009-01-16 10:38:43 +00004396 // the contents without worrying about updating the write barrier.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004397 CopyBlock(HeapObject::cast(clone)->address(),
4398 source->address(),
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004399 object_size);
4400 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004401
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004402 SLOW_ASSERT(
4403 JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004404 FixedArrayBase* elements = FixedArrayBase::cast(source->elements());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004405 FixedArray* properties = FixedArray::cast(source->properties());
4406 // Update elements if necessary.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00004407 if (elements->length() > 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004408 Object* elem;
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004409 { MaybeObject* maybe_elem;
4410 if (elements->map() == fixed_cow_array_map()) {
4411 maybe_elem = FixedArray::cast(elements);
4412 } else if (source->HasFastDoubleElements()) {
4413 maybe_elem = CopyFixedDoubleArray(FixedDoubleArray::cast(elements));
4414 } else {
4415 maybe_elem = CopyFixedArray(FixedArray::cast(elements));
4416 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004417 if (!maybe_elem->ToObject(&elem)) return maybe_elem;
4418 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004419 JSObject::cast(clone)->set_elements(FixedArrayBase::cast(elem), wb_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004420 }
4421 // Update properties if necessary.
4422 if (properties->length() > 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004423 Object* prop;
4424 { MaybeObject* maybe_prop = CopyFixedArray(properties);
4425 if (!maybe_prop->ToObject(&prop)) return maybe_prop;
4426 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004427 JSObject::cast(clone)->set_properties(FixedArray::cast(prop), wb_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004428 }
4429 // Return the new clone.
4430 return clone;
4431}
4432
4433
lrn@chromium.org34e60782011-09-15 07:25:40 +00004434MaybeObject* Heap::ReinitializeJSReceiver(
4435 JSReceiver* object, InstanceType type, int size) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004436 ASSERT(type >= FIRST_JS_OBJECT_TYPE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004437
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004438 // Allocate fresh map.
4439 // TODO(rossberg): Once we optimize proxies, cache these maps.
4440 Map* map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004441 MaybeObject* maybe = AllocateMap(type, size);
4442 if (!maybe->To<Map>(&map)) return maybe;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004443
lrn@chromium.org34e60782011-09-15 07:25:40 +00004444 // Check that the receiver has at least the size of the fresh object.
4445 int size_difference = object->map()->instance_size() - map->instance_size();
4446 ASSERT(size_difference >= 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004447
4448 map->set_prototype(object->map()->prototype());
4449
4450 // Allocate the backing storage for the properties.
4451 int prop_size = map->unused_property_fields() - map->inobject_properties();
4452 Object* properties;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004453 maybe = AllocateFixedArray(prop_size, TENURED);
4454 if (!maybe->ToObject(&properties)) return maybe;
4455
4456 // Functions require some allocation, which might fail here.
4457 SharedFunctionInfo* shared = NULL;
4458 if (type == JS_FUNCTION_TYPE) {
4459 String* name;
4460 maybe = LookupAsciiSymbol("<freezing call trap>");
4461 if (!maybe->To<String>(&name)) return maybe;
4462 maybe = AllocateSharedFunctionInfo(name);
4463 if (!maybe->To<SharedFunctionInfo>(&shared)) return maybe;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004464 }
4465
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004466 // Because of possible retries of this function after failure,
4467 // we must NOT fail after this point, where we have changed the type!
4468
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004469 // Reset the map for the object.
4470 object->set_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004471 JSObject* jsobj = JSObject::cast(object);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004472
4473 // Reinitialize the object from the constructor map.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004474 InitializeJSObjectFromMap(jsobj, FixedArray::cast(properties), map);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004475
4476 // Functions require some minimal initialization.
4477 if (type == JS_FUNCTION_TYPE) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004478 map->set_function_with_prototype(true);
4479 InitializeFunction(JSFunction::cast(object), shared, the_hole_value());
4480 JSFunction::cast(object)->set_context(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004481 isolate()->context()->native_context());
lrn@chromium.org34e60782011-09-15 07:25:40 +00004482 }
4483
4484 // Put in filler if the new object is smaller than the old.
4485 if (size_difference > 0) {
4486 CreateFillerObjectAt(
4487 object->address() + map->instance_size(), size_difference);
4488 }
4489
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004490 return object;
4491}
4492
4493
lrn@chromium.org303ada72010-10-27 09:33:13 +00004494MaybeObject* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor,
4495 JSGlobalProxy* object) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004496 ASSERT(constructor->has_initial_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004497 Map* map = constructor->initial_map();
4498
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004499 // Check that the already allocated object has the same size and type as
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004500 // objects allocated using the constructor.
4501 ASSERT(map->instance_size() == object->map()->instance_size());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004502 ASSERT(map->instance_type() == object->map()->instance_type());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004503
4504 // Allocate the backing storage for the properties.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004505 int prop_size = map->unused_property_fields() - map->inobject_properties();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004506 Object* properties;
4507 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, TENURED);
4508 if (!maybe_properties->ToObject(&properties)) return maybe_properties;
4509 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004510
4511 // Reset the map for the object.
4512 object->set_map(constructor->initial_map());
4513
4514 // Reinitialize the object from the constructor map.
4515 InitializeJSObjectFromMap(object, FixedArray::cast(properties), map);
4516 return object;
4517}
4518
4519
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004520MaybeObject* Heap::AllocateStringFromOneByte(Vector<const char> string,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004521 PretenureFlag pretenure) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004522 int length = string.length();
4523 if (length == 1) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004524 return Heap::LookupSingleCharacterStringFromCode(string[0]);
4525 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004526 Object* result;
4527 { MaybeObject* maybe_result =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004528 AllocateRawOneByteString(string.length(), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004529 if (!maybe_result->ToObject(&result)) return maybe_result;
4530 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004531
4532 // Copy the characters into the new object.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004533 CopyChars(SeqOneByteString::cast(result)->GetChars(), string.start(), length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004534 return result;
4535}
4536
4537
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004538MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector<const char> string,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004539 int non_ascii_start,
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004540 PretenureFlag pretenure) {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004541 // Continue counting the number of characters in the UTF-8 string, starting
4542 // from the first non-ascii character or word.
4543 int chars = non_ascii_start;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004544 Access<UnicodeCache::Utf8Decoder>
4545 decoder(isolate_->unicode_cache()->utf8_decoder());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004546 decoder->Reset(string.start() + non_ascii_start, string.length() - chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004547 while (decoder->has_more()) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004548 uint32_t r = decoder->GetNext();
4549 if (r <= unibrow::Utf16::kMaxNonSurrogateCharCode) {
4550 chars++;
4551 } else {
4552 chars += 2;
4553 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004554 }
4555
lrn@chromium.org303ada72010-10-27 09:33:13 +00004556 Object* result;
4557 { MaybeObject* maybe_result = AllocateRawTwoByteString(chars, pretenure);
4558 if (!maybe_result->ToObject(&result)) return maybe_result;
4559 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004560
4561 // Convert and copy the characters into the new object.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004562 SeqTwoByteString* twobyte = SeqTwoByteString::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004563 decoder->Reset(string.start(), string.length());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004564 int i = 0;
4565 while (i < chars) {
4566 uint32_t r = decoder->GetNext();
4567 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004568 twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::LeadSurrogate(r));
4569 twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::TrailSurrogate(r));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004570 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004571 twobyte->SeqTwoByteStringSet(i++, r);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004572 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004573 }
4574 return result;
4575}
4576
4577
lrn@chromium.org303ada72010-10-27 09:33:13 +00004578MaybeObject* Heap::AllocateStringFromTwoByte(Vector<const uc16> string,
4579 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004580 // Check if the string is an ASCII string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004581 Object* result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004582 int length = string.length();
4583 const uc16* start = string.start();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004584
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004585 if (String::IsAscii(start, length)) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004586 MaybeObject* maybe_result = AllocateRawOneByteString(length, pretenure);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004587 if (!maybe_result->ToObject(&result)) return maybe_result;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004588 CopyChars(SeqOneByteString::cast(result)->GetChars(), start, length);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004589 } else { // It's not an ASCII string.
4590 MaybeObject* maybe_result = AllocateRawTwoByteString(length, pretenure);
4591 if (!maybe_result->ToObject(&result)) return maybe_result;
4592 CopyChars(SeqTwoByteString::cast(result)->GetChars(), start, length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004593 }
4594 return result;
4595}
4596
4597
4598Map* Heap::SymbolMapForString(String* string) {
4599 // If the string is in new space it cannot be used as a symbol.
4600 if (InNewSpace(string)) return NULL;
4601
4602 // Find the corresponding symbol map for strings.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004603 switch (string->map()->instance_type()) {
4604 case STRING_TYPE: return symbol_map();
4605 case ASCII_STRING_TYPE: return ascii_symbol_map();
4606 case CONS_STRING_TYPE: return cons_symbol_map();
4607 case CONS_ASCII_STRING_TYPE: return cons_ascii_symbol_map();
4608 case EXTERNAL_STRING_TYPE: return external_symbol_map();
4609 case EXTERNAL_ASCII_STRING_TYPE: return external_ascii_symbol_map();
4610 case EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
4611 return external_symbol_with_ascii_data_map();
4612 case SHORT_EXTERNAL_STRING_TYPE: return short_external_symbol_map();
4613 case SHORT_EXTERNAL_ASCII_STRING_TYPE:
4614 return short_external_ascii_symbol_map();
4615 case SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
4616 return short_external_symbol_with_ascii_data_map();
4617 default: return NULL; // No match found.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004618 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004619}
4620
4621
lrn@chromium.org303ada72010-10-27 09:33:13 +00004622MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
4623 int chars,
4624 uint32_t hash_field) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004625 ASSERT(chars >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004626 // Ensure the chars matches the number of characters in the buffer.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004627 ASSERT(static_cast<unsigned>(chars) == buffer->Utf16Length());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004628 // Determine whether the string is ASCII.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004629 bool is_ascii = true;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004630 while (buffer->has_more()) {
4631 if (buffer->GetNext() > unibrow::Utf8::kMaxOneByteChar) {
4632 is_ascii = false;
4633 break;
4634 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004635 }
4636 buffer->Rewind();
4637
4638 // Compute map and object size.
4639 int size;
4640 Map* map;
4641
4642 if (is_ascii) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004643 if (chars > SeqOneByteString::kMaxLength) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004644 return Failure::OutOfMemoryException();
4645 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004646 map = ascii_symbol_map();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004647 size = SeqOneByteString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004648 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004649 if (chars > SeqTwoByteString::kMaxLength) {
4650 return Failure::OutOfMemoryException();
4651 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004652 map = symbol_map();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004653 size = SeqTwoByteString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004654 }
4655
4656 // Allocate string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004657 Object* result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004658 { MaybeObject* maybe_result = (size > Page::kMaxNonCodeHeapObjectSize)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004659 ? lo_space_->AllocateRaw(size, NOT_EXECUTABLE)
lrn@chromium.org303ada72010-10-27 09:33:13 +00004660 : old_data_space_->AllocateRaw(size);
4661 if (!maybe_result->ToObject(&result)) return maybe_result;
4662 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004663
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004664 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(map);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004665 // Set length and hash fields of the allocated string.
ager@chromium.org870a0b62008-11-04 11:43:05 +00004666 String* answer = String::cast(result);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004667 answer->set_length(chars);
4668 answer->set_hash_field(hash_field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004669
ager@chromium.org870a0b62008-11-04 11:43:05 +00004670 ASSERT_EQ(size, answer->Size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004671
4672 // Fill in the characters.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004673 int i = 0;
4674 while (i < chars) {
4675 uint32_t character = buffer->GetNext();
4676 if (character > unibrow::Utf16::kMaxNonSurrogateCharCode) {
4677 answer->Set(i++, unibrow::Utf16::LeadSurrogate(character));
4678 answer->Set(i++, unibrow::Utf16::TrailSurrogate(character));
4679 } else {
4680 answer->Set(i++, character);
4681 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004682 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00004683 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004684}
4685
4686
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004687MaybeObject* Heap::AllocateRawOneByteString(int length,
4688 PretenureFlag pretenure) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004689 if (length < 0 || length > SeqOneByteString::kMaxLength) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004690 return Failure::OutOfMemoryException();
4691 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004692
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004693 int size = SeqOneByteString::SizeFor(length);
4694 ASSERT(size <= SeqOneByteString::kMaxSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004695
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004696 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
4697 AllocationSpace retry_space = OLD_DATA_SPACE;
4698
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004699 if (space == NEW_SPACE) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004700 if (size > kMaxObjectSizeInNewSpace) {
4701 // Allocate in large object space, retry space will be ignored.
4702 space = LO_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004703 } else if (size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004704 // Allocate in new space, retry in large object space.
4705 retry_space = LO_SPACE;
4706 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004707 } else if (space == OLD_DATA_SPACE &&
4708 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004709 space = LO_SPACE;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004710 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004711 Object* result;
4712 { MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
4713 if (!maybe_result->ToObject(&result)) return maybe_result;
4714 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004715
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004716 // Partially initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004717 HeapObject::cast(result)->set_map_no_write_barrier(ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004718 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004719 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004720 ASSERT_EQ(size, HeapObject::cast(result)->Size());
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004721
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004722#ifdef VERIFY_HEAP
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004723 if (FLAG_verify_heap) {
4724 // Initialize string's content to ensure ASCII-ness (character range 0-127)
4725 // as required when verifying the heap.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004726 char* dest = SeqOneByteString::cast(result)->GetChars();
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004727 memset(dest, 0x0F, length * kCharSize);
4728 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004729#endif
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004730
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004731 return result;
4732}
4733
4734
lrn@chromium.org303ada72010-10-27 09:33:13 +00004735MaybeObject* Heap::AllocateRawTwoByteString(int length,
4736 PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004737 if (length < 0 || length > SeqTwoByteString::kMaxLength) {
4738 return Failure::OutOfMemoryException();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004739 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004740 int size = SeqTwoByteString::SizeFor(length);
4741 ASSERT(size <= SeqTwoByteString::kMaxSize);
4742 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
4743 AllocationSpace retry_space = OLD_DATA_SPACE;
4744
4745 if (space == NEW_SPACE) {
4746 if (size > kMaxObjectSizeInNewSpace) {
4747 // Allocate in large object space, retry space will be ignored.
4748 space = LO_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004749 } else if (size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004750 // Allocate in new space, retry in large object space.
4751 retry_space = LO_SPACE;
4752 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004753 } else if (space == OLD_DATA_SPACE &&
4754 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004755 space = LO_SPACE;
4756 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004757 Object* result;
4758 { MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
4759 if (!maybe_result->ToObject(&result)) return maybe_result;
4760 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004761
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004762 // Partially initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004763 HeapObject::cast(result)->set_map_no_write_barrier(string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004764 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004765 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004766 ASSERT_EQ(size, HeapObject::cast(result)->Size());
4767 return result;
4768}
4769
4770
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004771MaybeObject* Heap::AllocateJSArray(
4772 ElementsKind elements_kind,
4773 PretenureFlag pretenure) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004774 Context* native_context = isolate()->context()->native_context();
4775 JSFunction* array_function = native_context->array_function();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004776 Map* map = array_function->initial_map();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004777 Object* maybe_map_array = native_context->js_array_maps();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004778 if (!maybe_map_array->IsUndefined()) {
4779 Object* maybe_transitioned_map =
4780 FixedArray::cast(maybe_map_array)->get(elements_kind);
4781 if (!maybe_transitioned_map->IsUndefined()) {
4782 map = Map::cast(maybe_transitioned_map);
4783 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004784 }
4785
4786 return AllocateJSObjectFromMap(map, pretenure);
4787}
4788
4789
lrn@chromium.org303ada72010-10-27 09:33:13 +00004790MaybeObject* Heap::AllocateEmptyFixedArray() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004791 int size = FixedArray::SizeFor(0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004792 Object* result;
4793 { MaybeObject* maybe_result =
4794 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
4795 if (!maybe_result->ToObject(&result)) return maybe_result;
4796 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004797 // Initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004798 reinterpret_cast<FixedArray*>(result)->set_map_no_write_barrier(
4799 fixed_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004800 reinterpret_cast<FixedArray*>(result)->set_length(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004801 return result;
4802}
4803
4804
lrn@chromium.org303ada72010-10-27 09:33:13 +00004805MaybeObject* Heap::AllocateRawFixedArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004806 if (length < 0 || length > FixedArray::kMaxLength) {
4807 return Failure::OutOfMemoryException();
4808 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004809 ASSERT(length > 0);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004810 // Use the general function if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004811 if (always_allocate()) return AllocateFixedArray(length, TENURED);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004812 // Allocate the raw data for a fixed array.
4813 int size = FixedArray::SizeFor(length);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004814 return size <= kMaxObjectSizeInNewSpace
4815 ? new_space_.AllocateRaw(size)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004816 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004817}
4818
4819
lrn@chromium.org303ada72010-10-27 09:33:13 +00004820MaybeObject* Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004821 int len = src->length();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004822 Object* obj;
4823 { MaybeObject* maybe_obj = AllocateRawFixedArray(len);
4824 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4825 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004826 if (InNewSpace(obj)) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004827 HeapObject* dst = HeapObject::cast(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004828 dst->set_map_no_write_barrier(map);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004829 CopyBlock(dst->address() + kPointerSize,
4830 src->address() + kPointerSize,
4831 FixedArray::SizeFor(len) - kPointerSize);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004832 return obj;
4833 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004834 HeapObject::cast(obj)->set_map_no_write_barrier(map);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004835 FixedArray* result = FixedArray::cast(obj);
4836 result->set_length(len);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004837
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004838 // Copy the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004839 AssertNoAllocation no_gc;
4840 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004841 for (int i = 0; i < len; i++) result->set(i, src->get(i), mode);
4842 return result;
4843}
4844
4845
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004846MaybeObject* Heap::CopyFixedDoubleArrayWithMap(FixedDoubleArray* src,
4847 Map* map) {
4848 int len = src->length();
4849 Object* obj;
4850 { MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(len, NOT_TENURED);
4851 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4852 }
4853 HeapObject* dst = HeapObject::cast(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004854 dst->set_map_no_write_barrier(map);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004855 CopyBlock(
4856 dst->address() + FixedDoubleArray::kLengthOffset,
4857 src->address() + FixedDoubleArray::kLengthOffset,
4858 FixedDoubleArray::SizeFor(len) - FixedDoubleArray::kLengthOffset);
4859 return obj;
4860}
4861
4862
lrn@chromium.org303ada72010-10-27 09:33:13 +00004863MaybeObject* Heap::AllocateFixedArray(int length) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004864 ASSERT(length >= 0);
ager@chromium.org32912102009-01-16 10:38:43 +00004865 if (length == 0) return empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004866 Object* result;
4867 { MaybeObject* maybe_result = AllocateRawFixedArray(length);
4868 if (!maybe_result->ToObject(&result)) return maybe_result;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004869 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004870 // Initialize header.
4871 FixedArray* array = reinterpret_cast<FixedArray*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004872 array->set_map_no_write_barrier(fixed_array_map());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004873 array->set_length(length);
4874 // Initialize body.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004875 ASSERT(!InNewSpace(undefined_value()));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004876 MemsetPointer(array->data_start(), undefined_value(), length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004877 return result;
4878}
4879
4880
lrn@chromium.org303ada72010-10-27 09:33:13 +00004881MaybeObject* Heap::AllocateRawFixedArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004882 if (length < 0 || length > FixedArray::kMaxLength) {
4883 return Failure::OutOfMemoryException();
4884 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004885
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004886 AllocationSpace space =
4887 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004888 int size = FixedArray::SizeFor(length);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004889 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
4890 // Too big for new space.
4891 space = LO_SPACE;
4892 } else if (space == OLD_POINTER_SPACE &&
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004893 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004894 // Too big for old pointer space.
4895 space = LO_SPACE;
4896 }
4897
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004898 AllocationSpace retry_space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004899 (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_POINTER_SPACE : LO_SPACE;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004900
4901 return AllocateRaw(size, space, retry_space);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004902}
4903
4904
lrn@chromium.org303ada72010-10-27 09:33:13 +00004905MUST_USE_RESULT static MaybeObject* AllocateFixedArrayWithFiller(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004906 Heap* heap,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004907 int length,
4908 PretenureFlag pretenure,
4909 Object* filler) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004910 ASSERT(length >= 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004911 ASSERT(heap->empty_fixed_array()->IsFixedArray());
4912 if (length == 0) return heap->empty_fixed_array();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004913
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004914 ASSERT(!heap->InNewSpace(filler));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004915 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004916 { MaybeObject* maybe_result = heap->AllocateRawFixedArray(length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004917 if (!maybe_result->ToObject(&result)) return maybe_result;
4918 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004919
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004920 HeapObject::cast(result)->set_map_no_write_barrier(heap->fixed_array_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004921 FixedArray* array = FixedArray::cast(result);
4922 array->set_length(length);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004923 MemsetPointer(array->data_start(), filler, length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004924 return array;
4925}
4926
4927
lrn@chromium.org303ada72010-10-27 09:33:13 +00004928MaybeObject* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004929 return AllocateFixedArrayWithFiller(this,
4930 length,
4931 pretenure,
4932 undefined_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004933}
4934
4935
lrn@chromium.org303ada72010-10-27 09:33:13 +00004936MaybeObject* Heap::AllocateFixedArrayWithHoles(int length,
4937 PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004938 return AllocateFixedArrayWithFiller(this,
4939 length,
4940 pretenure,
4941 the_hole_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004942}
4943
4944
lrn@chromium.org303ada72010-10-27 09:33:13 +00004945MaybeObject* Heap::AllocateUninitializedFixedArray(int length) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004946 if (length == 0) return empty_fixed_array();
4947
lrn@chromium.org303ada72010-10-27 09:33:13 +00004948 Object* obj;
4949 { MaybeObject* maybe_obj = AllocateRawFixedArray(length);
4950 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4951 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004952
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004953 reinterpret_cast<FixedArray*>(obj)->set_map_no_write_barrier(
4954 fixed_array_map());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004955 FixedArray::cast(obj)->set_length(length);
4956 return obj;
4957}
4958
4959
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004960MaybeObject* Heap::AllocateEmptyFixedDoubleArray() {
4961 int size = FixedDoubleArray::SizeFor(0);
4962 Object* result;
4963 { MaybeObject* maybe_result =
4964 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
4965 if (!maybe_result->ToObject(&result)) return maybe_result;
4966 }
4967 // Initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004968 reinterpret_cast<FixedDoubleArray*>(result)->set_map_no_write_barrier(
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004969 fixed_double_array_map());
4970 reinterpret_cast<FixedDoubleArray*>(result)->set_length(0);
4971 return result;
4972}
4973
4974
4975MaybeObject* Heap::AllocateUninitializedFixedDoubleArray(
4976 int length,
4977 PretenureFlag pretenure) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004978 if (length == 0) return empty_fixed_array();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004979
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004980 Object* elements_object;
4981 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
4982 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj;
4983 FixedDoubleArray* elements =
4984 reinterpret_cast<FixedDoubleArray*>(elements_object);
4985
4986 elements->set_map_no_write_barrier(fixed_double_array_map());
4987 elements->set_length(length);
4988 return elements;
4989}
4990
4991
4992MaybeObject* Heap::AllocateFixedDoubleArrayWithHoles(
4993 int length,
4994 PretenureFlag pretenure) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004995 if (length == 0) return empty_fixed_array();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004996
4997 Object* elements_object;
4998 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
4999 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj;
5000 FixedDoubleArray* elements =
5001 reinterpret_cast<FixedDoubleArray*>(elements_object);
5002
5003 for (int i = 0; i < length; ++i) {
5004 elements->set_the_hole(i);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005005 }
5006
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005007 elements->set_map_no_write_barrier(fixed_double_array_map());
5008 elements->set_length(length);
5009 return elements;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005010}
5011
5012
5013MaybeObject* Heap::AllocateRawFixedDoubleArray(int length,
5014 PretenureFlag pretenure) {
5015 if (length < 0 || length > FixedDoubleArray::kMaxLength) {
5016 return Failure::OutOfMemoryException();
5017 }
5018
5019 AllocationSpace space =
5020 (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
5021 int size = FixedDoubleArray::SizeFor(length);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005022
5023#ifndef V8_HOST_ARCH_64_BIT
5024 size += kPointerSize;
5025#endif
5026
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005027 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
5028 // Too big for new space.
5029 space = LO_SPACE;
5030 } else if (space == OLD_DATA_SPACE &&
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005031 size > Page::kMaxNonCodeHeapObjectSize) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005032 // Too big for old data space.
5033 space = LO_SPACE;
5034 }
5035
5036 AllocationSpace retry_space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005037 (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_DATA_SPACE : LO_SPACE;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005038
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005039 HeapObject* object;
5040 { MaybeObject* maybe_object = AllocateRaw(size, space, retry_space);
5041 if (!maybe_object->To<HeapObject>(&object)) return maybe_object;
5042 }
5043
5044 return EnsureDoubleAligned(this, object, size);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005045}
5046
5047
lrn@chromium.org303ada72010-10-27 09:33:13 +00005048MaybeObject* Heap::AllocateHashTable(int length, PretenureFlag pretenure) {
5049 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005050 { MaybeObject* maybe_result = AllocateFixedArray(length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005051 if (!maybe_result->ToObject(&result)) return maybe_result;
5052 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005053 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(
5054 hash_table_map());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005055 ASSERT(result->IsHashTable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005056 return result;
5057}
5058
5059
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005060MaybeObject* Heap::AllocateNativeContext() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005061 Object* result;
5062 { MaybeObject* maybe_result =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005063 AllocateFixedArray(Context::NATIVE_CONTEXT_SLOTS);
5064 if (!maybe_result->ToObject(&result)) return maybe_result;
5065 }
5066 Context* context = reinterpret_cast<Context*>(result);
5067 context->set_map_no_write_barrier(native_context_map());
5068 context->set_js_array_maps(undefined_value());
5069 ASSERT(context->IsNativeContext());
5070 ASSERT(result->IsContext());
5071 return result;
5072}
5073
5074
5075MaybeObject* Heap::AllocateGlobalContext(JSFunction* function,
5076 ScopeInfo* scope_info) {
5077 Object* result;
5078 { MaybeObject* maybe_result =
5079 AllocateFixedArray(scope_info->ContextLength(), TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005080 if (!maybe_result->ToObject(&result)) return maybe_result;
5081 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005082 Context* context = reinterpret_cast<Context*>(result);
danno@chromium.orgeb831462012-08-24 11:57:08 +00005083 context->set_map_no_write_barrier(global_context_map());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005084 context->set_closure(function);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005085 context->set_previous(function->context());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005086 context->set_extension(scope_info);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005087 context->set_global_object(function->context()->global_object());
danno@chromium.orgeb831462012-08-24 11:57:08 +00005088 ASSERT(context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005089 ASSERT(result->IsContext());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005090 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005091}
5092
5093
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005094MaybeObject* Heap::AllocateModuleContext(ScopeInfo* scope_info) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005095 Object* result;
5096 { MaybeObject* maybe_result =
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005097 AllocateFixedArray(scope_info->ContextLength(), TENURED);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005098 if (!maybe_result->ToObject(&result)) return maybe_result;
5099 }
5100 Context* context = reinterpret_cast<Context*>(result);
5101 context->set_map_no_write_barrier(module_context_map());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005102 // Instance link will be set later.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005103 context->set_extension(Smi::FromInt(0));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005104 return context;
5105}
5106
5107
lrn@chromium.org303ada72010-10-27 09:33:13 +00005108MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005109 ASSERT(length >= Context::MIN_CONTEXT_SLOTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005110 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005111 { MaybeObject* maybe_result = AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005112 if (!maybe_result->ToObject(&result)) return maybe_result;
5113 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005114 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005115 context->set_map_no_write_barrier(function_context_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005116 context->set_closure(function);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005117 context->set_previous(function->context());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005118 context->set_extension(Smi::FromInt(0));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005119 context->set_global_object(function->context()->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005120 return context;
5121}
5122
5123
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005124MaybeObject* Heap::AllocateCatchContext(JSFunction* function,
5125 Context* previous,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005126 String* name,
5127 Object* thrown_object) {
5128 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == Context::THROWN_OBJECT_INDEX);
5129 Object* result;
5130 { MaybeObject* maybe_result =
5131 AllocateFixedArray(Context::MIN_CONTEXT_SLOTS + 1);
5132 if (!maybe_result->ToObject(&result)) return maybe_result;
5133 }
5134 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005135 context->set_map_no_write_barrier(catch_context_map());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005136 context->set_closure(function);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005137 context->set_previous(previous);
5138 context->set_extension(name);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005139 context->set_global_object(previous->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005140 context->set(Context::THROWN_OBJECT_INDEX, thrown_object);
5141 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005142}
5143
5144
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005145MaybeObject* Heap::AllocateWithContext(JSFunction* function,
5146 Context* previous,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005147 JSObject* extension) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005148 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005149 { MaybeObject* maybe_result = AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005150 if (!maybe_result->ToObject(&result)) return maybe_result;
5151 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005152 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005153 context->set_map_no_write_barrier(with_context_map());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005154 context->set_closure(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005155 context->set_previous(previous);
5156 context->set_extension(extension);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005157 context->set_global_object(previous->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005158 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005159}
5160
5161
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005162MaybeObject* Heap::AllocateBlockContext(JSFunction* function,
5163 Context* previous,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005164 ScopeInfo* scope_info) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005165 Object* result;
5166 { MaybeObject* maybe_result =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005167 AllocateFixedArrayWithHoles(scope_info->ContextLength());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005168 if (!maybe_result->ToObject(&result)) return maybe_result;
5169 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005170 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005171 context->set_map_no_write_barrier(block_context_map());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005172 context->set_closure(function);
5173 context->set_previous(previous);
5174 context->set_extension(scope_info);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005175 context->set_global_object(previous->global_object());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005176 return context;
5177}
5178
5179
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005180MaybeObject* Heap::AllocateScopeInfo(int length) {
5181 FixedArray* scope_info;
5182 MaybeObject* maybe_scope_info = AllocateFixedArray(length, TENURED);
5183 if (!maybe_scope_info->To(&scope_info)) return maybe_scope_info;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005184 scope_info->set_map_no_write_barrier(scope_info_map());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005185 return scope_info;
5186}
5187
5188
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00005189MaybeObject* Heap::AllocateExternal(void* value) {
5190 Foreign* foreign;
5191 { MaybeObject* maybe_result = AllocateForeign(static_cast<Address>(value));
5192 if (!maybe_result->To(&foreign)) return maybe_result;
5193 }
5194 JSObject* external;
5195 { MaybeObject* maybe_result = AllocateJSObjectFromMap(external_map());
5196 if (!maybe_result->To(&external)) return maybe_result;
5197 }
5198 external->SetInternalField(0, foreign);
5199 return external;
5200}
5201
5202
lrn@chromium.org303ada72010-10-27 09:33:13 +00005203MaybeObject* Heap::AllocateStruct(InstanceType type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005204 Map* map;
5205 switch (type) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005206#define MAKE_CASE(NAME, Name, name) \
5207 case NAME##_TYPE: map = name##_map(); break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005208STRUCT_LIST(MAKE_CASE)
5209#undef MAKE_CASE
5210 default:
5211 UNREACHABLE();
5212 return Failure::InternalError();
5213 }
5214 int size = map->instance_size();
5215 AllocationSpace space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005216 (size > Page::kMaxNonCodeHeapObjectSize) ? LO_SPACE : OLD_POINTER_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005217 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005218 { MaybeObject* maybe_result = Allocate(map, space);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005219 if (!maybe_result->ToObject(&result)) return maybe_result;
5220 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005221 Struct::cast(result)->InitializeBody(size);
5222 return result;
5223}
5224
5225
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005226bool Heap::IsHeapIterable() {
5227 return (!old_pointer_space()->was_swept_conservatively() &&
5228 !old_data_space()->was_swept_conservatively());
5229}
5230
5231
5232void Heap::EnsureHeapIsIterable() {
5233 ASSERT(IsAllocationAllowed());
5234 if (!IsHeapIterable()) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005235 CollectAllGarbage(kMakeHeapIterableMask, "Heap::EnsureHeapIsIterable");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005236 }
5237 ASSERT(IsHeapIterable());
5238}
5239
5240
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005241void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005242 incremental_marking()->Step(step_size,
5243 IncrementalMarking::NO_GC_VIA_STACK_GUARD);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005244
5245 if (incremental_marking()->IsComplete()) {
5246 bool uncommit = false;
5247 if (gc_count_at_last_idle_gc_ == gc_count_) {
5248 // No GC since the last full GC, the mutator is probably not active.
5249 isolate_->compilation_cache()->Clear();
5250 uncommit = true;
5251 }
5252 CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental");
5253 gc_count_at_last_idle_gc_ = gc_count_;
5254 if (uncommit) {
5255 new_space_.Shrink();
5256 UncommitFromSpace();
5257 }
5258 }
5259}
5260
5261
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005262bool Heap::IdleNotification(int hint) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005263 // Hints greater than this value indicate that
5264 // the embedder is requesting a lot of GC work.
danno@chromium.org88aa0582012-03-23 15:11:57 +00005265 const int kMaxHint = 1000;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005266 // Minimal hint that allows to do full GC.
5267 const int kMinHintForFullGC = 100;
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005268 intptr_t size_factor = Min(Max(hint, 20), kMaxHint) / 4;
5269 // The size factor is in range [5..250]. The numbers here are chosen from
5270 // experiments. If you changes them, make sure to test with
5271 // chrome/performance_ui_tests --gtest_filter="GeneralMixMemoryTest.*
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00005272 intptr_t step_size =
5273 size_factor * IncrementalMarking::kAllocatedThreshold;
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005274
5275 if (contexts_disposed_ > 0) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005276 if (hint >= kMaxHint) {
5277 // The embedder is requesting a lot of GC work after context disposal,
5278 // we age inline caches so that they don't keep objects from
5279 // the old context alive.
5280 AgeInlineCaches();
5281 }
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005282 int mark_sweep_time = Min(TimeMarkSweepWouldTakeInMs(), 1000);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005283 if (hint >= mark_sweep_time && !FLAG_expose_gc &&
5284 incremental_marking()->IsStopped()) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005285 HistogramTimerScope scope(isolate_->counters()->gc_context());
5286 CollectAllGarbage(kReduceMemoryFootprintMask,
5287 "idle notification: contexts disposed");
5288 } else {
5289 AdvanceIdleIncrementalMarking(step_size);
5290 contexts_disposed_ = 0;
5291 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005292 // After context disposal there is likely a lot of garbage remaining, reset
5293 // the idle notification counters in order to trigger more incremental GCs
5294 // on subsequent idle notifications.
5295 StartIdleRound();
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005296 return false;
5297 }
5298
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005299 if (!FLAG_incremental_marking || FLAG_expose_gc || Serializer::enabled()) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005300 return IdleGlobalGC();
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005301 }
5302
5303 // By doing small chunks of GC work in each IdleNotification,
5304 // perform a round of incremental GCs and after that wait until
5305 // the mutator creates enough garbage to justify a new round.
5306 // An incremental GC progresses as follows:
5307 // 1. many incremental marking steps,
5308 // 2. one old space mark-sweep-compact,
5309 // 3. many lazy sweep steps.
5310 // Use mark-sweep-compact events to count incremental GCs in a round.
5311
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005312
5313 if (incremental_marking()->IsStopped()) {
5314 if (!IsSweepingComplete() &&
5315 !AdvanceSweepers(static_cast<int>(step_size))) {
5316 return false;
5317 }
5318 }
5319
5320 if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) {
5321 if (EnoughGarbageSinceLastIdleRound()) {
5322 StartIdleRound();
5323 } else {
5324 return true;
5325 }
5326 }
5327
5328 int new_mark_sweeps = ms_count_ - ms_count_at_last_idle_notification_;
5329 mark_sweeps_since_idle_round_started_ += new_mark_sweeps;
5330 ms_count_at_last_idle_notification_ = ms_count_;
5331
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005332 int remaining_mark_sweeps = kMaxMarkSweepsInIdleRound -
5333 mark_sweeps_since_idle_round_started_;
5334
5335 if (remaining_mark_sweeps <= 0) {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005336 FinishIdleRound();
5337 return true;
5338 }
5339
5340 if (incremental_marking()->IsStopped()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005341 // If there are no more than two GCs left in this idle round and we are
5342 // allowed to do a full GC, then make those GCs full in order to compact
5343 // the code space.
5344 // TODO(ulan): Once we enable code compaction for incremental marking,
5345 // we can get rid of this special case and always start incremental marking.
5346 if (remaining_mark_sweeps <= 2 && hint >= kMinHintForFullGC) {
5347 CollectAllGarbage(kReduceMemoryFootprintMask,
5348 "idle notification: finalize idle round");
5349 } else {
5350 incremental_marking()->Start();
5351 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005352 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005353 if (!incremental_marking()->IsStopped()) {
5354 AdvanceIdleIncrementalMarking(step_size);
5355 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005356 return false;
5357}
5358
5359
5360bool Heap::IdleGlobalGC() {
ager@chromium.orga1645e22009-09-09 19:27:10 +00005361 static const int kIdlesBeforeScavenge = 4;
5362 static const int kIdlesBeforeMarkSweep = 7;
5363 static const int kIdlesBeforeMarkCompact = 8;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005364 static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005365 static const unsigned int kGCsBetweenCleanup = 4;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005366
5367 if (!last_idle_notification_gc_count_init_) {
5368 last_idle_notification_gc_count_ = gc_count_;
5369 last_idle_notification_gc_count_init_ = true;
5370 }
ager@chromium.org96c75b52009-08-26 09:13:16 +00005371
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005372 bool uncommit = true;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005373 bool finished = false;
5374
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005375 // Reset the number of idle notifications received when a number of
5376 // GCs have taken place. This allows another round of cleanup based
5377 // on idle notifications if enough work has been carried out to
5378 // provoke a number of garbage collections.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005379 if (gc_count_ - last_idle_notification_gc_count_ < kGCsBetweenCleanup) {
5380 number_idle_notifications_ =
5381 Min(number_idle_notifications_ + 1, kMaxIdleCount);
ager@chromium.org96c75b52009-08-26 09:13:16 +00005382 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005383 number_idle_notifications_ = 0;
5384 last_idle_notification_gc_count_ = gc_count_;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005385 }
5386
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005387 if (number_idle_notifications_ == kIdlesBeforeScavenge) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005388 CollectGarbage(NEW_SPACE, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005389 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005390 last_idle_notification_gc_count_ = gc_count_;
5391 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005392 // Before doing the mark-sweep collections we clear the
5393 // compilation cache to avoid hanging on to source code and
5394 // generated code for cached functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005395 isolate_->compilation_cache()->Clear();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005396
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005397 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005398 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005399 last_idle_notification_gc_count_ = gc_count_;
ager@chromium.orga1645e22009-09-09 19:27:10 +00005400
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005401 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005402 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005403 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005404 last_idle_notification_gc_count_ = gc_count_;
5405 number_idle_notifications_ = 0;
ager@chromium.orga1645e22009-09-09 19:27:10 +00005406 finished = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005407 } else if (number_idle_notifications_ > kIdlesBeforeMarkCompact) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005408 // If we have received more than kIdlesBeforeMarkCompact idle
5409 // notifications we do not perform any cleanup because we don't
5410 // expect to gain much by doing so.
5411 finished = true;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005412 }
5413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005414 if (uncommit) UncommitFromSpace();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005415
ager@chromium.org96c75b52009-08-26 09:13:16 +00005416 return finished;
5417}
5418
5419
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005420#ifdef DEBUG
5421
5422void Heap::Print() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005423 if (!HasBeenSetUp()) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005424 isolate()->PrintStack();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005425 AllSpaces spaces;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005426 for (Space* space = spaces.next(); space != NULL; space = spaces.next())
5427 space->Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005428}
5429
5430
5431void Heap::ReportCodeStatistics(const char* title) {
5432 PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title);
5433 PagedSpace::ResetCodeStatistics();
5434 // We do not look for code in new space, map space, or old space. If code
5435 // somehow ends up in those spaces, we would miss it here.
5436 code_space_->CollectCodeStatistics();
5437 lo_space_->CollectCodeStatistics();
5438 PagedSpace::ReportCodeStatistics();
5439}
5440
5441
5442// This function expects that NewSpace's allocated objects histogram is
5443// populated (via a call to CollectStatistics or else as a side effect of a
5444// just-completed scavenge collection).
5445void Heap::ReportHeapStatistics(const char* title) {
5446 USE(title);
5447 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n",
5448 title, gc_count_);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005449 PrintF("old_gen_promotion_limit_ %" V8_PTR_PREFIX "d\n",
5450 old_gen_promotion_limit_);
5451 PrintF("old_gen_allocation_limit_ %" V8_PTR_PREFIX "d\n",
5452 old_gen_allocation_limit_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005453 PrintF("old_gen_limit_factor_ %d\n", old_gen_limit_factor_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005454
5455 PrintF("\n");
5456 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005457 isolate_->global_handles()->PrintStats();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005458 PrintF("\n");
5459
5460 PrintF("Heap statistics : ");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005461 isolate_->memory_allocator()->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005462 PrintF("To space : ");
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005463 new_space_.ReportStatistics();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005464 PrintF("Old pointer space : ");
5465 old_pointer_space_->ReportStatistics();
5466 PrintF("Old data space : ");
5467 old_data_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005468 PrintF("Code space : ");
5469 code_space_->ReportStatistics();
5470 PrintF("Map space : ");
5471 map_space_->ReportStatistics();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005472 PrintF("Cell space : ");
5473 cell_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005474 PrintF("Large object space : ");
5475 lo_space_->ReportStatistics();
5476 PrintF(">>>>>> ========================================= >>>>>>\n");
5477}
5478
5479#endif // DEBUG
5480
5481bool Heap::Contains(HeapObject* value) {
5482 return Contains(value->address());
5483}
5484
5485
5486bool Heap::Contains(Address addr) {
5487 if (OS::IsOutsideAllocatedSpace(addr)) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005488 return HasBeenSetUp() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005489 (new_space_.ToSpaceContains(addr) ||
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005490 old_pointer_space_->Contains(addr) ||
5491 old_data_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005492 code_space_->Contains(addr) ||
5493 map_space_->Contains(addr) ||
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005494 cell_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005495 lo_space_->SlowContains(addr));
5496}
5497
5498
5499bool Heap::InSpace(HeapObject* value, AllocationSpace space) {
5500 return InSpace(value->address(), space);
5501}
5502
5503
5504bool Heap::InSpace(Address addr, AllocationSpace space) {
5505 if (OS::IsOutsideAllocatedSpace(addr)) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005506 if (!HasBeenSetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005507
5508 switch (space) {
5509 case NEW_SPACE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005510 return new_space_.ToSpaceContains(addr);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005511 case OLD_POINTER_SPACE:
5512 return old_pointer_space_->Contains(addr);
5513 case OLD_DATA_SPACE:
5514 return old_data_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005515 case CODE_SPACE:
5516 return code_space_->Contains(addr);
5517 case MAP_SPACE:
5518 return map_space_->Contains(addr);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005519 case CELL_SPACE:
5520 return cell_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005521 case LO_SPACE:
5522 return lo_space_->SlowContains(addr);
5523 }
5524
5525 return false;
5526}
5527
5528
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005529#ifdef VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005530void Heap::Verify() {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005531 CHECK(HasBeenSetUp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005532
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005533 store_buffer()->Verify();
5534
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005535 VerifyPointersVisitor visitor;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005536 IterateRoots(&visitor, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005537
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005538 new_space_.Verify();
5539
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005540 old_pointer_space_->Verify(&visitor);
5541 map_space_->Verify(&visitor);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005542
5543 VerifyPointersVisitor no_dirty_regions_visitor;
5544 old_data_space_->Verify(&no_dirty_regions_visitor);
5545 code_space_->Verify(&no_dirty_regions_visitor);
5546 cell_space_->Verify(&no_dirty_regions_visitor);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005547
5548 lo_space_->Verify();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005549}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005550#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005551
5552
lrn@chromium.org303ada72010-10-27 09:33:13 +00005553MaybeObject* Heap::LookupSymbol(Vector<const char> string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005554 Object* symbol = NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005555 Object* new_table;
5556 { MaybeObject* maybe_new_table =
5557 symbol_table()->LookupSymbol(string, &symbol);
5558 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5559 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005560 // Can't use set_symbol_table because SymbolTable::cast knows that
5561 // SymbolTable is a singleton and checks for identity.
5562 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005563 ASSERT(symbol != NULL);
5564 return symbol;
5565}
5566
5567
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005568MaybeObject* Heap::LookupAsciiSymbol(Vector<const char> string) {
5569 Object* symbol = NULL;
5570 Object* new_table;
5571 { MaybeObject* maybe_new_table =
5572 symbol_table()->LookupAsciiSymbol(string, &symbol);
5573 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5574 }
5575 // Can't use set_symbol_table because SymbolTable::cast knows that
5576 // SymbolTable is a singleton and checks for identity.
5577 roots_[kSymbolTableRootIndex] = new_table;
5578 ASSERT(symbol != NULL);
5579 return symbol;
5580}
5581
5582
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005583MaybeObject* Heap::LookupAsciiSymbol(Handle<SeqOneByteString> string,
danno@chromium.org40cb8782011-05-25 07:58:50 +00005584 int from,
5585 int length) {
5586 Object* symbol = NULL;
5587 Object* new_table;
5588 { MaybeObject* maybe_new_table =
5589 symbol_table()->LookupSubStringAsciiSymbol(string,
5590 from,
5591 length,
5592 &symbol);
5593 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5594 }
5595 // Can't use set_symbol_table because SymbolTable::cast knows that
5596 // SymbolTable is a singleton and checks for identity.
5597 roots_[kSymbolTableRootIndex] = new_table;
5598 ASSERT(symbol != NULL);
5599 return symbol;
5600}
5601
5602
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005603MaybeObject* Heap::LookupTwoByteSymbol(Vector<const uc16> string) {
5604 Object* symbol = NULL;
5605 Object* new_table;
5606 { MaybeObject* maybe_new_table =
5607 symbol_table()->LookupTwoByteSymbol(string, &symbol);
5608 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5609 }
5610 // Can't use set_symbol_table because SymbolTable::cast knows that
5611 // SymbolTable is a singleton and checks for identity.
5612 roots_[kSymbolTableRootIndex] = new_table;
5613 ASSERT(symbol != NULL);
5614 return symbol;
5615}
5616
5617
lrn@chromium.org303ada72010-10-27 09:33:13 +00005618MaybeObject* Heap::LookupSymbol(String* string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005619 if (string->IsSymbol()) return string;
5620 Object* symbol = NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005621 Object* new_table;
5622 { MaybeObject* maybe_new_table =
5623 symbol_table()->LookupString(string, &symbol);
5624 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5625 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005626 // Can't use set_symbol_table because SymbolTable::cast knows that
5627 // SymbolTable is a singleton and checks for identity.
5628 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005629 ASSERT(symbol != NULL);
5630 return symbol;
5631}
5632
5633
ager@chromium.org7c537e22008-10-16 08:43:32 +00005634bool Heap::LookupSymbolIfExists(String* string, String** symbol) {
5635 if (string->IsSymbol()) {
5636 *symbol = string;
5637 return true;
5638 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005639 return symbol_table()->LookupSymbolIfExists(string, symbol);
ager@chromium.org7c537e22008-10-16 08:43:32 +00005640}
5641
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005642
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005643void Heap::ZapFromSpace() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005644 NewSpacePageIterator it(new_space_.FromSpaceStart(),
5645 new_space_.FromSpaceEnd());
5646 while (it.has_next()) {
5647 NewSpacePage* page = it.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005648 for (Address cursor = page->area_start(), limit = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005649 cursor < limit;
5650 cursor += kPointerSize) {
5651 Memory::Address_at(cursor) = kFromSpaceZapValue;
5652 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005653 }
5654}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005655
5656
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005657void Heap::IterateAndMarkPointersToFromSpace(Address start,
5658 Address end,
5659 ObjectSlotCallback callback) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005660 Address slot_address = start;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005661
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005662 // We are not collecting slots on new space objects during mutation
5663 // thus we have to scan for pointers to evacuation candidates when we
5664 // promote objects. But we should not record any slots in non-black
5665 // objects. Grey object's slots would be rescanned.
5666 // White object might not survive until the end of collection
5667 // it would be a violation of the invariant to record it's slots.
5668 bool record_slots = false;
5669 if (incremental_marking()->IsCompacting()) {
5670 MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::FromAddress(start));
5671 record_slots = Marking::IsBlack(mark_bit);
5672 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005673
5674 while (slot_address < end) {
5675 Object** slot = reinterpret_cast<Object**>(slot_address);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005676 Object* object = *slot;
5677 // If the store buffer becomes overfull we mark pages as being exempt from
5678 // the store buffer. These pages are scanned to find pointers that point
5679 // to the new space. In that case we may hit newly promoted objects and
5680 // fix the pointers before the promotion queue gets to them. Thus the 'if'.
5681 if (object->IsHeapObject()) {
5682 if (Heap::InFromSpace(object)) {
5683 callback(reinterpret_cast<HeapObject**>(slot),
5684 HeapObject::cast(object));
5685 Object* new_object = *slot;
5686 if (InNewSpace(new_object)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005687 SLOW_ASSERT(Heap::InToSpace(new_object));
5688 SLOW_ASSERT(new_object->IsHeapObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005689 store_buffer_.EnterDirectlyIntoStoreBuffer(
5690 reinterpret_cast<Address>(slot));
5691 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005692 SLOW_ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_object));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005693 } else if (record_slots &&
5694 MarkCompactCollector::IsOnEvacuationCandidate(object)) {
5695 mark_compact_collector()->RecordSlot(slot, slot, object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005696 }
5697 }
5698 slot_address += kPointerSize;
5699 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005700}
5701
5702
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005703#ifdef DEBUG
5704typedef bool (*CheckStoreBufferFilter)(Object** addr);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005705
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005706
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005707bool IsAMapPointerAddress(Object** addr) {
5708 uintptr_t a = reinterpret_cast<uintptr_t>(addr);
5709 int mod = a % Map::kSize;
5710 return mod >= Map::kPointerFieldsBeginOffset &&
5711 mod < Map::kPointerFieldsEndOffset;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005712}
5713
5714
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005715bool EverythingsAPointer(Object** addr) {
5716 return true;
5717}
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005718
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005719
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005720static void CheckStoreBuffer(Heap* heap,
5721 Object** current,
5722 Object** limit,
5723 Object**** store_buffer_position,
5724 Object*** store_buffer_top,
5725 CheckStoreBufferFilter filter,
5726 Address special_garbage_start,
5727 Address special_garbage_end) {
5728 Map* free_space_map = heap->free_space_map();
5729 for ( ; current < limit; current++) {
5730 Object* o = *current;
5731 Address current_address = reinterpret_cast<Address>(current);
5732 // Skip free space.
5733 if (o == free_space_map) {
5734 Address current_address = reinterpret_cast<Address>(current);
5735 FreeSpace* free_space =
5736 FreeSpace::cast(HeapObject::FromAddress(current_address));
5737 int skip = free_space->Size();
5738 ASSERT(current_address + skip <= reinterpret_cast<Address>(limit));
5739 ASSERT(skip > 0);
5740 current_address += skip - kPointerSize;
5741 current = reinterpret_cast<Object**>(current_address);
5742 continue;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005743 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005744 // Skip the current linear allocation space between top and limit which is
5745 // unmarked with the free space map, but can contain junk.
5746 if (current_address == special_garbage_start &&
5747 special_garbage_end != special_garbage_start) {
5748 current_address = special_garbage_end - kPointerSize;
5749 current = reinterpret_cast<Object**>(current_address);
5750 continue;
5751 }
5752 if (!(*filter)(current)) continue;
5753 ASSERT(current_address < special_garbage_start ||
5754 current_address >= special_garbage_end);
5755 ASSERT(reinterpret_cast<uintptr_t>(o) != kFreeListZapValue);
5756 // We have to check that the pointer does not point into new space
5757 // without trying to cast it to a heap object since the hash field of
5758 // a string can contain values like 1 and 3 which are tagged null
5759 // pointers.
5760 if (!heap->InNewSpace(o)) continue;
5761 while (**store_buffer_position < current &&
5762 *store_buffer_position < store_buffer_top) {
5763 (*store_buffer_position)++;
5764 }
5765 if (**store_buffer_position != current ||
5766 *store_buffer_position == store_buffer_top) {
5767 Object** obj_start = current;
5768 while (!(*obj_start)->IsMap()) obj_start--;
5769 UNREACHABLE();
5770 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005771 }
5772}
5773
5774
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005775// Check that the store buffer contains all intergenerational pointers by
5776// scanning a page and ensuring that all pointers to young space are in the
5777// store buffer.
5778void Heap::OldPointerSpaceCheckStoreBuffer() {
5779 OldSpace* space = old_pointer_space();
5780 PageIterator pages(space);
5781
5782 store_buffer()->SortUniq();
5783
5784 while (pages.has_next()) {
5785 Page* page = pages.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005786 Object** current = reinterpret_cast<Object**>(page->area_start());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005787
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005788 Address end = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005789
5790 Object*** store_buffer_position = store_buffer()->Start();
5791 Object*** store_buffer_top = store_buffer()->Top();
5792
5793 Object** limit = reinterpret_cast<Object**>(end);
5794 CheckStoreBuffer(this,
5795 current,
5796 limit,
5797 &store_buffer_position,
5798 store_buffer_top,
5799 &EverythingsAPointer,
5800 space->top(),
5801 space->limit());
5802 }
5803}
5804
5805
5806void Heap::MapSpaceCheckStoreBuffer() {
5807 MapSpace* space = map_space();
5808 PageIterator pages(space);
5809
5810 store_buffer()->SortUniq();
5811
5812 while (pages.has_next()) {
5813 Page* page = pages.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005814 Object** current = reinterpret_cast<Object**>(page->area_start());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005815
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005816 Address end = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005817
5818 Object*** store_buffer_position = store_buffer()->Start();
5819 Object*** store_buffer_top = store_buffer()->Top();
5820
5821 Object** limit = reinterpret_cast<Object**>(end);
5822 CheckStoreBuffer(this,
5823 current,
5824 limit,
5825 &store_buffer_position,
5826 store_buffer_top,
5827 &IsAMapPointerAddress,
5828 space->top(),
5829 space->limit());
5830 }
5831}
5832
5833
5834void Heap::LargeObjectSpaceCheckStoreBuffer() {
5835 LargeObjectIterator it(lo_space());
5836 for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) {
5837 // We only have code, sequential strings, or fixed arrays in large
5838 // object space, and only fixed arrays can possibly contain pointers to
5839 // the young generation.
5840 if (object->IsFixedArray()) {
5841 Object*** store_buffer_position = store_buffer()->Start();
5842 Object*** store_buffer_top = store_buffer()->Top();
5843 Object** current = reinterpret_cast<Object**>(object->address());
5844 Object** limit =
5845 reinterpret_cast<Object**>(object->address() + object->Size());
5846 CheckStoreBuffer(this,
5847 current,
5848 limit,
5849 &store_buffer_position,
5850 store_buffer_top,
5851 &EverythingsAPointer,
5852 NULL,
5853 NULL);
5854 }
5855 }
5856}
5857#endif
5858
5859
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005860void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) {
5861 IterateStrongRoots(v, mode);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005862 IterateWeakRoots(v, mode);
5863}
5864
5865
5866void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005867 v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex]));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005868 v->Synchronize(VisitorSynchronization::kSymbolTable);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005869 if (mode != VISIT_ALL_IN_SCAVENGE &&
5870 mode != VISIT_ALL_IN_SWEEP_NEWSPACE) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005871 // Scavenge collections have special processing for this.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005872 external_string_table_.Iterate(v);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005873 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005874 v->Synchronize(VisitorSynchronization::kExternalStringsTable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005875}
5876
5877
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005878void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005879 v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005880 v->Synchronize(VisitorSynchronization::kStrongRootList);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005881
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00005882 v->VisitPointer(BitCast<Object**>(&hidden_symbol_));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005883 v->Synchronize(VisitorSynchronization::kSymbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005884
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005885 isolate_->bootstrapper()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005886 v->Synchronize(VisitorSynchronization::kBootstrapper);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005887 isolate_->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005888 v->Synchronize(VisitorSynchronization::kTop);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005889 Relocatable::Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005890 v->Synchronize(VisitorSynchronization::kRelocatable);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005891
5892#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005893 isolate_->debug()->Iterate(v);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005894 if (isolate_->deoptimizer_data() != NULL) {
5895 isolate_->deoptimizer_data()->Iterate(v);
5896 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005897#endif
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005898 v->Synchronize(VisitorSynchronization::kDebug);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005899 isolate_->compilation_cache()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005900 v->Synchronize(VisitorSynchronization::kCompilationCache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005901
5902 // Iterate over local handles in handle scopes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005903 isolate_->handle_scope_implementer()->Iterate(v);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005904 isolate_->IterateDeferredHandles(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005905 v->Synchronize(VisitorSynchronization::kHandleScope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005906
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005907 // Iterate over the builtin code objects and code stubs in the
5908 // heap. Note that it is not necessary to iterate over code objects
5909 // on scavenge collections.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005910 if (mode != VISIT_ALL_IN_SCAVENGE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005911 isolate_->builtins()->IterateBuiltins(v);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005912 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005913 v->Synchronize(VisitorSynchronization::kBuiltins);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005914
5915 // Iterate over global handles.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005916 switch (mode) {
5917 case VISIT_ONLY_STRONG:
5918 isolate_->global_handles()->IterateStrongRoots(v);
5919 break;
5920 case VISIT_ALL_IN_SCAVENGE:
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005921 isolate_->global_handles()->IterateNewSpaceStrongAndDependentRoots(v);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005922 break;
5923 case VISIT_ALL_IN_SWEEP_NEWSPACE:
5924 case VISIT_ALL:
5925 isolate_->global_handles()->IterateAllRoots(v);
5926 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005927 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005928 v->Synchronize(VisitorSynchronization::kGlobalHandles);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005929
5930 // Iterate over pointers being held by inactive threads.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005931 isolate_->thread_manager()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005932 v->Synchronize(VisitorSynchronization::kThreadManager);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005933
5934 // Iterate over the pointers the Serialization/Deserialization code is
5935 // holding.
5936 // During garbage collection this keeps the partial snapshot cache alive.
5937 // During deserialization of the startup snapshot this creates the partial
5938 // snapshot cache and deserializes the objects it refers to. During
5939 // serialization this does nothing, since the partial snapshot cache is
5940 // empty. However the next thing we do is create the partial snapshot,
5941 // filling up the partial snapshot cache with objects it needs as we go.
5942 SerializerDeserializer::Iterate(v);
5943 // We don't do a v->Synchronize call here, because in debug mode that will
5944 // output a flag to the snapshot. However at this point the serializer and
5945 // deserializer are deliberately a little unsynchronized (see above) so the
5946 // checking of the sync flag in the snapshot would fail.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005947}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005948
5949
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005950// TODO(1236194): Since the heap size is configurable on the command line
5951// and through the API, we should gracefully handle the case that the heap
5952// size is not big enough to fit all the initial objects.
ager@chromium.org01fe7df2010-11-10 11:59:11 +00005953bool Heap::ConfigureHeap(int max_semispace_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005954 intptr_t max_old_gen_size,
5955 intptr_t max_executable_size) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005956 if (HasBeenSetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005957
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00005958 if (FLAG_stress_compaction) {
5959 // This will cause more frequent GCs when stressing.
5960 max_semispace_size_ = Page::kPageSize;
5961 }
5962
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005963 if (max_semispace_size > 0) {
5964 if (max_semispace_size < Page::kPageSize) {
5965 max_semispace_size = Page::kPageSize;
5966 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00005967 PrintPID("Max semispace size cannot be less than %dkbytes\n",
5968 Page::kPageSize >> 10);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005969 }
5970 }
5971 max_semispace_size_ = max_semispace_size;
5972 }
ager@chromium.org3811b432009-10-28 14:53:37 +00005973
5974 if (Snapshot::IsEnabled()) {
5975 // If we are using a snapshot we always reserve the default amount
5976 // of memory for each semispace because code in the snapshot has
5977 // write-barrier code that relies on the size and alignment of new
5978 // space. We therefore cannot use a larger max semispace size
5979 // than the default reserved semispace size.
5980 if (max_semispace_size_ > reserved_semispace_size_) {
5981 max_semispace_size_ = reserved_semispace_size_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005982 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00005983 PrintPID("Max semispace size cannot be more than %dkbytes\n",
5984 reserved_semispace_size_ >> 10);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005985 }
ager@chromium.org3811b432009-10-28 14:53:37 +00005986 }
5987 } else {
5988 // If we are not using snapshots we reserve space for the actual
5989 // max semispace size.
5990 reserved_semispace_size_ = max_semispace_size_;
5991 }
5992
5993 if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size;
ager@chromium.org01fe7df2010-11-10 11:59:11 +00005994 if (max_executable_size > 0) {
5995 max_executable_size_ = RoundUp(max_executable_size, Page::kPageSize);
5996 }
5997
5998 // The max executable size must be less than or equal to the max old
5999 // generation size.
6000 if (max_executable_size_ > max_old_generation_size_) {
6001 max_executable_size_ = max_old_generation_size_;
6002 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006003
6004 // The new space size must be a power of two to support single-bit testing
6005 // for containment.
ager@chromium.org3811b432009-10-28 14:53:37 +00006006 max_semispace_size_ = RoundUpToPowerOf2(max_semispace_size_);
6007 reserved_semispace_size_ = RoundUpToPowerOf2(reserved_semispace_size_);
6008 initial_semispace_size_ = Min(initial_semispace_size_, max_semispace_size_);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006009 external_allocation_limit_ = 16 * max_semispace_size_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006010
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006011 // The old generation is paged and needs at least one page for each space.
6012 int paged_space_count = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1;
6013 max_old_generation_size_ = Max(static_cast<intptr_t>(paged_space_count *
6014 Page::kPageSize),
6015 RoundUp(max_old_generation_size_,
6016 Page::kPageSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006018 configured_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006019 return true;
6020}
6021
6022
kasper.lund7276f142008-07-30 08:49:36 +00006023bool Heap::ConfigureHeapDefault() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006024 return ConfigureHeap(static_cast<intptr_t>(FLAG_max_new_space_size / 2) * KB,
6025 static_cast<intptr_t>(FLAG_max_old_space_size) * MB,
6026 static_cast<intptr_t>(FLAG_max_executable_size) * MB);
kasper.lund7276f142008-07-30 08:49:36 +00006027}
6028
6029
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006030void Heap::RecordStats(HeapStats* stats, bool take_snapshot) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006031 *stats->start_marker = HeapStats::kStartMarker;
6032 *stats->end_marker = HeapStats::kEndMarker;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006033 *stats->new_space_size = new_space_.SizeAsInt();
6034 *stats->new_space_capacity = static_cast<int>(new_space_.Capacity());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006035 *stats->old_pointer_space_size = old_pointer_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006036 *stats->old_pointer_space_capacity = old_pointer_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006037 *stats->old_data_space_size = old_data_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006038 *stats->old_data_space_capacity = old_data_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006039 *stats->code_space_size = code_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006040 *stats->code_space_capacity = code_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006041 *stats->map_space_size = map_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006042 *stats->map_space_capacity = map_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006043 *stats->cell_space_size = cell_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006044 *stats->cell_space_capacity = cell_space_->Capacity();
6045 *stats->lo_space_size = lo_space_->Size();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006046 isolate_->global_handles()->RecordStats(stats);
6047 *stats->memory_allocator_size = isolate()->memory_allocator()->Size();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006048 *stats->memory_allocator_capacity =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006049 isolate()->memory_allocator()->Size() +
6050 isolate()->memory_allocator()->Available();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006051 *stats->os_error = OS::GetLastError();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006052 isolate()->memory_allocator()->Available();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006053 if (take_snapshot) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006054 HeapIterator iterator;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006055 for (HeapObject* obj = iterator.next();
6056 obj != NULL;
6057 obj = iterator.next()) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006058 InstanceType type = obj->map()->instance_type();
6059 ASSERT(0 <= type && type <= LAST_TYPE);
6060 stats->objects_per_type[type]++;
6061 stats->size_per_type[type] += obj->Size();
6062 }
6063 }
ager@chromium.org60121232009-12-03 11:25:37 +00006064}
6065
6066
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00006067intptr_t Heap::PromotedSpaceSizeOfObjects() {
6068 return old_pointer_space_->SizeOfObjects()
6069 + old_data_space_->SizeOfObjects()
6070 + code_space_->SizeOfObjects()
6071 + map_space_->SizeOfObjects()
6072 + cell_space_->SizeOfObjects()
6073 + lo_space_->SizeOfObjects();
6074}
6075
6076
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00006077intptr_t Heap::PromotedExternalMemorySize() {
kasper.lund7276f142008-07-30 08:49:36 +00006078 if (amount_of_external_allocated_memory_
6079 <= amount_of_external_allocated_memory_at_last_global_gc_) return 0;
6080 return amount_of_external_allocated_memory_
6081 - amount_of_external_allocated_memory_at_last_global_gc_;
6082}
6083
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00006084
6085V8_DECLARE_ONCE(initialize_gc_once);
6086
6087static void InitializeGCOnce() {
6088 InitializeScavengingVisitorsTables();
6089 NewSpaceScavenger::Initialize();
6090 MarkCompactCollector::Initialize();
6091}
6092
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006093bool Heap::SetUp(bool create_heap_objects) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006094#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006095 allocation_timeout_ = FLAG_gc_interval;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006096#endif
6097
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006098 // Initialize heap spaces and initial maps and objects. Whenever something
6099 // goes wrong, just return false. The caller should check the results and
6100 // call Heap::TearDown() to release allocated memory.
6101 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006102 // If the heap is not yet configured (e.g. through the API), configure it.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006103 // Configuration is based on the flags new-space-size (really the semispace
6104 // size) and old-space-size if set or the initial values of semispace_size_
6105 // and old_generation_size_ otherwise.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006106 if (!configured_) {
kasper.lund7276f142008-07-30 08:49:36 +00006107 if (!ConfigureHeapDefault()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006108 }
6109
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00006110 CallOnce(&initialize_gc_once, &InitializeGCOnce);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006111
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006112 MarkMapPointersAsEncoded(false);
6113
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006114 // Set up memory allocator.
6115 if (!isolate_->memory_allocator()->SetUp(MaxReserved(), MaxExecutableSize()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006116 return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006117
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006118 // Set up new space.
6119 if (!new_space_.SetUp(reserved_semispace_size_, max_semispace_size_)) {
ager@chromium.org3811b432009-10-28 14:53:37 +00006120 return false;
6121 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006122
ager@chromium.orga1645e22009-09-09 19:27:10 +00006123 // Initialize old pointer space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006124 old_pointer_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006125 new OldSpace(this,
6126 max_old_generation_size_,
6127 OLD_POINTER_SPACE,
6128 NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006129 if (old_pointer_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006130 if (!old_pointer_space_->SetUp()) return false;
ager@chromium.orga1645e22009-09-09 19:27:10 +00006131
6132 // Initialize old data space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006133 old_data_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006134 new OldSpace(this,
6135 max_old_generation_size_,
6136 OLD_DATA_SPACE,
6137 NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006138 if (old_data_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006139 if (!old_data_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006140
6141 // Initialize the code space, set its maximum capacity to the old
kasper.lund7276f142008-07-30 08:49:36 +00006142 // generation size. It needs executable memory.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006143 // On 64-bit platform(s), we put all code objects in a 2 GB range of
6144 // virtual address space, so that they can call each other with near calls.
6145 if (code_range_size_ > 0) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006146 if (!isolate_->code_range()->SetUp(code_range_size_)) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006147 return false;
6148 }
6149 }
6150
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006151 code_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006152 new OldSpace(this, max_old_generation_size_, CODE_SPACE, EXECUTABLE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006153 if (code_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006154 if (!code_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006155
6156 // Initialize map space.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00006157 map_space_ = new MapSpace(this, max_old_generation_size_, MAP_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006158 if (map_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006159 if (!map_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006160
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006161 // Initialize global property cell space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006162 cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006163 if (cell_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006164 if (!cell_space_->SetUp()) return false;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006165
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006166 // The large object code space may contain code or data. We set the memory
6167 // to be non-executable here for safety, but this means we need to enable it
6168 // explicitly when allocating large code objects.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006169 lo_space_ = new LargeObjectSpace(this, max_old_generation_size_, LO_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006170 if (lo_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006171 if (!lo_space_->SetUp()) return false;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006172
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006173 // Set up the seed that is used to randomize the string hash function.
6174 ASSERT(hash_seed() == 0);
6175 if (FLAG_randomize_hashes) {
6176 if (FLAG_hash_seed == 0) {
6177 set_hash_seed(
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006178 Smi::FromInt(V8::RandomPrivate(isolate()) & 0x3fffffff));
6179 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006180 set_hash_seed(Smi::FromInt(FLAG_hash_seed));
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006181 }
6182 }
6183
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006184 if (create_heap_objects) {
6185 // Create initial maps.
6186 if (!CreateInitialMaps()) return false;
6187 if (!CreateApiObjects()) return false;
6188
6189 // Create initial objects
6190 if (!CreateInitialObjects()) return false;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00006191
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006192 native_contexts_list_ = undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006193 }
6194
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006195 LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity()));
6196 LOG(isolate_, IntPtrTEvent("heap-available", Available()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006197
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006198 store_buffer()->SetUp();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006199
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006200 if (FLAG_parallel_recompilation) relocation_mutex_ = OS::CreateMutex();
6201
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006202 return true;
6203}
6204
6205
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006206void Heap::SetStackLimits() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006207 ASSERT(isolate_ != NULL);
6208 ASSERT(isolate_ == isolate());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006209 // On 64 bit machines, pointers are generally out of range of Smis. We write
6210 // something that looks like an out of range Smi to the GC.
6211
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006212 // Set up the special root array entries containing the stack limits.
6213 // These are actually addresses, but the tag makes the GC ignore it.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006214 roots_[kStackLimitRootIndex] =
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006215 reinterpret_cast<Object*>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006216 (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006217 roots_[kRealStackLimitRootIndex] =
6218 reinterpret_cast<Object*>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006219 (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006220}
6221
6222
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006223void Heap::TearDown() {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006224#ifdef VERIFY_HEAP
danno@chromium.org1044a4d2012-04-30 12:34:39 +00006225 if (FLAG_verify_heap) {
6226 Verify();
6227 }
6228#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006229
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006230 if (FLAG_print_cumulative_gc_stat) {
6231 PrintF("\n\n");
6232 PrintF("gc_count=%d ", gc_count_);
6233 PrintF("mark_sweep_count=%d ", ms_count_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006234 PrintF("max_gc_pause=%d ", get_max_gc_pause());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006235 PrintF("total_gc_time=%d ", total_gc_time_ms_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006236 PrintF("min_in_mutator=%d ", get_min_in_mutator());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006237 PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ",
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006238 get_max_alive_after_gc());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006239 PrintF("\n\n");
6240 }
6241
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006242 isolate_->global_handles()->TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006243
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006244 external_string_table_.TearDown();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00006245
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006246 new_space_.TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006247
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006248 if (old_pointer_space_ != NULL) {
6249 old_pointer_space_->TearDown();
6250 delete old_pointer_space_;
6251 old_pointer_space_ = NULL;
6252 }
6253
6254 if (old_data_space_ != NULL) {
6255 old_data_space_->TearDown();
6256 delete old_data_space_;
6257 old_data_space_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006258 }
6259
6260 if (code_space_ != NULL) {
6261 code_space_->TearDown();
6262 delete code_space_;
6263 code_space_ = NULL;
6264 }
6265
6266 if (map_space_ != NULL) {
6267 map_space_->TearDown();
6268 delete map_space_;
6269 map_space_ = NULL;
6270 }
6271
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006272 if (cell_space_ != NULL) {
6273 cell_space_->TearDown();
6274 delete cell_space_;
6275 cell_space_ = NULL;
6276 }
6277
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006278 if (lo_space_ != NULL) {
6279 lo_space_->TearDown();
6280 delete lo_space_;
6281 lo_space_ = NULL;
6282 }
6283
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006284 store_buffer()->TearDown();
6285 incremental_marking()->TearDown();
6286
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006287 isolate_->memory_allocator()->TearDown();
6288
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006289 delete relocation_mutex_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006290}
6291
6292
6293void Heap::Shrink() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006294 // Try to shrink all paged spaces.
6295 PagedSpaces spaces;
danno@chromium.org2c456792011-11-11 12:00:53 +00006296 for (PagedSpace* space = spaces.next();
6297 space != NULL;
6298 space = spaces.next()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006299 space->ReleaseAllUnusedPages();
danno@chromium.org2c456792011-11-11 12:00:53 +00006300 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006301}
6302
6303
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006304void Heap::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) {
6305 ASSERT(callback != NULL);
6306 GCPrologueCallbackPair pair(callback, gc_type);
6307 ASSERT(!gc_prologue_callbacks_.Contains(pair));
6308 return gc_prologue_callbacks_.Add(pair);
6309}
6310
6311
6312void Heap::RemoveGCPrologueCallback(GCPrologueCallback callback) {
6313 ASSERT(callback != NULL);
6314 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
6315 if (gc_prologue_callbacks_[i].callback == callback) {
6316 gc_prologue_callbacks_.Remove(i);
6317 return;
6318 }
6319 }
6320 UNREACHABLE();
6321}
6322
6323
6324void Heap::AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type) {
6325 ASSERT(callback != NULL);
6326 GCEpilogueCallbackPair pair(callback, gc_type);
6327 ASSERT(!gc_epilogue_callbacks_.Contains(pair));
6328 return gc_epilogue_callbacks_.Add(pair);
6329}
6330
6331
6332void Heap::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
6333 ASSERT(callback != NULL);
6334 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
6335 if (gc_epilogue_callbacks_[i].callback == callback) {
6336 gc_epilogue_callbacks_.Remove(i);
6337 return;
6338 }
6339 }
6340 UNREACHABLE();
6341}
6342
6343
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006344#ifdef DEBUG
6345
6346class PrintHandleVisitor: public ObjectVisitor {
6347 public:
6348 void VisitPointers(Object** start, Object** end) {
6349 for (Object** p = start; p < end; p++)
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006350 PrintF(" handle %p to %p\n",
6351 reinterpret_cast<void*>(p),
6352 reinterpret_cast<void*>(*p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006353 }
6354};
6355
6356void Heap::PrintHandles() {
6357 PrintF("Handles:\n");
6358 PrintHandleVisitor v;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006359 isolate_->handle_scope_implementer()->Iterate(&v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006360}
6361
6362#endif
6363
6364
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006365Space* AllSpaces::next() {
6366 switch (counter_++) {
6367 case NEW_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006368 return HEAP->new_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006369 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006370 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006371 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006372 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006373 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006374 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006375 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006376 return HEAP->map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006377 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006378 return HEAP->cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006379 case LO_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006380 return HEAP->lo_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006381 default:
6382 return NULL;
6383 }
6384}
6385
6386
6387PagedSpace* PagedSpaces::next() {
6388 switch (counter_++) {
6389 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006390 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006391 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006392 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006393 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006394 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006395 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006396 return HEAP->map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006397 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006398 return HEAP->cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006399 default:
6400 return NULL;
6401 }
6402}
6403
6404
6405
6406OldSpace* OldSpaces::next() {
6407 switch (counter_++) {
6408 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006409 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006410 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006411 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006412 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006413 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006414 default:
6415 return NULL;
6416 }
6417}
6418
6419
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006420SpaceIterator::SpaceIterator()
6421 : current_space_(FIRST_SPACE),
6422 iterator_(NULL),
6423 size_func_(NULL) {
6424}
6425
6426
6427SpaceIterator::SpaceIterator(HeapObjectCallback size_func)
6428 : current_space_(FIRST_SPACE),
6429 iterator_(NULL),
6430 size_func_(size_func) {
kasper.lund7276f142008-07-30 08:49:36 +00006431}
6432
6433
6434SpaceIterator::~SpaceIterator() {
6435 // Delete active iterator if any.
6436 delete iterator_;
6437}
6438
6439
6440bool SpaceIterator::has_next() {
6441 // Iterate until no more spaces.
6442 return current_space_ != LAST_SPACE;
6443}
6444
6445
6446ObjectIterator* SpaceIterator::next() {
6447 if (iterator_ != NULL) {
6448 delete iterator_;
6449 iterator_ = NULL;
6450 // Move to the next space
6451 current_space_++;
6452 if (current_space_ > LAST_SPACE) {
6453 return NULL;
6454 }
6455 }
6456
6457 // Return iterator for the new current space.
6458 return CreateIterator();
6459}
6460
6461
6462// Create an iterator for the space to iterate.
6463ObjectIterator* SpaceIterator::CreateIterator() {
6464 ASSERT(iterator_ == NULL);
6465
6466 switch (current_space_) {
6467 case NEW_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006468 iterator_ = new SemiSpaceIterator(HEAP->new_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006469 break;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006470 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006471 iterator_ = new HeapObjectIterator(HEAP->old_pointer_space(), size_func_);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006472 break;
6473 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006474 iterator_ = new HeapObjectIterator(HEAP->old_data_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006475 break;
6476 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006477 iterator_ = new HeapObjectIterator(HEAP->code_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006478 break;
6479 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006480 iterator_ = new HeapObjectIterator(HEAP->map_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006481 break;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006482 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006483 iterator_ = new HeapObjectIterator(HEAP->cell_space(), size_func_);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006484 break;
kasper.lund7276f142008-07-30 08:49:36 +00006485 case LO_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006486 iterator_ = new LargeObjectIterator(HEAP->lo_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006487 break;
6488 }
6489
6490 // Return the newly allocated iterator;
6491 ASSERT(iterator_ != NULL);
6492 return iterator_;
6493}
6494
6495
whesse@chromium.org023421e2010-12-21 12:19:12 +00006496class HeapObjectsFilter {
6497 public:
6498 virtual ~HeapObjectsFilter() {}
6499 virtual bool SkipObject(HeapObject* object) = 0;
6500};
6501
6502
whesse@chromium.org023421e2010-12-21 12:19:12 +00006503class UnreachableObjectsFilter : public HeapObjectsFilter {
6504 public:
6505 UnreachableObjectsFilter() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006506 MarkReachableObjects();
6507 }
6508
6509 ~UnreachableObjectsFilter() {
6510 Isolate::Current()->heap()->mark_compact_collector()->ClearMarkbits();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006511 }
6512
6513 bool SkipObject(HeapObject* object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006514 MarkBit mark_bit = Marking::MarkBitFrom(object);
6515 return !mark_bit.Get();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006516 }
6517
6518 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006519 class MarkingVisitor : public ObjectVisitor {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006520 public:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006521 MarkingVisitor() : marking_stack_(10) {}
whesse@chromium.org023421e2010-12-21 12:19:12 +00006522
6523 void VisitPointers(Object** start, Object** end) {
6524 for (Object** p = start; p < end; p++) {
6525 if (!(*p)->IsHeapObject()) continue;
6526 HeapObject* obj = HeapObject::cast(*p);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006527 MarkBit mark_bit = Marking::MarkBitFrom(obj);
6528 if (!mark_bit.Get()) {
6529 mark_bit.Set();
6530 marking_stack_.Add(obj);
whesse@chromium.org023421e2010-12-21 12:19:12 +00006531 }
6532 }
6533 }
6534
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006535 void TransitiveClosure() {
6536 while (!marking_stack_.is_empty()) {
6537 HeapObject* obj = marking_stack_.RemoveLast();
6538 obj->Iterate(this);
6539 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00006540 }
6541
6542 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006543 List<HeapObject*> marking_stack_;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006544 };
6545
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006546 void MarkReachableObjects() {
6547 Heap* heap = Isolate::Current()->heap();
6548 MarkingVisitor visitor;
6549 heap->IterateRoots(&visitor, VISIT_ALL);
6550 visitor.TransitiveClosure();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006551 }
6552
6553 AssertNoAllocation no_alloc;
6554};
6555
6556
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006557HeapIterator::HeapIterator()
6558 : filtering_(HeapIterator::kNoFiltering),
6559 filter_(NULL) {
6560 Init();
6561}
6562
6563
whesse@chromium.org023421e2010-12-21 12:19:12 +00006564HeapIterator::HeapIterator(HeapIterator::HeapObjectsFiltering filtering)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006565 : filtering_(filtering),
6566 filter_(NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006567 Init();
6568}
6569
6570
6571HeapIterator::~HeapIterator() {
6572 Shutdown();
6573}
6574
6575
6576void HeapIterator::Init() {
6577 // Start the iteration.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006578 space_iterator_ = new SpaceIterator;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006579 switch (filtering_) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006580 case kFilterUnreachable:
6581 filter_ = new UnreachableObjectsFilter;
6582 break;
6583 default:
6584 break;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006585 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006586 object_iterator_ = space_iterator_->next();
6587}
6588
6589
6590void HeapIterator::Shutdown() {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006591#ifdef DEBUG
whesse@chromium.org023421e2010-12-21 12:19:12 +00006592 // Assert that in filtering mode we have iterated through all
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006593 // objects. Otherwise, heap will be left in an inconsistent state.
whesse@chromium.org023421e2010-12-21 12:19:12 +00006594 if (filtering_ != kNoFiltering) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006595 ASSERT(object_iterator_ == NULL);
6596 }
6597#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006598 // Make sure the last iterator is deallocated.
6599 delete space_iterator_;
6600 space_iterator_ = NULL;
6601 object_iterator_ = NULL;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006602 delete filter_;
6603 filter_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006604}
6605
6606
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006607HeapObject* HeapIterator::next() {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006608 if (filter_ == NULL) return NextObject();
6609
6610 HeapObject* obj = NextObject();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006611 while (obj != NULL && filter_->SkipObject(obj)) obj = NextObject();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006612 return obj;
6613}
6614
6615
6616HeapObject* HeapIterator::NextObject() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006617 // No iterator means we are done.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006618 if (object_iterator_ == NULL) return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006619
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006620 if (HeapObject* obj = object_iterator_->next_object()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006621 // If the current iterator has more objects we are fine.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006622 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006623 } else {
6624 // Go though the spaces looking for one that has objects.
6625 while (space_iterator_->has_next()) {
6626 object_iterator_ = space_iterator_->next();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006627 if (HeapObject* obj = object_iterator_->next_object()) {
6628 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629 }
6630 }
6631 }
6632 // Done with the last space.
6633 object_iterator_ = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006634 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006635}
6636
6637
6638void HeapIterator::reset() {
6639 // Restart the iterator.
6640 Shutdown();
6641 Init();
6642}
6643
6644
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006645#if defined(DEBUG) || defined(LIVE_OBJECT_LIST)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006646
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006647Object* const PathTracer::kAnyGlobalObject = reinterpret_cast<Object*>(NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006648
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006649class PathTracer::MarkVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006650 public:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006651 explicit MarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652 void VisitPointers(Object** start, Object** end) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006653 // Scan all HeapObject pointers in [start, end)
6654 for (Object** p = start; !tracer_->found() && (p < end); p++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006655 if ((*p)->IsHeapObject())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006656 tracer_->MarkRecursively(p, this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006657 }
6658 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006659
6660 private:
6661 PathTracer* tracer_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006662};
6663
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006664
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006665class PathTracer::UnmarkVisitor: public ObjectVisitor {
6666 public:
6667 explicit UnmarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
6668 void VisitPointers(Object** start, Object** end) {
6669 // Scan all HeapObject pointers in [start, end)
6670 for (Object** p = start; p < end; p++) {
6671 if ((*p)->IsHeapObject())
6672 tracer_->UnmarkRecursively(p, this);
6673 }
6674 }
6675
6676 private:
6677 PathTracer* tracer_;
6678};
6679
6680
6681void PathTracer::VisitPointers(Object** start, Object** end) {
6682 bool done = ((what_to_find_ == FIND_FIRST) && found_target_);
6683 // Visit all HeapObject pointers in [start, end)
6684 for (Object** p = start; !done && (p < end); p++) {
6685 if ((*p)->IsHeapObject()) {
6686 TracePathFrom(p);
6687 done = ((what_to_find_ == FIND_FIRST) && found_target_);
6688 }
6689 }
6690}
6691
6692
6693void PathTracer::Reset() {
6694 found_target_ = false;
6695 object_stack_.Clear();
6696}
6697
6698
6699void PathTracer::TracePathFrom(Object** root) {
6700 ASSERT((search_target_ == kAnyGlobalObject) ||
6701 search_target_->IsHeapObject());
6702 found_target_in_trace_ = false;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00006703 Reset();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006704
6705 MarkVisitor mark_visitor(this);
6706 MarkRecursively(root, &mark_visitor);
6707
6708 UnmarkVisitor unmark_visitor(this);
6709 UnmarkRecursively(root, &unmark_visitor);
6710
6711 ProcessResults();
6712}
6713
6714
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006715static bool SafeIsNativeContext(HeapObject* obj) {
6716 return obj->map() == obj->GetHeap()->raw_unchecked_native_context_map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006717}
6718
6719
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006720void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006721 if (!(*p)->IsHeapObject()) return;
6722
6723 HeapObject* obj = HeapObject::cast(*p);
6724
6725 Object* map = obj->map();
6726
6727 if (!map->IsHeapObject()) return; // visited before
6728
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006729 if (found_target_in_trace_) return; // stop if target found
6730 object_stack_.Add(obj);
6731 if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) ||
6732 (obj == search_target_)) {
6733 found_target_in_trace_ = true;
6734 found_target_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006735 return;
6736 }
6737
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006738 bool is_native_context = SafeIsNativeContext(obj);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006739
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740 // not visited yet
6741 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
6742
6743 Address map_addr = map_p->address();
6744
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006745 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_addr + kMarkTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006746
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006747 // Scan the object body.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006748 if (is_native_context && (visit_mode_ == VISIT_ONLY_STRONG)) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006749 // This is specialized to scan Context's properly.
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00006750 Object** start = reinterpret_cast<Object**>(obj->address() +
6751 Context::kHeaderSize);
6752 Object** end = reinterpret_cast<Object**>(obj->address() +
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006753 Context::kHeaderSize + Context::FIRST_WEAK_SLOT * kPointerSize);
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00006754 mark_visitor->VisitPointers(start, end);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006755 } else {
6756 obj->IterateBody(map_p->instance_type(),
6757 obj->SizeFromMap(map_p),
6758 mark_visitor);
6759 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006760
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006761 // Scan the map after the body because the body is a lot more interesting
6762 // when doing leak detection.
6763 MarkRecursively(&map, mark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006764
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006765 if (!found_target_in_trace_) // don't pop if found the target
6766 object_stack_.RemoveLast();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006767}
6768
6769
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006770void PathTracer::UnmarkRecursively(Object** p, UnmarkVisitor* unmark_visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006771 if (!(*p)->IsHeapObject()) return;
6772
6773 HeapObject* obj = HeapObject::cast(*p);
6774
6775 Object* map = obj->map();
6776
6777 if (map->IsHeapObject()) return; // unmarked already
6778
6779 Address map_addr = reinterpret_cast<Address>(map);
6780
6781 map_addr -= kMarkTag;
6782
6783 ASSERT_TAG_ALIGNED(map_addr);
6784
6785 HeapObject* map_p = HeapObject::FromAddress(map_addr);
6786
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006787 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006788
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006789 UnmarkRecursively(reinterpret_cast<Object**>(&map_p), unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006790
6791 obj->IterateBody(Map::cast(map_p)->instance_type(),
6792 obj->SizeFromMap(Map::cast(map_p)),
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006793 unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006794}
6795
6796
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006797void PathTracer::ProcessResults() {
6798 if (found_target_) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006799 PrintF("=====================================\n");
6800 PrintF("==== Path to object ====\n");
6801 PrintF("=====================================\n\n");
6802
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006803 ASSERT(!object_stack_.is_empty());
6804 for (int i = 0; i < object_stack_.length(); i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006805 if (i > 0) PrintF("\n |\n |\n V\n\n");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006806 Object* obj = object_stack_[i];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006807 obj->Print();
6808 }
6809 PrintF("=====================================\n");
6810 }
6811}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006812#endif // DEBUG || LIVE_OBJECT_LIST
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006813
6814
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006815#ifdef DEBUG
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00006816// Triggers a depth-first traversal of reachable objects from one
6817// given root object and finds a path to a specific heap object and
6818// prints it.
6819void Heap::TracePathToObjectFrom(Object* target, Object* root) {
6820 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
6821 tracer.VisitPointer(&root);
6822}
6823
6824
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006825// Triggers a depth-first traversal of reachable objects from roots
6826// and finds a path to a specific heap object and prints it.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00006827void Heap::TracePathToObject(Object* target) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006828 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
6829 IterateRoots(&tracer, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006830}
6831
6832
6833// Triggers a depth-first traversal of reachable objects from roots
6834// and finds a path to any global object and prints it. Useful for
6835// determining the source for leaks of global objects.
6836void Heap::TracePathToGlobal() {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006837 PathTracer tracer(PathTracer::kAnyGlobalObject,
6838 PathTracer::FIND_ALL,
6839 VISIT_ALL);
6840 IterateRoots(&tracer, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006841}
6842#endif
6843
6844
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006845static intptr_t CountTotalHolesSize() {
6846 intptr_t holes_size = 0;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006847 OldSpaces spaces;
6848 for (OldSpace* space = spaces.next();
6849 space != NULL;
6850 space = spaces.next()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006851 holes_size += space->Waste() + space->Available();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006852 }
6853 return holes_size;
6854}
6855
6856
rossberg@chromium.org994edf62012-02-06 10:12:55 +00006857GCTracer::GCTracer(Heap* heap,
6858 const char* gc_reason,
6859 const char* collector_reason)
kasper.lund7276f142008-07-30 08:49:36 +00006860 : start_time_(0.0),
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00006861 start_object_size_(0),
6862 start_memory_size_(0),
kasper.lund7276f142008-07-30 08:49:36 +00006863 gc_count_(0),
6864 full_gc_count_(0),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006865 allocated_since_last_gc_(0),
6866 spent_in_mutator_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006867 promoted_objects_size_(0),
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00006868 nodes_died_in_new_space_(0),
6869 nodes_copied_in_new_space_(0),
6870 nodes_promoted_(0),
rossberg@chromium.org994edf62012-02-06 10:12:55 +00006871 heap_(heap),
6872 gc_reason_(gc_reason),
6873 collector_reason_(collector_reason) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006874 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
kasper.lund7276f142008-07-30 08:49:36 +00006875 start_time_ = OS::TimeCurrentMillis();
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00006876 start_object_size_ = heap_->SizeOfObjects();
6877 start_memory_size_ = heap_->isolate()->memory_allocator()->Size();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006878
6879 for (int i = 0; i < Scope::kNumberOfScopes; i++) {
6880 scopes_[i] = 0;
6881 }
6882
6883 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize();
6884
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006885 allocated_since_last_gc_ =
6886 heap_->SizeOfObjects() - heap_->alive_after_last_gc_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006887
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006888 if (heap_->last_gc_end_timestamp_ > 0) {
6889 spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006890 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006891
6892 steps_count_ = heap_->incremental_marking()->steps_count();
6893 steps_took_ = heap_->incremental_marking()->steps_took();
6894 longest_step_ = heap_->incremental_marking()->longest_step();
6895 steps_count_since_last_gc_ =
6896 heap_->incremental_marking()->steps_count_since_last_gc();
6897 steps_took_since_last_gc_ =
6898 heap_->incremental_marking()->steps_took_since_last_gc();
kasper.lund7276f142008-07-30 08:49:36 +00006899}
6900
6901
6902GCTracer::~GCTracer() {
kasper.lund7276f142008-07-30 08:49:36 +00006903 // Printf ONE line iff flag is set.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006904 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
6905
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006906 bool first_gc = (heap_->last_gc_end_timestamp_ == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006907
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006908 heap_->alive_after_last_gc_ = heap_->SizeOfObjects();
6909 heap_->last_gc_end_timestamp_ = OS::TimeCurrentMillis();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006910
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006911 int time = static_cast<int>(heap_->last_gc_end_timestamp_ - start_time_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006912
6913 // Update cumulative GC statistics if required.
6914 if (FLAG_print_cumulative_gc_stat) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006915 heap_->total_gc_time_ms_ += time;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006916 heap_->max_gc_pause_ = Max(heap_->max_gc_pause_, time);
6917 heap_->max_alive_after_gc_ = Max(heap_->max_alive_after_gc_,
6918 heap_->alive_after_last_gc_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006919 if (!first_gc) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006920 heap_->min_in_mutator_ = Min(heap_->min_in_mutator_,
6921 static_cast<int>(spent_in_mutator_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006922 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006923 } else if (FLAG_trace_gc_verbose) {
6924 heap_->total_gc_time_ms_ += time;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006925 }
6926
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006927 if (collector_ == SCAVENGER && FLAG_trace_gc_ignore_scavenger) return;
6928
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006929 PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init());
rossberg@chromium.org994edf62012-02-06 10:12:55 +00006930
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006931 if (!FLAG_trace_gc_nvp) {
6932 int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]);
6933
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00006934 double end_memory_size_mb =
6935 static_cast<double>(heap_->isolate()->memory_allocator()->Size()) / MB;
6936
6937 PrintF("%s %.1f (%.1f) -> %.1f (%.1f) MB, ",
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006938 CollectorString(),
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00006939 static_cast<double>(start_object_size_) / MB,
6940 static_cast<double>(start_memory_size_) / MB,
6941 SizeOfHeapObjects(),
6942 end_memory_size_mb);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006943
6944 if (external_time > 0) PrintF("%d / ", external_time);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006945 PrintF("%d ms", time);
6946 if (steps_count_ > 0) {
6947 if (collector_ == SCAVENGER) {
6948 PrintF(" (+ %d ms in %d steps since last GC)",
6949 static_cast<int>(steps_took_since_last_gc_),
6950 steps_count_since_last_gc_);
6951 } else {
6952 PrintF(" (+ %d ms in %d steps since start of marking, "
6953 "biggest step %f ms)",
6954 static_cast<int>(steps_took_),
6955 steps_count_,
6956 longest_step_);
6957 }
6958 }
rossberg@chromium.org994edf62012-02-06 10:12:55 +00006959
6960 if (gc_reason_ != NULL) {
6961 PrintF(" [%s]", gc_reason_);
6962 }
6963
6964 if (collector_reason_ != NULL) {
6965 PrintF(" [%s]", collector_reason_);
6966 }
6967
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006968 PrintF(".\n");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006969 } else {
6970 PrintF("pause=%d ", time);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006971 PrintF("mutator=%d ", static_cast<int>(spent_in_mutator_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006972 PrintF("gc=");
6973 switch (collector_) {
6974 case SCAVENGER:
6975 PrintF("s");
6976 break;
6977 case MARK_COMPACTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006978 PrintF("ms");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006979 break;
6980 default:
6981 UNREACHABLE();
6982 }
6983 PrintF(" ");
6984
6985 PrintF("external=%d ", static_cast<int>(scopes_[Scope::EXTERNAL]));
6986 PrintF("mark=%d ", static_cast<int>(scopes_[Scope::MC_MARK]));
6987 PrintF("sweep=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP]));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006988 PrintF("sweepns=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP_NEWSPACE]));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00006989 PrintF("evacuate=%d ", static_cast<int>(scopes_[Scope::MC_EVACUATE_PAGES]));
6990 PrintF("new_new=%d ",
6991 static_cast<int>(scopes_[Scope::MC_UPDATE_NEW_TO_NEW_POINTERS]));
6992 PrintF("root_new=%d ",
6993 static_cast<int>(scopes_[Scope::MC_UPDATE_ROOT_TO_NEW_POINTERS]));
6994 PrintF("old_new=%d ",
6995 static_cast<int>(scopes_[Scope::MC_UPDATE_OLD_TO_NEW_POINTERS]));
6996 PrintF("compaction_ptrs=%d ",
6997 static_cast<int>(scopes_[Scope::MC_UPDATE_POINTERS_TO_EVACUATED]));
6998 PrintF("intracompaction_ptrs=%d ", static_cast<int>(scopes_[
6999 Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED]));
7000 PrintF("misc_compaction=%d ",
7001 static_cast<int>(scopes_[Scope::MC_UPDATE_MISC_POINTERS]));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007002
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007003 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_object_size_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007004 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007005 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ",
7006 in_free_list_or_wasted_before_gc_);
7007 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007008
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007009 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_);
7010 PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_);
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00007011 PrintF("nodes_died_in_new=%d ", nodes_died_in_new_space_);
7012 PrintF("nodes_copied_in_new=%d ", nodes_copied_in_new_space_);
7013 PrintF("nodes_promoted=%d ", nodes_promoted_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007014
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007015 if (collector_ == SCAVENGER) {
7016 PrintF("stepscount=%d ", steps_count_since_last_gc_);
7017 PrintF("stepstook=%d ", static_cast<int>(steps_took_since_last_gc_));
7018 } else {
7019 PrintF("stepscount=%d ", steps_count_);
7020 PrintF("stepstook=%d ", static_cast<int>(steps_took_));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007021 PrintF("longeststep=%.f ", longest_step_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007022 }
7023
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007024 PrintF("\n");
7025 }
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007026
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007027 heap_->PrintShortHeapStatistics();
kasper.lund7276f142008-07-30 08:49:36 +00007028}
7029
7030
7031const char* GCTracer::CollectorString() {
7032 switch (collector_) {
7033 case SCAVENGER:
7034 return "Scavenge";
7035 case MARK_COMPACTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007036 return "Mark-sweep";
kasper.lund7276f142008-07-30 08:49:36 +00007037 }
7038 return "Unknown GC";
7039}
7040
7041
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007042int KeyedLookupCache::Hash(Map* map, String* name) {
7043 // Uses only lower 32 bits if pointers are larger.
7044 uintptr_t addr_hash =
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007045 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00007046 return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007047}
7048
7049
7050int KeyedLookupCache::Lookup(Map* map, String* name) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007051 int index = (Hash(map, name) & kHashMask);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007052 for (int i = 0; i < kEntriesPerBucket; i++) {
7053 Key& key = keys_[index + i];
7054 if ((key.map == map) && key.name->Equals(name)) {
7055 return field_offsets_[index + i];
7056 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007057 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007058 return kNotFound;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007059}
7060
7061
7062void KeyedLookupCache::Update(Map* map, String* name, int field_offset) {
7063 String* symbol;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007064 if (HEAP->LookupSymbolIfExists(name, &symbol)) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007065 int index = (Hash(map, symbol) & kHashMask);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007066 // After a GC there will be free slots, so we use them in order (this may
7067 // help to get the most frequently used one in position 0).
7068 for (int i = 0; i< kEntriesPerBucket; i++) {
7069 Key& key = keys_[index];
7070 Object* free_entry_indicator = NULL;
7071 if (key.map == free_entry_indicator) {
7072 key.map = map;
7073 key.name = symbol;
7074 field_offsets_[index + i] = field_offset;
7075 return;
7076 }
7077 }
7078 // No free entry found in this bucket, so we move them all down one and
7079 // put the new entry at position zero.
7080 for (int i = kEntriesPerBucket - 1; i > 0; i--) {
7081 Key& key = keys_[index + i];
7082 Key& key2 = keys_[index + i - 1];
7083 key = key2;
7084 field_offsets_[index + i] = field_offsets_[index + i - 1];
7085 }
7086
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007087 // Write the new first entry.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007088 Key& key = keys_[index];
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007089 key.map = map;
7090 key.name = symbol;
7091 field_offsets_[index] = field_offset;
7092 }
7093}
7094
7095
7096void KeyedLookupCache::Clear() {
7097 for (int index = 0; index < kLength; index++) keys_[index].map = NULL;
7098}
7099
7100
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007101void DescriptorLookupCache::Clear() {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007102 for (int index = 0; index < kLength; index++) keys_[index].source = NULL;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007103}
7104
7105
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007106#ifdef DEBUG
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007107void Heap::GarbageCollectionGreedyCheck() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007108 ASSERT(FLAG_gc_greedy);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007109 if (isolate_->bootstrapper()->IsActive()) return;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007110 if (disallow_allocation_failure()) return;
7111 CollectGarbage(NEW_SPACE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007112}
7113#endif
7114
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007115
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007116TranscendentalCache::SubCache::SubCache(Type t)
7117 : type_(t),
7118 isolate_(Isolate::Current()) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007119 uint32_t in0 = 0xffffffffu; // Bit-pattern for a NaN that isn't
7120 uint32_t in1 = 0xffffffffu; // generated by the FPU.
7121 for (int i = 0; i < kCacheSize; i++) {
7122 elements_[i].in[0] = in0;
7123 elements_[i].in[1] = in1;
7124 elements_[i].output = NULL;
7125 }
7126}
7127
7128
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007129void TranscendentalCache::Clear() {
7130 for (int i = 0; i < kNumberOfCaches; i++) {
7131 if (caches_[i] != NULL) {
7132 delete caches_[i];
7133 caches_[i] = NULL;
7134 }
7135 }
7136}
7137
7138
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007139void ExternalStringTable::CleanUp() {
7140 int last = 0;
7141 for (int i = 0; i < new_space_strings_.length(); ++i) {
danno@chromium.org72204d52012-10-31 10:02:10 +00007142 if (new_space_strings_[i] == heap_->the_hole_value()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007143 continue;
7144 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007145 if (heap_->InNewSpace(new_space_strings_[i])) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007146 new_space_strings_[last++] = new_space_strings_[i];
7147 } else {
7148 old_space_strings_.Add(new_space_strings_[i]);
7149 }
7150 }
7151 new_space_strings_.Rewind(last);
7152 last = 0;
7153 for (int i = 0; i < old_space_strings_.length(); ++i) {
danno@chromium.org72204d52012-10-31 10:02:10 +00007154 if (old_space_strings_[i] == heap_->the_hole_value()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007155 continue;
7156 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007157 ASSERT(!heap_->InNewSpace(old_space_strings_[i]));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007158 old_space_strings_[last++] = old_space_strings_[i];
7159 }
7160 old_space_strings_.Rewind(last);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007161#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007162 if (FLAG_verify_heap) {
7163 Verify();
7164 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007165#endif
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007166}
7167
7168
7169void ExternalStringTable::TearDown() {
7170 new_space_strings_.Free();
7171 old_space_strings_.Free();
7172}
7173
7174
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007175void Heap::QueueMemoryChunkForFree(MemoryChunk* chunk) {
7176 chunk->set_next_chunk(chunks_queued_for_free_);
7177 chunks_queued_for_free_ = chunk;
7178}
7179
7180
7181void Heap::FreeQueuedChunks() {
7182 if (chunks_queued_for_free_ == NULL) return;
7183 MemoryChunk* next;
7184 MemoryChunk* chunk;
7185 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
7186 next = chunk->next_chunk();
7187 chunk->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
7188
7189 if (chunk->owner()->identity() == LO_SPACE) {
7190 // StoreBuffer::Filter relies on MemoryChunk::FromAnyPointerAddress.
7191 // If FromAnyPointerAddress encounters a slot that belongs to a large
7192 // chunk queued for deletion it will fail to find the chunk because
7193 // it try to perform a search in the list of pages owned by of the large
7194 // object space and queued chunks were detached from that list.
7195 // To work around this we split large chunk into normal kPageSize aligned
danno@chromium.org2c456792011-11-11 12:00:53 +00007196 // pieces and initialize size, owner and flags field of every piece.
7197 // If FromAnyPointerAddress encounters a slot that belongs to one of
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007198 // these smaller pieces it will treat it as a slot on a normal Page.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007199 Address chunk_end = chunk->address() + chunk->size();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007200 MemoryChunk* inner = MemoryChunk::FromAddress(
7201 chunk->address() + Page::kPageSize);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007202 MemoryChunk* inner_last = MemoryChunk::FromAddress(chunk_end - 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007203 while (inner <= inner_last) {
7204 // Size of a large chunk is always a multiple of
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007205 // OS::AllocateAlignment() so there is always
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007206 // enough space for a fake MemoryChunk header.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007207 Address area_end = Min(inner->address() + Page::kPageSize, chunk_end);
7208 // Guard against overflow.
7209 if (area_end < inner->address()) area_end = chunk_end;
7210 inner->SetArea(inner->address(), area_end);
danno@chromium.org2c456792011-11-11 12:00:53 +00007211 inner->set_size(Page::kPageSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007212 inner->set_owner(lo_space());
7213 inner->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
7214 inner = MemoryChunk::FromAddress(
7215 inner->address() + Page::kPageSize);
7216 }
7217 }
7218 }
7219 isolate_->heap()->store_buffer()->Compact();
7220 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED);
7221 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
7222 next = chunk->next_chunk();
7223 isolate_->memory_allocator()->Free(chunk);
7224 }
7225 chunks_queued_for_free_ = NULL;
7226}
7227
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00007228
7229void Heap::RememberUnmappedPage(Address page, bool compacted) {
7230 uintptr_t p = reinterpret_cast<uintptr_t>(page);
7231 // Tag the page pointer to make it findable in the dump file.
7232 if (compacted) {
7233 p ^= 0xc1ead & (Page::kPageSize - 1); // Cleared.
7234 } else {
7235 p ^= 0x1d1ed & (Page::kPageSize - 1); // I died.
7236 }
7237 remembered_unmapped_pages_[remembered_unmapped_pages_index_] =
7238 reinterpret_cast<Address>(p);
7239 remembered_unmapped_pages_index_++;
7240 remembered_unmapped_pages_index_ %= kRememberedUnmappedPages;
7241}
7242
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00007243
7244void Heap::ClearObjectStats(bool clear_last_time_stats) {
7245 memset(object_counts_, 0, sizeof(object_counts_));
7246 memset(object_sizes_, 0, sizeof(object_sizes_));
7247 if (clear_last_time_stats) {
7248 memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_));
7249 memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_));
7250 }
7251}
7252
7253
7254static LazyMutex checkpoint_object_stats_mutex = LAZY_MUTEX_INITIALIZER;
7255
7256
7257void Heap::CheckpointObjectStats() {
7258 ScopedLock lock(checkpoint_object_stats_mutex.Pointer());
7259 Counters* counters = isolate()->counters();
7260#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7261 counters->count_of_##name()->Increment( \
7262 static_cast<int>(object_counts_[name])); \
7263 counters->count_of_##name()->Decrement( \
7264 static_cast<int>(object_counts_last_time_[name])); \
7265 counters->size_of_##name()->Increment( \
7266 static_cast<int>(object_sizes_[name])); \
7267 counters->size_of_##name()->Decrement( \
7268 static_cast<int>(object_sizes_last_time_[name]));
7269 INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7270#undef ADJUST_LAST_TIME_OBJECT_COUNT
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007271 int index;
7272#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7273 index = FIRST_CODE_KIND_SUB_TYPE + Code::name; \
7274 counters->count_of_CODE_TYPE_##name()->Increment( \
7275 static_cast<int>(object_counts_[index])); \
7276 counters->count_of_CODE_TYPE_##name()->Decrement( \
7277 static_cast<int>(object_counts_last_time_[index])); \
7278 counters->size_of_CODE_TYPE_##name()->Increment( \
7279 static_cast<int>(object_sizes_[index])); \
7280 counters->size_of_CODE_TYPE_##name()->Decrement( \
7281 static_cast<int>(object_sizes_last_time_[index]));
7282 CODE_KIND_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7283#undef ADJUST_LAST_TIME_OBJECT_COUNT
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007284#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7285 index = FIRST_FIXED_ARRAY_SUB_TYPE + name; \
7286 counters->count_of_FIXED_ARRAY_##name()->Increment( \
7287 static_cast<int>(object_counts_[index])); \
7288 counters->count_of_FIXED_ARRAY_##name()->Decrement( \
7289 static_cast<int>(object_counts_last_time_[index])); \
7290 counters->size_of_FIXED_ARRAY_##name()->Increment( \
7291 static_cast<int>(object_sizes_[index])); \
7292 counters->size_of_FIXED_ARRAY_##name()->Decrement( \
7293 static_cast<int>(object_sizes_last_time_[index]));
7294 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7295#undef ADJUST_LAST_TIME_OBJECT_COUNT
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007296
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00007297 memcpy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
7298 memcpy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
7299 ClearObjectStats();
7300}
7301
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007302} } // namespace v8::internal