blob: 5e760c3e6bbc853c79fc4c76e1aaae5871547618 [file] [log] [blame]
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "accessors.h"
31#include "api.h"
32#include "bootstrapper.h"
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000033#include "codegen.h"
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000034#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include "debug.h"
ricow@chromium.org4f693d62011-07-04 14:01:31 +000036#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "global-handles.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000038#include "heap-profiler.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000039#include "incremental-marking.h"
ager@chromium.org0ee099b2011-01-25 14:06:47 +000040#include "liveobjectlist-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "mark-compact.h"
42#include "natives.h"
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000043#include "objects-visiting.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000044#include "objects-visiting-inl.h"
fschneider@chromium.org7d10be52012-04-10 12:30:14 +000045#include "once.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000046#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047#include "scopeinfo.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000048#include "snapshot.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000049#include "store-buffer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050#include "v8threads.h"
ulan@chromium.org56c14af2012-09-20 12:51:09 +000051#include "v8utils.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000052#include "vm-state-inl.h"
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000053#if V8_TARGET_ARCH_ARM && !V8_INTERPRETED_REGEXP
ager@chromium.org18ad94b2009-09-02 08:22:29 +000054#include "regexp-macro-assembler.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000055#include "arm/regexp-macro-assembler-arm.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000056#endif
lrn@chromium.org7516f052011-03-30 08:52:27 +000057#if V8_TARGET_ARCH_MIPS && !V8_INTERPRETED_REGEXP
58#include "regexp-macro-assembler.h"
59#include "mips/regexp-macro-assembler-mips.h"
60#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
kasper.lund7276f142008-07-30 08:49:36 +000065
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000066Heap::Heap()
67 : isolate_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068// semispace_size_ should be a power of 2 and old_generation_size_ should be
69// a multiple of Page::kPageSize.
mmassi@chromium.org7028c052012-06-13 11:51:58 +000070#if defined(V8_TARGET_ARCH_X64)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000071#define LUMP_OF_MEMORY (2 * MB)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000072 code_range_size_(512*MB),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000073#else
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000074#define LUMP_OF_MEMORY MB
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000075 code_range_size_(0),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000076#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +000077#if defined(ANDROID)
78 reserved_semispace_size_(4 * Max(LUMP_OF_MEMORY, Page::kPageSize)),
79 max_semispace_size_(4 * Max(LUMP_OF_MEMORY, Page::kPageSize)),
80 initial_semispace_size_(Page::kPageSize),
81 max_old_generation_size_(192*MB),
82 max_executable_size_(max_old_generation_size_),
83#else
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000084 reserved_semispace_size_(8 * Max(LUMP_OF_MEMORY, Page::kPageSize)),
85 max_semispace_size_(8 * Max(LUMP_OF_MEMORY, Page::kPageSize)),
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000086 initial_semispace_size_(Page::kPageSize),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000087 max_old_generation_size_(700ul * LUMP_OF_MEMORY),
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000088 max_executable_size_(256l * LUMP_OF_MEMORY),
mmassi@chromium.org7028c052012-06-13 11:51:58 +000089#endif
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000090
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091// Variables set based on semispace_size_ and old_generation_size_ in
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000092// ConfigureHeap (survived_since_last_expansion_, external_allocation_limit_)
ager@chromium.org3811b432009-10-28 14:53:37 +000093// Will be 4 * reserved_semispace_size_ to ensure that young
94// generation can be aligned to its size.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000095 survived_since_last_expansion_(0),
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +000096 sweep_generation_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000097 always_allocate_scope_depth_(0),
98 linear_allocation_scope_depth_(0),
99 contexts_disposed_(0),
danno@chromium.org88aa0582012-03-23 15:11:57 +0000100 global_ic_age_(0),
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000101 flush_monomorphic_ics_(false),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000102 scan_on_scavenge_pages_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000103 new_space_(this),
104 old_pointer_space_(NULL),
105 old_data_space_(NULL),
106 code_space_(NULL),
107 map_space_(NULL),
108 cell_space_(NULL),
109 lo_space_(NULL),
110 gc_state_(NOT_IN_GC),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000111 gc_post_processing_depth_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000112 ms_count_(0),
113 gc_count_(0),
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000114 remembered_unmapped_pages_index_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000115 unflattened_strings_length_(0),
kasper.lund7276f142008-07-30 08:49:36 +0000116#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000117 allocation_allowed_(true),
118 allocation_timeout_(0),
119 disallow_allocation_failure_(false),
120 debug_utils_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121#endif // DEBUG
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000122 new_space_high_promotion_mode_active_(false),
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000123 old_gen_promotion_limit_(kMinimumPromotionLimit),
124 old_gen_allocation_limit_(kMinimumAllocationLimit),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000125 old_gen_limit_factor_(1),
126 size_of_old_gen_at_last_old_space_gc_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000127 external_allocation_limit_(0),
128 amount_of_external_allocated_memory_(0),
129 amount_of_external_allocated_memory_at_last_global_gc_(0),
130 old_gen_exhausted_(false),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000131 store_buffer_rebuilder_(store_buffer()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000132 hidden_symbol_(NULL),
133 global_gc_prologue_callback_(NULL),
134 global_gc_epilogue_callback_(NULL),
135 gc_safe_size_of_old_object_(NULL),
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000136 total_regexp_code_generated_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 tracer_(NULL),
138 young_survivors_after_last_gc_(0),
139 high_survival_rate_period_length_(0),
140 survival_rate_(0),
141 previous_survival_rate_trend_(Heap::STABLE),
142 survival_rate_trend_(Heap::STABLE),
143 max_gc_pause_(0),
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000144 total_gc_time_ms_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145 max_alive_after_gc_(0),
146 min_in_mutator_(kMaxInt),
147 alive_after_last_gc_(0),
148 last_gc_end_timestamp_(0.0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000149 store_buffer_(this),
150 marking_(this),
151 incremental_marking_(this),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000152 number_idle_notifications_(0),
153 last_idle_notification_gc_count_(0),
154 last_idle_notification_gc_count_init_(false),
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +0000155 mark_sweeps_since_idle_round_started_(0),
156 ms_count_at_last_idle_notification_(0),
157 gc_count_at_last_idle_gc_(0),
158 scavenges_since_last_idle_round_(kIdleScavengeThreshold),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000159 promotion_queue_(this),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 configured_(false),
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000161 chunks_queued_for_free_(NULL),
162 relocation_mutex_(NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000163 // Allow build-time customization of the max semispace size. Building
164 // V8 with snapshots and a non-default max semispace size is much
165 // easier if you can define it as part of the build environment.
166#if defined(V8_MAX_SEMISPACE_SIZE)
167 max_semispace_size_ = reserved_semispace_size_ = V8_MAX_SEMISPACE_SIZE;
168#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000169
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000170 intptr_t max_virtual = OS::MaxVirtualMemory();
171
172 if (max_virtual > 0) {
173 if (code_range_size_ > 0) {
174 // Reserve no more than 1/8 of the memory for the code range.
175 code_range_size_ = Min(code_range_size_, max_virtual >> 3);
176 }
177 }
178
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000179 memset(roots_, 0, sizeof(roots_[0]) * kRootListLength);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000180 native_contexts_list_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000181 mark_compact_collector_.heap_ = this;
182 external_string_table_.heap_ = this;
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000183 // Put a dummy entry in the remembered pages so we can find the list the
184 // minidump even if there are no real unmapped pages.
185 RememberUnmappedPage(NULL, false);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000186
187 ClearObjectStats(true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000188}
189
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000190
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000191intptr_t Heap::Capacity() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000192 if (!HasBeenSetUp()) return 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000193
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000194 return new_space_.Capacity() +
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000195 old_pointer_space_->Capacity() +
196 old_data_space_->Capacity() +
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000197 code_space_->Capacity() +
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000198 map_space_->Capacity() +
199 cell_space_->Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000200}
201
202
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000203intptr_t Heap::CommittedMemory() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000204 if (!HasBeenSetUp()) return 0;
ager@chromium.org3811b432009-10-28 14:53:37 +0000205
206 return new_space_.CommittedMemory() +
207 old_pointer_space_->CommittedMemory() +
208 old_data_space_->CommittedMemory() +
209 code_space_->CommittedMemory() +
210 map_space_->CommittedMemory() +
211 cell_space_->CommittedMemory() +
212 lo_space_->Size();
213}
214
danno@chromium.org72204d52012-10-31 10:02:10 +0000215
216size_t Heap::CommittedPhysicalMemory() {
217 if (!HasBeenSetUp()) return 0;
218
219 return new_space_.CommittedPhysicalMemory() +
220 old_pointer_space_->CommittedPhysicalMemory() +
221 old_data_space_->CommittedPhysicalMemory() +
222 code_space_->CommittedPhysicalMemory() +
223 map_space_->CommittedPhysicalMemory() +
224 cell_space_->CommittedPhysicalMemory() +
225 lo_space_->CommittedPhysicalMemory();
226}
227
228
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000229intptr_t Heap::CommittedMemoryExecutable() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000230 if (!HasBeenSetUp()) return 0;
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000231
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000232 return isolate()->memory_allocator()->SizeExecutable();
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000233}
234
ager@chromium.org3811b432009-10-28 14:53:37 +0000235
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000236intptr_t Heap::Available() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000237 if (!HasBeenSetUp()) return 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000239 return new_space_.Available() +
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000240 old_pointer_space_->Available() +
241 old_data_space_->Available() +
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000242 code_space_->Available() +
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000243 map_space_->Available() +
244 cell_space_->Available();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000245}
246
247
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000248bool Heap::HasBeenSetUp() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000249 return old_pointer_space_ != NULL &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000250 old_data_space_ != NULL &&
251 code_space_ != NULL &&
252 map_space_ != NULL &&
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000253 cell_space_ != NULL &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000254 lo_space_ != NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000255}
256
257
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000258int Heap::GcSafeSizeOfOldObject(HeapObject* object) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000259 if (IntrusiveMarking::IsMarked(object)) {
260 return IntrusiveMarking::SizeOfMarkedObject(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000261 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000262 return object->SizeFromMap(object->map());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000263}
264
265
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000266GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space,
267 const char** reason) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000268 // Is global GC requested?
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000269 if (space != NEW_SPACE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000270 isolate_->counters()->gc_compactor_caused_by_request()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000271 *reason = "GC in old space requested";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000272 return MARK_COMPACTOR;
273 }
274
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000275 if (FLAG_gc_global || (FLAG_stress_compaction && (gc_count_ & 1) != 0)) {
276 *reason = "GC in old space forced by flags";
277 return MARK_COMPACTOR;
278 }
279
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000280 // Is enough data promoted to justify a global GC?
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000281 if (OldGenerationPromotionLimitReached()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000282 isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000283 *reason = "promotion limit reached";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000284 return MARK_COMPACTOR;
285 }
286
287 // Have allocation in OLD and LO failed?
288 if (old_gen_exhausted_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000289 isolate_->counters()->
290 gc_compactor_caused_by_oldspace_exhaustion()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000291 *reason = "old generations exhausted";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000292 return MARK_COMPACTOR;
293 }
294
295 // Is there enough space left in OLD to guarantee that a scavenge can
296 // succeed?
297 //
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000298 // Note that MemoryAllocator->MaxAvailable() undercounts the memory available
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000299 // for object promotion. It counts only the bytes that the memory
300 // allocator has not yet allocated from the OS and assigned to any space,
301 // and does not count available bytes already in the old space or code
302 // space. Undercounting is safe---we may get an unrequested full GC when
303 // a scavenge would have succeeded.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 if (isolate_->memory_allocator()->MaxAvailable() <= new_space_.Size()) {
305 isolate_->counters()->
306 gc_compactor_caused_by_oldspace_exhaustion()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000307 *reason = "scavenge might not succeed";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000308 return MARK_COMPACTOR;
309 }
310
311 // Default
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000312 *reason = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000313 return SCAVENGER;
314}
315
316
317// TODO(1238405): Combine the infrastructure for --heap-stats and
318// --log-gc to avoid the complicated preprocessor and flag testing.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000319void Heap::ReportStatisticsBeforeGC() {
320 // Heap::ReportHeapStatistics will also log NewSpace statistics when
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000321 // compiled --log-gc is set. The following logic is used to avoid
322 // double logging.
323#ifdef DEBUG
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000324 if (FLAG_heap_stats || FLAG_log_gc) new_space_.CollectStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325 if (FLAG_heap_stats) {
326 ReportHeapStatistics("Before GC");
327 } else if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000328 new_space_.ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000329 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000330 if (FLAG_heap_stats || FLAG_log_gc) new_space_.ClearHistograms();
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000331#else
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000332 if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000333 new_space_.CollectStatistics();
334 new_space_.ReportStatistics();
335 new_space_.ClearHistograms();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000336 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000337#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338}
339
340
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000341void Heap::PrintShortHeapStatistics() {
342 if (!FLAG_trace_gc_verbose) return;
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000343 PrintPID("Memory allocator, used: %6" V8_PTR_PREFIX "d KB"
344 ", available: %6" V8_PTR_PREFIX "d KB\n",
345 isolate_->memory_allocator()->Size() / KB,
346 isolate_->memory_allocator()->Available() / KB);
347 PrintPID("New space, used: %6" V8_PTR_PREFIX "d KB"
348 ", available: %6" V8_PTR_PREFIX "d KB"
349 ", committed: %6" V8_PTR_PREFIX "d KB\n",
350 new_space_.Size() / KB,
351 new_space_.Available() / KB,
352 new_space_.CommittedMemory() / KB);
353 PrintPID("Old pointers, used: %6" V8_PTR_PREFIX "d KB"
354 ", available: %6" V8_PTR_PREFIX "d KB"
355 ", committed: %6" V8_PTR_PREFIX "d KB\n",
356 old_pointer_space_->SizeOfObjects() / KB,
357 old_pointer_space_->Available() / KB,
358 old_pointer_space_->CommittedMemory() / KB);
359 PrintPID("Old data space, used: %6" V8_PTR_PREFIX "d KB"
360 ", available: %6" V8_PTR_PREFIX "d KB"
361 ", committed: %6" V8_PTR_PREFIX "d KB\n",
362 old_data_space_->SizeOfObjects() / KB,
363 old_data_space_->Available() / KB,
364 old_data_space_->CommittedMemory() / KB);
365 PrintPID("Code space, used: %6" V8_PTR_PREFIX "d KB"
366 ", available: %6" V8_PTR_PREFIX "d KB"
367 ", committed: %6" V8_PTR_PREFIX "d KB\n",
368 code_space_->SizeOfObjects() / KB,
369 code_space_->Available() / KB,
370 code_space_->CommittedMemory() / KB);
371 PrintPID("Map space, used: %6" V8_PTR_PREFIX "d KB"
372 ", available: %6" V8_PTR_PREFIX "d KB"
373 ", committed: %6" V8_PTR_PREFIX "d KB\n",
374 map_space_->SizeOfObjects() / KB,
375 map_space_->Available() / KB,
376 map_space_->CommittedMemory() / KB);
377 PrintPID("Cell space, used: %6" V8_PTR_PREFIX "d KB"
378 ", available: %6" V8_PTR_PREFIX "d KB"
379 ", committed: %6" V8_PTR_PREFIX "d KB\n",
380 cell_space_->SizeOfObjects() / KB,
381 cell_space_->Available() / KB,
382 cell_space_->CommittedMemory() / KB);
383 PrintPID("Large object space, used: %6" V8_PTR_PREFIX "d KB"
384 ", available: %6" V8_PTR_PREFIX "d KB"
385 ", committed: %6" V8_PTR_PREFIX "d KB\n",
386 lo_space_->SizeOfObjects() / KB,
387 lo_space_->Available() / KB,
388 lo_space_->CommittedMemory() / KB);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000389 PrintPID("All spaces, used: %6" V8_PTR_PREFIX "d KB"
390 ", available: %6" V8_PTR_PREFIX "d KB"
391 ", committed: %6" V8_PTR_PREFIX "d KB\n",
392 this->SizeOfObjects() / KB,
393 this->Available() / KB,
394 this->CommittedMemory() / KB);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000395 PrintPID("Total time spent in GC : %d ms\n", total_gc_time_ms_);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000396}
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000397
398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399// TODO(1238405): Combine the infrastructure for --heap-stats and
400// --log-gc to avoid the complicated preprocessor and flag testing.
401void Heap::ReportStatisticsAfterGC() {
402 // Similar to the before GC, we use some complicated logic to ensure that
403 // NewSpace statistics are logged exactly once when --log-gc is turned on.
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000404#if defined(DEBUG)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000405 if (FLAG_heap_stats) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000406 new_space_.CollectStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000407 ReportHeapStatistics("After GC");
408 } else if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000409 new_space_.ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000411#else
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000412 if (FLAG_log_gc) new_space_.ReportStatistics();
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000413#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000415
416
417void Heap::GarbageCollectionPrologue() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 isolate_->transcendental_cache()->Clear();
ager@chromium.orgac091b72010-05-05 07:34:42 +0000419 ClearJSFunctionResultCaches();
kasper.lund7276f142008-07-30 08:49:36 +0000420 gc_count_++;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000421 unflattened_strings_length_ = 0;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000422
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000423 if (FLAG_flush_code && FLAG_flush_code_incrementally) {
424 mark_compact_collector()->EnableCodeFlushing(true);
425 }
426
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000427#ifdef VERIFY_HEAP
428 if (FLAG_verify_heap) {
429 Verify();
430 }
431#endif
432
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000433#ifdef DEBUG
434 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
435 allow_allocation(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000436
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437 if (FLAG_gc_verbose) Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000439 ReportStatisticsBeforeGC();
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000440#endif // DEBUG
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000441
442 LiveObjectList::GCPrologue();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000443 store_buffer()->GCPrologue();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444}
445
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000446
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000447intptr_t Heap::SizeOfObjects() {
448 intptr_t total = 0;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000449 AllSpaces spaces;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000450 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000451 total += space->SizeOfObjects();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000452 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000453 return total;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000454}
455
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000456
457void Heap::RepairFreeListsAfterBoot() {
458 PagedSpaces spaces;
459 for (PagedSpace* space = spaces.next();
460 space != NULL;
461 space = spaces.next()) {
462 space->RepairFreeListsAfterBoot();
463 }
464}
465
466
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000467void Heap::GarbageCollectionEpilogue() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000468 store_buffer()->GCEpilogue();
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000469 LiveObjectList::GCEpilogue();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000470
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000471 // In release mode, we only zap the from space under heap verification.
472 if (Heap::ShouldZapGarbage()) {
473 ZapFromSpace();
474 }
475
476#ifdef VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000477 if (FLAG_verify_heap) {
478 Verify();
479 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000480#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000481
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000482#ifdef DEBUG
483 allow_allocation(true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000484 if (FLAG_print_global_handles) isolate_->global_handles()->Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485 if (FLAG_print_handles) PrintHandles();
486 if (FLAG_gc_verbose) Print();
487 if (FLAG_code_stats) ReportCodeStatistics("After GC");
488#endif
489
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000490 isolate_->counters()->alive_after_last_gc()->Set(
491 static_cast<int>(SizeOfObjects()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000492
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000493 isolate_->counters()->symbol_table_capacity()->Set(
494 symbol_table()->Capacity());
495 isolate_->counters()->number_of_symbols()->Set(
496 symbol_table()->NumberOfElements());
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000497
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000498 if (CommittedMemory() > 0) {
499 isolate_->counters()->external_fragmentation_total()->AddSample(
500 static_cast<int>(100 - (SizeOfObjects() * 100.0) / CommittedMemory()));
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000501
502 isolate_->counters()->heap_fraction_map_space()->AddSample(
503 static_cast<int>(
504 (map_space()->CommittedMemory() * 100.0) / CommittedMemory()));
505 isolate_->counters()->heap_fraction_cell_space()->AddSample(
506 static_cast<int>(
507 (cell_space()->CommittedMemory() * 100.0) / CommittedMemory()));
508
509 isolate_->counters()->heap_sample_total_committed()->AddSample(
510 static_cast<int>(CommittedMemory() / KB));
511 isolate_->counters()->heap_sample_total_used()->AddSample(
512 static_cast<int>(SizeOfObjects() / KB));
513 isolate_->counters()->heap_sample_map_space_committed()->AddSample(
514 static_cast<int>(map_space()->CommittedMemory() / KB));
515 isolate_->counters()->heap_sample_cell_space_committed()->AddSample(
516 static_cast<int>(cell_space()->CommittedMemory() / KB));
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000517 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000518
519#define UPDATE_COUNTERS_FOR_SPACE(space) \
520 isolate_->counters()->space##_bytes_available()->Set( \
521 static_cast<int>(space()->Available())); \
522 isolate_->counters()->space##_bytes_committed()->Set( \
523 static_cast<int>(space()->CommittedMemory())); \
524 isolate_->counters()->space##_bytes_used()->Set( \
525 static_cast<int>(space()->SizeOfObjects()));
526#define UPDATE_FRAGMENTATION_FOR_SPACE(space) \
527 if (space()->CommittedMemory() > 0) { \
528 isolate_->counters()->external_fragmentation_##space()->AddSample( \
529 static_cast<int>(100 - \
530 (space()->SizeOfObjects() * 100.0) / space()->CommittedMemory())); \
531 }
532#define UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(space) \
533 UPDATE_COUNTERS_FOR_SPACE(space) \
534 UPDATE_FRAGMENTATION_FOR_SPACE(space)
535
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000536 UPDATE_COUNTERS_FOR_SPACE(new_space)
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000537 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(old_pointer_space)
538 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(old_data_space)
539 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(code_space)
540 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(map_space)
541 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(cell_space)
542 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(lo_space)
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000543#undef UPDATE_COUNTERS_FOR_SPACE
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000544#undef UPDATE_FRAGMENTATION_FOR_SPACE
545#undef UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000546
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000547#if defined(DEBUG)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548 ReportStatisticsAfterGC();
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000549#endif // DEBUG
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000550#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 isolate_->debug()->AfterGarbageCollection();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000552#endif // ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000553}
554
555
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000556void Heap::CollectAllGarbage(int flags, const char* gc_reason) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000557 // Since we are ignoring the return value, the exact choice of space does
558 // not matter, so long as we do not specify NEW_SPACE, which would not
559 // cause a full GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000560 mark_compact_collector_.SetFlags(flags);
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000561 CollectGarbage(OLD_POINTER_SPACE, gc_reason);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000562 mark_compact_collector_.SetFlags(kNoGCFlags);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000563}
564
565
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000566void Heap::CollectAllAvailableGarbage(const char* gc_reason) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000567 // Since we are ignoring the return value, the exact choice of space does
568 // not matter, so long as we do not specify NEW_SPACE, which would not
569 // cause a full GC.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000570 // Major GC would invoke weak handle callbacks on weakly reachable
571 // handles, but won't collect weakly reachable objects until next
572 // major GC. Therefore if we collect aggressively and weak handle callback
573 // has been invoked, we rerun major GC to release objects which become
574 // garbage.
575 // Note: as weak callbacks can execute arbitrary code, we cannot
576 // hope that eventually there will be no weak callbacks invocations.
577 // Therefore stop recollecting after several attempts.
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000578 mark_compact_collector()->SetFlags(kMakeHeapIterableMask |
579 kReduceMemoryFootprintMask);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000580 isolate_->compilation_cache()->Clear();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000581 const int kMaxNumberOfAttempts = 7;
582 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000583 if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR, gc_reason, NULL)) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000584 break;
585 }
586 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000587 mark_compact_collector()->SetFlags(kNoGCFlags);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000588 new_space_.Shrink();
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000589 UncommitFromSpace();
590 Shrink();
danno@chromium.orgc612e022011-11-10 11:38:15 +0000591 incremental_marking()->UncommitMarkingDeque();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000592}
593
594
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000595bool Heap::CollectGarbage(AllocationSpace space,
596 GarbageCollector collector,
597 const char* gc_reason,
598 const char* collector_reason) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599 // The VM is in the GC state until exiting this function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 VMState state(isolate_, GC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000601
602#ifdef DEBUG
603 // Reset the allocation timeout to the GC interval, but make sure to
604 // allow at least a few allocations after a collection. The reason
605 // for this is that we have a lot of allocation sequences and we
606 // assume that a garbage collection will allow the subsequent
607 // allocation attempts to go through.
608 allocation_timeout_ = Max(6, FLAG_gc_interval);
609#endif
610
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000611 if (collector == SCAVENGER && !incremental_marking()->IsStopped()) {
612 if (FLAG_trace_incremental_marking) {
613 PrintF("[IncrementalMarking] Scavenge during marking.\n");
614 }
615 }
616
617 if (collector == MARK_COMPACTOR &&
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000618 !mark_compact_collector()->abort_incremental_marking_ &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000619 !incremental_marking()->IsStopped() &&
620 !incremental_marking()->should_hurry() &&
621 FLAG_incremental_marking_steps) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000622 // Make progress in incremental marking.
623 const intptr_t kStepSizeWhenDelayedByScavenge = 1 * MB;
624 incremental_marking()->Step(kStepSizeWhenDelayedByScavenge,
625 IncrementalMarking::NO_GC_VIA_STACK_GUARD);
626 if (!incremental_marking()->IsComplete()) {
627 if (FLAG_trace_incremental_marking) {
628 PrintF("[IncrementalMarking] Delaying MarkSweep.\n");
629 }
630 collector = SCAVENGER;
631 collector_reason = "incremental marking delaying mark-sweep";
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000632 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000633 }
634
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000635 bool next_gc_likely_to_collect_more = false;
636
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000637 { GCTracer tracer(this, gc_reason, collector_reason);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000638 GarbageCollectionPrologue();
kasper.lund7276f142008-07-30 08:49:36 +0000639 // The GC count was incremented in the prologue. Tell the tracer about
640 // it.
641 tracer.set_gc_count(gc_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000642
kasper.lund7276f142008-07-30 08:49:36 +0000643 // Tell the tracer which collector we've selected.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000644 tracer.set_collector(collector);
645
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000646 HistogramTimer* rate = (collector == SCAVENGER)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 ? isolate_->counters()->gc_scavenger()
648 : isolate_->counters()->gc_compactor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 rate->Start();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000650 next_gc_likely_to_collect_more =
651 PerformGarbageCollection(collector, &tracer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000652 rate->Stop();
653
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000654 ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped());
655
656 // This can do debug callbacks and restart incremental marking.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000657 GarbageCollectionEpilogue();
658 }
659
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000660 if (incremental_marking()->IsStopped()) {
661 if (incremental_marking()->WorthActivating() && NextGCIsLikelyToBeFull()) {
662 incremental_marking()->Start();
663 }
664 }
665
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000666 return next_gc_likely_to_collect_more;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000667}
668
669
kasper.lund7276f142008-07-30 08:49:36 +0000670void Heap::PerformScavenge() {
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000671 GCTracer tracer(this, NULL, NULL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000672 if (incremental_marking()->IsStopped()) {
673 PerformGarbageCollection(SCAVENGER, &tracer);
674 } else {
675 PerformGarbageCollection(MARK_COMPACTOR, &tracer);
676 }
kasper.lund7276f142008-07-30 08:49:36 +0000677}
678
679
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000680#ifdef VERIFY_HEAP
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000681// Helper class for verifying the symbol table.
682class SymbolTableVerifier : public ObjectVisitor {
683 public:
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000684 void VisitPointers(Object** start, Object** end) {
685 // Visit all HeapObject pointers in [start, end).
686 for (Object** p = start; p < end; p++) {
687 if ((*p)->IsHeapObject()) {
688 // Check that the symbol is actually a symbol.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000689 CHECK((*p)->IsTheHole() || (*p)->IsUndefined() || (*p)->IsSymbol());
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000690 }
691 }
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000692 }
693};
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000694
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000695
696static void VerifySymbolTable() {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000697 SymbolTableVerifier verifier;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000698 HEAP->symbol_table()->IterateElements(&verifier);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000699}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000700#endif // VERIFY_HEAP
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000701
702
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000703static bool AbortIncrementalMarkingAndCollectGarbage(
704 Heap* heap,
705 AllocationSpace space,
706 const char* gc_reason = NULL) {
707 heap->mark_compact_collector()->SetFlags(Heap::kAbortIncrementalMarkingMask);
708 bool result = heap->CollectGarbage(space, gc_reason);
709 heap->mark_compact_collector()->SetFlags(Heap::kNoGCFlags);
710 return result;
711}
712
713
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000714void Heap::ReserveSpace(
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000715 int *sizes,
716 Address *locations_out) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000717 bool gc_performed = true;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000718 int counter = 0;
719 static const int kThreshold = 20;
720 while (gc_performed && counter++ < kThreshold) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000721 gc_performed = false;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000722 ASSERT(NEW_SPACE == FIRST_PAGED_SPACE - 1);
723 for (int space = NEW_SPACE; space <= LAST_PAGED_SPACE; space++) {
724 if (sizes[space] != 0) {
725 MaybeObject* allocation;
726 if (space == NEW_SPACE) {
727 allocation = new_space()->AllocateRaw(sizes[space]);
728 } else {
729 allocation = paged_space(space)->AllocateRaw(sizes[space]);
730 }
731 FreeListNode* node;
732 if (!allocation->To<FreeListNode>(&node)) {
733 if (space == NEW_SPACE) {
734 Heap::CollectGarbage(NEW_SPACE,
735 "failed to reserve space in the new space");
736 } else {
737 AbortIncrementalMarkingAndCollectGarbage(
738 this,
739 static_cast<AllocationSpace>(space),
740 "failed to reserve space in paged space");
741 }
742 gc_performed = true;
743 break;
744 } else {
745 // Mark with a free list node, in case we have a GC before
746 // deserializing.
747 node->set_size(this, sizes[space]);
748 locations_out[space] = node->address();
749 }
750 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000751 }
752 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000753
754 if (gc_performed) {
755 // Failed to reserve the space after several attempts.
756 V8::FatalProcessOutOfMemory("Heap::ReserveSpace");
757 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000758}
759
760
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000761void Heap::EnsureFromSpaceIsCommitted() {
762 if (new_space_.CommitFromSpaceIfNeeded()) return;
763
764 // Committing memory to from space failed.
765 // Try shrinking and try again.
766 Shrink();
767 if (new_space_.CommitFromSpaceIfNeeded()) return;
768
769 // Committing memory to from space failed again.
770 // Memory is exhausted and we will die.
771 V8::FatalProcessOutOfMemory("Committing semi space failed.");
772}
773
774
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000775void Heap::ClearJSFunctionResultCaches() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000776 if (isolate_->bootstrapper()->IsActive()) return;
ager@chromium.orgac091b72010-05-05 07:34:42 +0000777
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000778 Object* context = native_contexts_list_;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000779 while (!context->IsUndefined()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000780 // Get the caches for this context. GC can happen when the context
781 // is not fully initialized, so the caches can be undefined.
782 Object* caches_or_undefined =
783 Context::cast(context)->get(Context::JSFUNCTION_RESULT_CACHES_INDEX);
784 if (!caches_or_undefined->IsUndefined()) {
785 FixedArray* caches = FixedArray::cast(caches_or_undefined);
786 // Clear the caches:
787 int length = caches->length();
788 for (int i = 0; i < length; i++) {
789 JSFunctionResultCache::cast(caches->get(i))->Clear();
790 }
ager@chromium.orgac091b72010-05-05 07:34:42 +0000791 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000792 // Get the next context:
793 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000794 }
ager@chromium.orgac091b72010-05-05 07:34:42 +0000795}
796
797
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000798
ricow@chromium.org65fae842010-08-25 15:26:24 +0000799void Heap::ClearNormalizedMapCaches() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000800 if (isolate_->bootstrapper()->IsActive() &&
801 !incremental_marking()->IsMarking()) {
802 return;
803 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000804
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000805 Object* context = native_contexts_list_;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000806 while (!context->IsUndefined()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000807 // GC can happen when the context is not fully initialized,
808 // so the cache can be undefined.
809 Object* cache =
810 Context::cast(context)->get(Context::NORMALIZED_MAP_CACHE_INDEX);
811 if (!cache->IsUndefined()) {
812 NormalizedMapCache::cast(cache)->Clear();
813 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000814 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
815 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000816}
817
818
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000819void Heap::UpdateSurvivalRateTrend(int start_new_space_size) {
820 double survival_rate =
821 (static_cast<double>(young_survivors_after_last_gc_) * 100) /
822 start_new_space_size;
823
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000824 if (survival_rate > kYoungSurvivalRateHighThreshold) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000825 high_survival_rate_period_length_++;
826 } else {
827 high_survival_rate_period_length_ = 0;
828 }
829
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000830 if (survival_rate < kYoungSurvivalRateLowThreshold) {
831 low_survival_rate_period_length_++;
832 } else {
833 low_survival_rate_period_length_ = 0;
834 }
835
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000836 double survival_rate_diff = survival_rate_ - survival_rate;
837
838 if (survival_rate_diff > kYoungSurvivalRateAllowedDeviation) {
839 set_survival_rate_trend(DECREASING);
840 } else if (survival_rate_diff < -kYoungSurvivalRateAllowedDeviation) {
841 set_survival_rate_trend(INCREASING);
842 } else {
843 set_survival_rate_trend(STABLE);
844 }
845
846 survival_rate_ = survival_rate;
847}
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000848
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000849bool Heap::PerformGarbageCollection(GarbageCollector collector,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000850 GCTracer* tracer) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000851 bool next_gc_likely_to_collect_more = false;
852
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000853 if (collector != SCAVENGER) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000854 PROFILE(isolate_, CodeMovingGCEvent());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000855 }
856
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000857#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000858 if (FLAG_verify_heap) {
859 VerifySymbolTable();
860 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000861#endif
862
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863 if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) {
864 ASSERT(!allocation_allowed_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000865 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000866 global_gc_prologue_callback_();
867 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000868
869 GCType gc_type =
870 collector == MARK_COMPACTOR ? kGCTypeMarkSweepCompact : kGCTypeScavenge;
871
872 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
873 if (gc_type & gc_prologue_callbacks_[i].gc_type) {
874 gc_prologue_callbacks_[i].callback(gc_type, kNoGCCallbackFlags);
875 }
876 }
877
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000878 EnsureFromSpaceIsCommitted();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000879
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000880 int start_new_space_size = Heap::new_space()->SizeAsInt();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000881
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000882 if (IsHighSurvivalRate()) {
883 // We speed up the incremental marker if it is running so that it
884 // does not fall behind the rate of promotion, which would cause a
885 // constantly growing old space.
886 incremental_marking()->NotifyOfHighPromotionRate();
887 }
888
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889 if (collector == MARK_COMPACTOR) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000890 // Perform mark-sweep with optional compaction.
kasper.lund7276f142008-07-30 08:49:36 +0000891 MarkCompact(tracer);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000892 sweep_generation_++;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000893 bool high_survival_rate_during_scavenges = IsHighSurvivalRate() &&
894 IsStableOrIncreasingSurvivalTrend();
895
896 UpdateSurvivalRateTrend(start_new_space_size);
897
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000898 size_of_old_gen_at_last_old_space_gc_ = PromotedSpaceSizeOfObjects();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000899
lrn@chromium.org303ada72010-10-27 09:33:13 +0000900 if (high_survival_rate_during_scavenges &&
901 IsStableOrIncreasingSurvivalTrend()) {
902 // Stable high survival rates of young objects both during partial and
903 // full collection indicate that mutator is either building or modifying
904 // a structure with a long lifetime.
905 // In this case we aggressively raise old generation memory limits to
906 // postpone subsequent mark-sweep collection and thus trade memory
907 // space for the mutation speed.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000908 old_gen_limit_factor_ = 2;
909 } else {
910 old_gen_limit_factor_ = 1;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000911 }
912
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000913 old_gen_promotion_limit_ =
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000914 OldGenPromotionLimit(size_of_old_gen_at_last_old_space_gc_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000915 old_gen_allocation_limit_ =
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000916 OldGenAllocationLimit(size_of_old_gen_at_last_old_space_gc_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000917
lrn@chromium.org303ada72010-10-27 09:33:13 +0000918 old_gen_exhausted_ = false;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000919 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000920 tracer_ = tracer;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000921 Scavenge();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000922 tracer_ = NULL;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000923
924 UpdateSurvivalRateTrend(start_new_space_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000925 }
ager@chromium.org439e85a2009-08-26 13:15:29 +0000926
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000927 if (!new_space_high_promotion_mode_active_ &&
928 new_space_.Capacity() == new_space_.MaximumCapacity() &&
929 IsStableOrIncreasingSurvivalTrend() &&
930 IsHighSurvivalRate()) {
931 // Stable high survival rates even though young generation is at
932 // maximum capacity indicates that most objects will be promoted.
933 // To decrease scavenger pauses and final mark-sweep pauses, we
934 // have to limit maximal capacity of the young generation.
935 new_space_high_promotion_mode_active_ = true;
936 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000937 PrintPID("Limited new space size due to high promotion rate: %d MB\n",
938 new_space_.InitialCapacity() / MB);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000939 }
940 } else if (new_space_high_promotion_mode_active_ &&
941 IsStableOrDecreasingSurvivalTrend() &&
942 IsLowSurvivalRate()) {
943 // Decreasing low survival rates might indicate that the above high
944 // promotion mode is over and we should allow the young generation
945 // to grow again.
946 new_space_high_promotion_mode_active_ = false;
947 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000948 PrintPID("Unlimited new space size due to low promotion rate: %d MB\n",
949 new_space_.MaximumCapacity() / MB);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000950 }
951 }
952
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000953 if (new_space_high_promotion_mode_active_ &&
954 new_space_.Capacity() > new_space_.InitialCapacity()) {
955 new_space_.Shrink();
956 }
957
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000958 isolate_->counters()->objs_since_last_young()->Set(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000959
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000960 gc_post_processing_depth_++;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000961 { DisableAssertNoAllocation allow_allocation;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000962 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000963 next_gc_likely_to_collect_more =
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000964 isolate_->global_handles()->PostGarbageCollectionProcessing(collector);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000965 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000966 gc_post_processing_depth_--;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000967
ager@chromium.org3811b432009-10-28 14:53:37 +0000968 // Update relocatables.
969 Relocatable::PostGarbageCollectionProcessing();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000970
kasper.lund7276f142008-07-30 08:49:36 +0000971 if (collector == MARK_COMPACTOR) {
972 // Register the amount of external allocated memory.
973 amount_of_external_allocated_memory_at_last_global_gc_ =
974 amount_of_external_allocated_memory_;
975 }
976
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000977 GCCallbackFlags callback_flags = kNoGCCallbackFlags;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000978 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
979 if (gc_type & gc_epilogue_callbacks_[i].gc_type) {
980 gc_epilogue_callbacks_[i].callback(gc_type, callback_flags);
981 }
982 }
983
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984 if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) {
985 ASSERT(!allocation_allowed_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000986 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000987 global_gc_epilogue_callback_();
988 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000989
990#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000991 if (FLAG_verify_heap) {
992 VerifySymbolTable();
993 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000994#endif
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000995
996 return next_gc_likely_to_collect_more;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997}
998
999
kasper.lund7276f142008-07-30 08:49:36 +00001000void Heap::MarkCompact(GCTracer* tracer) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001001 gc_state_ = MARK_COMPACT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001002 LOG(isolate_, ResourceEvent("markcompact", "begin"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001004 mark_compact_collector_.Prepare(tracer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001005
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001006 ms_count_++;
1007 tracer->set_full_gc_count(ms_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001008
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001009 MarkCompactPrologue();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001010
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001011 mark_compact_collector_.CollectGarbage();
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001012
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001013 LOG(isolate_, ResourceEvent("markcompact", "end"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014
1015 gc_state_ = NOT_IN_GC;
1016
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001017 isolate_->counters()->objs_since_last_full()->Set(0);
kasperl@chromium.org8b2bb262010-03-01 09:46:28 +00001018
1019 contexts_disposed_ = 0;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001020
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001021 flush_monomorphic_ics_ = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001022}
1023
1024
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001025void Heap::MarkCompactPrologue() {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001026 // At any old GC clear the keyed lookup cache to enable collection of unused
1027 // maps.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001028 isolate_->keyed_lookup_cache()->Clear();
1029 isolate_->context_slot_cache()->Clear();
1030 isolate_->descriptor_lookup_cache()->Clear();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001031 RegExpResultsCache::Clear(string_split_cache());
1032 RegExpResultsCache::Clear(regexp_multiple_cache());
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001033
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001034 isolate_->compilation_cache()->MarkCompactPrologue();
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001035
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001036 CompletelyClearInstanceofCache();
1037
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001038 FlushNumberStringCache();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001039 if (FLAG_cleanup_code_caches_at_gc) {
1040 polymorphic_code_cache()->set_cache(undefined_value());
1041 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001042
1043 ClearNormalizedMapCaches();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001044}
1045
1046
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001047Object* Heap::FindCodeObject(Address a) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001048 return isolate()->inner_pointer_to_code_cache()->
1049 GcSafeFindCodeForInnerPointer(a);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001050}
1051
1052
1053// Helper class for copying HeapObjects
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001054class ScavengeVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001055 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001056 explicit ScavengeVisitor(Heap* heap) : heap_(heap) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001058 void VisitPointer(Object** p) { ScavengePointer(p); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001059
1060 void VisitPointers(Object** start, Object** end) {
1061 // Copy all HeapObject pointers in [start, end)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001062 for (Object** p = start; p < end; p++) ScavengePointer(p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001063 }
1064
1065 private:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001066 void ScavengePointer(Object** p) {
1067 Object* object = *p;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001068 if (!heap_->InNewSpace(object)) return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001069 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
1070 reinterpret_cast<HeapObject*>(object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001071 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001072
1073 Heap* heap_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001074};
1075
1076
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001077#ifdef VERIFY_HEAP
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001078// Visitor class to verify pointers in code or data space do not point into
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001079// new space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001080class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001081 public:
1082 void VisitPointers(Object** start, Object**end) {
1083 for (Object** current = start; current < end; current++) {
1084 if ((*current)->IsHeapObject()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001085 CHECK(!HEAP->InNewSpace(HeapObject::cast(*current)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001086 }
1087 }
1088 }
1089};
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001090
1091
1092static void VerifyNonPointerSpacePointers() {
1093 // Verify that there are no pointers to new space in spaces where we
1094 // do not expect them.
1095 VerifyNonPointerSpacePointersVisitor v;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001096 HeapObjectIterator code_it(HEAP->code_space());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001097 for (HeapObject* object = code_it.Next();
1098 object != NULL; object = code_it.Next())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001099 object->Iterate(&v);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001100
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001101 // The old data space was normally swept conservatively so that the iterator
1102 // doesn't work, so we normally skip the next bit.
1103 if (!HEAP->old_data_space()->was_swept_conservatively()) {
1104 HeapObjectIterator data_it(HEAP->old_data_space());
1105 for (HeapObject* object = data_it.Next();
1106 object != NULL; object = data_it.Next())
1107 object->Iterate(&v);
1108 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001109}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001110#endif // VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001112
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001113void Heap::CheckNewSpaceExpansionCriteria() {
1114 if (new_space_.Capacity() < new_space_.MaximumCapacity() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001115 survived_since_last_expansion_ > new_space_.Capacity() &&
1116 !new_space_high_promotion_mode_active_) {
1117 // Grow the size of new space if there is room to grow, enough data
1118 // has survived scavenge since the last expansion and we are not in
1119 // high promotion mode.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001120 new_space_.Grow();
1121 survived_since_last_expansion_ = 0;
1122 }
1123}
1124
1125
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001126static bool IsUnscavengedHeapObject(Heap* heap, Object** p) {
1127 return heap->InNewSpace(*p) &&
1128 !HeapObject::cast(*p)->map_word().IsForwardingAddress();
1129}
1130
1131
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001132void Heap::ScavengeStoreBufferCallback(
1133 Heap* heap,
1134 MemoryChunk* page,
1135 StoreBufferEvent event) {
1136 heap->store_buffer_rebuilder_.Callback(page, event);
1137}
1138
1139
1140void StoreBufferRebuilder::Callback(MemoryChunk* page, StoreBufferEvent event) {
1141 if (event == kStoreBufferStartScanningPagesEvent) {
1142 start_of_current_page_ = NULL;
1143 current_page_ = NULL;
1144 } else if (event == kStoreBufferScanningPageEvent) {
1145 if (current_page_ != NULL) {
1146 // If this page already overflowed the store buffer during this iteration.
1147 if (current_page_->scan_on_scavenge()) {
1148 // Then we should wipe out the entries that have been added for it.
1149 store_buffer_->SetTop(start_of_current_page_);
1150 } else if (store_buffer_->Top() - start_of_current_page_ >=
1151 (store_buffer_->Limit() - store_buffer_->Top()) >> 2) {
1152 // Did we find too many pointers in the previous page? The heuristic is
1153 // that no page can take more then 1/5 the remaining slots in the store
1154 // buffer.
1155 current_page_->set_scan_on_scavenge(true);
1156 store_buffer_->SetTop(start_of_current_page_);
1157 } else {
1158 // In this case the page we scanned took a reasonable number of slots in
1159 // the store buffer. It has now been rehabilitated and is no longer
1160 // marked scan_on_scavenge.
1161 ASSERT(!current_page_->scan_on_scavenge());
1162 }
1163 }
1164 start_of_current_page_ = store_buffer_->Top();
1165 current_page_ = page;
1166 } else if (event == kStoreBufferFullEvent) {
1167 // The current page overflowed the store buffer again. Wipe out its entries
1168 // in the store buffer and mark it scan-on-scavenge again. This may happen
1169 // several times while scanning.
1170 if (current_page_ == NULL) {
1171 // Store Buffer overflowed while scanning promoted objects. These are not
1172 // in any particular page, though they are likely to be clustered by the
1173 // allocation routines.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001174 store_buffer_->EnsureSpace(StoreBuffer::kStoreBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001175 } else {
1176 // Store Buffer overflowed while scanning a particular old space page for
1177 // pointers to new space.
1178 ASSERT(current_page_ == page);
1179 ASSERT(page != NULL);
1180 current_page_->set_scan_on_scavenge(true);
1181 ASSERT(start_of_current_page_ != store_buffer_->Top());
1182 store_buffer_->SetTop(start_of_current_page_);
1183 }
1184 } else {
1185 UNREACHABLE();
1186 }
1187}
1188
1189
danno@chromium.orgc612e022011-11-10 11:38:15 +00001190void PromotionQueue::Initialize() {
1191 // Assumes that a NewSpacePage exactly fits a number of promotion queue
1192 // entries (where each is a pair of intptr_t). This allows us to simplify
1193 // the test fpr when to switch pages.
1194 ASSERT((Page::kPageSize - MemoryChunk::kBodyOffset) % (2 * kPointerSize)
1195 == 0);
1196 limit_ = reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceStart());
1197 front_ = rear_ =
1198 reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceEnd());
1199 emergency_stack_ = NULL;
1200 guard_ = false;
1201}
1202
1203
1204void PromotionQueue::RelocateQueueHead() {
1205 ASSERT(emergency_stack_ == NULL);
1206
1207 Page* p = Page::FromAllocationTop(reinterpret_cast<Address>(rear_));
1208 intptr_t* head_start = rear_;
1209 intptr_t* head_end =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001210 Min(front_, reinterpret_cast<intptr_t*>(p->area_end()));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001211
1212 int entries_count =
1213 static_cast<int>(head_end - head_start) / kEntrySizeInWords;
1214
1215 emergency_stack_ = new List<Entry>(2 * entries_count);
1216
1217 while (head_start != head_end) {
1218 int size = static_cast<int>(*(head_start++));
1219 HeapObject* obj = reinterpret_cast<HeapObject*>(*(head_start++));
1220 emergency_stack_->Add(Entry(obj, size));
1221 }
1222 rear_ = head_end;
1223}
1224
1225
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001226class ScavengeWeakObjectRetainer : public WeakObjectRetainer {
1227 public:
1228 explicit ScavengeWeakObjectRetainer(Heap* heap) : heap_(heap) { }
1229
1230 virtual Object* RetainAs(Object* object) {
1231 if (!heap_->InFromSpace(object)) {
1232 return object;
1233 }
1234
1235 MapWord map_word = HeapObject::cast(object)->map_word();
1236 if (map_word.IsForwardingAddress()) {
1237 return map_word.ToForwardingAddress();
1238 }
1239 return NULL;
1240 }
1241
1242 private:
1243 Heap* heap_;
1244};
1245
1246
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247void Heap::Scavenge() {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001248 RelocationLock relocation_lock(this);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001249
1250#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001251 if (FLAG_verify_heap) VerifyNonPointerSpacePointers();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001252#endif
1253
1254 gc_state_ = SCAVENGE;
1255
1256 // Implements Cheney's copying algorithm
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001257 LOG(isolate_, ResourceEvent("scavenge", "begin"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001259 // Clear descriptor cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001260 isolate_->descriptor_lookup_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001261
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001262 // Used for updating survived_since_last_expansion_ at function end.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001263 intptr_t survived_watermark = PromotedSpaceSizeOfObjects();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001264
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001265 CheckNewSpaceExpansionCriteria();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001267 SelectScavengingVisitorsTable();
1268
1269 incremental_marking()->PrepareForScavenge();
1270
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001271 AdvanceSweepers(static_cast<int>(new_space_.Size()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001272
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001273 // Flip the semispaces. After flipping, to space is empty, from space has
1274 // live objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001275 new_space_.Flip();
1276 new_space_.ResetAllocationInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001278 // We need to sweep newly copied objects which can be either in the
1279 // to space or promoted to the old generation. For to-space
1280 // objects, we treat the bottom of the to space as a queue. Newly
1281 // copied and unswept objects lie between a 'front' mark and the
1282 // allocation pointer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283 //
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001284 // Promoted objects can go into various old-generation spaces, and
1285 // can be allocated internally in the spaces (from the free list).
1286 // We treat the top of the to space as a queue of addresses of
1287 // promoted objects. The addresses of newly promoted and unswept
1288 // objects lie between a 'front' mark and a 'rear' mark that is
1289 // updated as a side effect of promoting an object.
1290 //
1291 // There is guaranteed to be enough room at the top of the to space
1292 // for the addresses of promoted objects: every object promoted
1293 // frees up its size in bytes from the top of the new space, and
1294 // objects are at least one pointer in size.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001295 Address new_space_front = new_space_.ToSpaceStart();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001296 promotion_queue_.Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001297
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001298#ifdef DEBUG
1299 store_buffer()->Clean();
1300#endif
1301
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 ScavengeVisitor scavenge_visitor(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303 // Copy roots.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001304 IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001305
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001306 // Copy objects reachable from the old generation.
1307 {
1308 StoreBufferRebuildScope scope(this,
1309 store_buffer(),
1310 &ScavengeStoreBufferCallback);
1311 store_buffer()->IteratePointersToNewSpace(&ScavengeObject);
1312 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001313
1314 // Copy objects reachable from cells by scavenging cell values directly.
1315 HeapObjectIterator cell_iterator(cell_space_);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001316 for (HeapObject* heap_object = cell_iterator.Next();
1317 heap_object != NULL;
1318 heap_object = cell_iterator.Next()) {
1319 if (heap_object->IsJSGlobalPropertyCell()) {
1320 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(heap_object);
1321 Address value_address = cell->ValueAddress();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001322 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address));
1323 }
1324 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001326 // Copy objects reachable from the code flushing candidates list.
1327 MarkCompactCollector* collector = mark_compact_collector();
1328 if (collector->is_code_flushing_enabled()) {
1329 collector->code_flusher()->IteratePointersToFromSpace(&scavenge_visitor);
1330 }
1331
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001332 // Scavenge object reachable from the native contexts list directly.
1333 scavenge_visitor.VisitPointer(BitCast<Object**>(&native_contexts_list_));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001334
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001335 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001336
1337 while (IterateObjectGroups(&scavenge_visitor)) {
1338 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
1339 }
1340 isolate()->global_handles()->RemoveObjectGroups();
1341
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001342 isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles(
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001343 &IsUnscavengedHeapObject);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001344 isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots(
1345 &scavenge_visitor);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001346 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
1347
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001348 UpdateNewSpaceReferencesInExternalStringTable(
1349 &UpdateNewSpaceReferenceInExternalStringTableEntry);
1350
danno@chromium.orgc612e022011-11-10 11:38:15 +00001351 promotion_queue_.Destroy();
1352
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001353 LiveObjectList::UpdateReferencesForScavengeGC();
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001354 if (!FLAG_watch_ic_patching) {
1355 isolate()->runtime_profiler()->UpdateSamplesAfterScavenge();
1356 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001357 incremental_marking()->UpdateMarkingDequeAfterScavenge();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001358
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001359 ScavengeWeakObjectRetainer weak_object_retainer(this);
1360 ProcessWeakReferences(&weak_object_retainer);
1361
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001362 ASSERT(new_space_front == new_space_.top());
1363
1364 // Set age mark.
1365 new_space_.set_age_mark(new_space_.top());
1366
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001367 new_space_.LowerInlineAllocationLimit(
1368 new_space_.inline_allocation_limit_step());
1369
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001370 // Update how much has survived scavenge.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001371 IncrementYoungSurvivorsCounter(static_cast<int>(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001372 (PromotedSpaceSizeOfObjects() - survived_watermark) + new_space_.Size()));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001373
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 LOG(isolate_, ResourceEvent("scavenge", "end"));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001375
1376 gc_state_ = NOT_IN_GC;
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001377
1378 scavenges_since_last_idle_round_++;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001379}
1380
1381
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001382// TODO(mstarzinger): Unify this method with
1383// MarkCompactCollector::MarkObjectGroups().
1384bool Heap::IterateObjectGroups(ObjectVisitor* scavenge_visitor) {
1385 List<ObjectGroup*>* object_groups =
1386 isolate()->global_handles()->object_groups();
1387
1388 int last = 0;
1389 bool changed = false;
1390 for (int i = 0; i < object_groups->length(); i++) {
1391 ObjectGroup* entry = object_groups->at(i);
1392 ASSERT(entry != NULL);
1393
1394 Object*** objects = entry->objects_;
1395 bool group_marked = false;
1396 for (size_t j = 0; j < entry->length_; j++) {
1397 Object* object = *objects[j];
1398 if (object->IsHeapObject()) {
1399 if (!IsUnscavengedHeapObject(this, &object)) {
1400 group_marked = true;
1401 break;
1402 }
1403 }
1404 }
1405
1406 if (!group_marked) {
1407 (*object_groups)[last++] = entry;
1408 continue;
1409 }
1410
1411 for (size_t j = 0; j < entry->length_; ++j) {
1412 Object* object = *objects[j];
1413 if (object->IsHeapObject()) {
1414 scavenge_visitor->VisitPointer(&object);
1415 changed = true;
1416 }
1417 }
1418
1419 entry->Dispose();
1420 object_groups->at(i) = NULL;
1421 }
1422 object_groups->Rewind(last);
1423 return changed;
1424}
1425
1426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001427String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
1428 Object** p) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001429 MapWord first_word = HeapObject::cast(*p)->map_word();
1430
1431 if (!first_word.IsForwardingAddress()) {
1432 // Unreachable external string can be finalized.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001433 heap->FinalizeExternalString(String::cast(*p));
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001434 return NULL;
1435 }
1436
1437 // String is still reachable.
1438 return String::cast(first_word.ToForwardingAddress());
1439}
1440
1441
1442void Heap::UpdateNewSpaceReferencesInExternalStringTable(
1443 ExternalStringTableUpdaterCallback updater_func) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001444#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001445 if (FLAG_verify_heap) {
1446 external_string_table_.Verify();
1447 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001448#endif
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001449
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001450 if (external_string_table_.new_space_strings_.is_empty()) return;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001451
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001452 Object** start = &external_string_table_.new_space_strings_[0];
1453 Object** end = start + external_string_table_.new_space_strings_.length();
1454 Object** last = start;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001455
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001456 for (Object** p = start; p < end; ++p) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 ASSERT(InFromSpace(*p));
1458 String* target = updater_func(this, p);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001459
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001460 if (target == NULL) continue;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001461
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001462 ASSERT(target->IsExternalString());
1463
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001464 if (InNewSpace(target)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001465 // String is still in new space. Update the table entry.
1466 *last = target;
1467 ++last;
1468 } else {
1469 // String got promoted. Move it to the old string list.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001470 external_string_table_.AddOldString(target);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001471 }
1472 }
1473
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001474 ASSERT(last <= end);
1475 external_string_table_.ShrinkNewStrings(static_cast<int>(last - start));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001476}
1477
1478
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001479void Heap::UpdateReferencesInExternalStringTable(
1480 ExternalStringTableUpdaterCallback updater_func) {
1481
1482 // Update old space string references.
1483 if (external_string_table_.old_space_strings_.length() > 0) {
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001484 Object** start = &external_string_table_.old_space_strings_[0];
1485 Object** end = start + external_string_table_.old_space_strings_.length();
1486 for (Object** p = start; p < end; ++p) *p = updater_func(this, p);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001487 }
1488
1489 UpdateNewSpaceReferencesInExternalStringTable(updater_func);
1490}
1491
1492
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001493static Object* ProcessFunctionWeakReferences(Heap* heap,
1494 Object* function,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001495 WeakObjectRetainer* retainer,
1496 bool record_slots) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001497 Object* undefined = heap->undefined_value();
1498 Object* head = undefined;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001499 JSFunction* tail = NULL;
1500 Object* candidate = function;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 while (candidate != undefined) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001502 // Check whether to keep the candidate in the list.
1503 JSFunction* candidate_function = reinterpret_cast<JSFunction*>(candidate);
1504 Object* retain = retainer->RetainAs(candidate);
1505 if (retain != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001506 if (head == undefined) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001507 // First element in the list.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001508 head = retain;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001509 } else {
1510 // Subsequent elements in the list.
1511 ASSERT(tail != NULL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001512 tail->set_next_function_link(retain);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001513 if (record_slots) {
1514 Object** next_function =
1515 HeapObject::RawField(tail, JSFunction::kNextFunctionLinkOffset);
1516 heap->mark_compact_collector()->RecordSlot(
1517 next_function, next_function, retain);
1518 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001519 }
1520 // Retained function is new tail.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001521 candidate_function = reinterpret_cast<JSFunction*>(retain);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001522 tail = candidate_function;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001523
1524 ASSERT(retain->IsUndefined() || retain->IsJSFunction());
1525
1526 if (retain == undefined) break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001527 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001528
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001529 // Move to next element in the list.
1530 candidate = candidate_function->next_function_link();
1531 }
1532
1533 // Terminate the list if there is one or more elements.
1534 if (tail != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001535 tail->set_next_function_link(undefined);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001536 }
1537
1538 return head;
1539}
1540
1541
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001542void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001543 Object* undefined = undefined_value();
1544 Object* head = undefined;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001545 Context* tail = NULL;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001546 Object* candidate = native_contexts_list_;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001547
1548 // We don't record weak slots during marking or scavenges.
1549 // Instead we do it once when we complete mark-compact cycle.
1550 // Note that write barrier has no effect if we are already in the middle of
1551 // compacting mark-sweep cycle and we have to record slots manually.
1552 bool record_slots =
1553 gc_state() == MARK_COMPACT &&
1554 mark_compact_collector()->is_compacting();
1555
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001556 while (candidate != undefined) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001557 // Check whether to keep the candidate in the list.
1558 Context* candidate_context = reinterpret_cast<Context*>(candidate);
1559 Object* retain = retainer->RetainAs(candidate);
1560 if (retain != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001561 if (head == undefined) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001562 // First element in the list.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001563 head = retain;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001564 } else {
1565 // Subsequent elements in the list.
1566 ASSERT(tail != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001567 tail->set_unchecked(this,
1568 Context::NEXT_CONTEXT_LINK,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001569 retain,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001570 UPDATE_WRITE_BARRIER);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001571
1572 if (record_slots) {
1573 Object** next_context =
1574 HeapObject::RawField(
1575 tail, FixedArray::SizeFor(Context::NEXT_CONTEXT_LINK));
1576 mark_compact_collector()->RecordSlot(
1577 next_context, next_context, retain);
1578 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001579 }
1580 // Retained context is new tail.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001581 candidate_context = reinterpret_cast<Context*>(retain);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001582 tail = candidate_context;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001583
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001584 if (retain == undefined) break;
1585
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001586 // Process the weak list of optimized functions for the context.
1587 Object* function_list_head =
1588 ProcessFunctionWeakReferences(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001589 this,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001590 candidate_context->get(Context::OPTIMIZED_FUNCTIONS_LIST),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001591 retainer,
1592 record_slots);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001593 candidate_context->set_unchecked(this,
1594 Context::OPTIMIZED_FUNCTIONS_LIST,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001595 function_list_head,
1596 UPDATE_WRITE_BARRIER);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001597 if (record_slots) {
1598 Object** optimized_functions =
1599 HeapObject::RawField(
1600 tail, FixedArray::SizeFor(Context::OPTIMIZED_FUNCTIONS_LIST));
1601 mark_compact_collector()->RecordSlot(
1602 optimized_functions, optimized_functions, function_list_head);
1603 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001604 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001605
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001606 // Move to next element in the list.
1607 candidate = candidate_context->get(Context::NEXT_CONTEXT_LINK);
1608 }
1609
1610 // Terminate the list if there is one or more elements.
1611 if (tail != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001612 tail->set_unchecked(this,
1613 Context::NEXT_CONTEXT_LINK,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001614 Heap::undefined_value(),
1615 UPDATE_WRITE_BARRIER);
1616 }
1617
1618 // Update the head of the list of contexts.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001619 native_contexts_list_ = head;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001620}
1621
1622
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001623void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) {
1624 AssertNoAllocation no_allocation;
1625
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001626 // Both the external string table and the symbol table may contain
1627 // external strings, but neither lists them exhaustively, nor is the
1628 // intersection set empty. Therefore we iterate over the external string
1629 // table first, ignoring symbols, and then over the symbol table.
1630
1631 class ExternalStringTableVisitorAdapter : public ObjectVisitor {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001632 public:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001633 explicit ExternalStringTableVisitorAdapter(
1634 v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001635 virtual void VisitPointers(Object** start, Object** end) {
1636 for (Object** p = start; p < end; p++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001637 // Visit non-symbol external strings,
1638 // since symbols are listed in the symbol table.
1639 if (!(*p)->IsSymbol()) {
1640 ASSERT((*p)->IsExternalString());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001641 visitor_->VisitExternalString(Utils::ToLocal(
1642 Handle<String>(String::cast(*p))));
1643 }
1644 }
1645 }
1646 private:
1647 v8::ExternalResourceVisitor* visitor_;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001648 } external_string_table_visitor(visitor);
1649
1650 external_string_table_.Iterate(&external_string_table_visitor);
1651
1652 class SymbolTableVisitorAdapter : public ObjectVisitor {
1653 public:
1654 explicit SymbolTableVisitorAdapter(
1655 v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
1656 virtual void VisitPointers(Object** start, Object** end) {
1657 for (Object** p = start; p < end; p++) {
1658 if ((*p)->IsExternalString()) {
1659 ASSERT((*p)->IsSymbol());
1660 visitor_->VisitExternalString(Utils::ToLocal(
1661 Handle<String>(String::cast(*p))));
1662 }
1663 }
1664 }
1665 private:
1666 v8::ExternalResourceVisitor* visitor_;
1667 } symbol_table_visitor(visitor);
1668
1669 symbol_table()->IterateElements(&symbol_table_visitor);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001670}
1671
1672
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001673class NewSpaceScavenger : public StaticNewSpaceVisitor<NewSpaceScavenger> {
1674 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001675 static inline void VisitPointer(Heap* heap, Object** p) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001676 Object* object = *p;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001677 if (!heap->InNewSpace(object)) return;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001678 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
1679 reinterpret_cast<HeapObject*>(object));
1680 }
1681};
1682
1683
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001684Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
1685 Address new_space_front) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001686 do {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001687 SemiSpace::AssertValidRange(new_space_front, new_space_.top());
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001688 // The addresses new_space_front and new_space_.top() define a
1689 // queue of unprocessed copied objects. Process them until the
1690 // queue is empty.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001691 while (new_space_front != new_space_.top()) {
1692 if (!NewSpacePage::IsAtEnd(new_space_front)) {
1693 HeapObject* object = HeapObject::FromAddress(new_space_front);
1694 new_space_front +=
1695 NewSpaceScavenger::IterateBody(object->map(), object);
1696 } else {
1697 new_space_front =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001698 NewSpacePage::FromLimit(new_space_front)->next_page()->area_start();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001699 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001700 }
1701
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001702 // Promote and process all the to-be-promoted objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001703 {
1704 StoreBufferRebuildScope scope(this,
1705 store_buffer(),
1706 &ScavengeStoreBufferCallback);
1707 while (!promotion_queue()->is_empty()) {
1708 HeapObject* target;
1709 int size;
1710 promotion_queue()->remove(&target, &size);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001711
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001712 // Promoted object might be already partially visited
1713 // during old space pointer iteration. Thus we search specificly
1714 // for pointers to from semispace instead of looking for pointers
1715 // to new space.
1716 ASSERT(!target->IsMap());
1717 IterateAndMarkPointersToFromSpace(target->address(),
1718 target->address() + size,
1719 &ScavengeObject);
1720 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001721 }
1722
1723 // Take another spin if there are now unswept objects in new space
1724 // (there are currently no more unswept promoted objects).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001725 } while (new_space_front != new_space_.top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001726
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001727 return new_space_front;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001728}
1729
1730
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001731STATIC_ASSERT((FixedDoubleArray::kHeaderSize & kDoubleAlignmentMask) == 0);
1732
1733
1734INLINE(static HeapObject* EnsureDoubleAligned(Heap* heap,
1735 HeapObject* object,
1736 int size));
1737
1738static HeapObject* EnsureDoubleAligned(Heap* heap,
1739 HeapObject* object,
1740 int size) {
1741 if ((OffsetFrom(object->address()) & kDoubleAlignmentMask) != 0) {
1742 heap->CreateFillerObjectAt(object->address(), kPointerSize);
1743 return HeapObject::FromAddress(object->address() + kPointerSize);
1744 } else {
1745 heap->CreateFillerObjectAt(object->address() + size - kPointerSize,
1746 kPointerSize);
1747 return object;
1748 }
1749}
1750
1751
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001752enum LoggingAndProfiling {
1753 LOGGING_AND_PROFILING_ENABLED,
1754 LOGGING_AND_PROFILING_DISABLED
1755};
1756
1757
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001758enum MarksHandling { TRANSFER_MARKS, IGNORE_MARKS };
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001759
1760
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001761template<MarksHandling marks_handling,
1762 LoggingAndProfiling logging_and_profiling_mode>
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001763class ScavengingVisitor : public StaticVisitorBase {
1764 public:
1765 static void Initialize() {
1766 table_.Register(kVisitSeqAsciiString, &EvacuateSeqAsciiString);
1767 table_.Register(kVisitSeqTwoByteString, &EvacuateSeqTwoByteString);
1768 table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate);
1769 table_.Register(kVisitByteArray, &EvacuateByteArray);
1770 table_.Register(kVisitFixedArray, &EvacuateFixedArray);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001771 table_.Register(kVisitFixedDoubleArray, &EvacuateFixedDoubleArray);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001772
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001773 table_.Register(kVisitNativeContext,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001774 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001775 template VisitSpecialized<Context::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001776
1777 table_.Register(kVisitConsString,
1778 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001779 template VisitSpecialized<ConsString::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001780
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001781 table_.Register(kVisitSlicedString,
1782 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1783 template VisitSpecialized<SlicedString::kSize>);
1784
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001785 table_.Register(kVisitSharedFunctionInfo,
1786 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001787 template VisitSpecialized<SharedFunctionInfo::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001788
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001789 table_.Register(kVisitJSWeakMap,
1790 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1791 Visit);
1792
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001793 table_.Register(kVisitJSRegExp,
1794 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1795 Visit);
1796
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001797 if (marks_handling == IGNORE_MARKS) {
1798 table_.Register(kVisitJSFunction,
1799 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1800 template VisitSpecialized<JSFunction::kSize>);
1801 } else {
1802 table_.Register(kVisitJSFunction, &EvacuateJSFunction);
1803 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001804
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001805 table_.RegisterSpecializations<ObjectEvacuationStrategy<DATA_OBJECT>,
1806 kVisitDataObject,
1807 kVisitDataObjectGeneric>();
1808
1809 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>,
1810 kVisitJSObject,
1811 kVisitJSObjectGeneric>();
1812
1813 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>,
1814 kVisitStruct,
1815 kVisitStructGeneric>();
1816 }
1817
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001818 static VisitorDispatchTable<ScavengingCallback>* GetTable() {
1819 return &table_;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001820 }
1821
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001822 private:
1823 enum ObjectContents { DATA_OBJECT, POINTER_OBJECT };
1824 enum SizeRestriction { SMALL, UNKNOWN_SIZE };
1825
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826 static void RecordCopiedObject(Heap* heap, HeapObject* obj) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001827 bool should_record = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001828#ifdef DEBUG
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001829 should_record = FLAG_heap_stats;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001830#endif
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001831 should_record = should_record || FLAG_log_gc;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001832 if (should_record) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001833 if (heap->new_space()->Contains(obj)) {
1834 heap->new_space()->RecordAllocation(obj);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001835 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836 heap->new_space()->RecordPromotion(obj);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001837 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001838 }
1839 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001840
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001841 // Helper function used by CopyObject to copy a source object to an
1842 // allocated target object and update the forwarding pointer in the source
1843 // object. Returns the target object.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001844 INLINE(static void MigrateObject(Heap* heap,
1845 HeapObject* source,
1846 HeapObject* target,
1847 int size)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001848 // Copy the content of source to target.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001849 heap->CopyBlock(target->address(), source->address(), size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001850
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001851 // Set the forwarding address.
1852 source->set_map_word(MapWord::FromForwardingAddress(target));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001854 if (logging_and_profiling_mode == LOGGING_AND_PROFILING_ENABLED) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001855 // Update NewSpace stats if necessary.
1856 RecordCopiedObject(heap, target);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001857 HEAP_PROFILE(heap, ObjectMoveEvent(source->address(), target->address()));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001858 Isolate* isolate = heap->isolate();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001859 if (isolate->logger()->is_logging_code_events() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001860 CpuProfiler::is_profiling(isolate)) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001861 if (target->IsSharedFunctionInfo()) {
1862 PROFILE(isolate, SharedFunctionInfoMoveEvent(
1863 source->address(), target->address()));
1864 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001865 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001866 }
1867
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001868 if (marks_handling == TRANSFER_MARKS) {
1869 if (Marking::TransferColor(source, target)) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001870 MemoryChunk::IncrementLiveBytesFromGC(target->address(), size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001871 }
1872 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001873 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001874
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001875
1876 template<ObjectContents object_contents,
1877 SizeRestriction size_restriction,
1878 int alignment>
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001879 static inline void EvacuateObject(Map* map,
1880 HeapObject** slot,
1881 HeapObject* object,
1882 int object_size) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001883 SLOW_ASSERT((size_restriction != SMALL) ||
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001884 (object_size <= Page::kMaxNonCodeHeapObjectSize));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001885 SLOW_ASSERT(object->Size() == object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001886
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001887 int allocation_size = object_size;
1888 if (alignment != kObjectAlignment) {
1889 ASSERT(alignment == kDoubleAlignment);
1890 allocation_size += kPointerSize;
1891 }
1892
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001893 Heap* heap = map->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001894 if (heap->ShouldBePromoted(object->address(), object_size)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001895 MaybeObject* maybe_result;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001896
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001897 if ((size_restriction != SMALL) &&
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001898 (allocation_size > Page::kMaxNonCodeHeapObjectSize)) {
1899 maybe_result = heap->lo_space()->AllocateRaw(allocation_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001900 NOT_EXECUTABLE);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001901 } else {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001902 if (object_contents == DATA_OBJECT) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001903 maybe_result = heap->old_data_space()->AllocateRaw(allocation_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001904 } else {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001905 maybe_result =
1906 heap->old_pointer_space()->AllocateRaw(allocation_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001907 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001908 }
1909
lrn@chromium.org303ada72010-10-27 09:33:13 +00001910 Object* result = NULL; // Initialization to please compiler.
1911 if (maybe_result->ToObject(&result)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001912 HeapObject* target = HeapObject::cast(result);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001913
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001914 if (alignment != kObjectAlignment) {
1915 target = EnsureDoubleAligned(heap, target, allocation_size);
1916 }
1917
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001918 // Order is important: slot might be inside of the target if target
1919 // was allocated over a dead object and slot comes from the store
1920 // buffer.
1921 *slot = target;
1922 MigrateObject(heap, object, target, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001923
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001924 if (object_contents == POINTER_OBJECT) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001925 if (map->instance_type() == JS_FUNCTION_TYPE) {
1926 heap->promotion_queue()->insert(
1927 target, JSFunction::kNonWeakFieldsEndOffset);
1928 } else {
1929 heap->promotion_queue()->insert(target, object_size);
1930 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001931 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001932
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001933 heap->tracer()->increment_promoted_objects_size(object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001934 return;
1935 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001936 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001937 MaybeObject* allocation = heap->new_space()->AllocateRaw(allocation_size);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001938 heap->promotion_queue()->SetNewLimit(heap->new_space()->top());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001939 Object* result = allocation->ToObjectUnchecked();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001940 HeapObject* target = HeapObject::cast(result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001941
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001942 if (alignment != kObjectAlignment) {
1943 target = EnsureDoubleAligned(heap, target, allocation_size);
1944 }
1945
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001946 // Order is important: slot might be inside of the target if target
1947 // was allocated over a dead object and slot comes from the store
1948 // buffer.
1949 *slot = target;
1950 MigrateObject(heap, object, target, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001951 return;
1952 }
1953
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001954
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001955 static inline void EvacuateJSFunction(Map* map,
1956 HeapObject** slot,
1957 HeapObject* object) {
1958 ObjectEvacuationStrategy<POINTER_OBJECT>::
1959 template VisitSpecialized<JSFunction::kSize>(map, slot, object);
1960
1961 HeapObject* target = *slot;
1962 MarkBit mark_bit = Marking::MarkBitFrom(target);
1963 if (Marking::IsBlack(mark_bit)) {
1964 // This object is black and it might not be rescanned by marker.
1965 // We should explicitly record code entry slot for compaction because
1966 // promotion queue processing (IterateAndMarkPointersToFromSpace) will
1967 // miss it as it is not HeapObject-tagged.
1968 Address code_entry_slot =
1969 target->address() + JSFunction::kCodeEntryOffset;
1970 Code* code = Code::cast(Code::GetObjectFromEntryAddress(code_entry_slot));
1971 map->GetHeap()->mark_compact_collector()->
1972 RecordCodeEntrySlot(code_entry_slot, code);
1973 }
1974 }
1975
1976
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001977 static inline void EvacuateFixedArray(Map* map,
1978 HeapObject** slot,
1979 HeapObject* object) {
1980 int object_size = FixedArray::BodyDescriptor::SizeOf(map, object);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001981 EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(map,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001982 slot,
1983 object,
1984 object_size);
1985 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001986
1987
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001988 static inline void EvacuateFixedDoubleArray(Map* map,
1989 HeapObject** slot,
1990 HeapObject* object) {
1991 int length = reinterpret_cast<FixedDoubleArray*>(object)->length();
1992 int object_size = FixedDoubleArray::SizeFor(length);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001993 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kDoubleAlignment>(
1994 map,
1995 slot,
1996 object,
1997 object_size);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001998 }
1999
2000
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002001 static inline void EvacuateByteArray(Map* map,
2002 HeapObject** slot,
2003 HeapObject* object) {
2004 int object_size = reinterpret_cast<ByteArray*>(object)->ByteArraySize();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002005 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
2006 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002007 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002008
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002009
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002010 static inline void EvacuateSeqAsciiString(Map* map,
2011 HeapObject** slot,
2012 HeapObject* object) {
2013 int object_size = SeqAsciiString::cast(object)->
2014 SeqAsciiStringSize(map->instance_type());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002015 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
2016 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002017 }
2018
2019
2020 static inline void EvacuateSeqTwoByteString(Map* map,
2021 HeapObject** slot,
2022 HeapObject* object) {
2023 int object_size = SeqTwoByteString::cast(object)->
2024 SeqTwoByteStringSize(map->instance_type());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002025 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
2026 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002027 }
2028
2029
2030 static inline bool IsShortcutCandidate(int type) {
2031 return ((type & kShortcutTypeMask) == kShortcutTypeTag);
2032 }
2033
2034 static inline void EvacuateShortcutCandidate(Map* map,
2035 HeapObject** slot,
2036 HeapObject* object) {
2037 ASSERT(IsShortcutCandidate(map->instance_type()));
2038
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002039 Heap* heap = map->GetHeap();
2040
2041 if (marks_handling == IGNORE_MARKS &&
2042 ConsString::cast(object)->unchecked_second() ==
2043 heap->empty_string()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002044 HeapObject* first =
2045 HeapObject::cast(ConsString::cast(object)->unchecked_first());
2046
2047 *slot = first;
2048
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002049 if (!heap->InNewSpace(first)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002050 object->set_map_word(MapWord::FromForwardingAddress(first));
2051 return;
2052 }
2053
2054 MapWord first_word = first->map_word();
2055 if (first_word.IsForwardingAddress()) {
2056 HeapObject* target = first_word.ToForwardingAddress();
2057
2058 *slot = target;
2059 object->set_map_word(MapWord::FromForwardingAddress(target));
2060 return;
2061 }
2062
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002063 heap->DoScavengeObject(first->map(), slot, first);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002064 object->set_map_word(MapWord::FromForwardingAddress(*slot));
2065 return;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002066 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002067
2068 int object_size = ConsString::kSize;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002069 EvacuateObject<POINTER_OBJECT, SMALL, kObjectAlignment>(
2070 map, slot, object, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002071 }
2072
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002073 template<ObjectContents object_contents>
2074 class ObjectEvacuationStrategy {
2075 public:
2076 template<int object_size>
2077 static inline void VisitSpecialized(Map* map,
2078 HeapObject** slot,
2079 HeapObject* object) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002080 EvacuateObject<object_contents, SMALL, kObjectAlignment>(
2081 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002082 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002083
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002084 static inline void Visit(Map* map,
2085 HeapObject** slot,
2086 HeapObject* object) {
2087 int object_size = map->instance_size();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002088 EvacuateObject<object_contents, SMALL, kObjectAlignment>(
2089 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002090 }
2091 };
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002093 static VisitorDispatchTable<ScavengingCallback> table_;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002094};
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002095
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002096
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002097template<MarksHandling marks_handling,
2098 LoggingAndProfiling logging_and_profiling_mode>
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002099VisitorDispatchTable<ScavengingCallback>
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002100 ScavengingVisitor<marks_handling, logging_and_profiling_mode>::table_;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002101
2102
2103static void InitializeScavengingVisitorsTables() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002104 ScavengingVisitor<TRANSFER_MARKS,
2105 LOGGING_AND_PROFILING_DISABLED>::Initialize();
2106 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_DISABLED>::Initialize();
2107 ScavengingVisitor<TRANSFER_MARKS,
2108 LOGGING_AND_PROFILING_ENABLED>::Initialize();
2109 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_ENABLED>::Initialize();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002110}
2111
2112
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002113void Heap::SelectScavengingVisitorsTable() {
2114 bool logging_and_profiling =
2115 isolate()->logger()->is_logging() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002116 CpuProfiler::is_profiling(isolate()) ||
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002117 (isolate()->heap_profiler() != NULL &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002118 isolate()->heap_profiler()->is_profiling());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002119
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002120 if (!incremental_marking()->IsMarking()) {
2121 if (!logging_and_profiling) {
2122 scavenging_visitors_table_.CopyFrom(
2123 ScavengingVisitor<IGNORE_MARKS,
2124 LOGGING_AND_PROFILING_DISABLED>::GetTable());
2125 } else {
2126 scavenging_visitors_table_.CopyFrom(
2127 ScavengingVisitor<IGNORE_MARKS,
2128 LOGGING_AND_PROFILING_ENABLED>::GetTable());
2129 }
2130 } else {
2131 if (!logging_and_profiling) {
2132 scavenging_visitors_table_.CopyFrom(
2133 ScavengingVisitor<TRANSFER_MARKS,
2134 LOGGING_AND_PROFILING_DISABLED>::GetTable());
2135 } else {
2136 scavenging_visitors_table_.CopyFrom(
2137 ScavengingVisitor<TRANSFER_MARKS,
2138 LOGGING_AND_PROFILING_ENABLED>::GetTable());
2139 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002140
2141 if (incremental_marking()->IsCompacting()) {
2142 // When compacting forbid short-circuiting of cons-strings.
2143 // Scavenging code relies on the fact that new space object
2144 // can't be evacuated into evacuation candidate but
2145 // short-circuiting violates this assumption.
2146 scavenging_visitors_table_.Register(
2147 StaticVisitorBase::kVisitShortcutCandidate,
2148 scavenging_visitors_table_.GetVisitorById(
2149 StaticVisitorBase::kVisitConsString));
2150 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002151 }
2152}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002153
2154
2155void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002156 SLOW_ASSERT(HEAP->InFromSpace(object));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002157 MapWord first_word = object->map_word();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002158 SLOW_ASSERT(!first_word.IsForwardingAddress());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002159 Map* map = first_word.ToMap();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002160 map->GetHeap()->DoScavengeObject(map, p, object);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002161}
2162
2163
lrn@chromium.org303ada72010-10-27 09:33:13 +00002164MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type,
2165 int instance_size) {
2166 Object* result;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002167 MaybeObject* maybe_result = AllocateRawMap();
2168 if (!maybe_result->ToObject(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002169
2170 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002171 reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002172 reinterpret_cast<Map*>(result)->set_instance_type(instance_type);
2173 reinterpret_cast<Map*>(result)->set_instance_size(instance_size);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002174 reinterpret_cast<Map*>(result)->set_visitor_id(
2175 StaticVisitorBase::GetVisitorId(instance_type, instance_size));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002176 reinterpret_cast<Map*>(result)->set_inobject_properties(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002177 reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002178 reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002179 reinterpret_cast<Map*>(result)->set_bit_field(0);
2180 reinterpret_cast<Map*>(result)->set_bit_field2(0);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002181 int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) |
2182 Map::OwnsDescriptors::encode(true);
2183 reinterpret_cast<Map*>(result)->set_bit_field3(bit_field3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002184 return result;
2185}
2186
2187
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002188MaybeObject* Heap::AllocateMap(InstanceType instance_type,
2189 int instance_size,
2190 ElementsKind elements_kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002191 Object* result;
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002192 MaybeObject* maybe_result = AllocateRawMap();
2193 if (!maybe_result->To(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002194
2195 Map* map = reinterpret_cast<Map*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002196 map->set_map_no_write_barrier(meta_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002197 map->set_instance_type(instance_type);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002198 map->set_visitor_id(
2199 StaticVisitorBase::GetVisitorId(instance_type, instance_size));
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002200 map->set_prototype(null_value(), SKIP_WRITE_BARRIER);
2201 map->set_constructor(null_value(), SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002202 map->set_instance_size(instance_size);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002203 map->set_inobject_properties(0);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002204 map->set_pre_allocated_property_fields(0);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002205 map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002206 map->init_back_pointer(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002207 map->set_unused_property_fields(0);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002208 map->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002209 map->set_bit_field(0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002210 map->set_bit_field2(1 << Map::kIsExtensible);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002211 int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) |
2212 Map::OwnsDescriptors::encode(true);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002213 map->set_bit_field3(bit_field3);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002214 map->set_elements_kind(elements_kind);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002215
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002216 return map;
2217}
2218
2219
lrn@chromium.org303ada72010-10-27 09:33:13 +00002220MaybeObject* Heap::AllocateCodeCache() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002221 CodeCache* code_cache;
2222 { MaybeObject* maybe_code_cache = AllocateStruct(CODE_CACHE_TYPE);
2223 if (!maybe_code_cache->To(&code_cache)) return maybe_code_cache;
lrn@chromium.org303ada72010-10-27 09:33:13 +00002224 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002225 code_cache->set_default_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
2226 code_cache->set_normal_type_cache(undefined_value(), SKIP_WRITE_BARRIER);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002227 return code_cache;
2228}
2229
2230
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002231MaybeObject* Heap::AllocatePolymorphicCodeCache() {
2232 return AllocateStruct(POLYMORPHIC_CODE_CACHE_TYPE);
2233}
2234
2235
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002236MaybeObject* Heap::AllocateAccessorPair() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002237 AccessorPair* accessors;
2238 { MaybeObject* maybe_accessors = AllocateStruct(ACCESSOR_PAIR_TYPE);
2239 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002240 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002241 accessors->set_getter(the_hole_value(), SKIP_WRITE_BARRIER);
2242 accessors->set_setter(the_hole_value(), SKIP_WRITE_BARRIER);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002243 return accessors;
2244}
2245
2246
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002247MaybeObject* Heap::AllocateTypeFeedbackInfo() {
2248 TypeFeedbackInfo* info;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002249 { MaybeObject* maybe_info = AllocateStruct(TYPE_FEEDBACK_INFO_TYPE);
2250 if (!maybe_info->To(&info)) return maybe_info;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002251 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002252 info->initialize_storage();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002253 info->set_type_feedback_cells(TypeFeedbackCells::cast(empty_fixed_array()),
2254 SKIP_WRITE_BARRIER);
2255 return info;
2256}
2257
2258
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002259MaybeObject* Heap::AllocateAliasedArgumentsEntry(int aliased_context_slot) {
2260 AliasedArgumentsEntry* entry;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002261 { MaybeObject* maybe_entry = AllocateStruct(ALIASED_ARGUMENTS_ENTRY_TYPE);
2262 if (!maybe_entry->To(&entry)) return maybe_entry;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002263 }
2264 entry->set_aliased_context_slot(aliased_context_slot);
2265 return entry;
2266}
2267
2268
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002269const Heap::StringTypeTable Heap::string_type_table[] = {
2270#define STRING_TYPE_ELEMENT(type, size, name, camel_name) \
2271 {type, size, k##camel_name##MapRootIndex},
2272 STRING_TYPE_LIST(STRING_TYPE_ELEMENT)
2273#undef STRING_TYPE_ELEMENT
2274};
2275
2276
2277const Heap::ConstantSymbolTable Heap::constant_symbol_table[] = {
2278#define CONSTANT_SYMBOL_ELEMENT(name, contents) \
2279 {contents, k##name##RootIndex},
2280 SYMBOL_LIST(CONSTANT_SYMBOL_ELEMENT)
2281#undef CONSTANT_SYMBOL_ELEMENT
2282};
2283
2284
2285const Heap::StructTable Heap::struct_table[] = {
2286#define STRUCT_TABLE_ELEMENT(NAME, Name, name) \
2287 { NAME##_TYPE, Name::kSize, k##Name##MapRootIndex },
2288 STRUCT_LIST(STRUCT_TABLE_ELEMENT)
2289#undef STRUCT_TABLE_ELEMENT
2290};
2291
2292
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002293bool Heap::CreateInitialMaps() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002294 Object* obj;
2295 { MaybeObject* maybe_obj = AllocatePartialMap(MAP_TYPE, Map::kSize);
2296 if (!maybe_obj->ToObject(&obj)) return false;
2297 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002298 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002299 Map* new_meta_map = reinterpret_cast<Map*>(obj);
2300 set_meta_map(new_meta_map);
2301 new_meta_map->set_map(new_meta_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002302
lrn@chromium.org303ada72010-10-27 09:33:13 +00002303 { MaybeObject* maybe_obj =
2304 AllocatePartialMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2305 if (!maybe_obj->ToObject(&obj)) return false;
2306 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002307 set_fixed_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002308
lrn@chromium.org303ada72010-10-27 09:33:13 +00002309 { MaybeObject* maybe_obj = AllocatePartialMap(ODDBALL_TYPE, Oddball::kSize);
2310 if (!maybe_obj->ToObject(&obj)) return false;
2311 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002312 set_oddball_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002313
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002314 // Allocate the empty array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002315 { MaybeObject* maybe_obj = AllocateEmptyFixedArray();
2316 if (!maybe_obj->ToObject(&obj)) return false;
2317 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002318 set_empty_fixed_array(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002319
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002320 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002321 if (!maybe_obj->ToObject(&obj)) return false;
2322 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002323 set_null_value(Oddball::cast(obj));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002324 Oddball::cast(obj)->set_kind(Oddball::kNull);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002325
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002326 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE);
2327 if (!maybe_obj->ToObject(&obj)) return false;
2328 }
2329 set_undefined_value(Oddball::cast(obj));
2330 Oddball::cast(obj)->set_kind(Oddball::kUndefined);
2331 ASSERT(!InNewSpace(undefined_value()));
2332
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002333 // Allocate the empty descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002334 { MaybeObject* maybe_obj = AllocateEmptyFixedArray();
2335 if (!maybe_obj->ToObject(&obj)) return false;
2336 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002337 set_empty_descriptor_array(DescriptorArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002338
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002339 // Fix the instance_descriptors for the existing maps.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002340 meta_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002341 meta_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002342 meta_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002343
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002344 fixed_array_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002345 fixed_array_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002346 fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002347
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002348 oddball_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002349 oddball_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002350 oddball_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002351
2352 // Fix prototype object for existing maps.
2353 meta_map()->set_prototype(null_value());
2354 meta_map()->set_constructor(null_value());
2355
2356 fixed_array_map()->set_prototype(null_value());
2357 fixed_array_map()->set_constructor(null_value());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002358
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002359 oddball_map()->set_prototype(null_value());
2360 oddball_map()->set_constructor(null_value());
2361
lrn@chromium.org303ada72010-10-27 09:33:13 +00002362 { MaybeObject* maybe_obj =
2363 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2364 if (!maybe_obj->ToObject(&obj)) return false;
2365 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002366 set_fixed_cow_array_map(Map::cast(obj));
2367 ASSERT(fixed_array_map() != fixed_cow_array_map());
2368
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002369 { MaybeObject* maybe_obj =
2370 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2371 if (!maybe_obj->ToObject(&obj)) return false;
2372 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002373 set_scope_info_map(Map::cast(obj));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002374
lrn@chromium.org303ada72010-10-27 09:33:13 +00002375 { MaybeObject* maybe_obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
2376 if (!maybe_obj->ToObject(&obj)) return false;
2377 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002378 set_heap_number_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002379
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002380 { MaybeObject* maybe_obj = AllocateMap(FOREIGN_TYPE, Foreign::kSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002381 if (!maybe_obj->ToObject(&obj)) return false;
2382 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002383 set_foreign_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002384
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002385 for (unsigned i = 0; i < ARRAY_SIZE(string_type_table); i++) {
2386 const StringTypeTable& entry = string_type_table[i];
lrn@chromium.org303ada72010-10-27 09:33:13 +00002387 { MaybeObject* maybe_obj = AllocateMap(entry.type, entry.size);
2388 if (!maybe_obj->ToObject(&obj)) return false;
2389 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002390 roots_[entry.index] = Map::cast(obj);
2391 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002392
lrn@chromium.org303ada72010-10-27 09:33:13 +00002393 { MaybeObject* maybe_obj = AllocateMap(STRING_TYPE, kVariableSizeSentinel);
2394 if (!maybe_obj->ToObject(&obj)) return false;
2395 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002396 set_undetectable_string_map(Map::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002397 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002398
lrn@chromium.org303ada72010-10-27 09:33:13 +00002399 { MaybeObject* maybe_obj =
2400 AllocateMap(ASCII_STRING_TYPE, kVariableSizeSentinel);
2401 if (!maybe_obj->ToObject(&obj)) return false;
2402 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002403 set_undetectable_ascii_string_map(Map::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002404 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002405
lrn@chromium.org303ada72010-10-27 09:33:13 +00002406 { MaybeObject* maybe_obj =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002407 AllocateMap(FIXED_DOUBLE_ARRAY_TYPE, kVariableSizeSentinel);
2408 if (!maybe_obj->ToObject(&obj)) return false;
2409 }
2410 set_fixed_double_array_map(Map::cast(obj));
2411
2412 { MaybeObject* maybe_obj =
lrn@chromium.org303ada72010-10-27 09:33:13 +00002413 AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel);
2414 if (!maybe_obj->ToObject(&obj)) return false;
2415 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002416 set_byte_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002417
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002418 { MaybeObject* maybe_obj =
2419 AllocateMap(FREE_SPACE_TYPE, kVariableSizeSentinel);
2420 if (!maybe_obj->ToObject(&obj)) return false;
2421 }
2422 set_free_space_map(Map::cast(obj));
2423
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002424 { MaybeObject* maybe_obj = AllocateByteArray(0, TENURED);
2425 if (!maybe_obj->ToObject(&obj)) return false;
2426 }
2427 set_empty_byte_array(ByteArray::cast(obj));
2428
lrn@chromium.org303ada72010-10-27 09:33:13 +00002429 { MaybeObject* maybe_obj =
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002430 AllocateMap(EXTERNAL_PIXEL_ARRAY_TYPE, ExternalArray::kAlignedSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002431 if (!maybe_obj->ToObject(&obj)) return false;
2432 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002433 set_external_pixel_array_map(Map::cast(obj));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002434
lrn@chromium.org303ada72010-10-27 09:33:13 +00002435 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_BYTE_ARRAY_TYPE,
2436 ExternalArray::kAlignedSize);
2437 if (!maybe_obj->ToObject(&obj)) return false;
2438 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002439 set_external_byte_array_map(Map::cast(obj));
2440
lrn@chromium.org303ada72010-10-27 09:33:13 +00002441 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE,
2442 ExternalArray::kAlignedSize);
2443 if (!maybe_obj->ToObject(&obj)) return false;
2444 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002445 set_external_unsigned_byte_array_map(Map::cast(obj));
2446
lrn@chromium.org303ada72010-10-27 09:33:13 +00002447 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_SHORT_ARRAY_TYPE,
2448 ExternalArray::kAlignedSize);
2449 if (!maybe_obj->ToObject(&obj)) return false;
2450 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002451 set_external_short_array_map(Map::cast(obj));
2452
lrn@chromium.org303ada72010-10-27 09:33:13 +00002453 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE,
2454 ExternalArray::kAlignedSize);
2455 if (!maybe_obj->ToObject(&obj)) return false;
2456 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002457 set_external_unsigned_short_array_map(Map::cast(obj));
2458
lrn@chromium.org303ada72010-10-27 09:33:13 +00002459 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_INT_ARRAY_TYPE,
2460 ExternalArray::kAlignedSize);
2461 if (!maybe_obj->ToObject(&obj)) return false;
2462 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002463 set_external_int_array_map(Map::cast(obj));
2464
lrn@chromium.org303ada72010-10-27 09:33:13 +00002465 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE,
2466 ExternalArray::kAlignedSize);
2467 if (!maybe_obj->ToObject(&obj)) return false;
2468 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002469 set_external_unsigned_int_array_map(Map::cast(obj));
2470
lrn@chromium.org303ada72010-10-27 09:33:13 +00002471 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_FLOAT_ARRAY_TYPE,
2472 ExternalArray::kAlignedSize);
2473 if (!maybe_obj->ToObject(&obj)) return false;
2474 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002475 set_external_float_array_map(Map::cast(obj));
2476
whesse@chromium.org7b260152011-06-20 15:33:18 +00002477 { MaybeObject* maybe_obj =
2478 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2479 if (!maybe_obj->ToObject(&obj)) return false;
2480 }
2481 set_non_strict_arguments_elements_map(Map::cast(obj));
2482
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002483 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_DOUBLE_ARRAY_TYPE,
2484 ExternalArray::kAlignedSize);
2485 if (!maybe_obj->ToObject(&obj)) return false;
2486 }
2487 set_external_double_array_map(Map::cast(obj));
2488
lrn@chromium.org303ada72010-10-27 09:33:13 +00002489 { MaybeObject* maybe_obj = AllocateMap(CODE_TYPE, kVariableSizeSentinel);
2490 if (!maybe_obj->ToObject(&obj)) return false;
2491 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002492 set_code_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002493
lrn@chromium.org303ada72010-10-27 09:33:13 +00002494 { MaybeObject* maybe_obj = AllocateMap(JS_GLOBAL_PROPERTY_CELL_TYPE,
2495 JSGlobalPropertyCell::kSize);
2496 if (!maybe_obj->ToObject(&obj)) return false;
2497 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002498 set_global_property_cell_map(Map::cast(obj));
2499
lrn@chromium.org303ada72010-10-27 09:33:13 +00002500 { MaybeObject* maybe_obj = AllocateMap(FILLER_TYPE, kPointerSize);
2501 if (!maybe_obj->ToObject(&obj)) return false;
2502 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002503 set_one_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002504
lrn@chromium.org303ada72010-10-27 09:33:13 +00002505 { MaybeObject* maybe_obj = AllocateMap(FILLER_TYPE, 2 * kPointerSize);
2506 if (!maybe_obj->ToObject(&obj)) return false;
2507 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002508 set_two_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002509
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002510 for (unsigned i = 0; i < ARRAY_SIZE(struct_table); i++) {
2511 const StructTable& entry = struct_table[i];
lrn@chromium.org303ada72010-10-27 09:33:13 +00002512 { MaybeObject* maybe_obj = AllocateMap(entry.type, entry.size);
2513 if (!maybe_obj->ToObject(&obj)) return false;
2514 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002515 roots_[entry.index] = Map::cast(obj);
2516 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002517
lrn@chromium.org303ada72010-10-27 09:33:13 +00002518 { MaybeObject* maybe_obj =
2519 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2520 if (!maybe_obj->ToObject(&obj)) return false;
2521 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002522 set_hash_table_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002523
lrn@chromium.org303ada72010-10-27 09:33:13 +00002524 { MaybeObject* maybe_obj =
2525 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2526 if (!maybe_obj->ToObject(&obj)) return false;
2527 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002528 set_function_context_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002529
lrn@chromium.org303ada72010-10-27 09:33:13 +00002530 { MaybeObject* maybe_obj =
2531 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2532 if (!maybe_obj->ToObject(&obj)) return false;
2533 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002534 set_catch_context_map(Map::cast(obj));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002535
lrn@chromium.org303ada72010-10-27 09:33:13 +00002536 { MaybeObject* maybe_obj =
2537 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2538 if (!maybe_obj->ToObject(&obj)) return false;
2539 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002540 set_with_context_map(Map::cast(obj));
2541
2542 { MaybeObject* maybe_obj =
2543 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2544 if (!maybe_obj->ToObject(&obj)) return false;
2545 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002546 set_block_context_map(Map::cast(obj));
2547
2548 { MaybeObject* maybe_obj =
2549 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2550 if (!maybe_obj->ToObject(&obj)) return false;
2551 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002552 set_module_context_map(Map::cast(obj));
2553
2554 { MaybeObject* maybe_obj =
2555 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2556 if (!maybe_obj->ToObject(&obj)) return false;
2557 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002558 set_global_context_map(Map::cast(obj));
2559
2560 { MaybeObject* maybe_obj =
2561 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2562 if (!maybe_obj->ToObject(&obj)) return false;
2563 }
2564 Map* native_context_map = Map::cast(obj);
2565 native_context_map->set_dictionary_map(true);
2566 native_context_map->set_visitor_id(StaticVisitorBase::kVisitNativeContext);
2567 set_native_context_map(native_context_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002568
lrn@chromium.org303ada72010-10-27 09:33:13 +00002569 { MaybeObject* maybe_obj = AllocateMap(SHARED_FUNCTION_INFO_TYPE,
2570 SharedFunctionInfo::kAlignedSize);
2571 if (!maybe_obj->ToObject(&obj)) return false;
2572 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002573 set_shared_function_info_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002574
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002575 { MaybeObject* maybe_obj = AllocateMap(JS_MESSAGE_OBJECT_TYPE,
2576 JSMessageObject::kSize);
2577 if (!maybe_obj->ToObject(&obj)) return false;
2578 }
2579 set_message_object_map(Map::cast(obj));
2580
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002581 Map* external_map;
2582 { MaybeObject* maybe_obj =
2583 AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize + kPointerSize);
2584 if (!maybe_obj->To(&external_map)) return false;
2585 }
2586 external_map->set_is_extensible(false);
2587 set_external_map(external_map);
2588
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002589 ASSERT(!InNewSpace(empty_fixed_array()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002590 return true;
2591}
2592
2593
lrn@chromium.org303ada72010-10-27 09:33:13 +00002594MaybeObject* Heap::AllocateHeapNumber(double value, PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002595 // Statically ensure that it is safe to allocate heap numbers in paged
2596 // spaces.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002597 STATIC_ASSERT(HeapNumber::kSize <= Page::kNonCodeObjectAreaSize);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002598 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002599
lrn@chromium.org303ada72010-10-27 09:33:13 +00002600 Object* result;
2601 { MaybeObject* maybe_result =
2602 AllocateRaw(HeapNumber::kSize, space, OLD_DATA_SPACE);
2603 if (!maybe_result->ToObject(&result)) return maybe_result;
2604 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002605
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002606 HeapObject::cast(result)->set_map_no_write_barrier(heap_number_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002607 HeapNumber::cast(result)->set_value(value);
2608 return result;
2609}
2610
2611
lrn@chromium.org303ada72010-10-27 09:33:13 +00002612MaybeObject* Heap::AllocateHeapNumber(double value) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002613 // Use general version, if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002614 if (always_allocate()) return AllocateHeapNumber(value, TENURED);
2615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002616 // This version of AllocateHeapNumber is optimized for
2617 // allocation in new space.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002618 STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxNonCodeHeapObjectSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002619 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002620 Object* result;
2621 { MaybeObject* maybe_result = new_space_.AllocateRaw(HeapNumber::kSize);
2622 if (!maybe_result->ToObject(&result)) return maybe_result;
2623 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002624 HeapObject::cast(result)->set_map_no_write_barrier(heap_number_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002625 HeapNumber::cast(result)->set_value(value);
2626 return result;
2627}
2628
2629
lrn@chromium.org303ada72010-10-27 09:33:13 +00002630MaybeObject* Heap::AllocateJSGlobalPropertyCell(Object* value) {
2631 Object* result;
2632 { MaybeObject* maybe_result = AllocateRawCell();
2633 if (!maybe_result->ToObject(&result)) return maybe_result;
2634 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002635 HeapObject::cast(result)->set_map_no_write_barrier(
2636 global_property_cell_map());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002637 JSGlobalPropertyCell::cast(result)->set_value(value);
2638 return result;
2639}
2640
2641
lrn@chromium.org303ada72010-10-27 09:33:13 +00002642MaybeObject* Heap::CreateOddball(const char* to_string,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002643 Object* to_number,
2644 byte kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002645 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002646 { MaybeObject* maybe_result = Allocate(oddball_map(), OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002647 if (!maybe_result->ToObject(&result)) return maybe_result;
2648 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002649 return Oddball::cast(result)->Initialize(to_string, to_number, kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002650}
2651
2652
2653bool Heap::CreateApiObjects() {
2654 Object* obj;
2655
lrn@chromium.org303ada72010-10-27 09:33:13 +00002656 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
2657 if (!maybe_obj->ToObject(&obj)) return false;
2658 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002659 // Don't use Smi-only elements optimizations for objects with the neander
2660 // map. There are too many cases where element values are set directly with a
2661 // bottleneck to trap the Smi-only -> fast elements transition, and there
2662 // appears to be no benefit for optimize this case.
2663 Map* new_neander_map = Map::cast(obj);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002664 new_neander_map->set_elements_kind(TERMINAL_FAST_ELEMENTS_KIND);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002665 set_neander_map(new_neander_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002666
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002667 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(neander_map());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002668 if (!maybe_obj->ToObject(&obj)) return false;
2669 }
2670 Object* elements;
2671 { MaybeObject* maybe_elements = AllocateFixedArray(2);
2672 if (!maybe_elements->ToObject(&elements)) return false;
2673 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002674 FixedArray::cast(elements)->set(0, Smi::FromInt(0));
2675 JSObject::cast(obj)->set_elements(FixedArray::cast(elements));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002676 set_message_listeners(JSObject::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002677
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002678 return true;
2679}
2680
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002681
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002682void Heap::CreateJSEntryStub() {
2683 JSEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002684 set_js_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002685}
2686
2687
2688void Heap::CreateJSConstructEntryStub() {
2689 JSConstructEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002690 set_js_construct_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002691}
2692
2693
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002694void Heap::CreateFixedStubs() {
2695 // Here we create roots for fixed stubs. They are needed at GC
2696 // for cooking and uncooking (check out frames.cc).
2697 // The eliminates the need for doing dictionary lookup in the
2698 // stub cache for these stubs.
2699 HandleScope scope;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002700 // gcc-4.4 has problem generating correct code of following snippet:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002701 // { JSEntryStub stub;
2702 // js_entry_code_ = *stub.GetCode();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002703 // }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002704 // { JSConstructEntryStub stub;
2705 // js_construct_entry_code_ = *stub.GetCode();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002706 // }
2707 // To workaround the problem, make separate functions without inlining.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002708 Heap::CreateJSEntryStub();
2709 Heap::CreateJSConstructEntryStub();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002710
2711 // Create stubs that should be there, so we don't unexpectedly have to
2712 // create them if we need them during the creation of another stub.
2713 // Stub creation mixes raw pointers and handles in an unsafe manner so
2714 // we cannot create stubs while we are creating stubs.
2715 CodeStub::GenerateStubsAheadOfTime();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002716}
2717
2718
2719bool Heap::CreateInitialObjects() {
2720 Object* obj;
2721
2722 // The -0 value must be set before NumberFromDouble works.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002723 { MaybeObject* maybe_obj = AllocateHeapNumber(-0.0, TENURED);
2724 if (!maybe_obj->ToObject(&obj)) return false;
2725 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002726 set_minus_zero_value(HeapNumber::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002727 ASSERT(signbit(minus_zero_value()->Number()) != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002728
lrn@chromium.org303ada72010-10-27 09:33:13 +00002729 { MaybeObject* maybe_obj = AllocateHeapNumber(OS::nan_value(), TENURED);
2730 if (!maybe_obj->ToObject(&obj)) return false;
2731 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002732 set_nan_value(HeapNumber::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002733
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002734 { MaybeObject* maybe_obj = AllocateHeapNumber(V8_INFINITY, TENURED);
2735 if (!maybe_obj->ToObject(&obj)) return false;
2736 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002737 set_infinity_value(HeapNumber::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002738
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00002739 // The hole has not been created yet, but we want to put something
2740 // predictable in the gaps in the symbol table, so lets make that Smi zero.
2741 set_the_hole_value(reinterpret_cast<Oddball*>(Smi::FromInt(0)));
2742
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002743 // Allocate initial symbol table.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002744 { MaybeObject* maybe_obj = SymbolTable::Allocate(kInitialSymbolTableSize);
2745 if (!maybe_obj->ToObject(&obj)) return false;
2746 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002747 // Don't use set_symbol_table() due to asserts.
2748 roots_[kSymbolTableRootIndex] = obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002749
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002750 // Finish initializing oddballs after creating symboltable.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002751 { MaybeObject* maybe_obj =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002752 undefined_value()->Initialize("undefined",
2753 nan_value(),
2754 Oddball::kUndefined);
2755 if (!maybe_obj->ToObject(&obj)) return false;
2756 }
2757
2758 // Initialize the null_value.
2759 { MaybeObject* maybe_obj =
2760 null_value()->Initialize("null", Smi::FromInt(0), Oddball::kNull);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002761 if (!maybe_obj->ToObject(&obj)) return false;
2762 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002763
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002764 { MaybeObject* maybe_obj = CreateOddball("true",
2765 Smi::FromInt(1),
2766 Oddball::kTrue);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002767 if (!maybe_obj->ToObject(&obj)) return false;
2768 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002769 set_true_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002770
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002771 { MaybeObject* maybe_obj = CreateOddball("false",
2772 Smi::FromInt(0),
2773 Oddball::kFalse);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002774 if (!maybe_obj->ToObject(&obj)) return false;
2775 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002776 set_false_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002777
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002778 { MaybeObject* maybe_obj = CreateOddball("hole",
2779 Smi::FromInt(-1),
2780 Oddball::kTheHole);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002781 if (!maybe_obj->ToObject(&obj)) return false;
2782 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002783 set_the_hole_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002784
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002785 { MaybeObject* maybe_obj = CreateOddball("arguments_marker",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002786 Smi::FromInt(-4),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002787 Oddball::kArgumentMarker);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002788 if (!maybe_obj->ToObject(&obj)) return false;
2789 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002790 set_arguments_marker(Oddball::cast(obj));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002791
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002792 { MaybeObject* maybe_obj = CreateOddball("no_interceptor_result_sentinel",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002793 Smi::FromInt(-2),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002794 Oddball::kOther);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002795 if (!maybe_obj->ToObject(&obj)) return false;
2796 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002797 set_no_interceptor_result_sentinel(obj);
2798
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002799 { MaybeObject* maybe_obj = CreateOddball("termination_exception",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002800 Smi::FromInt(-3),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002801 Oddball::kOther);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002802 if (!maybe_obj->ToObject(&obj)) return false;
2803 }
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00002804 set_termination_exception(obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002805
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002806 // Allocate the empty string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002807 { MaybeObject* maybe_obj = AllocateRawAsciiString(0, TENURED);
2808 if (!maybe_obj->ToObject(&obj)) return false;
2809 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002810 set_empty_string(String::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002811
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002812 for (unsigned i = 0; i < ARRAY_SIZE(constant_symbol_table); i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002813 { MaybeObject* maybe_obj =
2814 LookupAsciiSymbol(constant_symbol_table[i].contents);
2815 if (!maybe_obj->ToObject(&obj)) return false;
2816 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002817 roots_[constant_symbol_table[i].index] = String::cast(obj);
2818 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002819
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002820 // Allocate the hidden symbol which is used to identify the hidden properties
2821 // in JSObjects. The hash code has a special value so that it will not match
2822 // the empty string when searching for the property. It cannot be part of the
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002823 // loop above because it needs to be allocated manually with the special
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002824 // hash code in place. The hash code for the hidden_symbol is zero to ensure
2825 // that it will always be at the first entry in property descriptors.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002826 { MaybeObject* maybe_obj =
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002827 AllocateSymbol(CStrVector(""), 0, String::kEmptyStringHash);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002828 if (!maybe_obj->ToObject(&obj)) return false;
2829 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002830 hidden_symbol_ = String::cast(obj);
2831
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002832 // Allocate the foreign for __proto__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002833 { MaybeObject* maybe_obj =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002834 AllocateForeign((Address) &Accessors::ObjectPrototype);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002835 if (!maybe_obj->ToObject(&obj)) return false;
2836 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002837 set_prototype_accessors(Foreign::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002838
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002839 // Allocate the code_stubs dictionary. The initial size is set to avoid
2840 // expanding the dictionary during bootstrapping.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002841 { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(128);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002842 if (!maybe_obj->ToObject(&obj)) return false;
2843 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002844 set_code_stubs(UnseededNumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002845
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002846
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002847 // Allocate the non_monomorphic_cache used in stub-cache.cc. The initial size
2848 // is set to avoid expanding the dictionary during bootstrapping.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002849 { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(64);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002850 if (!maybe_obj->ToObject(&obj)) return false;
2851 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002852 set_non_monomorphic_cache(UnseededNumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002853
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002854 { MaybeObject* maybe_obj = AllocatePolymorphicCodeCache();
2855 if (!maybe_obj->ToObject(&obj)) return false;
2856 }
2857 set_polymorphic_code_cache(PolymorphicCodeCache::cast(obj));
2858
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002859 set_instanceof_cache_function(Smi::FromInt(0));
2860 set_instanceof_cache_map(Smi::FromInt(0));
2861 set_instanceof_cache_answer(Smi::FromInt(0));
2862
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002863 CreateFixedStubs();
2864
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002865 // Allocate the dictionary of intrinsic function names.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002866 { MaybeObject* maybe_obj = StringDictionary::Allocate(Runtime::kNumFunctions);
2867 if (!maybe_obj->ToObject(&obj)) return false;
2868 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002869 { MaybeObject* maybe_obj = Runtime::InitializeIntrinsicFunctionNames(this,
2870 obj);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002871 if (!maybe_obj->ToObject(&obj)) return false;
2872 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002873 set_intrinsic_function_names(StringDictionary::cast(obj));
2874
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002875 { MaybeObject* maybe_obj = AllocateInitialNumberStringCache();
2876 if (!maybe_obj->ToObject(&obj)) return false;
2877 }
2878 set_number_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002879
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002880 // Allocate cache for single character ASCII strings.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002881 { MaybeObject* maybe_obj =
2882 AllocateFixedArray(String::kMaxAsciiCharCode + 1, TENURED);
2883 if (!maybe_obj->ToObject(&obj)) return false;
2884 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002885 set_single_character_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002886
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002887 // Allocate cache for string split.
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002888 { MaybeObject* maybe_obj = AllocateFixedArray(
2889 RegExpResultsCache::kRegExpResultsCacheSize, TENURED);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002890 if (!maybe_obj->ToObject(&obj)) return false;
2891 }
2892 set_string_split_cache(FixedArray::cast(obj));
2893
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002894 { MaybeObject* maybe_obj = AllocateFixedArray(
2895 RegExpResultsCache::kRegExpResultsCacheSize, TENURED);
2896 if (!maybe_obj->ToObject(&obj)) return false;
2897 }
2898 set_regexp_multiple_cache(FixedArray::cast(obj));
2899
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002900 // Allocate cache for external strings pointing to native source code.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002901 { MaybeObject* maybe_obj = AllocateFixedArray(Natives::GetBuiltinsCount());
2902 if (!maybe_obj->ToObject(&obj)) return false;
2903 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002904 set_natives_source_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002905
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002906 // Allocate object to hold object observation state.
2907 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
2908 if (!maybe_obj->ToObject(&obj)) return false;
2909 }
2910 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(Map::cast(obj));
2911 if (!maybe_obj->ToObject(&obj)) return false;
2912 }
2913 set_observation_state(JSObject::cast(obj));
2914
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002915 // Handling of script id generation is in FACTORY->NewScript.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002916 set_last_script_id(undefined_value());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002917
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002918 // Initialize keyed lookup cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002919 isolate_->keyed_lookup_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002920
2921 // Initialize context slot cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002922 isolate_->context_slot_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002923
2924 // Initialize descriptor cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002925 isolate_->descriptor_lookup_cache()->Clear();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002926
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002927 // Initialize compilation cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002928 isolate_->compilation_cache()->Clear();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002929
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002930 return true;
2931}
2932
2933
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002934bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) {
2935 RootListIndex writable_roots[] = {
2936 kStoreBufferTopRootIndex,
2937 kStackLimitRootIndex,
2938 kInstanceofCacheFunctionRootIndex,
2939 kInstanceofCacheMapRootIndex,
2940 kInstanceofCacheAnswerRootIndex,
2941 kCodeStubsRootIndex,
2942 kNonMonomorphicCacheRootIndex,
2943 kPolymorphicCodeCacheRootIndex,
2944 kLastScriptIdRootIndex,
2945 kEmptyScriptRootIndex,
2946 kRealStackLimitRootIndex,
2947 kArgumentsAdaptorDeoptPCOffsetRootIndex,
2948 kConstructStubDeoptPCOffsetRootIndex,
2949 kGetterStubDeoptPCOffsetRootIndex,
2950 kSetterStubDeoptPCOffsetRootIndex,
2951 kSymbolTableRootIndex,
2952 };
2953
2954 for (unsigned int i = 0; i < ARRAY_SIZE(writable_roots); i++) {
2955 if (root_index == writable_roots[i])
2956 return true;
2957 }
2958 return false;
2959}
2960
2961
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002962Object* RegExpResultsCache::Lookup(Heap* heap,
2963 String* key_string,
2964 Object* key_pattern,
2965 ResultsCacheType type) {
2966 FixedArray* cache;
2967 if (!key_string->IsSymbol()) return Smi::FromInt(0);
2968 if (type == STRING_SPLIT_SUBSTRINGS) {
2969 ASSERT(key_pattern->IsString());
2970 if (!key_pattern->IsSymbol()) return Smi::FromInt(0);
2971 cache = heap->string_split_cache();
2972 } else {
2973 ASSERT(type == REGEXP_MULTIPLE_INDICES);
2974 ASSERT(key_pattern->IsFixedArray());
2975 cache = heap->regexp_multiple_cache();
2976 }
2977
2978 uint32_t hash = key_string->Hash();
2979 uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) &
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002980 ~(kArrayEntriesPerCacheEntry - 1));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002981 if (cache->get(index + kStringOffset) == key_string &&
2982 cache->get(index + kPatternOffset) == key_pattern) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002983 return cache->get(index + kArrayOffset);
2984 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002985 index =
2986 ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1));
2987 if (cache->get(index + kStringOffset) == key_string &&
2988 cache->get(index + kPatternOffset) == key_pattern) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002989 return cache->get(index + kArrayOffset);
2990 }
2991 return Smi::FromInt(0);
2992}
2993
2994
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002995void RegExpResultsCache::Enter(Heap* heap,
2996 String* key_string,
2997 Object* key_pattern,
2998 FixedArray* value_array,
2999 ResultsCacheType type) {
3000 FixedArray* cache;
3001 if (!key_string->IsSymbol()) return;
3002 if (type == STRING_SPLIT_SUBSTRINGS) {
3003 ASSERT(key_pattern->IsString());
3004 if (!key_pattern->IsSymbol()) return;
3005 cache = heap->string_split_cache();
3006 } else {
3007 ASSERT(type == REGEXP_MULTIPLE_INDICES);
3008 ASSERT(key_pattern->IsFixedArray());
3009 cache = heap->regexp_multiple_cache();
3010 }
3011
3012 uint32_t hash = key_string->Hash();
3013 uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) &
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003014 ~(kArrayEntriesPerCacheEntry - 1));
3015 if (cache->get(index + kStringOffset) == Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003016 cache->set(index + kStringOffset, key_string);
3017 cache->set(index + kPatternOffset, key_pattern);
3018 cache->set(index + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003019 } else {
3020 uint32_t index2 =
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003021 ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1));
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003022 if (cache->get(index2 + kStringOffset) == Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003023 cache->set(index2 + kStringOffset, key_string);
3024 cache->set(index2 + kPatternOffset, key_pattern);
3025 cache->set(index2 + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003026 } else {
3027 cache->set(index2 + kStringOffset, Smi::FromInt(0));
3028 cache->set(index2 + kPatternOffset, Smi::FromInt(0));
3029 cache->set(index2 + kArrayOffset, Smi::FromInt(0));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003030 cache->set(index + kStringOffset, key_string);
3031 cache->set(index + kPatternOffset, key_pattern);
3032 cache->set(index + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003033 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003034 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003035 // If the array is a reasonably short list of substrings, convert it into a
3036 // list of symbols.
3037 if (type == STRING_SPLIT_SUBSTRINGS && value_array->length() < 100) {
3038 for (int i = 0; i < value_array->length(); i++) {
3039 String* str = String::cast(value_array->get(i));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003040 Object* symbol;
3041 MaybeObject* maybe_symbol = heap->LookupSymbol(str);
3042 if (maybe_symbol->ToObject(&symbol)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003043 value_array->set(i, symbol);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003044 }
3045 }
3046 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003047 // Convert backing store to a copy-on-write array.
3048 value_array->set_map_no_write_barrier(heap->fixed_cow_array_map());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003049}
3050
3051
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003052void RegExpResultsCache::Clear(FixedArray* cache) {
3053 for (int i = 0; i < kRegExpResultsCacheSize; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003054 cache->set(i, Smi::FromInt(0));
3055 }
3056}
3057
3058
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003059MaybeObject* Heap::AllocateInitialNumberStringCache() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003060 MaybeObject* maybe_obj =
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003061 AllocateFixedArray(kInitialNumberStringCacheSize * 2, TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003062 return maybe_obj;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003063}
3064
3065
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003066int Heap::FullSizeNumberStringCacheLength() {
3067 // Compute the size of the number string cache based on the max newspace size.
3068 // The number string cache has a minimum size based on twice the initial cache
3069 // size to ensure that it is bigger after being made 'full size'.
3070 int number_string_cache_size = max_semispace_size_ / 512;
3071 number_string_cache_size = Max(kInitialNumberStringCacheSize * 2,
3072 Min(0x4000, number_string_cache_size));
3073 // There is a string and a number per entry so the length is twice the number
3074 // of entries.
3075 return number_string_cache_size * 2;
3076}
3077
3078
3079void Heap::AllocateFullSizeNumberStringCache() {
3080 // The idea is to have a small number string cache in the snapshot to keep
3081 // boot-time memory usage down. If we expand the number string cache already
3082 // while creating the snapshot then that didn't work out.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003083 ASSERT(!Serializer::enabled() || FLAG_extra_code != NULL);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003084 MaybeObject* maybe_obj =
3085 AllocateFixedArray(FullSizeNumberStringCacheLength(), TENURED);
3086 Object* new_cache;
3087 if (maybe_obj->ToObject(&new_cache)) {
3088 // We don't bother to repopulate the cache with entries from the old cache.
3089 // It will be repopulated soon enough with new strings.
3090 set_number_string_cache(FixedArray::cast(new_cache));
3091 }
3092 // If allocation fails then we just return without doing anything. It is only
3093 // a cache, so best effort is OK here.
3094}
3095
3096
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003097void Heap::FlushNumberStringCache() {
3098 // Flush the number to string cache.
3099 int len = number_string_cache()->length();
3100 for (int i = 0; i < len; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003101 number_string_cache()->set_undefined(this, i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003102 }
3103}
3104
3105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003106static inline int double_get_hash(double d) {
3107 DoubleRepresentation rep(d);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003108 return static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003109}
3110
3111
3112static inline int smi_get_hash(Smi* smi) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003113 return smi->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003114}
3115
3116
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003117Object* Heap::GetNumberStringCache(Object* number) {
3118 int hash;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003119 int mask = (number_string_cache()->length() >> 1) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003120 if (number->IsSmi()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003121 hash = smi_get_hash(Smi::cast(number)) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003122 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003123 hash = double_get_hash(number->Number()) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003124 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003125 Object* key = number_string_cache()->get(hash * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003126 if (key == number) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003127 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003128 } else if (key->IsHeapNumber() &&
3129 number->IsHeapNumber() &&
3130 key->Number() == number->Number()) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003131 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003132 }
3133 return undefined_value();
3134}
3135
3136
3137void Heap::SetNumberStringCache(Object* number, String* string) {
3138 int hash;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003139 int mask = (number_string_cache()->length() >> 1) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003140 if (number->IsSmi()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003141 hash = smi_get_hash(Smi::cast(number)) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003142 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003143 hash = double_get_hash(number->Number()) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003144 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003145 if (number_string_cache()->get(hash * 2) != undefined_value() &&
3146 number_string_cache()->length() != FullSizeNumberStringCacheLength()) {
3147 // The first time we have a hash collision, we move to the full sized
3148 // number string cache.
3149 AllocateFullSizeNumberStringCache();
3150 return;
3151 }
3152 number_string_cache()->set(hash * 2, number);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003153 number_string_cache()->set(hash * 2 + 1, string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003154}
3155
3156
lrn@chromium.org303ada72010-10-27 09:33:13 +00003157MaybeObject* Heap::NumberToString(Object* number,
3158 bool check_number_string_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003159 isolate_->counters()->number_to_string_runtime()->Increment();
ager@chromium.org357bf652010-04-12 11:30:10 +00003160 if (check_number_string_cache) {
3161 Object* cached = GetNumberStringCache(number);
3162 if (cached != undefined_value()) {
3163 return cached;
3164 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003165 }
3166
3167 char arr[100];
3168 Vector<char> buffer(arr, ARRAY_SIZE(arr));
3169 const char* str;
3170 if (number->IsSmi()) {
3171 int num = Smi::cast(number)->value();
3172 str = IntToCString(num, buffer);
3173 } else {
3174 double num = HeapNumber::cast(number)->value();
3175 str = DoubleToCString(num, buffer);
3176 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003177
lrn@chromium.org303ada72010-10-27 09:33:13 +00003178 Object* js_string;
3179 MaybeObject* maybe_js_string = AllocateStringFromAscii(CStrVector(str));
3180 if (maybe_js_string->ToObject(&js_string)) {
3181 SetNumberStringCache(number, String::cast(js_string));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003182 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00003183 return maybe_js_string;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003184}
3185
3186
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003187MaybeObject* Heap::Uint32ToString(uint32_t value,
3188 bool check_number_string_cache) {
3189 Object* number;
3190 MaybeObject* maybe = NumberFromUint32(value);
3191 if (!maybe->To<Object>(&number)) return maybe;
3192 return NumberToString(number, check_number_string_cache);
3193}
3194
3195
ager@chromium.org3811b432009-10-28 14:53:37 +00003196Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) {
3197 return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]);
3198}
3199
3200
3201Heap::RootListIndex Heap::RootIndexForExternalArrayType(
3202 ExternalArrayType array_type) {
3203 switch (array_type) {
3204 case kExternalByteArray:
3205 return kExternalByteArrayMapRootIndex;
3206 case kExternalUnsignedByteArray:
3207 return kExternalUnsignedByteArrayMapRootIndex;
3208 case kExternalShortArray:
3209 return kExternalShortArrayMapRootIndex;
3210 case kExternalUnsignedShortArray:
3211 return kExternalUnsignedShortArrayMapRootIndex;
3212 case kExternalIntArray:
3213 return kExternalIntArrayMapRootIndex;
3214 case kExternalUnsignedIntArray:
3215 return kExternalUnsignedIntArrayMapRootIndex;
3216 case kExternalFloatArray:
3217 return kExternalFloatArrayMapRootIndex;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003218 case kExternalDoubleArray:
3219 return kExternalDoubleArrayMapRootIndex;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003220 case kExternalPixelArray:
3221 return kExternalPixelArrayMapRootIndex;
ager@chromium.org3811b432009-10-28 14:53:37 +00003222 default:
3223 UNREACHABLE();
3224 return kUndefinedValueRootIndex;
3225 }
3226}
3227
3228
lrn@chromium.org303ada72010-10-27 09:33:13 +00003229MaybeObject* Heap::NumberFromDouble(double value, PretenureFlag pretenure) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003230 // We need to distinguish the minus zero value and this cannot be
3231 // done after conversion to int. Doing this by comparing bit
3232 // patterns is faster than using fpclassify() et al.
3233 static const DoubleRepresentation minus_zero(-0.0);
3234
3235 DoubleRepresentation rep(value);
3236 if (rep.bits == minus_zero.bits) {
3237 return AllocateHeapNumber(-0.0, pretenure);
3238 }
3239
3240 int int_value = FastD2I(value);
3241 if (value == int_value && Smi::IsValid(int_value)) {
3242 return Smi::FromInt(int_value);
3243 }
3244
3245 // Materialize the value in the heap.
3246 return AllocateHeapNumber(value, pretenure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003247}
3248
3249
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003250MaybeObject* Heap::AllocateForeign(Address address, PretenureFlag pretenure) {
3251 // Statically ensure that it is safe to allocate foreigns in paged spaces.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003252 STATIC_ASSERT(Foreign::kSize <= Page::kMaxNonCodeHeapObjectSize);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003253 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003254 Foreign* result;
3255 MaybeObject* maybe_result = Allocate(foreign_map(), space);
3256 if (!maybe_result->To(&result)) return maybe_result;
3257 result->set_foreign_address(address);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003258 return result;
3259}
3260
3261
lrn@chromium.org303ada72010-10-27 09:33:13 +00003262MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003263 SharedFunctionInfo* share;
3264 MaybeObject* maybe = Allocate(shared_function_info_map(), OLD_POINTER_SPACE);
3265 if (!maybe->To<SharedFunctionInfo>(&share)) return maybe;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003266
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003267 // Set pointer fields.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003268 share->set_name(name);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003269 Code* illegal = isolate_->builtins()->builtin(Builtins::kIllegal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003270 share->set_code(illegal);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003271 share->ClearOptimizedCodeMap();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003272 share->set_scope_info(ScopeInfo::Empty());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003273 Code* construct_stub =
3274 isolate_->builtins()->builtin(Builtins::kJSConstructStubGeneric);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003275 share->set_construct_stub(construct_stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003276 share->set_instance_class_name(Object_symbol());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003277 share->set_function_data(undefined_value(), SKIP_WRITE_BARRIER);
3278 share->set_script(undefined_value(), SKIP_WRITE_BARRIER);
3279 share->set_debug_info(undefined_value(), SKIP_WRITE_BARRIER);
3280 share->set_inferred_name(empty_string(), SKIP_WRITE_BARRIER);
3281 share->set_initial_map(undefined_value(), SKIP_WRITE_BARRIER);
3282 share->set_this_property_assignments(undefined_value(), SKIP_WRITE_BARRIER);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003283 share->set_ast_node_count(0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003284 share->set_stress_deopt_counter(FLAG_deopt_every_n_times);
3285 share->set_counters(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003286
3287 // Set integer fields (smi or int, depending on the architecture).
3288 share->set_length(0);
3289 share->set_formal_parameter_count(0);
3290 share->set_expected_nof_properties(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003291 share->set_num_literals(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003292 share->set_start_position_and_type(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003293 share->set_end_position(0);
3294 share->set_function_token_position(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003295 // All compiler hints default to false or 0.
3296 share->set_compiler_hints(0);
3297 share->set_this_property_assignments_count(0);
3298 share->set_opt_count(0);
3299
3300 return share;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003301}
3302
3303
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003304MaybeObject* Heap::AllocateJSMessageObject(String* type,
3305 JSArray* arguments,
3306 int start_position,
3307 int end_position,
3308 Object* script,
3309 Object* stack_trace,
3310 Object* stack_frames) {
3311 Object* result;
3312 { MaybeObject* maybe_result = Allocate(message_object_map(), NEW_SPACE);
3313 if (!maybe_result->ToObject(&result)) return maybe_result;
3314 }
3315 JSMessageObject* message = JSMessageObject::cast(result);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003316 message->set_properties(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003317 message->initialize_elements();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003318 message->set_elements(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003319 message->set_type(type);
3320 message->set_arguments(arguments);
3321 message->set_start_position(start_position);
3322 message->set_end_position(end_position);
3323 message->set_script(script);
3324 message->set_stack_trace(stack_trace);
3325 message->set_stack_frames(stack_frames);
3326 return result;
3327}
3328
3329
3330
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003331// Returns true for a character in a range. Both limits are inclusive.
3332static inline bool Between(uint32_t character, uint32_t from, uint32_t to) {
3333 // This makes uses of the the unsigned wraparound.
3334 return character - from <= to - from;
3335}
3336
3337
lrn@chromium.org303ada72010-10-27 09:33:13 +00003338MUST_USE_RESULT static inline MaybeObject* MakeOrFindTwoCharacterString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003339 Heap* heap,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003340 uint32_t c1,
3341 uint32_t c2) {
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003342 String* symbol;
3343 // Numeric strings have a different hash algorithm not known by
3344 // LookupTwoCharsSymbolIfExists, so we skip this step for such strings.
3345 if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003346 heap->symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) {
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003347 return symbol;
3348 // Now we know the length is 2, we might as well make use of that fact
3349 // when building the new string.
3350 } else if ((c1 | c2) <= String::kMaxAsciiCharCodeU) { // We can do this
3351 ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1)); // because of this.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003352 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003353 { MaybeObject* maybe_result = heap->AllocateRawAsciiString(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003354 if (!maybe_result->ToObject(&result)) return maybe_result;
3355 }
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003356 char* dest = SeqAsciiString::cast(result)->GetChars();
3357 dest[0] = c1;
3358 dest[1] = c2;
3359 return result;
3360 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003361 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003362 { MaybeObject* maybe_result = heap->AllocateRawTwoByteString(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003363 if (!maybe_result->ToObject(&result)) return maybe_result;
3364 }
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003365 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
3366 dest[0] = c1;
3367 dest[1] = c2;
3368 return result;
3369 }
3370}
3371
3372
lrn@chromium.org303ada72010-10-27 09:33:13 +00003373MaybeObject* Heap::AllocateConsString(String* first, String* second) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003374 int first_length = first->length();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003375 if (first_length == 0) {
3376 return second;
3377 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003378
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003379 int second_length = second->length();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003380 if (second_length == 0) {
3381 return first;
3382 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003383
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003384 int length = first_length + second_length;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003385
3386 // Optimization for 2-byte strings often used as keys in a decompression
3387 // dictionary. Check whether we already have the string in the symbol
3388 // table to prevent creation of many unneccesary strings.
3389 if (length == 2) {
3390 unsigned c1 = first->Get(0);
3391 unsigned c2 = second->Get(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003392 return MakeOrFindTwoCharacterString(this, c1, c2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003393 }
3394
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003395 bool first_is_ascii = first->IsAsciiRepresentation();
3396 bool second_is_ascii = second->IsAsciiRepresentation();
3397 bool is_ascii = first_is_ascii && second_is_ascii;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003398
ager@chromium.org3e875802009-06-29 08:26:34 +00003399 // Make sure that an out of memory exception is thrown if the length
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003400 // of the new cons string is too large.
3401 if (length > String::kMaxLength || length < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003402 isolate()->context()->mark_out_of_memory();
ager@chromium.org3e875802009-06-29 08:26:34 +00003403 return Failure::OutOfMemoryException();
3404 }
3405
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003406 bool is_ascii_data_in_two_byte_string = false;
3407 if (!is_ascii) {
3408 // At least one of the strings uses two-byte representation so we
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003409 // can't use the fast case code for short ASCII strings below, but
3410 // we can try to save memory if all chars actually fit in ASCII.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003411 is_ascii_data_in_two_byte_string =
3412 first->HasOnlyAsciiChars() && second->HasOnlyAsciiChars();
3413 if (is_ascii_data_in_two_byte_string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003414 isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003415 }
3416 }
3417
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003418 // If the resulting string is small make a flat string.
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003419 if (length < ConsString::kMinLength) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003420 // Note that neither of the two inputs can be a slice because:
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003421 STATIC_ASSERT(ConsString::kMinLength <= SlicedString::kMinLength);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003422 ASSERT(first->IsFlat());
3423 ASSERT(second->IsFlat());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003424 if (is_ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003425 Object* result;
3426 { MaybeObject* maybe_result = AllocateRawAsciiString(length);
3427 if (!maybe_result->ToObject(&result)) return maybe_result;
3428 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003429 // Copy the characters into the new object.
3430 char* dest = SeqAsciiString::cast(result)->GetChars();
ager@chromium.org3e875802009-06-29 08:26:34 +00003431 // Copy first part.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003432 const char* src;
3433 if (first->IsExternalString()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003434 src = ExternalAsciiString::cast(first)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003435 } else {
3436 src = SeqAsciiString::cast(first)->GetChars();
3437 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003438 for (int i = 0; i < first_length; i++) *dest++ = src[i];
3439 // Copy second part.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003440 if (second->IsExternalString()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003441 src = ExternalAsciiString::cast(second)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003442 } else {
3443 src = SeqAsciiString::cast(second)->GetChars();
3444 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003445 for (int i = 0; i < second_length; i++) *dest++ = src[i];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003446 return result;
3447 } else {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003448 if (is_ascii_data_in_two_byte_string) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003449 Object* result;
3450 { MaybeObject* maybe_result = AllocateRawAsciiString(length);
3451 if (!maybe_result->ToObject(&result)) return maybe_result;
3452 }
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003453 // Copy the characters into the new object.
3454 char* dest = SeqAsciiString::cast(result)->GetChars();
3455 String::WriteToFlat(first, dest, 0, first_length);
3456 String::WriteToFlat(second, dest + first_length, 0, second_length);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003457 isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003458 return result;
3459 }
3460
lrn@chromium.org303ada72010-10-27 09:33:13 +00003461 Object* result;
3462 { MaybeObject* maybe_result = AllocateRawTwoByteString(length);
3463 if (!maybe_result->ToObject(&result)) return maybe_result;
3464 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003465 // Copy the characters into the new object.
3466 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003467 String::WriteToFlat(first, dest, 0, first_length);
3468 String::WriteToFlat(second, dest + first_length, 0, second_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003469 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003470 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003471 }
3472
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003473 Map* map = (is_ascii || is_ascii_data_in_two_byte_string) ?
3474 cons_ascii_string_map() : cons_string_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003475
lrn@chromium.org303ada72010-10-27 09:33:13 +00003476 Object* result;
3477 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3478 if (!maybe_result->ToObject(&result)) return maybe_result;
3479 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003480
3481 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003482 ConsString* cons_string = ConsString::cast(result);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003483 WriteBarrierMode mode = cons_string->GetWriteBarrierMode(no_gc);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003484 cons_string->set_length(length);
3485 cons_string->set_hash_field(String::kEmptyHashField);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003486 cons_string->set_first(first, mode);
3487 cons_string->set_second(second, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003488 return result;
3489}
3490
3491
lrn@chromium.org303ada72010-10-27 09:33:13 +00003492MaybeObject* Heap::AllocateSubString(String* buffer,
ager@chromium.org04921a82011-06-27 13:21:41 +00003493 int start,
3494 int end,
3495 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003496 int length = end - start;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003497 if (length <= 0) {
ager@chromium.org04921a82011-06-27 13:21:41 +00003498 return empty_string();
3499 } else if (length == 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003500 return LookupSingleCharacterStringFromCode(buffer->Get(start));
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003501 } else if (length == 2) {
3502 // Optimization for 2-byte strings often used as keys in a decompression
3503 // dictionary. Check whether we already have the string in the symbol
3504 // table to prevent creation of many unneccesary strings.
3505 unsigned c1 = buffer->Get(start);
3506 unsigned c2 = buffer->Get(start + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003507 return MakeOrFindTwoCharacterString(this, c1, c2);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003508 }
3509
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003510 // Make an attempt to flatten the buffer to reduce access time.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003511 buffer = buffer->TryFlattenGetString();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003512
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003513 if (!FLAG_string_slices ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003514 !buffer->IsFlat() ||
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003515 length < SlicedString::kMinLength ||
3516 pretenure == TENURED) {
3517 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003518 // WriteToFlat takes care of the case when an indirect string has a
3519 // different encoding from its underlying string. These encodings may
3520 // differ because of externalization.
3521 bool is_ascii = buffer->IsAsciiRepresentation();
3522 { MaybeObject* maybe_result = is_ascii
3523 ? AllocateRawAsciiString(length, pretenure)
3524 : AllocateRawTwoByteString(length, pretenure);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003525 if (!maybe_result->ToObject(&result)) return maybe_result;
3526 }
3527 String* string_result = String::cast(result);
3528 // Copy the characters into the new object.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003529 if (is_ascii) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003530 ASSERT(string_result->IsAsciiRepresentation());
3531 char* dest = SeqAsciiString::cast(string_result)->GetChars();
3532 String::WriteToFlat(buffer, dest, start, end);
3533 } else {
3534 ASSERT(string_result->IsTwoByteRepresentation());
3535 uc16* dest = SeqTwoByteString::cast(string_result)->GetChars();
3536 String::WriteToFlat(buffer, dest, start, end);
3537 }
3538 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003539 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003540
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003541 ASSERT(buffer->IsFlat());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003542#if VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003543 if (FLAG_verify_heap) {
3544 buffer->StringVerify();
3545 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003546#endif
3547
3548 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003549 // When slicing an indirect string we use its encoding for a newly created
3550 // slice and don't check the encoding of the underlying string. This is safe
3551 // even if the encodings are different because of externalization. If an
3552 // indirect ASCII string is pointing to a two-byte string, the two-byte char
3553 // codes of the underlying string must still fit into ASCII (because
3554 // externalization must not change char codes).
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003555 { Map* map = buffer->IsAsciiRepresentation()
3556 ? sliced_ascii_string_map()
3557 : sliced_string_map();
3558 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3559 if (!maybe_result->ToObject(&result)) return maybe_result;
3560 }
3561
3562 AssertNoAllocation no_gc;
3563 SlicedString* sliced_string = SlicedString::cast(result);
3564 sliced_string->set_length(length);
3565 sliced_string->set_hash_field(String::kEmptyHashField);
3566 if (buffer->IsConsString()) {
3567 ConsString* cons = ConsString::cast(buffer);
3568 ASSERT(cons->second()->length() == 0);
3569 sliced_string->set_parent(cons->first());
3570 sliced_string->set_offset(start);
3571 } else if (buffer->IsSlicedString()) {
3572 // Prevent nesting sliced strings.
3573 SlicedString* parent_slice = SlicedString::cast(buffer);
3574 sliced_string->set_parent(parent_slice->parent());
3575 sliced_string->set_offset(start + parent_slice->offset());
3576 } else {
3577 sliced_string->set_parent(buffer);
3578 sliced_string->set_offset(start);
3579 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003580 ASSERT(sliced_string->parent()->IsSeqString() ||
3581 sliced_string->parent()->IsExternalString());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003582 return result;
3583}
3584
3585
lrn@chromium.org303ada72010-10-27 09:33:13 +00003586MaybeObject* Heap::AllocateExternalStringFromAscii(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003587 const ExternalAsciiString::Resource* resource) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003588 size_t length = resource->length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003589 if (length > static_cast<size_t>(String::kMaxLength)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003590 isolate()->context()->mark_out_of_memory();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003591 return Failure::OutOfMemoryException();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003592 }
3593
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00003594 ASSERT(String::IsAscii(resource->data(), static_cast<int>(length)));
3595
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003596 Map* map = external_ascii_string_map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003597 Object* result;
3598 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3599 if (!maybe_result->ToObject(&result)) return maybe_result;
3600 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003601
3602 ExternalAsciiString* external_string = ExternalAsciiString::cast(result);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003603 external_string->set_length(static_cast<int>(length));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003604 external_string->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003605 external_string->set_resource(resource);
3606
3607 return result;
3608}
3609
3610
lrn@chromium.org303ada72010-10-27 09:33:13 +00003611MaybeObject* Heap::AllocateExternalStringFromTwoByte(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003612 const ExternalTwoByteString::Resource* resource) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003613 size_t length = resource->length();
3614 if (length > static_cast<size_t>(String::kMaxLength)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003615 isolate()->context()->mark_out_of_memory();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003616 return Failure::OutOfMemoryException();
3617 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003618
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003619 // For small strings we check whether the resource contains only
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003620 // ASCII characters. If yes, we use a different string map.
3621 static const size_t kAsciiCheckLengthLimit = 32;
3622 bool is_ascii = length <= kAsciiCheckLengthLimit &&
3623 String::IsAscii(resource->data(), static_cast<int>(length));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003624 Map* map = is_ascii ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003625 external_string_with_ascii_data_map() : external_string_map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003626 Object* result;
3627 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3628 if (!maybe_result->ToObject(&result)) return maybe_result;
3629 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003630
3631 ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003632 external_string->set_length(static_cast<int>(length));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003633 external_string->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003634 external_string->set_resource(resource);
3635
3636 return result;
3637}
3638
3639
lrn@chromium.org303ada72010-10-27 09:33:13 +00003640MaybeObject* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003641 if (code <= String::kMaxAsciiCharCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003642 Object* value = single_character_string_cache()->get(code);
3643 if (value != undefined_value()) return value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003644
3645 char buffer[1];
3646 buffer[0] = static_cast<char>(code);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003647 Object* result;
3648 MaybeObject* maybe_result = LookupSymbol(Vector<const char>(buffer, 1));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003649
lrn@chromium.org303ada72010-10-27 09:33:13 +00003650 if (!maybe_result->ToObject(&result)) return maybe_result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003651 single_character_string_cache()->set(code, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003652 return result;
3653 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003654
lrn@chromium.org303ada72010-10-27 09:33:13 +00003655 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003656 { MaybeObject* maybe_result = AllocateRawTwoByteString(1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003657 if (!maybe_result->ToObject(&result)) return maybe_result;
3658 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00003659 String* answer = String::cast(result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003660 answer->Set(0, code);
ager@chromium.org870a0b62008-11-04 11:43:05 +00003661 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003662}
3663
3664
lrn@chromium.org303ada72010-10-27 09:33:13 +00003665MaybeObject* Heap::AllocateByteArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003666 if (length < 0 || length > ByteArray::kMaxLength) {
3667 return Failure::OutOfMemoryException();
3668 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003669 if (pretenure == NOT_TENURED) {
3670 return AllocateByteArray(length);
3671 }
3672 int size = ByteArray::SizeFor(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003673 Object* result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003674 { MaybeObject* maybe_result = (size <= Page::kMaxNonCodeHeapObjectSize)
lrn@chromium.org303ada72010-10-27 09:33:13 +00003675 ? old_data_space_->AllocateRaw(size)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003676 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003677 if (!maybe_result->ToObject(&result)) return maybe_result;
3678 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003679
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003680 reinterpret_cast<ByteArray*>(result)->set_map_no_write_barrier(
3681 byte_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003682 reinterpret_cast<ByteArray*>(result)->set_length(length);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003683 return result;
3684}
3685
3686
lrn@chromium.org303ada72010-10-27 09:33:13 +00003687MaybeObject* Heap::AllocateByteArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003688 if (length < 0 || length > ByteArray::kMaxLength) {
3689 return Failure::OutOfMemoryException();
3690 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003691 int size = ByteArray::SizeFor(length);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003692 AllocationSpace space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003693 (size > Page::kMaxNonCodeHeapObjectSize) ? LO_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003694 Object* result;
3695 { MaybeObject* maybe_result = AllocateRaw(size, space, OLD_DATA_SPACE);
3696 if (!maybe_result->ToObject(&result)) return maybe_result;
3697 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003699 reinterpret_cast<ByteArray*>(result)->set_map_no_write_barrier(
3700 byte_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003701 reinterpret_cast<ByteArray*>(result)->set_length(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003702 return result;
3703}
3704
3705
ager@chromium.org6f10e412009-02-13 10:11:16 +00003706void Heap::CreateFillerObjectAt(Address addr, int size) {
3707 if (size == 0) return;
3708 HeapObject* filler = HeapObject::FromAddress(addr);
3709 if (size == kPointerSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003710 filler->set_map_no_write_barrier(one_pointer_filler_map());
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00003711 } else if (size == 2 * kPointerSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003712 filler->set_map_no_write_barrier(two_pointer_filler_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +00003713 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003714 filler->set_map_no_write_barrier(free_space_map());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003715 FreeSpace::cast(filler)->set_size(size);
ager@chromium.org6f10e412009-02-13 10:11:16 +00003716 }
3717}
3718
3719
lrn@chromium.org303ada72010-10-27 09:33:13 +00003720MaybeObject* Heap::AllocateExternalArray(int length,
3721 ExternalArrayType array_type,
3722 void* external_pointer,
3723 PretenureFlag pretenure) {
ager@chromium.org3811b432009-10-28 14:53:37 +00003724 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003725 Object* result;
3726 { MaybeObject* maybe_result = AllocateRaw(ExternalArray::kAlignedSize,
3727 space,
3728 OLD_DATA_SPACE);
3729 if (!maybe_result->ToObject(&result)) return maybe_result;
3730 }
ager@chromium.org3811b432009-10-28 14:53:37 +00003731
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003732 reinterpret_cast<ExternalArray*>(result)->set_map_no_write_barrier(
ager@chromium.org3811b432009-10-28 14:53:37 +00003733 MapForExternalArrayType(array_type));
3734 reinterpret_cast<ExternalArray*>(result)->set_length(length);
3735 reinterpret_cast<ExternalArray*>(result)->set_external_pointer(
3736 external_pointer);
3737
3738 return result;
3739}
3740
3741
lrn@chromium.org303ada72010-10-27 09:33:13 +00003742MaybeObject* Heap::CreateCode(const CodeDesc& desc,
3743 Code::Flags flags,
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003744 Handle<Object> self_reference,
3745 bool immovable) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003746 // Allocate ByteArray before the Code object, so that we do not risk
3747 // leaving uninitialized Code object (and breaking the heap).
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003748 ByteArray* reloc_info;
3749 MaybeObject* maybe_reloc_info = AllocateByteArray(desc.reloc_size, TENURED);
3750 if (!maybe_reloc_info->To(&reloc_info)) return maybe_reloc_info;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003751
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003752 // Compute size.
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003753 int body_size = RoundUp(desc.instr_size, kObjectAlignment);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003754 int obj_size = Code::SizeFor(body_size);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003755 ASSERT(IsAligned(static_cast<intptr_t>(obj_size), kCodeAlignment));
lrn@chromium.org303ada72010-10-27 09:33:13 +00003756 MaybeObject* maybe_result;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003757 // Large code objects and code objects which should stay at a fixed address
3758 // are allocated in large object space.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003759 HeapObject* result;
3760 bool force_lo_space = obj_size > code_space()->AreaSize();
3761 if (force_lo_space) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003762 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003763 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003764 maybe_result = code_space_->AllocateRaw(obj_size);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003765 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003766 if (!maybe_result->To<HeapObject>(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003768 if (immovable && !force_lo_space &&
3769 // Objects on the first page of each space are never moved.
3770 !code_space_->FirstPage()->Contains(result->address())) {
3771 // Discard the first code allocation, which was on a page where it could be
3772 // moved.
3773 CreateFillerObjectAt(result->address(), obj_size);
3774 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
3775 if (!maybe_result->To<HeapObject>(&result)) return maybe_result;
3776 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003777
3778 // Initialize the object
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003779 result->set_map_no_write_barrier(code_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003780 Code* code = Code::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003781 ASSERT(!isolate_->code_range()->exists() ||
3782 isolate_->code_range()->contains(code->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003783 code->set_instruction_size(desc.instr_size);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003784 code->set_relocation_info(reloc_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003785 code->set_flags(flags);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003786 if (code->is_call_stub() || code->is_keyed_call_stub()) {
3787 code->set_check_type(RECEIVER_MAP_CHECK);
3788 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003789 code->set_deoptimization_data(empty_fixed_array(), SKIP_WRITE_BARRIER);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003790 code->set_type_feedback_info(undefined_value(), SKIP_WRITE_BARRIER);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003791 code->set_handler_table(empty_fixed_array(), SKIP_WRITE_BARRIER);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00003792 code->set_gc_metadata(Smi::FromInt(0));
danno@chromium.org88aa0582012-03-23 15:11:57 +00003793 code->set_ic_age(global_ic_age_);
kasperl@chromium.org061ef742009-02-27 12:16:20 +00003794 // Allow self references to created code object by patching the handle to
3795 // point to the newly allocated Code object.
3796 if (!self_reference.is_null()) {
3797 *(self_reference.location()) = code;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003798 }
3799 // Migrate generated code.
3800 // The generated code can contain Object** values (typically from handles)
3801 // that are dereferenced during the copy to point directly to the actual heap
3802 // objects. These pointers can include references to the code object itself,
3803 // through the self_reference parameter.
3804 code->CopyFrom(desc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003805
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003806#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003807 if (FLAG_verify_heap) {
3808 code->Verify();
3809 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003810#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003811 return code;
3812}
3813
3814
lrn@chromium.org303ada72010-10-27 09:33:13 +00003815MaybeObject* Heap::CopyCode(Code* code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003816 // Allocate an object the same size as the code object.
3817 int obj_size = code->Size();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003818 MaybeObject* maybe_result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003819 if (obj_size > code_space()->AreaSize()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003820 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003821 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003822 maybe_result = code_space_->AllocateRaw(obj_size);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003823 }
3824
lrn@chromium.org303ada72010-10-27 09:33:13 +00003825 Object* result;
3826 if (!maybe_result->ToObject(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003827
3828 // Copy code object.
3829 Address old_addr = code->address();
3830 Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003831 CopyBlock(new_addr, old_addr, obj_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003832 // Relocate the copy.
3833 Code* new_code = Code::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003834 ASSERT(!isolate_->code_range()->exists() ||
3835 isolate_->code_range()->contains(code->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003836 new_code->Relocate(new_addr - old_addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003837 return new_code;
3838}
3839
3840
lrn@chromium.org303ada72010-10-27 09:33:13 +00003841MaybeObject* Heap::CopyCode(Code* code, Vector<byte> reloc_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003842 // Allocate ByteArray before the Code object, so that we do not risk
3843 // leaving uninitialized Code object (and breaking the heap).
lrn@chromium.org303ada72010-10-27 09:33:13 +00003844 Object* reloc_info_array;
3845 { MaybeObject* maybe_reloc_info_array =
3846 AllocateByteArray(reloc_info.length(), TENURED);
3847 if (!maybe_reloc_info_array->ToObject(&reloc_info_array)) {
3848 return maybe_reloc_info_array;
3849 }
3850 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003851
3852 int new_body_size = RoundUp(code->instruction_size(), kObjectAlignment);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003853
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003854 int new_obj_size = Code::SizeFor(new_body_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003855
3856 Address old_addr = code->address();
3857
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00003858 size_t relocation_offset =
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003859 static_cast<size_t>(code->instruction_end() - old_addr);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003860
lrn@chromium.org303ada72010-10-27 09:33:13 +00003861 MaybeObject* maybe_result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003862 if (new_obj_size > code_space()->AreaSize()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003863 maybe_result = lo_space_->AllocateRaw(new_obj_size, EXECUTABLE);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003864 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003865 maybe_result = code_space_->AllocateRaw(new_obj_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003866 }
3867
lrn@chromium.org303ada72010-10-27 09:33:13 +00003868 Object* result;
3869 if (!maybe_result->ToObject(&result)) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003870
3871 // Copy code object.
3872 Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
3873
3874 // Copy header and instructions.
3875 memcpy(new_addr, old_addr, relocation_offset);
3876
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003877 Code* new_code = Code::cast(result);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003878 new_code->set_relocation_info(ByteArray::cast(reloc_info_array));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003879
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003880 // Copy patched rinfo.
3881 memcpy(new_code->relocation_start(), reloc_info.start(), reloc_info.length());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003882
3883 // Relocate the copy.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003884 ASSERT(!isolate_->code_range()->exists() ||
3885 isolate_->code_range()->contains(code->address()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003886 new_code->Relocate(new_addr - old_addr);
3887
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003888#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003889 if (FLAG_verify_heap) {
3890 code->Verify();
3891 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003892#endif
3893 return new_code;
3894}
3895
3896
lrn@chromium.org303ada72010-10-27 09:33:13 +00003897MaybeObject* Heap::Allocate(Map* map, AllocationSpace space) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003898 ASSERT(gc_state_ == NOT_IN_GC);
3899 ASSERT(map->instance_type() != MAP_TYPE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003900 // If allocation failures are disallowed, we may allocate in a different
3901 // space when new space is full and the object is not a large object.
3902 AllocationSpace retry_space =
3903 (space != NEW_SPACE) ? space : TargetSpaceId(map->instance_type());
lrn@chromium.org303ada72010-10-27 09:33:13 +00003904 Object* result;
3905 { MaybeObject* maybe_result =
3906 AllocateRaw(map->instance_size(), space, retry_space);
3907 if (!maybe_result->ToObject(&result)) return maybe_result;
3908 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003909 // No need for write barrier since object is white and map is in old space.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003910 HeapObject::cast(result)->set_map_no_write_barrier(map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003911 return result;
3912}
3913
3914
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003915void Heap::InitializeFunction(JSFunction* function,
3916 SharedFunctionInfo* shared,
3917 Object* prototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003918 ASSERT(!prototype->IsMap());
3919 function->initialize_properties();
3920 function->initialize_elements();
3921 function->set_shared(shared);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00003922 function->set_code(shared->code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003923 function->set_prototype_or_initial_map(prototype);
3924 function->set_context(undefined_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003925 function->set_literals_or_bindings(empty_fixed_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003926 function->set_next_function_link(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003927}
3928
3929
lrn@chromium.org303ada72010-10-27 09:33:13 +00003930MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00003931 // Allocate the prototype. Make sure to use the object function
3932 // from the function's context, since the function can be from a
3933 // different context.
3934 JSFunction* object_function =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003935 function->context()->native_context()->object_function();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003936
3937 // Each function prototype gets a copy of the object function map.
3938 // This avoid unwanted sharing of maps between prototypes of different
3939 // constructors.
3940 Map* new_map;
3941 ASSERT(object_function->has_initial_map());
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003942 MaybeObject* maybe_map = object_function->initial_map()->Copy();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003943 if (!maybe_map->To(&new_map)) return maybe_map;
3944
lrn@chromium.org303ada72010-10-27 09:33:13 +00003945 Object* prototype;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003946 MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map);
3947 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
3948
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003949 // When creating the prototype for the function we must set its
3950 // constructor to the function.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003951 MaybeObject* maybe_failure =
3952 JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
3953 constructor_symbol(), function, DONT_ENUM);
3954 if (maybe_failure->IsFailure()) return maybe_failure;
3955
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003956 return prototype;
3957}
3958
3959
lrn@chromium.org303ada72010-10-27 09:33:13 +00003960MaybeObject* Heap::AllocateFunction(Map* function_map,
3961 SharedFunctionInfo* shared,
3962 Object* prototype,
3963 PretenureFlag pretenure) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003964 AllocationSpace space =
3965 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003966 Object* result;
3967 { MaybeObject* maybe_result = Allocate(function_map, space);
3968 if (!maybe_result->ToObject(&result)) return maybe_result;
3969 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003970 InitializeFunction(JSFunction::cast(result), shared, prototype);
3971 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003972}
3973
3974
lrn@chromium.org303ada72010-10-27 09:33:13 +00003975MaybeObject* Heap::AllocateArgumentsObject(Object* callee, int length) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003976 // To get fast allocation and map sharing for arguments objects we
3977 // allocate them based on an arguments boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003979 JSObject* boilerplate;
3980 int arguments_object_size;
3981 bool strict_mode_callee = callee->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003982 !JSFunction::cast(callee)->shared()->is_classic_mode();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003983 if (strict_mode_callee) {
3984 boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003985 isolate()->context()->native_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003986 strict_mode_arguments_boilerplate();
3987 arguments_object_size = kArgumentsObjectSizeStrict;
3988 } else {
3989 boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003990 isolate()->context()->native_context()->arguments_boilerplate();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003991 arguments_object_size = kArgumentsObjectSize;
3992 }
3993
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003994 // This calls Copy directly rather than using Heap::AllocateRaw so we
3995 // duplicate the check here.
3996 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
3997
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003998 // Check that the size of the boilerplate matches our
3999 // expectations. The ArgumentsAccessStub::GenerateNewObject relies
4000 // on the size being a known constant.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004001 ASSERT(arguments_object_size == boilerplate->map()->instance_size());
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00004002
4003 // Do the allocation.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004004 Object* result;
4005 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004006 AllocateRaw(arguments_object_size, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004007 if (!maybe_result->ToObject(&result)) return maybe_result;
4008 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004009
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004010 // Copy the content. The arguments boilerplate doesn't have any
4011 // fields that point to new space so it's safe to skip the write
4012 // barrier here.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004013 CopyBlock(HeapObject::cast(result)->address(),
4014 boilerplate->address(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004015 JSObject::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004016
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004017 // Set the length property.
4018 JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsLengthIndex,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004019 Smi::FromInt(length),
4020 SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004021 // Set the callee property for non-strict mode arguments object only.
4022 if (!strict_mode_callee) {
4023 JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsCalleeIndex,
4024 callee);
4025 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004026
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027 // Check the state of the object
4028 ASSERT(JSObject::cast(result)->HasFastProperties());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004029 ASSERT(JSObject::cast(result)->HasFastObjectElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004030
4031 return result;
4032}
4033
4034
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004035static bool HasDuplicates(DescriptorArray* descriptors) {
4036 int count = descriptors->number_of_descriptors();
4037 if (count > 1) {
4038 String* prev_key = descriptors->GetKey(0);
4039 for (int i = 1; i != count; i++) {
4040 String* current_key = descriptors->GetKey(i);
4041 if (prev_key == current_key) return true;
4042 prev_key = current_key;
4043 }
4044 }
4045 return false;
4046}
4047
4048
lrn@chromium.org303ada72010-10-27 09:33:13 +00004049MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004050 ASSERT(!fun->has_initial_map());
4051
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004052 // First create a new map with the size and number of in-object properties
4053 // suggested by the function.
4054 int instance_size = fun->shared()->CalculateInstanceSize();
4055 int in_object_properties = fun->shared()->CalculateInObjectProperties();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004056 Map* map;
4057 MaybeObject* maybe_map = AllocateMap(JS_OBJECT_TYPE, instance_size);
4058 if (!maybe_map->To(&map)) return maybe_map;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004059
4060 // Fetch or allocate prototype.
4061 Object* prototype;
4062 if (fun->has_instance_prototype()) {
4063 prototype = fun->instance_prototype();
4064 } else {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004065 MaybeObject* maybe_prototype = AllocateFunctionPrototype(fun);
4066 if (!maybe_prototype->To(&prototype)) return maybe_prototype;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004068 map->set_inobject_properties(in_object_properties);
4069 map->set_unused_property_fields(in_object_properties);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004070 map->set_prototype(prototype);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004071 ASSERT(map->has_fast_object_elements());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004072
ager@chromium.org5c838252010-02-19 08:53:10 +00004073 // If the function has only simple this property assignments add
4074 // field descriptors for these to the initial map as the object
4075 // cannot be constructed without having these properties. Guard by
4076 // the inline_new flag so we only change the map if we generate a
4077 // specialized construct stub.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004078 ASSERT(in_object_properties <= Map::kMaxPreAllocatedPropertyFields);
ager@chromium.org5c838252010-02-19 08:53:10 +00004079 if (fun->shared()->CanGenerateInlineConstructor(prototype)) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004080 int count = fun->shared()->this_property_assignments_count();
4081 if (count > in_object_properties) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004082 // Inline constructor can only handle inobject properties.
4083 fun->shared()->ForbidInlineConstructor();
4084 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004085 DescriptorArray* descriptors;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00004086 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(count);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004087 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
4088
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004089 DescriptorArray::WhitenessWitness witness(descriptors);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004090 for (int i = 0; i < count; i++) {
4091 String* name = fun->shared()->GetThisPropertyAssignmentName(i);
4092 ASSERT(name->IsSymbol());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004093 FieldDescriptor field(name, i, NONE, i + 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004094 descriptors->Set(i, &field, witness);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004095 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004096 descriptors->Sort();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004097
4098 // The descriptors may contain duplicates because the compiler does not
4099 // guarantee the uniqueness of property names (it would have required
4100 // quadratic time). Once the descriptors are sorted we can check for
4101 // duplicates in linear time.
4102 if (HasDuplicates(descriptors)) {
4103 fun->shared()->ForbidInlineConstructor();
4104 } else {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004105 map->InitializeDescriptors(descriptors);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004106 map->set_pre_allocated_property_fields(count);
4107 map->set_unused_property_fields(in_object_properties - count);
4108 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004109 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004110 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004111
4112 fun->shared()->StartInobjectSlackTracking(map);
4113
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004114 return map;
4115}
4116
4117
4118void Heap::InitializeJSObjectFromMap(JSObject* obj,
4119 FixedArray* properties,
4120 Map* map) {
4121 obj->set_properties(properties);
4122 obj->initialize_elements();
4123 // TODO(1240798): Initialize the object's body using valid initial values
4124 // according to the object's initial map. For example, if the map's
4125 // instance type is JS_ARRAY_TYPE, the length field should be initialized
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004126 // to a number (e.g. Smi::FromInt(0)) and the elements initialized to a
4127 // fixed array (e.g. Heap::empty_fixed_array()). Currently, the object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004128 // verification code has to cope with (temporarily) invalid objects. See
4129 // for example, JSArray::JSArrayVerify).
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004130 Object* filler;
4131 // We cannot always fill with one_pointer_filler_map because objects
4132 // created from API functions expect their internal fields to be initialized
4133 // with undefined_value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004134 // Pre-allocated fields need to be initialized with undefined_value as well
4135 // so that object accesses before the constructor completes (e.g. in the
4136 // debugger) will not cause a crash.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004137 if (map->constructor()->IsJSFunction() &&
4138 JSFunction::cast(map->constructor())->shared()->
4139 IsInobjectSlackTrackingInProgress()) {
4140 // We might want to shrink the object later.
4141 ASSERT(obj->GetInternalFieldCount() == 0);
4142 filler = Heap::one_pointer_filler_map();
4143 } else {
4144 filler = Heap::undefined_value();
4145 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004146 obj->InitializeBody(map, Heap::undefined_value(), filler);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004147}
4148
4149
lrn@chromium.org303ada72010-10-27 09:33:13 +00004150MaybeObject* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004151 // JSFunctions should be allocated using AllocateFunction to be
4152 // properly initialized.
4153 ASSERT(map->instance_type() != JS_FUNCTION_TYPE);
4154
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00004155 // Both types of global objects should be allocated using
4156 // AllocateGlobalObject to be properly initialized.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004157 ASSERT(map->instance_type() != JS_GLOBAL_OBJECT_TYPE);
4158 ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE);
4159
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004160 // Allocate the backing storage for the properties.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004161 int prop_size =
4162 map->pre_allocated_property_fields() +
4163 map->unused_property_fields() -
4164 map->inobject_properties();
4165 ASSERT(prop_size >= 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004166 Object* properties;
4167 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, pretenure);
4168 if (!maybe_properties->ToObject(&properties)) return maybe_properties;
4169 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004170
4171 // Allocate the JSObject.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004172 AllocationSpace space =
4173 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004174 if (map->instance_size() > Page::kMaxNonCodeHeapObjectSize) space = LO_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004175 Object* obj;
4176 { MaybeObject* maybe_obj = Allocate(map, space);
4177 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4178 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004179
4180 // Initialize the JSObject.
4181 InitializeJSObjectFromMap(JSObject::cast(obj),
4182 FixedArray::cast(properties),
4183 map);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004184 ASSERT(JSObject::cast(obj)->HasFastSmiOrObjectElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185 return obj;
4186}
4187
4188
lrn@chromium.org303ada72010-10-27 09:33:13 +00004189MaybeObject* Heap::AllocateJSObject(JSFunction* constructor,
4190 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004191 // Allocate the initial map if absent.
4192 if (!constructor->has_initial_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004193 Object* initial_map;
4194 { MaybeObject* maybe_initial_map = AllocateInitialMap(constructor);
4195 if (!maybe_initial_map->ToObject(&initial_map)) return maybe_initial_map;
4196 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004197 constructor->set_initial_map(Map::cast(initial_map));
4198 Map::cast(initial_map)->set_constructor(constructor);
4199 }
4200 // Allocate the object based on the constructors initial map.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004201 MaybeObject* result = AllocateJSObjectFromMap(
4202 constructor->initial_map(), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004203#ifdef DEBUG
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004204 // Make sure result is NOT a global object if valid.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004205 Object* non_failure;
4206 ASSERT(!result->ToObject(&non_failure) || !non_failure->IsGlobalObject());
4207#endif
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004208 return result;
4209}
4210
4211
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004212MaybeObject* Heap::AllocateJSModule(Context* context, ScopeInfo* scope_info) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004213 // Allocate a fresh map. Modules do not have a prototype.
4214 Map* map;
4215 MaybeObject* maybe_map = AllocateMap(JS_MODULE_TYPE, JSModule::kSize);
4216 if (!maybe_map->To(&map)) return maybe_map;
4217 // Allocate the object based on the map.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004218 JSModule* module;
4219 MaybeObject* maybe_module = AllocateJSObjectFromMap(map, TENURED);
4220 if (!maybe_module->To(&module)) return maybe_module;
4221 module->set_context(context);
4222 module->set_scope_info(scope_info);
4223 return module;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004224}
4225
4226
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004227MaybeObject* Heap::AllocateJSArrayAndStorage(
4228 ElementsKind elements_kind,
4229 int length,
4230 int capacity,
4231 ArrayStorageAllocationMode mode,
4232 PretenureFlag pretenure) {
4233 ASSERT(capacity >= length);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004234 if (length != 0 && mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE) {
4235 elements_kind = GetHoleyElementsKind(elements_kind);
4236 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004237 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
4238 JSArray* array;
4239 if (!maybe_array->To(&array)) return maybe_array;
4240
4241 if (capacity == 0) {
4242 array->set_length(Smi::FromInt(0));
4243 array->set_elements(empty_fixed_array());
4244 return array;
4245 }
4246
4247 FixedArrayBase* elms;
4248 MaybeObject* maybe_elms = NULL;
4249 if (elements_kind == FAST_DOUBLE_ELEMENTS) {
4250 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
4251 maybe_elms = AllocateUninitializedFixedDoubleArray(capacity);
4252 } else {
4253 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
4254 maybe_elms = AllocateFixedDoubleArrayWithHoles(capacity);
4255 }
4256 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004257 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004258 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
4259 maybe_elms = AllocateUninitializedFixedArray(capacity);
4260 } else {
4261 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
4262 maybe_elms = AllocateFixedArrayWithHoles(capacity);
4263 }
4264 }
4265 if (!maybe_elms->To(&elms)) return maybe_elms;
4266
4267 array->set_elements(elms);
4268 array->set_length(Smi::FromInt(length));
4269 return array;
4270}
4271
4272
4273MaybeObject* Heap::AllocateJSArrayWithElements(
4274 FixedArrayBase* elements,
4275 ElementsKind elements_kind,
4276 PretenureFlag pretenure) {
4277 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
4278 JSArray* array;
4279 if (!maybe_array->To(&array)) return maybe_array;
4280
4281 array->set_elements(elements);
4282 array->set_length(Smi::FromInt(elements->length()));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004283 array->ValidateElements();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004284 return array;
4285}
4286
4287
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004288MaybeObject* Heap::AllocateJSProxy(Object* handler, Object* prototype) {
4289 // Allocate map.
4290 // TODO(rossberg): Once we optimize proxies, think about a scheme to share
4291 // maps. Will probably depend on the identity of the handler object, too.
danno@chromium.org40cb8782011-05-25 07:58:50 +00004292 Map* map;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004293 MaybeObject* maybe_map_obj = AllocateMap(JS_PROXY_TYPE, JSProxy::kSize);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004294 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004295 map->set_prototype(prototype);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004296
4297 // Allocate the proxy object.
lrn@chromium.org34e60782011-09-15 07:25:40 +00004298 JSProxy* result;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004299 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004300 if (!maybe_result->To<JSProxy>(&result)) return maybe_result;
4301 result->InitializeBody(map->instance_size(), Smi::FromInt(0));
4302 result->set_handler(handler);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004303 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004304 return result;
4305}
4306
4307
4308MaybeObject* Heap::AllocateJSFunctionProxy(Object* handler,
4309 Object* call_trap,
4310 Object* construct_trap,
4311 Object* prototype) {
4312 // Allocate map.
4313 // TODO(rossberg): Once we optimize proxies, think about a scheme to share
4314 // maps. Will probably depend on the identity of the handler object, too.
4315 Map* map;
4316 MaybeObject* maybe_map_obj =
4317 AllocateMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize);
4318 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
4319 map->set_prototype(prototype);
4320
4321 // Allocate the proxy object.
4322 JSFunctionProxy* result;
4323 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
4324 if (!maybe_result->To<JSFunctionProxy>(&result)) return maybe_result;
4325 result->InitializeBody(map->instance_size(), Smi::FromInt(0));
4326 result->set_handler(handler);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004327 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004328 result->set_call_trap(call_trap);
4329 result->set_construct_trap(construct_trap);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004330 return result;
4331}
4332
4333
lrn@chromium.org303ada72010-10-27 09:33:13 +00004334MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004335 ASSERT(constructor->has_initial_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004336 Map* map = constructor->initial_map();
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004337 ASSERT(map->is_dictionary_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004338
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004339 // Make sure no field properties are described in the initial map.
4340 // This guarantees us that normalizing the properties does not
4341 // require us to change property values to JSGlobalPropertyCells.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004342 ASSERT(map->NextFreePropertyIndex() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004343
4344 // Make sure we don't have a ton of pre-allocated slots in the
4345 // global objects. They will be unused once we normalize the object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004346 ASSERT(map->unused_property_fields() == 0);
4347 ASSERT(map->inobject_properties() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004348
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004349 // Initial size of the backing store to avoid resize of the storage during
4350 // bootstrapping. The size differs between the JS global object ad the
4351 // builtins object.
4352 int initial_size = map->instance_type() == JS_GLOBAL_OBJECT_TYPE ? 64 : 512;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004353
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004354 // Allocate a dictionary object for backing storage.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004355 StringDictionary* dictionary;
4356 MaybeObject* maybe_dictionary =
4357 StringDictionary::Allocate(
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004358 map->NumberOfOwnDescriptors() * 2 + initial_size);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004359 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004360
4361 // The global object might be created from an object template with accessors.
4362 // Fill these accessors into the dictionary.
4363 DescriptorArray* descs = map->instance_descriptors();
4364 for (int i = 0; i < descs->number_of_descriptors(); i++) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004365 PropertyDetails details = descs->GetDetails(i);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004366 ASSERT(details.type() == CALLBACKS); // Only accessors are expected.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004367 PropertyDetails d = PropertyDetails(details.attributes(),
4368 CALLBACKS,
4369 details.descriptor_index());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004370 Object* value = descs->GetCallbacksObject(i);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004371 MaybeObject* maybe_value = AllocateJSGlobalPropertyCell(value);
4372 if (!maybe_value->ToObject(&value)) return maybe_value;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004373
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004374 MaybeObject* maybe_added = dictionary->Add(descs->GetKey(i), value, d);
4375 if (!maybe_added->To(&dictionary)) return maybe_added;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004376 }
4377
4378 // Allocate the global object and initialize it with the backing store.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004379 JSObject* global;
4380 MaybeObject* maybe_global = Allocate(map, OLD_POINTER_SPACE);
4381 if (!maybe_global->To(&global)) return maybe_global;
4382
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004383 InitializeJSObjectFromMap(global, dictionary, map);
4384
4385 // Create a new map for the global object.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004386 Map* new_map;
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004387 MaybeObject* maybe_map = map->CopyDropDescriptors();
4388 if (!maybe_map->To(&new_map)) return maybe_map;
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004389 new_map->set_dictionary_map(true);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004390
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004391 // Set up the global object as a normalized object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004392 global->set_map(new_map);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004393 global->set_properties(dictionary);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004394
4395 // Make sure result is a global object with properties in dictionary.
4396 ASSERT(global->IsGlobalObject());
4397 ASSERT(!global->HasFastProperties());
4398 return global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004399}
4400
4401
lrn@chromium.org303ada72010-10-27 09:33:13 +00004402MaybeObject* Heap::CopyJSObject(JSObject* source) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004403 // Never used to copy functions. If functions need to be copied we
4404 // have to be careful to clear the literals array.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004405 SLOW_ASSERT(!source->IsJSFunction());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004406
4407 // Make the clone.
4408 Map* map = source->map();
4409 int object_size = map->instance_size();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004410 Object* clone;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004411
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004412 WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER;
4413
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004414 // If we're forced to always allocate, we use the general allocation
4415 // functions which may leave us with an object in old space.
4416 if (always_allocate()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004417 { MaybeObject* maybe_clone =
4418 AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE);
4419 if (!maybe_clone->ToObject(&clone)) return maybe_clone;
4420 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004421 Address clone_address = HeapObject::cast(clone)->address();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004422 CopyBlock(clone_address,
4423 source->address(),
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004424 object_size);
4425 // Update write barrier for all fields that lie beyond the header.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004426 RecordWrites(clone_address,
4427 JSObject::kHeaderSize,
antonm@chromium.org8e5e3382010-03-24 09:56:30 +00004428 (object_size - JSObject::kHeaderSize) / kPointerSize);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004429 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004430 wb_mode = SKIP_WRITE_BARRIER;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004431 { MaybeObject* maybe_clone = new_space_.AllocateRaw(object_size);
4432 if (!maybe_clone->ToObject(&clone)) return maybe_clone;
4433 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004434 SLOW_ASSERT(InNewSpace(clone));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004435 // Since we know the clone is allocated in new space, we can copy
ager@chromium.org32912102009-01-16 10:38:43 +00004436 // the contents without worrying about updating the write barrier.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004437 CopyBlock(HeapObject::cast(clone)->address(),
4438 source->address(),
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004439 object_size);
4440 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004441
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004442 SLOW_ASSERT(
4443 JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004444 FixedArrayBase* elements = FixedArrayBase::cast(source->elements());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004445 FixedArray* properties = FixedArray::cast(source->properties());
4446 // Update elements if necessary.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00004447 if (elements->length() > 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004448 Object* elem;
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004449 { MaybeObject* maybe_elem;
4450 if (elements->map() == fixed_cow_array_map()) {
4451 maybe_elem = FixedArray::cast(elements);
4452 } else if (source->HasFastDoubleElements()) {
4453 maybe_elem = CopyFixedDoubleArray(FixedDoubleArray::cast(elements));
4454 } else {
4455 maybe_elem = CopyFixedArray(FixedArray::cast(elements));
4456 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004457 if (!maybe_elem->ToObject(&elem)) return maybe_elem;
4458 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004459 JSObject::cast(clone)->set_elements(FixedArrayBase::cast(elem), wb_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004460 }
4461 // Update properties if necessary.
4462 if (properties->length() > 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004463 Object* prop;
4464 { MaybeObject* maybe_prop = CopyFixedArray(properties);
4465 if (!maybe_prop->ToObject(&prop)) return maybe_prop;
4466 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004467 JSObject::cast(clone)->set_properties(FixedArray::cast(prop), wb_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004468 }
4469 // Return the new clone.
4470 return clone;
4471}
4472
4473
lrn@chromium.org34e60782011-09-15 07:25:40 +00004474MaybeObject* Heap::ReinitializeJSReceiver(
4475 JSReceiver* object, InstanceType type, int size) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004476 ASSERT(type >= FIRST_JS_OBJECT_TYPE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004477
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004478 // Allocate fresh map.
4479 // TODO(rossberg): Once we optimize proxies, cache these maps.
4480 Map* map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004481 MaybeObject* maybe = AllocateMap(type, size);
4482 if (!maybe->To<Map>(&map)) return maybe;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004483
lrn@chromium.org34e60782011-09-15 07:25:40 +00004484 // Check that the receiver has at least the size of the fresh object.
4485 int size_difference = object->map()->instance_size() - map->instance_size();
4486 ASSERT(size_difference >= 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004487
4488 map->set_prototype(object->map()->prototype());
4489
4490 // Allocate the backing storage for the properties.
4491 int prop_size = map->unused_property_fields() - map->inobject_properties();
4492 Object* properties;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004493 maybe = AllocateFixedArray(prop_size, TENURED);
4494 if (!maybe->ToObject(&properties)) return maybe;
4495
4496 // Functions require some allocation, which might fail here.
4497 SharedFunctionInfo* shared = NULL;
4498 if (type == JS_FUNCTION_TYPE) {
4499 String* name;
4500 maybe = LookupAsciiSymbol("<freezing call trap>");
4501 if (!maybe->To<String>(&name)) return maybe;
4502 maybe = AllocateSharedFunctionInfo(name);
4503 if (!maybe->To<SharedFunctionInfo>(&shared)) return maybe;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004504 }
4505
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004506 // Because of possible retries of this function after failure,
4507 // we must NOT fail after this point, where we have changed the type!
4508
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004509 // Reset the map for the object.
4510 object->set_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004511 JSObject* jsobj = JSObject::cast(object);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004512
4513 // Reinitialize the object from the constructor map.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004514 InitializeJSObjectFromMap(jsobj, FixedArray::cast(properties), map);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004515
4516 // Functions require some minimal initialization.
4517 if (type == JS_FUNCTION_TYPE) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004518 map->set_function_with_prototype(true);
4519 InitializeFunction(JSFunction::cast(object), shared, the_hole_value());
4520 JSFunction::cast(object)->set_context(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004521 isolate()->context()->native_context());
lrn@chromium.org34e60782011-09-15 07:25:40 +00004522 }
4523
4524 // Put in filler if the new object is smaller than the old.
4525 if (size_difference > 0) {
4526 CreateFillerObjectAt(
4527 object->address() + map->instance_size(), size_difference);
4528 }
4529
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004530 return object;
4531}
4532
4533
lrn@chromium.org303ada72010-10-27 09:33:13 +00004534MaybeObject* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor,
4535 JSGlobalProxy* object) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004536 ASSERT(constructor->has_initial_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004537 Map* map = constructor->initial_map();
4538
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004539 // Check that the already allocated object has the same size and type as
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004540 // objects allocated using the constructor.
4541 ASSERT(map->instance_size() == object->map()->instance_size());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004542 ASSERT(map->instance_type() == object->map()->instance_type());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004543
4544 // Allocate the backing storage for the properties.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004545 int prop_size = map->unused_property_fields() - map->inobject_properties();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004546 Object* properties;
4547 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, TENURED);
4548 if (!maybe_properties->ToObject(&properties)) return maybe_properties;
4549 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004550
4551 // Reset the map for the object.
4552 object->set_map(constructor->initial_map());
4553
4554 // Reinitialize the object from the constructor map.
4555 InitializeJSObjectFromMap(object, FixedArray::cast(properties), map);
4556 return object;
4557}
4558
4559
lrn@chromium.org303ada72010-10-27 09:33:13 +00004560MaybeObject* Heap::AllocateStringFromAscii(Vector<const char> string,
4561 PretenureFlag pretenure) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004562 int length = string.length();
4563 if (length == 1) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004564 return Heap::LookupSingleCharacterStringFromCode(string[0]);
4565 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004566 Object* result;
4567 { MaybeObject* maybe_result =
4568 AllocateRawAsciiString(string.length(), pretenure);
4569 if (!maybe_result->ToObject(&result)) return maybe_result;
4570 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004571
4572 // Copy the characters into the new object.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004573 CopyChars(SeqAsciiString::cast(result)->GetChars(), string.start(), length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004574 return result;
4575}
4576
4577
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004578MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector<const char> string,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004579 int non_ascii_start,
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004580 PretenureFlag pretenure) {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004581 // Continue counting the number of characters in the UTF-8 string, starting
4582 // from the first non-ascii character or word.
4583 int chars = non_ascii_start;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004584 Access<UnicodeCache::Utf8Decoder>
4585 decoder(isolate_->unicode_cache()->utf8_decoder());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004586 decoder->Reset(string.start() + non_ascii_start, string.length() - chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004587 while (decoder->has_more()) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004588 uint32_t r = decoder->GetNext();
4589 if (r <= unibrow::Utf16::kMaxNonSurrogateCharCode) {
4590 chars++;
4591 } else {
4592 chars += 2;
4593 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004594 }
4595
lrn@chromium.org303ada72010-10-27 09:33:13 +00004596 Object* result;
4597 { MaybeObject* maybe_result = AllocateRawTwoByteString(chars, pretenure);
4598 if (!maybe_result->ToObject(&result)) return maybe_result;
4599 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004600
4601 // Convert and copy the characters into the new object.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004602 SeqTwoByteString* twobyte = SeqTwoByteString::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603 decoder->Reset(string.start(), string.length());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004604 int i = 0;
4605 while (i < chars) {
4606 uint32_t r = decoder->GetNext();
4607 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004608 twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::LeadSurrogate(r));
4609 twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::TrailSurrogate(r));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004610 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004611 twobyte->SeqTwoByteStringSet(i++, r);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004612 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004613 }
4614 return result;
4615}
4616
4617
lrn@chromium.org303ada72010-10-27 09:33:13 +00004618MaybeObject* Heap::AllocateStringFromTwoByte(Vector<const uc16> string,
4619 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004620 // Check if the string is an ASCII string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004621 Object* result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004622 int length = string.length();
4623 const uc16* start = string.start();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004624
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004625 if (String::IsAscii(start, length)) {
4626 MaybeObject* maybe_result = AllocateRawAsciiString(length, pretenure);
4627 if (!maybe_result->ToObject(&result)) return maybe_result;
4628 CopyChars(SeqAsciiString::cast(result)->GetChars(), start, length);
4629 } else { // It's not an ASCII string.
4630 MaybeObject* maybe_result = AllocateRawTwoByteString(length, pretenure);
4631 if (!maybe_result->ToObject(&result)) return maybe_result;
4632 CopyChars(SeqTwoByteString::cast(result)->GetChars(), start, length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004633 }
4634 return result;
4635}
4636
4637
4638Map* Heap::SymbolMapForString(String* string) {
4639 // If the string is in new space it cannot be used as a symbol.
4640 if (InNewSpace(string)) return NULL;
4641
4642 // Find the corresponding symbol map for strings.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004643 switch (string->map()->instance_type()) {
4644 case STRING_TYPE: return symbol_map();
4645 case ASCII_STRING_TYPE: return ascii_symbol_map();
4646 case CONS_STRING_TYPE: return cons_symbol_map();
4647 case CONS_ASCII_STRING_TYPE: return cons_ascii_symbol_map();
4648 case EXTERNAL_STRING_TYPE: return external_symbol_map();
4649 case EXTERNAL_ASCII_STRING_TYPE: return external_ascii_symbol_map();
4650 case EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
4651 return external_symbol_with_ascii_data_map();
4652 case SHORT_EXTERNAL_STRING_TYPE: return short_external_symbol_map();
4653 case SHORT_EXTERNAL_ASCII_STRING_TYPE:
4654 return short_external_ascii_symbol_map();
4655 case SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
4656 return short_external_symbol_with_ascii_data_map();
4657 default: return NULL; // No match found.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004658 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004659}
4660
4661
lrn@chromium.org303ada72010-10-27 09:33:13 +00004662MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
4663 int chars,
4664 uint32_t hash_field) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004665 ASSERT(chars >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004666 // Ensure the chars matches the number of characters in the buffer.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004667 ASSERT(static_cast<unsigned>(chars) == buffer->Utf16Length());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004668 // Determine whether the string is ASCII.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004669 bool is_ascii = true;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004670 while (buffer->has_more()) {
4671 if (buffer->GetNext() > unibrow::Utf8::kMaxOneByteChar) {
4672 is_ascii = false;
4673 break;
4674 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004675 }
4676 buffer->Rewind();
4677
4678 // Compute map and object size.
4679 int size;
4680 Map* map;
4681
4682 if (is_ascii) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004683 if (chars > SeqAsciiString::kMaxLength) {
4684 return Failure::OutOfMemoryException();
4685 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004686 map = ascii_symbol_map();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004687 size = SeqAsciiString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004688 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004689 if (chars > SeqTwoByteString::kMaxLength) {
4690 return Failure::OutOfMemoryException();
4691 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004692 map = symbol_map();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004693 size = SeqTwoByteString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004694 }
4695
4696 // Allocate string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004697 Object* result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004698 { MaybeObject* maybe_result = (size > Page::kMaxNonCodeHeapObjectSize)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004699 ? lo_space_->AllocateRaw(size, NOT_EXECUTABLE)
lrn@chromium.org303ada72010-10-27 09:33:13 +00004700 : old_data_space_->AllocateRaw(size);
4701 if (!maybe_result->ToObject(&result)) return maybe_result;
4702 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004703
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004704 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(map);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004705 // Set length and hash fields of the allocated string.
ager@chromium.org870a0b62008-11-04 11:43:05 +00004706 String* answer = String::cast(result);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004707 answer->set_length(chars);
4708 answer->set_hash_field(hash_field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004709
ager@chromium.org870a0b62008-11-04 11:43:05 +00004710 ASSERT_EQ(size, answer->Size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004711
4712 // Fill in the characters.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004713 int i = 0;
4714 while (i < chars) {
4715 uint32_t character = buffer->GetNext();
4716 if (character > unibrow::Utf16::kMaxNonSurrogateCharCode) {
4717 answer->Set(i++, unibrow::Utf16::LeadSurrogate(character));
4718 answer->Set(i++, unibrow::Utf16::TrailSurrogate(character));
4719 } else {
4720 answer->Set(i++, character);
4721 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004722 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00004723 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004724}
4725
4726
lrn@chromium.org303ada72010-10-27 09:33:13 +00004727MaybeObject* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004728 if (length < 0 || length > SeqAsciiString::kMaxLength) {
4729 return Failure::OutOfMemoryException();
4730 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004731
ager@chromium.org7c537e22008-10-16 08:43:32 +00004732 int size = SeqAsciiString::SizeFor(length);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004733 ASSERT(size <= SeqAsciiString::kMaxSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004734
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004735 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
4736 AllocationSpace retry_space = OLD_DATA_SPACE;
4737
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004738 if (space == NEW_SPACE) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004739 if (size > kMaxObjectSizeInNewSpace) {
4740 // Allocate in large object space, retry space will be ignored.
4741 space = LO_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004742 } else if (size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004743 // Allocate in new space, retry in large object space.
4744 retry_space = LO_SPACE;
4745 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004746 } else if (space == OLD_DATA_SPACE &&
4747 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004748 space = LO_SPACE;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004749 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004750 Object* result;
4751 { MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
4752 if (!maybe_result->ToObject(&result)) return maybe_result;
4753 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004754
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004755 // Partially initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004756 HeapObject::cast(result)->set_map_no_write_barrier(ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004757 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004758 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004759 ASSERT_EQ(size, HeapObject::cast(result)->Size());
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004760
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004761#ifdef VERIFY_HEAP
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004762 if (FLAG_verify_heap) {
4763 // Initialize string's content to ensure ASCII-ness (character range 0-127)
4764 // as required when verifying the heap.
4765 char* dest = SeqAsciiString::cast(result)->GetChars();
4766 memset(dest, 0x0F, length * kCharSize);
4767 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004768#endif
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004769
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004770 return result;
4771}
4772
4773
lrn@chromium.org303ada72010-10-27 09:33:13 +00004774MaybeObject* Heap::AllocateRawTwoByteString(int length,
4775 PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004776 if (length < 0 || length > SeqTwoByteString::kMaxLength) {
4777 return Failure::OutOfMemoryException();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004778 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004779 int size = SeqTwoByteString::SizeFor(length);
4780 ASSERT(size <= SeqTwoByteString::kMaxSize);
4781 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
4782 AllocationSpace retry_space = OLD_DATA_SPACE;
4783
4784 if (space == NEW_SPACE) {
4785 if (size > kMaxObjectSizeInNewSpace) {
4786 // Allocate in large object space, retry space will be ignored.
4787 space = LO_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004788 } else if (size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004789 // Allocate in new space, retry in large object space.
4790 retry_space = LO_SPACE;
4791 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004792 } else if (space == OLD_DATA_SPACE &&
4793 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004794 space = LO_SPACE;
4795 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004796 Object* result;
4797 { MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
4798 if (!maybe_result->ToObject(&result)) return maybe_result;
4799 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004800
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004801 // Partially initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004802 HeapObject::cast(result)->set_map_no_write_barrier(string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004803 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004804 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004805 ASSERT_EQ(size, HeapObject::cast(result)->Size());
4806 return result;
4807}
4808
4809
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004810MaybeObject* Heap::AllocateJSArray(
4811 ElementsKind elements_kind,
4812 PretenureFlag pretenure) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004813 Context* native_context = isolate()->context()->native_context();
4814 JSFunction* array_function = native_context->array_function();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004815 Map* map = array_function->initial_map();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004816 Object* maybe_map_array = native_context->js_array_maps();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004817 if (!maybe_map_array->IsUndefined()) {
4818 Object* maybe_transitioned_map =
4819 FixedArray::cast(maybe_map_array)->get(elements_kind);
4820 if (!maybe_transitioned_map->IsUndefined()) {
4821 map = Map::cast(maybe_transitioned_map);
4822 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004823 }
4824
4825 return AllocateJSObjectFromMap(map, pretenure);
4826}
4827
4828
lrn@chromium.org303ada72010-10-27 09:33:13 +00004829MaybeObject* Heap::AllocateEmptyFixedArray() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004830 int size = FixedArray::SizeFor(0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004831 Object* result;
4832 { MaybeObject* maybe_result =
4833 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
4834 if (!maybe_result->ToObject(&result)) return maybe_result;
4835 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004836 // Initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004837 reinterpret_cast<FixedArray*>(result)->set_map_no_write_barrier(
4838 fixed_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004839 reinterpret_cast<FixedArray*>(result)->set_length(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004840 return result;
4841}
4842
4843
lrn@chromium.org303ada72010-10-27 09:33:13 +00004844MaybeObject* Heap::AllocateRawFixedArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004845 if (length < 0 || length > FixedArray::kMaxLength) {
4846 return Failure::OutOfMemoryException();
4847 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004848 ASSERT(length > 0);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004849 // Use the general function if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004850 if (always_allocate()) return AllocateFixedArray(length, TENURED);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004851 // Allocate the raw data for a fixed array.
4852 int size = FixedArray::SizeFor(length);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004853 return size <= kMaxObjectSizeInNewSpace
4854 ? new_space_.AllocateRaw(size)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004855 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004856}
4857
4858
lrn@chromium.org303ada72010-10-27 09:33:13 +00004859MaybeObject* Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004860 int len = src->length();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004861 Object* obj;
4862 { MaybeObject* maybe_obj = AllocateRawFixedArray(len);
4863 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4864 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004865 if (InNewSpace(obj)) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004866 HeapObject* dst = HeapObject::cast(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004867 dst->set_map_no_write_barrier(map);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004868 CopyBlock(dst->address() + kPointerSize,
4869 src->address() + kPointerSize,
4870 FixedArray::SizeFor(len) - kPointerSize);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004871 return obj;
4872 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004873 HeapObject::cast(obj)->set_map_no_write_barrier(map);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004874 FixedArray* result = FixedArray::cast(obj);
4875 result->set_length(len);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004876
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004877 // Copy the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004878 AssertNoAllocation no_gc;
4879 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004880 for (int i = 0; i < len; i++) result->set(i, src->get(i), mode);
4881 return result;
4882}
4883
4884
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004885MaybeObject* Heap::CopyFixedDoubleArrayWithMap(FixedDoubleArray* src,
4886 Map* map) {
4887 int len = src->length();
4888 Object* obj;
4889 { MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(len, NOT_TENURED);
4890 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4891 }
4892 HeapObject* dst = HeapObject::cast(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004893 dst->set_map_no_write_barrier(map);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004894 CopyBlock(
4895 dst->address() + FixedDoubleArray::kLengthOffset,
4896 src->address() + FixedDoubleArray::kLengthOffset,
4897 FixedDoubleArray::SizeFor(len) - FixedDoubleArray::kLengthOffset);
4898 return obj;
4899}
4900
4901
lrn@chromium.org303ada72010-10-27 09:33:13 +00004902MaybeObject* Heap::AllocateFixedArray(int length) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004903 ASSERT(length >= 0);
ager@chromium.org32912102009-01-16 10:38:43 +00004904 if (length == 0) return empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004905 Object* result;
4906 { MaybeObject* maybe_result = AllocateRawFixedArray(length);
4907 if (!maybe_result->ToObject(&result)) return maybe_result;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004908 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004909 // Initialize header.
4910 FixedArray* array = reinterpret_cast<FixedArray*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004911 array->set_map_no_write_barrier(fixed_array_map());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004912 array->set_length(length);
4913 // Initialize body.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004914 ASSERT(!InNewSpace(undefined_value()));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004915 MemsetPointer(array->data_start(), undefined_value(), length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004916 return result;
4917}
4918
4919
lrn@chromium.org303ada72010-10-27 09:33:13 +00004920MaybeObject* Heap::AllocateRawFixedArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004921 if (length < 0 || length > FixedArray::kMaxLength) {
4922 return Failure::OutOfMemoryException();
4923 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004924
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004925 AllocationSpace space =
4926 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004927 int size = FixedArray::SizeFor(length);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004928 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
4929 // Too big for new space.
4930 space = LO_SPACE;
4931 } else if (space == OLD_POINTER_SPACE &&
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004932 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004933 // Too big for old pointer space.
4934 space = LO_SPACE;
4935 }
4936
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004937 AllocationSpace retry_space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004938 (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_POINTER_SPACE : LO_SPACE;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004939
4940 return AllocateRaw(size, space, retry_space);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004941}
4942
4943
lrn@chromium.org303ada72010-10-27 09:33:13 +00004944MUST_USE_RESULT static MaybeObject* AllocateFixedArrayWithFiller(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004945 Heap* heap,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004946 int length,
4947 PretenureFlag pretenure,
4948 Object* filler) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004949 ASSERT(length >= 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004950 ASSERT(heap->empty_fixed_array()->IsFixedArray());
4951 if (length == 0) return heap->empty_fixed_array();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004952
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004953 ASSERT(!heap->InNewSpace(filler));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004954 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004955 { MaybeObject* maybe_result = heap->AllocateRawFixedArray(length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004956 if (!maybe_result->ToObject(&result)) return maybe_result;
4957 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004958
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004959 HeapObject::cast(result)->set_map_no_write_barrier(heap->fixed_array_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004960 FixedArray* array = FixedArray::cast(result);
4961 array->set_length(length);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004962 MemsetPointer(array->data_start(), filler, length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004963 return array;
4964}
4965
4966
lrn@chromium.org303ada72010-10-27 09:33:13 +00004967MaybeObject* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004968 return AllocateFixedArrayWithFiller(this,
4969 length,
4970 pretenure,
4971 undefined_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004972}
4973
4974
lrn@chromium.org303ada72010-10-27 09:33:13 +00004975MaybeObject* Heap::AllocateFixedArrayWithHoles(int length,
4976 PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004977 return AllocateFixedArrayWithFiller(this,
4978 length,
4979 pretenure,
4980 the_hole_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004981}
4982
4983
lrn@chromium.org303ada72010-10-27 09:33:13 +00004984MaybeObject* Heap::AllocateUninitializedFixedArray(int length) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004985 if (length == 0) return empty_fixed_array();
4986
lrn@chromium.org303ada72010-10-27 09:33:13 +00004987 Object* obj;
4988 { MaybeObject* maybe_obj = AllocateRawFixedArray(length);
4989 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4990 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004991
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004992 reinterpret_cast<FixedArray*>(obj)->set_map_no_write_barrier(
4993 fixed_array_map());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004994 FixedArray::cast(obj)->set_length(length);
4995 return obj;
4996}
4997
4998
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004999MaybeObject* Heap::AllocateEmptyFixedDoubleArray() {
5000 int size = FixedDoubleArray::SizeFor(0);
5001 Object* result;
5002 { MaybeObject* maybe_result =
5003 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
5004 if (!maybe_result->ToObject(&result)) return maybe_result;
5005 }
5006 // Initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005007 reinterpret_cast<FixedDoubleArray*>(result)->set_map_no_write_barrier(
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005008 fixed_double_array_map());
5009 reinterpret_cast<FixedDoubleArray*>(result)->set_length(0);
5010 return result;
5011}
5012
5013
5014MaybeObject* Heap::AllocateUninitializedFixedDoubleArray(
5015 int length,
5016 PretenureFlag pretenure) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005017 if (length == 0) return empty_fixed_array();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005018
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005019 Object* elements_object;
5020 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
5021 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj;
5022 FixedDoubleArray* elements =
5023 reinterpret_cast<FixedDoubleArray*>(elements_object);
5024
5025 elements->set_map_no_write_barrier(fixed_double_array_map());
5026 elements->set_length(length);
5027 return elements;
5028}
5029
5030
5031MaybeObject* Heap::AllocateFixedDoubleArrayWithHoles(
5032 int length,
5033 PretenureFlag pretenure) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005034 if (length == 0) return empty_fixed_array();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005035
5036 Object* elements_object;
5037 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
5038 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj;
5039 FixedDoubleArray* elements =
5040 reinterpret_cast<FixedDoubleArray*>(elements_object);
5041
5042 for (int i = 0; i < length; ++i) {
5043 elements->set_the_hole(i);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005044 }
5045
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005046 elements->set_map_no_write_barrier(fixed_double_array_map());
5047 elements->set_length(length);
5048 return elements;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005049}
5050
5051
5052MaybeObject* Heap::AllocateRawFixedDoubleArray(int length,
5053 PretenureFlag pretenure) {
5054 if (length < 0 || length > FixedDoubleArray::kMaxLength) {
5055 return Failure::OutOfMemoryException();
5056 }
5057
5058 AllocationSpace space =
5059 (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
5060 int size = FixedDoubleArray::SizeFor(length);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005061
5062#ifndef V8_HOST_ARCH_64_BIT
5063 size += kPointerSize;
5064#endif
5065
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005066 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
5067 // Too big for new space.
5068 space = LO_SPACE;
5069 } else if (space == OLD_DATA_SPACE &&
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005070 size > Page::kMaxNonCodeHeapObjectSize) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005071 // Too big for old data space.
5072 space = LO_SPACE;
5073 }
5074
5075 AllocationSpace retry_space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005076 (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_DATA_SPACE : LO_SPACE;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005077
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005078 HeapObject* object;
5079 { MaybeObject* maybe_object = AllocateRaw(size, space, retry_space);
5080 if (!maybe_object->To<HeapObject>(&object)) return maybe_object;
5081 }
5082
5083 return EnsureDoubleAligned(this, object, size);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005084}
5085
5086
lrn@chromium.org303ada72010-10-27 09:33:13 +00005087MaybeObject* Heap::AllocateHashTable(int length, PretenureFlag pretenure) {
5088 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005089 { MaybeObject* maybe_result = AllocateFixedArray(length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005090 if (!maybe_result->ToObject(&result)) return maybe_result;
5091 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005092 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(
5093 hash_table_map());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005094 ASSERT(result->IsHashTable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005095 return result;
5096}
5097
5098
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005099MaybeObject* Heap::AllocateNativeContext() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005100 Object* result;
5101 { MaybeObject* maybe_result =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005102 AllocateFixedArray(Context::NATIVE_CONTEXT_SLOTS);
5103 if (!maybe_result->ToObject(&result)) return maybe_result;
5104 }
5105 Context* context = reinterpret_cast<Context*>(result);
5106 context->set_map_no_write_barrier(native_context_map());
5107 context->set_js_array_maps(undefined_value());
5108 ASSERT(context->IsNativeContext());
5109 ASSERT(result->IsContext());
5110 return result;
5111}
5112
5113
5114MaybeObject* Heap::AllocateGlobalContext(JSFunction* function,
5115 ScopeInfo* scope_info) {
5116 Object* result;
5117 { MaybeObject* maybe_result =
5118 AllocateFixedArray(scope_info->ContextLength(), TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005119 if (!maybe_result->ToObject(&result)) return maybe_result;
5120 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005121 Context* context = reinterpret_cast<Context*>(result);
danno@chromium.orgeb831462012-08-24 11:57:08 +00005122 context->set_map_no_write_barrier(global_context_map());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005123 context->set_closure(function);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005124 context->set_previous(function->context());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005125 context->set_extension(scope_info);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005126 context->set_global_object(function->context()->global_object());
danno@chromium.orgeb831462012-08-24 11:57:08 +00005127 ASSERT(context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005128 ASSERT(result->IsContext());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005129 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005130}
5131
5132
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005133MaybeObject* Heap::AllocateModuleContext(ScopeInfo* scope_info) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005134 Object* result;
5135 { MaybeObject* maybe_result =
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005136 AllocateFixedArray(scope_info->ContextLength(), TENURED);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005137 if (!maybe_result->ToObject(&result)) return maybe_result;
5138 }
5139 Context* context = reinterpret_cast<Context*>(result);
5140 context->set_map_no_write_barrier(module_context_map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005141 // Context links will be set later.
5142 context->set_extension(Smi::FromInt(0));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005143 return context;
5144}
5145
5146
lrn@chromium.org303ada72010-10-27 09:33:13 +00005147MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005148 ASSERT(length >= Context::MIN_CONTEXT_SLOTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005149 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005150 { MaybeObject* maybe_result = AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005151 if (!maybe_result->ToObject(&result)) return maybe_result;
5152 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005153 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005154 context->set_map_no_write_barrier(function_context_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005155 context->set_closure(function);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005156 context->set_previous(function->context());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005157 context->set_extension(Smi::FromInt(0));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005158 context->set_global_object(function->context()->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005159 return context;
5160}
5161
5162
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005163MaybeObject* Heap::AllocateCatchContext(JSFunction* function,
5164 Context* previous,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005165 String* name,
5166 Object* thrown_object) {
5167 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == Context::THROWN_OBJECT_INDEX);
5168 Object* result;
5169 { MaybeObject* maybe_result =
5170 AllocateFixedArray(Context::MIN_CONTEXT_SLOTS + 1);
5171 if (!maybe_result->ToObject(&result)) return maybe_result;
5172 }
5173 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005174 context->set_map_no_write_barrier(catch_context_map());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005175 context->set_closure(function);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005176 context->set_previous(previous);
5177 context->set_extension(name);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005178 context->set_global_object(previous->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005179 context->set(Context::THROWN_OBJECT_INDEX, thrown_object);
5180 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005181}
5182
5183
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005184MaybeObject* Heap::AllocateWithContext(JSFunction* function,
5185 Context* previous,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005186 JSObject* extension) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005187 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005188 { MaybeObject* maybe_result = AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005189 if (!maybe_result->ToObject(&result)) return maybe_result;
5190 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005191 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005192 context->set_map_no_write_barrier(with_context_map());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005193 context->set_closure(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005194 context->set_previous(previous);
5195 context->set_extension(extension);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005196 context->set_global_object(previous->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005197 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005198}
5199
5200
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005201MaybeObject* Heap::AllocateBlockContext(JSFunction* function,
5202 Context* previous,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005203 ScopeInfo* scope_info) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005204 Object* result;
5205 { MaybeObject* maybe_result =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005206 AllocateFixedArrayWithHoles(scope_info->ContextLength());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005207 if (!maybe_result->ToObject(&result)) return maybe_result;
5208 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005209 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005210 context->set_map_no_write_barrier(block_context_map());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005211 context->set_closure(function);
5212 context->set_previous(previous);
5213 context->set_extension(scope_info);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005214 context->set_global_object(previous->global_object());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005215 return context;
5216}
5217
5218
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005219MaybeObject* Heap::AllocateScopeInfo(int length) {
5220 FixedArray* scope_info;
5221 MaybeObject* maybe_scope_info = AllocateFixedArray(length, TENURED);
5222 if (!maybe_scope_info->To(&scope_info)) return maybe_scope_info;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005223 scope_info->set_map_no_write_barrier(scope_info_map());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005224 return scope_info;
5225}
5226
5227
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00005228MaybeObject* Heap::AllocateExternal(void* value) {
5229 Foreign* foreign;
5230 { MaybeObject* maybe_result = AllocateForeign(static_cast<Address>(value));
5231 if (!maybe_result->To(&foreign)) return maybe_result;
5232 }
5233 JSObject* external;
5234 { MaybeObject* maybe_result = AllocateJSObjectFromMap(external_map());
5235 if (!maybe_result->To(&external)) return maybe_result;
5236 }
5237 external->SetInternalField(0, foreign);
5238 return external;
5239}
5240
5241
lrn@chromium.org303ada72010-10-27 09:33:13 +00005242MaybeObject* Heap::AllocateStruct(InstanceType type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005243 Map* map;
5244 switch (type) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005245#define MAKE_CASE(NAME, Name, name) \
5246 case NAME##_TYPE: map = name##_map(); break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005247STRUCT_LIST(MAKE_CASE)
5248#undef MAKE_CASE
5249 default:
5250 UNREACHABLE();
5251 return Failure::InternalError();
5252 }
5253 int size = map->instance_size();
5254 AllocationSpace space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005255 (size > Page::kMaxNonCodeHeapObjectSize) ? LO_SPACE : OLD_POINTER_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005256 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005257 { MaybeObject* maybe_result = Allocate(map, space);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005258 if (!maybe_result->ToObject(&result)) return maybe_result;
5259 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005260 Struct::cast(result)->InitializeBody(size);
5261 return result;
5262}
5263
5264
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005265bool Heap::IsHeapIterable() {
5266 return (!old_pointer_space()->was_swept_conservatively() &&
5267 !old_data_space()->was_swept_conservatively());
5268}
5269
5270
5271void Heap::EnsureHeapIsIterable() {
5272 ASSERT(IsAllocationAllowed());
5273 if (!IsHeapIterable()) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005274 CollectAllGarbage(kMakeHeapIterableMask, "Heap::EnsureHeapIsIterable");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005275 }
5276 ASSERT(IsHeapIterable());
5277}
5278
5279
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005280void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005281 incremental_marking()->Step(step_size,
5282 IncrementalMarking::NO_GC_VIA_STACK_GUARD);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005283
5284 if (incremental_marking()->IsComplete()) {
5285 bool uncommit = false;
5286 if (gc_count_at_last_idle_gc_ == gc_count_) {
5287 // No GC since the last full GC, the mutator is probably not active.
5288 isolate_->compilation_cache()->Clear();
5289 uncommit = true;
5290 }
5291 CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental");
5292 gc_count_at_last_idle_gc_ = gc_count_;
5293 if (uncommit) {
5294 new_space_.Shrink();
5295 UncommitFromSpace();
5296 }
5297 }
5298}
5299
5300
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005301bool Heap::IdleNotification(int hint) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005302 // Hints greater than this value indicate that
5303 // the embedder is requesting a lot of GC work.
danno@chromium.org88aa0582012-03-23 15:11:57 +00005304 const int kMaxHint = 1000;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005305 // Minimal hint that allows to do full GC.
5306 const int kMinHintForFullGC = 100;
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005307 intptr_t size_factor = Min(Max(hint, 20), kMaxHint) / 4;
5308 // The size factor is in range [5..250]. The numbers here are chosen from
5309 // experiments. If you changes them, make sure to test with
5310 // chrome/performance_ui_tests --gtest_filter="GeneralMixMemoryTest.*
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00005311 intptr_t step_size =
5312 size_factor * IncrementalMarking::kAllocatedThreshold;
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005313
5314 if (contexts_disposed_ > 0) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005315 if (hint >= kMaxHint) {
5316 // The embedder is requesting a lot of GC work after context disposal,
5317 // we age inline caches so that they don't keep objects from
5318 // the old context alive.
5319 AgeInlineCaches();
5320 }
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005321 int mark_sweep_time = Min(TimeMarkSweepWouldTakeInMs(), 1000);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005322 if (hint >= mark_sweep_time && !FLAG_expose_gc &&
5323 incremental_marking()->IsStopped()) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005324 HistogramTimerScope scope(isolate_->counters()->gc_context());
5325 CollectAllGarbage(kReduceMemoryFootprintMask,
5326 "idle notification: contexts disposed");
5327 } else {
5328 AdvanceIdleIncrementalMarking(step_size);
5329 contexts_disposed_ = 0;
5330 }
5331 // Make sure that we have no pending context disposals.
5332 // Take into account that we might have decided to delay full collection
5333 // because incremental marking is in progress.
5334 ASSERT((contexts_disposed_ == 0) || !incremental_marking()->IsStopped());
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005335 // After context disposal there is likely a lot of garbage remaining, reset
5336 // the idle notification counters in order to trigger more incremental GCs
5337 // on subsequent idle notifications.
5338 StartIdleRound();
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005339 return false;
5340 }
5341
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005342 if (!FLAG_incremental_marking || FLAG_expose_gc || Serializer::enabled()) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005343 return IdleGlobalGC();
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005344 }
5345
5346 // By doing small chunks of GC work in each IdleNotification,
5347 // perform a round of incremental GCs and after that wait until
5348 // the mutator creates enough garbage to justify a new round.
5349 // An incremental GC progresses as follows:
5350 // 1. many incremental marking steps,
5351 // 2. one old space mark-sweep-compact,
5352 // 3. many lazy sweep steps.
5353 // Use mark-sweep-compact events to count incremental GCs in a round.
5354
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005355
5356 if (incremental_marking()->IsStopped()) {
5357 if (!IsSweepingComplete() &&
5358 !AdvanceSweepers(static_cast<int>(step_size))) {
5359 return false;
5360 }
5361 }
5362
5363 if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) {
5364 if (EnoughGarbageSinceLastIdleRound()) {
5365 StartIdleRound();
5366 } else {
5367 return true;
5368 }
5369 }
5370
5371 int new_mark_sweeps = ms_count_ - ms_count_at_last_idle_notification_;
5372 mark_sweeps_since_idle_round_started_ += new_mark_sweeps;
5373 ms_count_at_last_idle_notification_ = ms_count_;
5374
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005375 int remaining_mark_sweeps = kMaxMarkSweepsInIdleRound -
5376 mark_sweeps_since_idle_round_started_;
5377
5378 if (remaining_mark_sweeps <= 0) {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005379 FinishIdleRound();
5380 return true;
5381 }
5382
5383 if (incremental_marking()->IsStopped()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005384 // If there are no more than two GCs left in this idle round and we are
5385 // allowed to do a full GC, then make those GCs full in order to compact
5386 // the code space.
5387 // TODO(ulan): Once we enable code compaction for incremental marking,
5388 // we can get rid of this special case and always start incremental marking.
5389 if (remaining_mark_sweeps <= 2 && hint >= kMinHintForFullGC) {
5390 CollectAllGarbage(kReduceMemoryFootprintMask,
5391 "idle notification: finalize idle round");
5392 } else {
5393 incremental_marking()->Start();
5394 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005395 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005396 if (!incremental_marking()->IsStopped()) {
5397 AdvanceIdleIncrementalMarking(step_size);
5398 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005399 return false;
5400}
5401
5402
5403bool Heap::IdleGlobalGC() {
ager@chromium.orga1645e22009-09-09 19:27:10 +00005404 static const int kIdlesBeforeScavenge = 4;
5405 static const int kIdlesBeforeMarkSweep = 7;
5406 static const int kIdlesBeforeMarkCompact = 8;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005407 static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005408 static const unsigned int kGCsBetweenCleanup = 4;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005409
5410 if (!last_idle_notification_gc_count_init_) {
5411 last_idle_notification_gc_count_ = gc_count_;
5412 last_idle_notification_gc_count_init_ = true;
5413 }
ager@chromium.org96c75b52009-08-26 09:13:16 +00005414
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005415 bool uncommit = true;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005416 bool finished = false;
5417
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005418 // Reset the number of idle notifications received when a number of
5419 // GCs have taken place. This allows another round of cleanup based
5420 // on idle notifications if enough work has been carried out to
5421 // provoke a number of garbage collections.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005422 if (gc_count_ - last_idle_notification_gc_count_ < kGCsBetweenCleanup) {
5423 number_idle_notifications_ =
5424 Min(number_idle_notifications_ + 1, kMaxIdleCount);
ager@chromium.org96c75b52009-08-26 09:13:16 +00005425 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005426 number_idle_notifications_ = 0;
5427 last_idle_notification_gc_count_ = gc_count_;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005428 }
5429
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005430 if (number_idle_notifications_ == kIdlesBeforeScavenge) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005431 CollectGarbage(NEW_SPACE, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005432 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005433 last_idle_notification_gc_count_ = gc_count_;
5434 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005435 // Before doing the mark-sweep collections we clear the
5436 // compilation cache to avoid hanging on to source code and
5437 // generated code for cached functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005438 isolate_->compilation_cache()->Clear();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005439
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005440 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005441 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005442 last_idle_notification_gc_count_ = gc_count_;
ager@chromium.orga1645e22009-09-09 19:27:10 +00005443
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005444 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005445 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005446 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005447 last_idle_notification_gc_count_ = gc_count_;
5448 number_idle_notifications_ = 0;
ager@chromium.orga1645e22009-09-09 19:27:10 +00005449 finished = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005450 } else if (number_idle_notifications_ > kIdlesBeforeMarkCompact) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005451 // If we have received more than kIdlesBeforeMarkCompact idle
5452 // notifications we do not perform any cleanup because we don't
5453 // expect to gain much by doing so.
5454 finished = true;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005455 }
5456
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005457 if (uncommit) UncommitFromSpace();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005458
ager@chromium.org96c75b52009-08-26 09:13:16 +00005459 return finished;
5460}
5461
5462
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005463#ifdef DEBUG
5464
5465void Heap::Print() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005466 if (!HasBeenSetUp()) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005467 isolate()->PrintStack();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005468 AllSpaces spaces;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005469 for (Space* space = spaces.next(); space != NULL; space = spaces.next())
5470 space->Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005471}
5472
5473
5474void Heap::ReportCodeStatistics(const char* title) {
5475 PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title);
5476 PagedSpace::ResetCodeStatistics();
5477 // We do not look for code in new space, map space, or old space. If code
5478 // somehow ends up in those spaces, we would miss it here.
5479 code_space_->CollectCodeStatistics();
5480 lo_space_->CollectCodeStatistics();
5481 PagedSpace::ReportCodeStatistics();
5482}
5483
5484
5485// This function expects that NewSpace's allocated objects histogram is
5486// populated (via a call to CollectStatistics or else as a side effect of a
5487// just-completed scavenge collection).
5488void Heap::ReportHeapStatistics(const char* title) {
5489 USE(title);
5490 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n",
5491 title, gc_count_);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005492 PrintF("old_gen_promotion_limit_ %" V8_PTR_PREFIX "d\n",
5493 old_gen_promotion_limit_);
5494 PrintF("old_gen_allocation_limit_ %" V8_PTR_PREFIX "d\n",
5495 old_gen_allocation_limit_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005496 PrintF("old_gen_limit_factor_ %d\n", old_gen_limit_factor_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005497
5498 PrintF("\n");
5499 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005500 isolate_->global_handles()->PrintStats();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005501 PrintF("\n");
5502
5503 PrintF("Heap statistics : ");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005504 isolate_->memory_allocator()->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005505 PrintF("To space : ");
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005506 new_space_.ReportStatistics();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005507 PrintF("Old pointer space : ");
5508 old_pointer_space_->ReportStatistics();
5509 PrintF("Old data space : ");
5510 old_data_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005511 PrintF("Code space : ");
5512 code_space_->ReportStatistics();
5513 PrintF("Map space : ");
5514 map_space_->ReportStatistics();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005515 PrintF("Cell space : ");
5516 cell_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005517 PrintF("Large object space : ");
5518 lo_space_->ReportStatistics();
5519 PrintF(">>>>>> ========================================= >>>>>>\n");
5520}
5521
5522#endif // DEBUG
5523
5524bool Heap::Contains(HeapObject* value) {
5525 return Contains(value->address());
5526}
5527
5528
5529bool Heap::Contains(Address addr) {
5530 if (OS::IsOutsideAllocatedSpace(addr)) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005531 return HasBeenSetUp() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005532 (new_space_.ToSpaceContains(addr) ||
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005533 old_pointer_space_->Contains(addr) ||
5534 old_data_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005535 code_space_->Contains(addr) ||
5536 map_space_->Contains(addr) ||
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005537 cell_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005538 lo_space_->SlowContains(addr));
5539}
5540
5541
5542bool Heap::InSpace(HeapObject* value, AllocationSpace space) {
5543 return InSpace(value->address(), space);
5544}
5545
5546
5547bool Heap::InSpace(Address addr, AllocationSpace space) {
5548 if (OS::IsOutsideAllocatedSpace(addr)) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005549 if (!HasBeenSetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005550
5551 switch (space) {
5552 case NEW_SPACE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005553 return new_space_.ToSpaceContains(addr);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005554 case OLD_POINTER_SPACE:
5555 return old_pointer_space_->Contains(addr);
5556 case OLD_DATA_SPACE:
5557 return old_data_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005558 case CODE_SPACE:
5559 return code_space_->Contains(addr);
5560 case MAP_SPACE:
5561 return map_space_->Contains(addr);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005562 case CELL_SPACE:
5563 return cell_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005564 case LO_SPACE:
5565 return lo_space_->SlowContains(addr);
5566 }
5567
5568 return false;
5569}
5570
5571
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005572#ifdef VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005573void Heap::Verify() {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005574 CHECK(HasBeenSetUp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005575
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005576 store_buffer()->Verify();
5577
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005578 VerifyPointersVisitor visitor;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005579 IterateRoots(&visitor, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005580
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005581 new_space_.Verify();
5582
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005583 old_pointer_space_->Verify(&visitor);
5584 map_space_->Verify(&visitor);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005585
5586 VerifyPointersVisitor no_dirty_regions_visitor;
5587 old_data_space_->Verify(&no_dirty_regions_visitor);
5588 code_space_->Verify(&no_dirty_regions_visitor);
5589 cell_space_->Verify(&no_dirty_regions_visitor);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005590
5591 lo_space_->Verify();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005592}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005593#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005594
5595
lrn@chromium.org303ada72010-10-27 09:33:13 +00005596MaybeObject* Heap::LookupSymbol(Vector<const char> string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005597 Object* symbol = NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005598 Object* new_table;
5599 { MaybeObject* maybe_new_table =
5600 symbol_table()->LookupSymbol(string, &symbol);
5601 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5602 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005603 // Can't use set_symbol_table because SymbolTable::cast knows that
5604 // SymbolTable is a singleton and checks for identity.
5605 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005606 ASSERT(symbol != NULL);
5607 return symbol;
5608}
5609
5610
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005611MaybeObject* Heap::LookupAsciiSymbol(Vector<const char> string) {
5612 Object* symbol = NULL;
5613 Object* new_table;
5614 { MaybeObject* maybe_new_table =
5615 symbol_table()->LookupAsciiSymbol(string, &symbol);
5616 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5617 }
5618 // Can't use set_symbol_table because SymbolTable::cast knows that
5619 // SymbolTable is a singleton and checks for identity.
5620 roots_[kSymbolTableRootIndex] = new_table;
5621 ASSERT(symbol != NULL);
5622 return symbol;
5623}
5624
5625
danno@chromium.org40cb8782011-05-25 07:58:50 +00005626MaybeObject* Heap::LookupAsciiSymbol(Handle<SeqAsciiString> string,
5627 int from,
5628 int length) {
5629 Object* symbol = NULL;
5630 Object* new_table;
5631 { MaybeObject* maybe_new_table =
5632 symbol_table()->LookupSubStringAsciiSymbol(string,
5633 from,
5634 length,
5635 &symbol);
5636 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5637 }
5638 // Can't use set_symbol_table because SymbolTable::cast knows that
5639 // SymbolTable is a singleton and checks for identity.
5640 roots_[kSymbolTableRootIndex] = new_table;
5641 ASSERT(symbol != NULL);
5642 return symbol;
5643}
5644
5645
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005646MaybeObject* Heap::LookupTwoByteSymbol(Vector<const uc16> string) {
5647 Object* symbol = NULL;
5648 Object* new_table;
5649 { MaybeObject* maybe_new_table =
5650 symbol_table()->LookupTwoByteSymbol(string, &symbol);
5651 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5652 }
5653 // Can't use set_symbol_table because SymbolTable::cast knows that
5654 // SymbolTable is a singleton and checks for identity.
5655 roots_[kSymbolTableRootIndex] = new_table;
5656 ASSERT(symbol != NULL);
5657 return symbol;
5658}
5659
5660
lrn@chromium.org303ada72010-10-27 09:33:13 +00005661MaybeObject* Heap::LookupSymbol(String* string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005662 if (string->IsSymbol()) return string;
5663 Object* symbol = NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005664 Object* new_table;
5665 { MaybeObject* maybe_new_table =
5666 symbol_table()->LookupString(string, &symbol);
5667 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5668 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005669 // Can't use set_symbol_table because SymbolTable::cast knows that
5670 // SymbolTable is a singleton and checks for identity.
5671 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005672 ASSERT(symbol != NULL);
5673 return symbol;
5674}
5675
5676
ager@chromium.org7c537e22008-10-16 08:43:32 +00005677bool Heap::LookupSymbolIfExists(String* string, String** symbol) {
5678 if (string->IsSymbol()) {
5679 *symbol = string;
5680 return true;
5681 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005682 return symbol_table()->LookupSymbolIfExists(string, symbol);
ager@chromium.org7c537e22008-10-16 08:43:32 +00005683}
5684
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005685
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005686void Heap::ZapFromSpace() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005687 NewSpacePageIterator it(new_space_.FromSpaceStart(),
5688 new_space_.FromSpaceEnd());
5689 while (it.has_next()) {
5690 NewSpacePage* page = it.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005691 for (Address cursor = page->area_start(), limit = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005692 cursor < limit;
5693 cursor += kPointerSize) {
5694 Memory::Address_at(cursor) = kFromSpaceZapValue;
5695 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005696 }
5697}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005698
5699
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005700void Heap::IterateAndMarkPointersToFromSpace(Address start,
5701 Address end,
5702 ObjectSlotCallback callback) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005703 Address slot_address = start;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005704
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005705 // We are not collecting slots on new space objects during mutation
5706 // thus we have to scan for pointers to evacuation candidates when we
5707 // promote objects. But we should not record any slots in non-black
5708 // objects. Grey object's slots would be rescanned.
5709 // White object might not survive until the end of collection
5710 // it would be a violation of the invariant to record it's slots.
5711 bool record_slots = false;
5712 if (incremental_marking()->IsCompacting()) {
5713 MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::FromAddress(start));
5714 record_slots = Marking::IsBlack(mark_bit);
5715 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005716
5717 while (slot_address < end) {
5718 Object** slot = reinterpret_cast<Object**>(slot_address);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005719 Object* object = *slot;
5720 // If the store buffer becomes overfull we mark pages as being exempt from
5721 // the store buffer. These pages are scanned to find pointers that point
5722 // to the new space. In that case we may hit newly promoted objects and
5723 // fix the pointers before the promotion queue gets to them. Thus the 'if'.
5724 if (object->IsHeapObject()) {
5725 if (Heap::InFromSpace(object)) {
5726 callback(reinterpret_cast<HeapObject**>(slot),
5727 HeapObject::cast(object));
5728 Object* new_object = *slot;
5729 if (InNewSpace(new_object)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005730 SLOW_ASSERT(Heap::InToSpace(new_object));
5731 SLOW_ASSERT(new_object->IsHeapObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005732 store_buffer_.EnterDirectlyIntoStoreBuffer(
5733 reinterpret_cast<Address>(slot));
5734 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005735 SLOW_ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_object));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005736 } else if (record_slots &&
5737 MarkCompactCollector::IsOnEvacuationCandidate(object)) {
5738 mark_compact_collector()->RecordSlot(slot, slot, object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005739 }
5740 }
5741 slot_address += kPointerSize;
5742 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005743}
5744
5745
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005746#ifdef DEBUG
5747typedef bool (*CheckStoreBufferFilter)(Object** addr);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005748
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005749
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005750bool IsAMapPointerAddress(Object** addr) {
5751 uintptr_t a = reinterpret_cast<uintptr_t>(addr);
5752 int mod = a % Map::kSize;
5753 return mod >= Map::kPointerFieldsBeginOffset &&
5754 mod < Map::kPointerFieldsEndOffset;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005755}
5756
5757
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005758bool EverythingsAPointer(Object** addr) {
5759 return true;
5760}
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005761
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005762
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005763static void CheckStoreBuffer(Heap* heap,
5764 Object** current,
5765 Object** limit,
5766 Object**** store_buffer_position,
5767 Object*** store_buffer_top,
5768 CheckStoreBufferFilter filter,
5769 Address special_garbage_start,
5770 Address special_garbage_end) {
5771 Map* free_space_map = heap->free_space_map();
5772 for ( ; current < limit; current++) {
5773 Object* o = *current;
5774 Address current_address = reinterpret_cast<Address>(current);
5775 // Skip free space.
5776 if (o == free_space_map) {
5777 Address current_address = reinterpret_cast<Address>(current);
5778 FreeSpace* free_space =
5779 FreeSpace::cast(HeapObject::FromAddress(current_address));
5780 int skip = free_space->Size();
5781 ASSERT(current_address + skip <= reinterpret_cast<Address>(limit));
5782 ASSERT(skip > 0);
5783 current_address += skip - kPointerSize;
5784 current = reinterpret_cast<Object**>(current_address);
5785 continue;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005786 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005787 // Skip the current linear allocation space between top and limit which is
5788 // unmarked with the free space map, but can contain junk.
5789 if (current_address == special_garbage_start &&
5790 special_garbage_end != special_garbage_start) {
5791 current_address = special_garbage_end - kPointerSize;
5792 current = reinterpret_cast<Object**>(current_address);
5793 continue;
5794 }
5795 if (!(*filter)(current)) continue;
5796 ASSERT(current_address < special_garbage_start ||
5797 current_address >= special_garbage_end);
5798 ASSERT(reinterpret_cast<uintptr_t>(o) != kFreeListZapValue);
5799 // We have to check that the pointer does not point into new space
5800 // without trying to cast it to a heap object since the hash field of
5801 // a string can contain values like 1 and 3 which are tagged null
5802 // pointers.
5803 if (!heap->InNewSpace(o)) continue;
5804 while (**store_buffer_position < current &&
5805 *store_buffer_position < store_buffer_top) {
5806 (*store_buffer_position)++;
5807 }
5808 if (**store_buffer_position != current ||
5809 *store_buffer_position == store_buffer_top) {
5810 Object** obj_start = current;
5811 while (!(*obj_start)->IsMap()) obj_start--;
5812 UNREACHABLE();
5813 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005814 }
5815}
5816
5817
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005818// Check that the store buffer contains all intergenerational pointers by
5819// scanning a page and ensuring that all pointers to young space are in the
5820// store buffer.
5821void Heap::OldPointerSpaceCheckStoreBuffer() {
5822 OldSpace* space = old_pointer_space();
5823 PageIterator pages(space);
5824
5825 store_buffer()->SortUniq();
5826
5827 while (pages.has_next()) {
5828 Page* page = pages.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005829 Object** current = reinterpret_cast<Object**>(page->area_start());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005830
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005831 Address end = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005832
5833 Object*** store_buffer_position = store_buffer()->Start();
5834 Object*** store_buffer_top = store_buffer()->Top();
5835
5836 Object** limit = reinterpret_cast<Object**>(end);
5837 CheckStoreBuffer(this,
5838 current,
5839 limit,
5840 &store_buffer_position,
5841 store_buffer_top,
5842 &EverythingsAPointer,
5843 space->top(),
5844 space->limit());
5845 }
5846}
5847
5848
5849void Heap::MapSpaceCheckStoreBuffer() {
5850 MapSpace* space = map_space();
5851 PageIterator pages(space);
5852
5853 store_buffer()->SortUniq();
5854
5855 while (pages.has_next()) {
5856 Page* page = pages.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005857 Object** current = reinterpret_cast<Object**>(page->area_start());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005858
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005859 Address end = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005860
5861 Object*** store_buffer_position = store_buffer()->Start();
5862 Object*** store_buffer_top = store_buffer()->Top();
5863
5864 Object** limit = reinterpret_cast<Object**>(end);
5865 CheckStoreBuffer(this,
5866 current,
5867 limit,
5868 &store_buffer_position,
5869 store_buffer_top,
5870 &IsAMapPointerAddress,
5871 space->top(),
5872 space->limit());
5873 }
5874}
5875
5876
5877void Heap::LargeObjectSpaceCheckStoreBuffer() {
5878 LargeObjectIterator it(lo_space());
5879 for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) {
5880 // We only have code, sequential strings, or fixed arrays in large
5881 // object space, and only fixed arrays can possibly contain pointers to
5882 // the young generation.
5883 if (object->IsFixedArray()) {
5884 Object*** store_buffer_position = store_buffer()->Start();
5885 Object*** store_buffer_top = store_buffer()->Top();
5886 Object** current = reinterpret_cast<Object**>(object->address());
5887 Object** limit =
5888 reinterpret_cast<Object**>(object->address() + object->Size());
5889 CheckStoreBuffer(this,
5890 current,
5891 limit,
5892 &store_buffer_position,
5893 store_buffer_top,
5894 &EverythingsAPointer,
5895 NULL,
5896 NULL);
5897 }
5898 }
5899}
5900#endif
5901
5902
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005903void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) {
5904 IterateStrongRoots(v, mode);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005905 IterateWeakRoots(v, mode);
5906}
5907
5908
5909void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005910 v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex]));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005911 v->Synchronize(VisitorSynchronization::kSymbolTable);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005912 if (mode != VISIT_ALL_IN_SCAVENGE &&
5913 mode != VISIT_ALL_IN_SWEEP_NEWSPACE) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005914 // Scavenge collections have special processing for this.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005915 external_string_table_.Iterate(v);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005916 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005917 v->Synchronize(VisitorSynchronization::kExternalStringsTable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918}
5919
5920
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005921void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005922 v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005923 v->Synchronize(VisitorSynchronization::kStrongRootList);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005924
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00005925 v->VisitPointer(BitCast<Object**>(&hidden_symbol_));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005926 v->Synchronize(VisitorSynchronization::kSymbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005927
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005928 isolate_->bootstrapper()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005929 v->Synchronize(VisitorSynchronization::kBootstrapper);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005930 isolate_->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005931 v->Synchronize(VisitorSynchronization::kTop);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005932 Relocatable::Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005933 v->Synchronize(VisitorSynchronization::kRelocatable);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005934
5935#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005936 isolate_->debug()->Iterate(v);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005937 if (isolate_->deoptimizer_data() != NULL) {
5938 isolate_->deoptimizer_data()->Iterate(v);
5939 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005940#endif
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005941 v->Synchronize(VisitorSynchronization::kDebug);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005942 isolate_->compilation_cache()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005943 v->Synchronize(VisitorSynchronization::kCompilationCache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005944
5945 // Iterate over local handles in handle scopes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005946 isolate_->handle_scope_implementer()->Iterate(v);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005947 isolate_->IterateDeferredHandles(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005948 v->Synchronize(VisitorSynchronization::kHandleScope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005949
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005950 // Iterate over the builtin code objects and code stubs in the
5951 // heap. Note that it is not necessary to iterate over code objects
5952 // on scavenge collections.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005953 if (mode != VISIT_ALL_IN_SCAVENGE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005954 isolate_->builtins()->IterateBuiltins(v);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005955 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005956 v->Synchronize(VisitorSynchronization::kBuiltins);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005957
5958 // Iterate over global handles.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005959 switch (mode) {
5960 case VISIT_ONLY_STRONG:
5961 isolate_->global_handles()->IterateStrongRoots(v);
5962 break;
5963 case VISIT_ALL_IN_SCAVENGE:
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005964 isolate_->global_handles()->IterateNewSpaceStrongAndDependentRoots(v);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005965 break;
5966 case VISIT_ALL_IN_SWEEP_NEWSPACE:
5967 case VISIT_ALL:
5968 isolate_->global_handles()->IterateAllRoots(v);
5969 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005970 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005971 v->Synchronize(VisitorSynchronization::kGlobalHandles);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005972
5973 // Iterate over pointers being held by inactive threads.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005974 isolate_->thread_manager()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005975 v->Synchronize(VisitorSynchronization::kThreadManager);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005976
5977 // Iterate over the pointers the Serialization/Deserialization code is
5978 // holding.
5979 // During garbage collection this keeps the partial snapshot cache alive.
5980 // During deserialization of the startup snapshot this creates the partial
5981 // snapshot cache and deserializes the objects it refers to. During
5982 // serialization this does nothing, since the partial snapshot cache is
5983 // empty. However the next thing we do is create the partial snapshot,
5984 // filling up the partial snapshot cache with objects it needs as we go.
5985 SerializerDeserializer::Iterate(v);
5986 // We don't do a v->Synchronize call here, because in debug mode that will
5987 // output a flag to the snapshot. However at this point the serializer and
5988 // deserializer are deliberately a little unsynchronized (see above) so the
5989 // checking of the sync flag in the snapshot would fail.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005990}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005991
5992
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005993// TODO(1236194): Since the heap size is configurable on the command line
5994// and through the API, we should gracefully handle the case that the heap
5995// size is not big enough to fit all the initial objects.
ager@chromium.org01fe7df2010-11-10 11:59:11 +00005996bool Heap::ConfigureHeap(int max_semispace_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005997 intptr_t max_old_gen_size,
5998 intptr_t max_executable_size) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005999 if (HasBeenSetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006000
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00006001 if (FLAG_stress_compaction) {
6002 // This will cause more frequent GCs when stressing.
6003 max_semispace_size_ = Page::kPageSize;
6004 }
6005
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006006 if (max_semispace_size > 0) {
6007 if (max_semispace_size < Page::kPageSize) {
6008 max_semispace_size = Page::kPageSize;
6009 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006010 PrintPID("Max semispace size cannot be less than %dkbytes\n",
6011 Page::kPageSize >> 10);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006012 }
6013 }
6014 max_semispace_size_ = max_semispace_size;
6015 }
ager@chromium.org3811b432009-10-28 14:53:37 +00006016
6017 if (Snapshot::IsEnabled()) {
6018 // If we are using a snapshot we always reserve the default amount
6019 // of memory for each semispace because code in the snapshot has
6020 // write-barrier code that relies on the size and alignment of new
6021 // space. We therefore cannot use a larger max semispace size
6022 // than the default reserved semispace size.
6023 if (max_semispace_size_ > reserved_semispace_size_) {
6024 max_semispace_size_ = reserved_semispace_size_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006025 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006026 PrintPID("Max semispace size cannot be more than %dkbytes\n",
6027 reserved_semispace_size_ >> 10);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006028 }
ager@chromium.org3811b432009-10-28 14:53:37 +00006029 }
6030 } else {
6031 // If we are not using snapshots we reserve space for the actual
6032 // max semispace size.
6033 reserved_semispace_size_ = max_semispace_size_;
6034 }
6035
6036 if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size;
ager@chromium.org01fe7df2010-11-10 11:59:11 +00006037 if (max_executable_size > 0) {
6038 max_executable_size_ = RoundUp(max_executable_size, Page::kPageSize);
6039 }
6040
6041 // The max executable size must be less than or equal to the max old
6042 // generation size.
6043 if (max_executable_size_ > max_old_generation_size_) {
6044 max_executable_size_ = max_old_generation_size_;
6045 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006046
6047 // The new space size must be a power of two to support single-bit testing
6048 // for containment.
ager@chromium.org3811b432009-10-28 14:53:37 +00006049 max_semispace_size_ = RoundUpToPowerOf2(max_semispace_size_);
6050 reserved_semispace_size_ = RoundUpToPowerOf2(reserved_semispace_size_);
6051 initial_semispace_size_ = Min(initial_semispace_size_, max_semispace_size_);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006052 external_allocation_limit_ = 16 * max_semispace_size_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006054 // The old generation is paged and needs at least one page for each space.
6055 int paged_space_count = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1;
6056 max_old_generation_size_ = Max(static_cast<intptr_t>(paged_space_count *
6057 Page::kPageSize),
6058 RoundUp(max_old_generation_size_,
6059 Page::kPageSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006060
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006061 configured_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006062 return true;
6063}
6064
6065
kasper.lund7276f142008-07-30 08:49:36 +00006066bool Heap::ConfigureHeapDefault() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006067 return ConfigureHeap(static_cast<intptr_t>(FLAG_max_new_space_size / 2) * KB,
6068 static_cast<intptr_t>(FLAG_max_old_space_size) * MB,
6069 static_cast<intptr_t>(FLAG_max_executable_size) * MB);
kasper.lund7276f142008-07-30 08:49:36 +00006070}
6071
6072
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006073void Heap::RecordStats(HeapStats* stats, bool take_snapshot) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006074 *stats->start_marker = HeapStats::kStartMarker;
6075 *stats->end_marker = HeapStats::kEndMarker;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006076 *stats->new_space_size = new_space_.SizeAsInt();
6077 *stats->new_space_capacity = static_cast<int>(new_space_.Capacity());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006078 *stats->old_pointer_space_size = old_pointer_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006079 *stats->old_pointer_space_capacity = old_pointer_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006080 *stats->old_data_space_size = old_data_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006081 *stats->old_data_space_capacity = old_data_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006082 *stats->code_space_size = code_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006083 *stats->code_space_capacity = code_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006084 *stats->map_space_size = map_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006085 *stats->map_space_capacity = map_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006086 *stats->cell_space_size = cell_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006087 *stats->cell_space_capacity = cell_space_->Capacity();
6088 *stats->lo_space_size = lo_space_->Size();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006089 isolate_->global_handles()->RecordStats(stats);
6090 *stats->memory_allocator_size = isolate()->memory_allocator()->Size();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006091 *stats->memory_allocator_capacity =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006092 isolate()->memory_allocator()->Size() +
6093 isolate()->memory_allocator()->Available();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006094 *stats->os_error = OS::GetLastError();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006095 isolate()->memory_allocator()->Available();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006096 if (take_snapshot) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006097 HeapIterator iterator;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006098 for (HeapObject* obj = iterator.next();
6099 obj != NULL;
6100 obj = iterator.next()) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006101 InstanceType type = obj->map()->instance_type();
6102 ASSERT(0 <= type && type <= LAST_TYPE);
6103 stats->objects_per_type[type]++;
6104 stats->size_per_type[type] += obj->Size();
6105 }
6106 }
ager@chromium.org60121232009-12-03 11:25:37 +00006107}
6108
6109
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00006110intptr_t Heap::PromotedSpaceSizeOfObjects() {
6111 return old_pointer_space_->SizeOfObjects()
6112 + old_data_space_->SizeOfObjects()
6113 + code_space_->SizeOfObjects()
6114 + map_space_->SizeOfObjects()
6115 + cell_space_->SizeOfObjects()
6116 + lo_space_->SizeOfObjects();
6117}
6118
6119
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00006120intptr_t Heap::PromotedExternalMemorySize() {
kasper.lund7276f142008-07-30 08:49:36 +00006121 if (amount_of_external_allocated_memory_
6122 <= amount_of_external_allocated_memory_at_last_global_gc_) return 0;
6123 return amount_of_external_allocated_memory_
6124 - amount_of_external_allocated_memory_at_last_global_gc_;
6125}
6126
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006127#ifdef DEBUG
6128
6129// Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject.
6130static const int kMarkTag = 2;
6131
6132
6133class HeapDebugUtils {
6134 public:
6135 explicit HeapDebugUtils(Heap* heap)
6136 : search_for_any_global_(false),
6137 search_target_(NULL),
6138 found_target_(false),
6139 object_stack_(20),
6140 heap_(heap) {
6141 }
6142
6143 class MarkObjectVisitor : public ObjectVisitor {
6144 public:
6145 explicit MarkObjectVisitor(HeapDebugUtils* utils) : utils_(utils) { }
6146
6147 void VisitPointers(Object** start, Object** end) {
6148 // Copy all HeapObject pointers in [start, end)
6149 for (Object** p = start; p < end; p++) {
6150 if ((*p)->IsHeapObject())
6151 utils_->MarkObjectRecursively(p);
6152 }
6153 }
6154
6155 HeapDebugUtils* utils_;
6156 };
6157
6158 void MarkObjectRecursively(Object** p) {
6159 if (!(*p)->IsHeapObject()) return;
6160
6161 HeapObject* obj = HeapObject::cast(*p);
6162
6163 Object* map = obj->map();
6164
6165 if (!map->IsHeapObject()) return; // visited before
6166
6167 if (found_target_) return; // stop if target found
6168 object_stack_.Add(obj);
6169 if ((search_for_any_global_ && obj->IsJSGlobalObject()) ||
6170 (!search_for_any_global_ && (obj == search_target_))) {
6171 found_target_ = true;
6172 return;
6173 }
6174
6175 // not visited yet
6176 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
6177
6178 Address map_addr = map_p->address();
6179
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006180 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_addr + kMarkTag));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006181
6182 MarkObjectRecursively(&map);
6183
6184 MarkObjectVisitor mark_visitor(this);
6185
6186 obj->IterateBody(map_p->instance_type(), obj->SizeFromMap(map_p),
6187 &mark_visitor);
6188
6189 if (!found_target_) // don't pop if found the target
6190 object_stack_.RemoveLast();
6191 }
6192
6193
6194 class UnmarkObjectVisitor : public ObjectVisitor {
6195 public:
6196 explicit UnmarkObjectVisitor(HeapDebugUtils* utils) : utils_(utils) { }
6197
6198 void VisitPointers(Object** start, Object** end) {
6199 // Copy all HeapObject pointers in [start, end)
6200 for (Object** p = start; p < end; p++) {
6201 if ((*p)->IsHeapObject())
6202 utils_->UnmarkObjectRecursively(p);
6203 }
6204 }
6205
6206 HeapDebugUtils* utils_;
6207 };
6208
6209
6210 void UnmarkObjectRecursively(Object** p) {
6211 if (!(*p)->IsHeapObject()) return;
6212
6213 HeapObject* obj = HeapObject::cast(*p);
6214
6215 Object* map = obj->map();
6216
6217 if (map->IsHeapObject()) return; // unmarked already
6218
6219 Address map_addr = reinterpret_cast<Address>(map);
6220
6221 map_addr -= kMarkTag;
6222
6223 ASSERT_TAG_ALIGNED(map_addr);
6224
6225 HeapObject* map_p = HeapObject::FromAddress(map_addr);
6226
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006227 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_p));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006228
6229 UnmarkObjectRecursively(reinterpret_cast<Object**>(&map_p));
6230
6231 UnmarkObjectVisitor unmark_visitor(this);
6232
6233 obj->IterateBody(Map::cast(map_p)->instance_type(),
6234 obj->SizeFromMap(Map::cast(map_p)),
6235 &unmark_visitor);
6236 }
6237
6238
6239 void MarkRootObjectRecursively(Object** root) {
6240 if (search_for_any_global_) {
6241 ASSERT(search_target_ == NULL);
6242 } else {
6243 ASSERT(search_target_->IsHeapObject());
6244 }
6245 found_target_ = false;
6246 object_stack_.Clear();
6247
6248 MarkObjectRecursively(root);
6249 UnmarkObjectRecursively(root);
6250
6251 if (found_target_) {
6252 PrintF("=====================================\n");
6253 PrintF("==== Path to object ====\n");
6254 PrintF("=====================================\n\n");
6255
6256 ASSERT(!object_stack_.is_empty());
6257 for (int i = 0; i < object_stack_.length(); i++) {
6258 if (i > 0) PrintF("\n |\n |\n V\n\n");
6259 Object* obj = object_stack_[i];
6260 obj->Print();
6261 }
6262 PrintF("=====================================\n");
6263 }
6264 }
6265
6266 // Helper class for visiting HeapObjects recursively.
6267 class MarkRootVisitor: public ObjectVisitor {
6268 public:
6269 explicit MarkRootVisitor(HeapDebugUtils* utils) : utils_(utils) { }
6270
6271 void VisitPointers(Object** start, Object** end) {
6272 // Visit all HeapObject pointers in [start, end)
6273 for (Object** p = start; p < end; p++) {
6274 if ((*p)->IsHeapObject())
6275 utils_->MarkRootObjectRecursively(p);
6276 }
6277 }
6278
6279 HeapDebugUtils* utils_;
6280 };
6281
6282 bool search_for_any_global_;
6283 Object* search_target_;
6284 bool found_target_;
6285 List<Object*> object_stack_;
6286 Heap* heap_;
6287
6288 friend class Heap;
6289};
6290
6291#endif
kasper.lund7276f142008-07-30 08:49:36 +00006292
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00006293
6294V8_DECLARE_ONCE(initialize_gc_once);
6295
6296static void InitializeGCOnce() {
6297 InitializeScavengingVisitorsTables();
6298 NewSpaceScavenger::Initialize();
6299 MarkCompactCollector::Initialize();
6300}
6301
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006302bool Heap::SetUp(bool create_heap_objects) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006303#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006304 allocation_timeout_ = FLAG_gc_interval;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006305 debug_utils_ = new HeapDebugUtils(this);
6306#endif
6307
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006308 // Initialize heap spaces and initial maps and objects. Whenever something
6309 // goes wrong, just return false. The caller should check the results and
6310 // call Heap::TearDown() to release allocated memory.
6311 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006312 // If the heap is not yet configured (e.g. through the API), configure it.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006313 // Configuration is based on the flags new-space-size (really the semispace
6314 // size) and old-space-size if set or the initial values of semispace_size_
6315 // and old_generation_size_ otherwise.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006316 if (!configured_) {
kasper.lund7276f142008-07-30 08:49:36 +00006317 if (!ConfigureHeapDefault()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006318 }
6319
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00006320 CallOnce(&initialize_gc_once, &InitializeGCOnce);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006321
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006322 MarkMapPointersAsEncoded(false);
6323
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006324 // Set up memory allocator.
6325 if (!isolate_->memory_allocator()->SetUp(MaxReserved(), MaxExecutableSize()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006326 return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006327
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006328 // Set up new space.
6329 if (!new_space_.SetUp(reserved_semispace_size_, max_semispace_size_)) {
ager@chromium.org3811b432009-10-28 14:53:37 +00006330 return false;
6331 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006332
ager@chromium.orga1645e22009-09-09 19:27:10 +00006333 // Initialize old pointer space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006334 old_pointer_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006335 new OldSpace(this,
6336 max_old_generation_size_,
6337 OLD_POINTER_SPACE,
6338 NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006339 if (old_pointer_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006340 if (!old_pointer_space_->SetUp()) return false;
ager@chromium.orga1645e22009-09-09 19:27:10 +00006341
6342 // Initialize old data space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006343 old_data_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006344 new OldSpace(this,
6345 max_old_generation_size_,
6346 OLD_DATA_SPACE,
6347 NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006348 if (old_data_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006349 if (!old_data_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006350
6351 // Initialize the code space, set its maximum capacity to the old
kasper.lund7276f142008-07-30 08:49:36 +00006352 // generation size. It needs executable memory.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006353 // On 64-bit platform(s), we put all code objects in a 2 GB range of
6354 // virtual address space, so that they can call each other with near calls.
6355 if (code_range_size_ > 0) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006356 if (!isolate_->code_range()->SetUp(code_range_size_)) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006357 return false;
6358 }
6359 }
6360
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006361 code_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006362 new OldSpace(this, max_old_generation_size_, CODE_SPACE, EXECUTABLE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006363 if (code_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006364 if (!code_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006365
6366 // Initialize map space.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00006367 map_space_ = new MapSpace(this, max_old_generation_size_, MAP_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006368 if (map_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006369 if (!map_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006370
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006371 // Initialize global property cell space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006372 cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006373 if (cell_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006374 if (!cell_space_->SetUp()) return false;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006375
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006376 // The large object code space may contain code or data. We set the memory
6377 // to be non-executable here for safety, but this means we need to enable it
6378 // explicitly when allocating large code objects.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006379 lo_space_ = new LargeObjectSpace(this, max_old_generation_size_, LO_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006380 if (lo_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006381 if (!lo_space_->SetUp()) return false;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006382
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006383 // Set up the seed that is used to randomize the string hash function.
6384 ASSERT(hash_seed() == 0);
6385 if (FLAG_randomize_hashes) {
6386 if (FLAG_hash_seed == 0) {
6387 set_hash_seed(
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006388 Smi::FromInt(V8::RandomPrivate(isolate()) & 0x3fffffff));
6389 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006390 set_hash_seed(Smi::FromInt(FLAG_hash_seed));
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006391 }
6392 }
6393
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006394 if (create_heap_objects) {
6395 // Create initial maps.
6396 if (!CreateInitialMaps()) return false;
6397 if (!CreateApiObjects()) return false;
6398
6399 // Create initial objects
6400 if (!CreateInitialObjects()) return false;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00006401
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006402 native_contexts_list_ = undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006403 }
6404
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006405 LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity()));
6406 LOG(isolate_, IntPtrTEvent("heap-available", Available()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006407
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006408 store_buffer()->SetUp();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006409
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006410 if (FLAG_parallel_recompilation) relocation_mutex_ = OS::CreateMutex();
6411
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006412 return true;
6413}
6414
6415
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006416void Heap::SetStackLimits() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006417 ASSERT(isolate_ != NULL);
6418 ASSERT(isolate_ == isolate());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006419 // On 64 bit machines, pointers are generally out of range of Smis. We write
6420 // something that looks like an out of range Smi to the GC.
6421
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006422 // Set up the special root array entries containing the stack limits.
6423 // These are actually addresses, but the tag makes the GC ignore it.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006424 roots_[kStackLimitRootIndex] =
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006425 reinterpret_cast<Object*>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006426 (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006427 roots_[kRealStackLimitRootIndex] =
6428 reinterpret_cast<Object*>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006429 (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006430}
6431
6432
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006433void Heap::TearDown() {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006434#ifdef VERIFY_HEAP
danno@chromium.org1044a4d2012-04-30 12:34:39 +00006435 if (FLAG_verify_heap) {
6436 Verify();
6437 }
6438#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006439
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006440 if (FLAG_print_cumulative_gc_stat) {
6441 PrintF("\n\n");
6442 PrintF("gc_count=%d ", gc_count_);
6443 PrintF("mark_sweep_count=%d ", ms_count_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006444 PrintF("max_gc_pause=%d ", get_max_gc_pause());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006445 PrintF("total_gc_time=%d ", total_gc_time_ms_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006446 PrintF("min_in_mutator=%d ", get_min_in_mutator());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006447 PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ",
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006448 get_max_alive_after_gc());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006449 PrintF("\n\n");
6450 }
6451
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006452 isolate_->global_handles()->TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006453
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006454 external_string_table_.TearDown();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00006455
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006456 new_space_.TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006457
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006458 if (old_pointer_space_ != NULL) {
6459 old_pointer_space_->TearDown();
6460 delete old_pointer_space_;
6461 old_pointer_space_ = NULL;
6462 }
6463
6464 if (old_data_space_ != NULL) {
6465 old_data_space_->TearDown();
6466 delete old_data_space_;
6467 old_data_space_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006468 }
6469
6470 if (code_space_ != NULL) {
6471 code_space_->TearDown();
6472 delete code_space_;
6473 code_space_ = NULL;
6474 }
6475
6476 if (map_space_ != NULL) {
6477 map_space_->TearDown();
6478 delete map_space_;
6479 map_space_ = NULL;
6480 }
6481
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006482 if (cell_space_ != NULL) {
6483 cell_space_->TearDown();
6484 delete cell_space_;
6485 cell_space_ = NULL;
6486 }
6487
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006488 if (lo_space_ != NULL) {
6489 lo_space_->TearDown();
6490 delete lo_space_;
6491 lo_space_ = NULL;
6492 }
6493
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006494 store_buffer()->TearDown();
6495 incremental_marking()->TearDown();
6496
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006497 isolate_->memory_allocator()->TearDown();
6498
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006499 delete relocation_mutex_;
6500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006501#ifdef DEBUG
6502 delete debug_utils_;
6503 debug_utils_ = NULL;
6504#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006505}
6506
6507
6508void Heap::Shrink() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006509 // Try to shrink all paged spaces.
6510 PagedSpaces spaces;
danno@chromium.org2c456792011-11-11 12:00:53 +00006511 for (PagedSpace* space = spaces.next();
6512 space != NULL;
6513 space = spaces.next()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006514 space->ReleaseAllUnusedPages();
danno@chromium.org2c456792011-11-11 12:00:53 +00006515 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006516}
6517
6518
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006519void Heap::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) {
6520 ASSERT(callback != NULL);
6521 GCPrologueCallbackPair pair(callback, gc_type);
6522 ASSERT(!gc_prologue_callbacks_.Contains(pair));
6523 return gc_prologue_callbacks_.Add(pair);
6524}
6525
6526
6527void Heap::RemoveGCPrologueCallback(GCPrologueCallback callback) {
6528 ASSERT(callback != NULL);
6529 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
6530 if (gc_prologue_callbacks_[i].callback == callback) {
6531 gc_prologue_callbacks_.Remove(i);
6532 return;
6533 }
6534 }
6535 UNREACHABLE();
6536}
6537
6538
6539void Heap::AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type) {
6540 ASSERT(callback != NULL);
6541 GCEpilogueCallbackPair pair(callback, gc_type);
6542 ASSERT(!gc_epilogue_callbacks_.Contains(pair));
6543 return gc_epilogue_callbacks_.Add(pair);
6544}
6545
6546
6547void Heap::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
6548 ASSERT(callback != NULL);
6549 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
6550 if (gc_epilogue_callbacks_[i].callback == callback) {
6551 gc_epilogue_callbacks_.Remove(i);
6552 return;
6553 }
6554 }
6555 UNREACHABLE();
6556}
6557
6558
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006559#ifdef DEBUG
6560
6561class PrintHandleVisitor: public ObjectVisitor {
6562 public:
6563 void VisitPointers(Object** start, Object** end) {
6564 for (Object** p = start; p < end; p++)
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006565 PrintF(" handle %p to %p\n",
6566 reinterpret_cast<void*>(p),
6567 reinterpret_cast<void*>(*p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006568 }
6569};
6570
6571void Heap::PrintHandles() {
6572 PrintF("Handles:\n");
6573 PrintHandleVisitor v;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006574 isolate_->handle_scope_implementer()->Iterate(&v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575}
6576
6577#endif
6578
6579
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006580Space* AllSpaces::next() {
6581 switch (counter_++) {
6582 case NEW_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006583 return HEAP->new_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006584 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006585 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006586 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006587 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006588 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006589 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006590 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006591 return HEAP->map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006592 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006593 return HEAP->cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006594 case LO_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006595 return HEAP->lo_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006596 default:
6597 return NULL;
6598 }
6599}
6600
6601
6602PagedSpace* PagedSpaces::next() {
6603 switch (counter_++) {
6604 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006605 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006606 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006607 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006608 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006609 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006610 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006611 return HEAP->map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006612 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006613 return HEAP->cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006614 default:
6615 return NULL;
6616 }
6617}
6618
6619
6620
6621OldSpace* OldSpaces::next() {
6622 switch (counter_++) {
6623 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006624 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006625 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006626 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006627 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006628 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006629 default:
6630 return NULL;
6631 }
6632}
6633
6634
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006635SpaceIterator::SpaceIterator()
6636 : current_space_(FIRST_SPACE),
6637 iterator_(NULL),
6638 size_func_(NULL) {
6639}
6640
6641
6642SpaceIterator::SpaceIterator(HeapObjectCallback size_func)
6643 : current_space_(FIRST_SPACE),
6644 iterator_(NULL),
6645 size_func_(size_func) {
kasper.lund7276f142008-07-30 08:49:36 +00006646}
6647
6648
6649SpaceIterator::~SpaceIterator() {
6650 // Delete active iterator if any.
6651 delete iterator_;
6652}
6653
6654
6655bool SpaceIterator::has_next() {
6656 // Iterate until no more spaces.
6657 return current_space_ != LAST_SPACE;
6658}
6659
6660
6661ObjectIterator* SpaceIterator::next() {
6662 if (iterator_ != NULL) {
6663 delete iterator_;
6664 iterator_ = NULL;
6665 // Move to the next space
6666 current_space_++;
6667 if (current_space_ > LAST_SPACE) {
6668 return NULL;
6669 }
6670 }
6671
6672 // Return iterator for the new current space.
6673 return CreateIterator();
6674}
6675
6676
6677// Create an iterator for the space to iterate.
6678ObjectIterator* SpaceIterator::CreateIterator() {
6679 ASSERT(iterator_ == NULL);
6680
6681 switch (current_space_) {
6682 case NEW_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006683 iterator_ = new SemiSpaceIterator(HEAP->new_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006684 break;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006685 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006686 iterator_ = new HeapObjectIterator(HEAP->old_pointer_space(), size_func_);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006687 break;
6688 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006689 iterator_ = new HeapObjectIterator(HEAP->old_data_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006690 break;
6691 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006692 iterator_ = new HeapObjectIterator(HEAP->code_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006693 break;
6694 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006695 iterator_ = new HeapObjectIterator(HEAP->map_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006696 break;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006697 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006698 iterator_ = new HeapObjectIterator(HEAP->cell_space(), size_func_);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006699 break;
kasper.lund7276f142008-07-30 08:49:36 +00006700 case LO_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006701 iterator_ = new LargeObjectIterator(HEAP->lo_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006702 break;
6703 }
6704
6705 // Return the newly allocated iterator;
6706 ASSERT(iterator_ != NULL);
6707 return iterator_;
6708}
6709
6710
whesse@chromium.org023421e2010-12-21 12:19:12 +00006711class HeapObjectsFilter {
6712 public:
6713 virtual ~HeapObjectsFilter() {}
6714 virtual bool SkipObject(HeapObject* object) = 0;
6715};
6716
6717
whesse@chromium.org023421e2010-12-21 12:19:12 +00006718class UnreachableObjectsFilter : public HeapObjectsFilter {
6719 public:
6720 UnreachableObjectsFilter() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006721 MarkReachableObjects();
6722 }
6723
6724 ~UnreachableObjectsFilter() {
6725 Isolate::Current()->heap()->mark_compact_collector()->ClearMarkbits();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006726 }
6727
6728 bool SkipObject(HeapObject* object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006729 MarkBit mark_bit = Marking::MarkBitFrom(object);
6730 return !mark_bit.Get();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006731 }
6732
6733 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006734 class MarkingVisitor : public ObjectVisitor {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006735 public:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006736 MarkingVisitor() : marking_stack_(10) {}
whesse@chromium.org023421e2010-12-21 12:19:12 +00006737
6738 void VisitPointers(Object** start, Object** end) {
6739 for (Object** p = start; p < end; p++) {
6740 if (!(*p)->IsHeapObject()) continue;
6741 HeapObject* obj = HeapObject::cast(*p);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006742 MarkBit mark_bit = Marking::MarkBitFrom(obj);
6743 if (!mark_bit.Get()) {
6744 mark_bit.Set();
6745 marking_stack_.Add(obj);
whesse@chromium.org023421e2010-12-21 12:19:12 +00006746 }
6747 }
6748 }
6749
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006750 void TransitiveClosure() {
6751 while (!marking_stack_.is_empty()) {
6752 HeapObject* obj = marking_stack_.RemoveLast();
6753 obj->Iterate(this);
6754 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00006755 }
6756
6757 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006758 List<HeapObject*> marking_stack_;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006759 };
6760
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006761 void MarkReachableObjects() {
6762 Heap* heap = Isolate::Current()->heap();
6763 MarkingVisitor visitor;
6764 heap->IterateRoots(&visitor, VISIT_ALL);
6765 visitor.TransitiveClosure();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006766 }
6767
6768 AssertNoAllocation no_alloc;
6769};
6770
6771
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006772HeapIterator::HeapIterator()
6773 : filtering_(HeapIterator::kNoFiltering),
6774 filter_(NULL) {
6775 Init();
6776}
6777
6778
whesse@chromium.org023421e2010-12-21 12:19:12 +00006779HeapIterator::HeapIterator(HeapIterator::HeapObjectsFiltering filtering)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006780 : filtering_(filtering),
6781 filter_(NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006782 Init();
6783}
6784
6785
6786HeapIterator::~HeapIterator() {
6787 Shutdown();
6788}
6789
6790
6791void HeapIterator::Init() {
6792 // Start the iteration.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006793 space_iterator_ = new SpaceIterator;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006794 switch (filtering_) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006795 case kFilterUnreachable:
6796 filter_ = new UnreachableObjectsFilter;
6797 break;
6798 default:
6799 break;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006800 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006801 object_iterator_ = space_iterator_->next();
6802}
6803
6804
6805void HeapIterator::Shutdown() {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006806#ifdef DEBUG
whesse@chromium.org023421e2010-12-21 12:19:12 +00006807 // Assert that in filtering mode we have iterated through all
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006808 // objects. Otherwise, heap will be left in an inconsistent state.
whesse@chromium.org023421e2010-12-21 12:19:12 +00006809 if (filtering_ != kNoFiltering) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006810 ASSERT(object_iterator_ == NULL);
6811 }
6812#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006813 // Make sure the last iterator is deallocated.
6814 delete space_iterator_;
6815 space_iterator_ = NULL;
6816 object_iterator_ = NULL;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006817 delete filter_;
6818 filter_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006819}
6820
6821
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006822HeapObject* HeapIterator::next() {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006823 if (filter_ == NULL) return NextObject();
6824
6825 HeapObject* obj = NextObject();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006826 while (obj != NULL && filter_->SkipObject(obj)) obj = NextObject();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006827 return obj;
6828}
6829
6830
6831HeapObject* HeapIterator::NextObject() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006832 // No iterator means we are done.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006833 if (object_iterator_ == NULL) return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006834
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006835 if (HeapObject* obj = object_iterator_->next_object()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006836 // If the current iterator has more objects we are fine.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006837 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006838 } else {
6839 // Go though the spaces looking for one that has objects.
6840 while (space_iterator_->has_next()) {
6841 object_iterator_ = space_iterator_->next();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006842 if (HeapObject* obj = object_iterator_->next_object()) {
6843 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006844 }
6845 }
6846 }
6847 // Done with the last space.
6848 object_iterator_ = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006849 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006850}
6851
6852
6853void HeapIterator::reset() {
6854 // Restart the iterator.
6855 Shutdown();
6856 Init();
6857}
6858
6859
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006860#if defined(DEBUG) || defined(LIVE_OBJECT_LIST)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006861
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006862Object* const PathTracer::kAnyGlobalObject = reinterpret_cast<Object*>(NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006863
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006864class PathTracer::MarkVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006865 public:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006866 explicit MarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006867 void VisitPointers(Object** start, Object** end) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006868 // Scan all HeapObject pointers in [start, end)
6869 for (Object** p = start; !tracer_->found() && (p < end); p++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006870 if ((*p)->IsHeapObject())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006871 tracer_->MarkRecursively(p, this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006872 }
6873 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006874
6875 private:
6876 PathTracer* tracer_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006877};
6878
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006879
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006880class PathTracer::UnmarkVisitor: public ObjectVisitor {
6881 public:
6882 explicit UnmarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
6883 void VisitPointers(Object** start, Object** end) {
6884 // Scan all HeapObject pointers in [start, end)
6885 for (Object** p = start; p < end; p++) {
6886 if ((*p)->IsHeapObject())
6887 tracer_->UnmarkRecursively(p, this);
6888 }
6889 }
6890
6891 private:
6892 PathTracer* tracer_;
6893};
6894
6895
6896void PathTracer::VisitPointers(Object** start, Object** end) {
6897 bool done = ((what_to_find_ == FIND_FIRST) && found_target_);
6898 // Visit all HeapObject pointers in [start, end)
6899 for (Object** p = start; !done && (p < end); p++) {
6900 if ((*p)->IsHeapObject()) {
6901 TracePathFrom(p);
6902 done = ((what_to_find_ == FIND_FIRST) && found_target_);
6903 }
6904 }
6905}
6906
6907
6908void PathTracer::Reset() {
6909 found_target_ = false;
6910 object_stack_.Clear();
6911}
6912
6913
6914void PathTracer::TracePathFrom(Object** root) {
6915 ASSERT((search_target_ == kAnyGlobalObject) ||
6916 search_target_->IsHeapObject());
6917 found_target_in_trace_ = false;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00006918 Reset();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006919
6920 MarkVisitor mark_visitor(this);
6921 MarkRecursively(root, &mark_visitor);
6922
6923 UnmarkVisitor unmark_visitor(this);
6924 UnmarkRecursively(root, &unmark_visitor);
6925
6926 ProcessResults();
6927}
6928
6929
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006930static bool SafeIsNativeContext(HeapObject* obj) {
6931 return obj->map() == obj->GetHeap()->raw_unchecked_native_context_map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006932}
6933
6934
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006935void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006936 if (!(*p)->IsHeapObject()) return;
6937
6938 HeapObject* obj = HeapObject::cast(*p);
6939
6940 Object* map = obj->map();
6941
6942 if (!map->IsHeapObject()) return; // visited before
6943
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006944 if (found_target_in_trace_) return; // stop if target found
6945 object_stack_.Add(obj);
6946 if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) ||
6947 (obj == search_target_)) {
6948 found_target_in_trace_ = true;
6949 found_target_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006950 return;
6951 }
6952
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006953 bool is_native_context = SafeIsNativeContext(obj);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006954
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006955 // not visited yet
6956 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
6957
6958 Address map_addr = map_p->address();
6959
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006960 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_addr + kMarkTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006961
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006962 // Scan the object body.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006963 if (is_native_context && (visit_mode_ == VISIT_ONLY_STRONG)) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006964 // This is specialized to scan Context's properly.
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00006965 Object** start = reinterpret_cast<Object**>(obj->address() +
6966 Context::kHeaderSize);
6967 Object** end = reinterpret_cast<Object**>(obj->address() +
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006968 Context::kHeaderSize + Context::FIRST_WEAK_SLOT * kPointerSize);
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00006969 mark_visitor->VisitPointers(start, end);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006970 } else {
6971 obj->IterateBody(map_p->instance_type(),
6972 obj->SizeFromMap(map_p),
6973 mark_visitor);
6974 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006975
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006976 // Scan the map after the body because the body is a lot more interesting
6977 // when doing leak detection.
6978 MarkRecursively(&map, mark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006979
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006980 if (!found_target_in_trace_) // don't pop if found the target
6981 object_stack_.RemoveLast();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006982}
6983
6984
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006985void PathTracer::UnmarkRecursively(Object** p, UnmarkVisitor* unmark_visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006986 if (!(*p)->IsHeapObject()) return;
6987
6988 HeapObject* obj = HeapObject::cast(*p);
6989
6990 Object* map = obj->map();
6991
6992 if (map->IsHeapObject()) return; // unmarked already
6993
6994 Address map_addr = reinterpret_cast<Address>(map);
6995
6996 map_addr -= kMarkTag;
6997
6998 ASSERT_TAG_ALIGNED(map_addr);
6999
7000 HeapObject* map_p = HeapObject::FromAddress(map_addr);
7001
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007002 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007003
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007004 UnmarkRecursively(reinterpret_cast<Object**>(&map_p), unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007005
7006 obj->IterateBody(Map::cast(map_p)->instance_type(),
7007 obj->SizeFromMap(Map::cast(map_p)),
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007008 unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007009}
7010
7011
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007012void PathTracer::ProcessResults() {
7013 if (found_target_) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007014 PrintF("=====================================\n");
7015 PrintF("==== Path to object ====\n");
7016 PrintF("=====================================\n\n");
7017
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007018 ASSERT(!object_stack_.is_empty());
7019 for (int i = 0; i < object_stack_.length(); i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007020 if (i > 0) PrintF("\n |\n |\n V\n\n");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007021 Object* obj = object_stack_[i];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007022 obj->Print();
7023 }
7024 PrintF("=====================================\n");
7025 }
7026}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007027#endif // DEBUG || LIVE_OBJECT_LIST
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007028
7029
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007030#ifdef DEBUG
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00007031// Triggers a depth-first traversal of reachable objects from one
7032// given root object and finds a path to a specific heap object and
7033// prints it.
7034void Heap::TracePathToObjectFrom(Object* target, Object* root) {
7035 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
7036 tracer.VisitPointer(&root);
7037}
7038
7039
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007040// Triggers a depth-first traversal of reachable objects from roots
7041// and finds a path to a specific heap object and prints it.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007042void Heap::TracePathToObject(Object* target) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007043 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
7044 IterateRoots(&tracer, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007045}
7046
7047
7048// Triggers a depth-first traversal of reachable objects from roots
7049// and finds a path to any global object and prints it. Useful for
7050// determining the source for leaks of global objects.
7051void Heap::TracePathToGlobal() {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007052 PathTracer tracer(PathTracer::kAnyGlobalObject,
7053 PathTracer::FIND_ALL,
7054 VISIT_ALL);
7055 IterateRoots(&tracer, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007056}
7057#endif
7058
7059
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007060static intptr_t CountTotalHolesSize() {
7061 intptr_t holes_size = 0;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007062 OldSpaces spaces;
7063 for (OldSpace* space = spaces.next();
7064 space != NULL;
7065 space = spaces.next()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007066 holes_size += space->Waste() + space->Available();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007067 }
7068 return holes_size;
7069}
7070
7071
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007072GCTracer::GCTracer(Heap* heap,
7073 const char* gc_reason,
7074 const char* collector_reason)
kasper.lund7276f142008-07-30 08:49:36 +00007075 : start_time_(0.0),
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007076 start_object_size_(0),
7077 start_memory_size_(0),
kasper.lund7276f142008-07-30 08:49:36 +00007078 gc_count_(0),
7079 full_gc_count_(0),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007080 allocated_since_last_gc_(0),
7081 spent_in_mutator_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007082 promoted_objects_size_(0),
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007083 heap_(heap),
7084 gc_reason_(gc_reason),
7085 collector_reason_(collector_reason) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007086 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
kasper.lund7276f142008-07-30 08:49:36 +00007087 start_time_ = OS::TimeCurrentMillis();
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007088 start_object_size_ = heap_->SizeOfObjects();
7089 start_memory_size_ = heap_->isolate()->memory_allocator()->Size();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007090
7091 for (int i = 0; i < Scope::kNumberOfScopes; i++) {
7092 scopes_[i] = 0;
7093 }
7094
7095 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize();
7096
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007097 allocated_since_last_gc_ =
7098 heap_->SizeOfObjects() - heap_->alive_after_last_gc_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007099
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007100 if (heap_->last_gc_end_timestamp_ > 0) {
7101 spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007102 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007103
7104 steps_count_ = heap_->incremental_marking()->steps_count();
7105 steps_took_ = heap_->incremental_marking()->steps_took();
7106 longest_step_ = heap_->incremental_marking()->longest_step();
7107 steps_count_since_last_gc_ =
7108 heap_->incremental_marking()->steps_count_since_last_gc();
7109 steps_took_since_last_gc_ =
7110 heap_->incremental_marking()->steps_took_since_last_gc();
kasper.lund7276f142008-07-30 08:49:36 +00007111}
7112
7113
7114GCTracer::~GCTracer() {
kasper.lund7276f142008-07-30 08:49:36 +00007115 // Printf ONE line iff flag is set.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007116 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
7117
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007118 bool first_gc = (heap_->last_gc_end_timestamp_ == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007119
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007120 heap_->alive_after_last_gc_ = heap_->SizeOfObjects();
7121 heap_->last_gc_end_timestamp_ = OS::TimeCurrentMillis();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007122
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007123 int time = static_cast<int>(heap_->last_gc_end_timestamp_ - start_time_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007124
7125 // Update cumulative GC statistics if required.
7126 if (FLAG_print_cumulative_gc_stat) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007127 heap_->total_gc_time_ms_ += time;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007128 heap_->max_gc_pause_ = Max(heap_->max_gc_pause_, time);
7129 heap_->max_alive_after_gc_ = Max(heap_->max_alive_after_gc_,
7130 heap_->alive_after_last_gc_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007131 if (!first_gc) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007132 heap_->min_in_mutator_ = Min(heap_->min_in_mutator_,
7133 static_cast<int>(spent_in_mutator_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007134 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007135 } else if (FLAG_trace_gc_verbose) {
7136 heap_->total_gc_time_ms_ += time;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007137 }
7138
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007139 if (collector_ == SCAVENGER && FLAG_trace_gc_ignore_scavenger) return;
7140
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00007141 PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init());
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007142
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007143 if (!FLAG_trace_gc_nvp) {
7144 int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]);
7145
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007146 double end_memory_size_mb =
7147 static_cast<double>(heap_->isolate()->memory_allocator()->Size()) / MB;
7148
7149 PrintF("%s %.1f (%.1f) -> %.1f (%.1f) MB, ",
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007150 CollectorString(),
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007151 static_cast<double>(start_object_size_) / MB,
7152 static_cast<double>(start_memory_size_) / MB,
7153 SizeOfHeapObjects(),
7154 end_memory_size_mb);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007155
7156 if (external_time > 0) PrintF("%d / ", external_time);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007157 PrintF("%d ms", time);
7158 if (steps_count_ > 0) {
7159 if (collector_ == SCAVENGER) {
7160 PrintF(" (+ %d ms in %d steps since last GC)",
7161 static_cast<int>(steps_took_since_last_gc_),
7162 steps_count_since_last_gc_);
7163 } else {
7164 PrintF(" (+ %d ms in %d steps since start of marking, "
7165 "biggest step %f ms)",
7166 static_cast<int>(steps_took_),
7167 steps_count_,
7168 longest_step_);
7169 }
7170 }
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007171
7172 if (gc_reason_ != NULL) {
7173 PrintF(" [%s]", gc_reason_);
7174 }
7175
7176 if (collector_reason_ != NULL) {
7177 PrintF(" [%s]", collector_reason_);
7178 }
7179
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007180 PrintF(".\n");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007181 } else {
7182 PrintF("pause=%d ", time);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007183 PrintF("mutator=%d ", static_cast<int>(spent_in_mutator_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007184 PrintF("gc=");
7185 switch (collector_) {
7186 case SCAVENGER:
7187 PrintF("s");
7188 break;
7189 case MARK_COMPACTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007190 PrintF("ms");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007191 break;
7192 default:
7193 UNREACHABLE();
7194 }
7195 PrintF(" ");
7196
7197 PrintF("external=%d ", static_cast<int>(scopes_[Scope::EXTERNAL]));
7198 PrintF("mark=%d ", static_cast<int>(scopes_[Scope::MC_MARK]));
7199 PrintF("sweep=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP]));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007200 PrintF("sweepns=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP_NEWSPACE]));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00007201 PrintF("evacuate=%d ", static_cast<int>(scopes_[Scope::MC_EVACUATE_PAGES]));
7202 PrintF("new_new=%d ",
7203 static_cast<int>(scopes_[Scope::MC_UPDATE_NEW_TO_NEW_POINTERS]));
7204 PrintF("root_new=%d ",
7205 static_cast<int>(scopes_[Scope::MC_UPDATE_ROOT_TO_NEW_POINTERS]));
7206 PrintF("old_new=%d ",
7207 static_cast<int>(scopes_[Scope::MC_UPDATE_OLD_TO_NEW_POINTERS]));
7208 PrintF("compaction_ptrs=%d ",
7209 static_cast<int>(scopes_[Scope::MC_UPDATE_POINTERS_TO_EVACUATED]));
7210 PrintF("intracompaction_ptrs=%d ", static_cast<int>(scopes_[
7211 Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED]));
7212 PrintF("misc_compaction=%d ",
7213 static_cast<int>(scopes_[Scope::MC_UPDATE_MISC_POINTERS]));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007214
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007215 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_object_size_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007216 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007217 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ",
7218 in_free_list_or_wasted_before_gc_);
7219 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007220
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007221 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_);
7222 PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007223
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007224 if (collector_ == SCAVENGER) {
7225 PrintF("stepscount=%d ", steps_count_since_last_gc_);
7226 PrintF("stepstook=%d ", static_cast<int>(steps_took_since_last_gc_));
7227 } else {
7228 PrintF("stepscount=%d ", steps_count_);
7229 PrintF("stepstook=%d ", static_cast<int>(steps_took_));
7230 }
7231
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007232 PrintF("\n");
7233 }
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007234
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007235 heap_->PrintShortHeapStatistics();
kasper.lund7276f142008-07-30 08:49:36 +00007236}
7237
7238
7239const char* GCTracer::CollectorString() {
7240 switch (collector_) {
7241 case SCAVENGER:
7242 return "Scavenge";
7243 case MARK_COMPACTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007244 return "Mark-sweep";
kasper.lund7276f142008-07-30 08:49:36 +00007245 }
7246 return "Unknown GC";
7247}
7248
7249
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007250int KeyedLookupCache::Hash(Map* map, String* name) {
7251 // Uses only lower 32 bits if pointers are larger.
7252 uintptr_t addr_hash =
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007253 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00007254 return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007255}
7256
7257
7258int KeyedLookupCache::Lookup(Map* map, String* name) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007259 int index = (Hash(map, name) & kHashMask);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007260 for (int i = 0; i < kEntriesPerBucket; i++) {
7261 Key& key = keys_[index + i];
7262 if ((key.map == map) && key.name->Equals(name)) {
7263 return field_offsets_[index + i];
7264 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007265 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007266 return kNotFound;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007267}
7268
7269
7270void KeyedLookupCache::Update(Map* map, String* name, int field_offset) {
7271 String* symbol;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007272 if (HEAP->LookupSymbolIfExists(name, &symbol)) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007273 int index = (Hash(map, symbol) & kHashMask);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007274 // After a GC there will be free slots, so we use them in order (this may
7275 // help to get the most frequently used one in position 0).
7276 for (int i = 0; i< kEntriesPerBucket; i++) {
7277 Key& key = keys_[index];
7278 Object* free_entry_indicator = NULL;
7279 if (key.map == free_entry_indicator) {
7280 key.map = map;
7281 key.name = symbol;
7282 field_offsets_[index + i] = field_offset;
7283 return;
7284 }
7285 }
7286 // No free entry found in this bucket, so we move them all down one and
7287 // put the new entry at position zero.
7288 for (int i = kEntriesPerBucket - 1; i > 0; i--) {
7289 Key& key = keys_[index + i];
7290 Key& key2 = keys_[index + i - 1];
7291 key = key2;
7292 field_offsets_[index + i] = field_offsets_[index + i - 1];
7293 }
7294
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007295 // Write the new first entry.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007296 Key& key = keys_[index];
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007297 key.map = map;
7298 key.name = symbol;
7299 field_offsets_[index] = field_offset;
7300 }
7301}
7302
7303
7304void KeyedLookupCache::Clear() {
7305 for (int index = 0; index < kLength; index++) keys_[index].map = NULL;
7306}
7307
7308
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007309void DescriptorLookupCache::Clear() {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007310 for (int index = 0; index < kLength; index++) keys_[index].source = NULL;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007311}
7312
7313
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007314#ifdef DEBUG
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007315void Heap::GarbageCollectionGreedyCheck() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007316 ASSERT(FLAG_gc_greedy);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007317 if (isolate_->bootstrapper()->IsActive()) return;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007318 if (disallow_allocation_failure()) return;
7319 CollectGarbage(NEW_SPACE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007320}
7321#endif
7322
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007323
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007324TranscendentalCache::SubCache::SubCache(Type t)
7325 : type_(t),
7326 isolate_(Isolate::Current()) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007327 uint32_t in0 = 0xffffffffu; // Bit-pattern for a NaN that isn't
7328 uint32_t in1 = 0xffffffffu; // generated by the FPU.
7329 for (int i = 0; i < kCacheSize; i++) {
7330 elements_[i].in[0] = in0;
7331 elements_[i].in[1] = in1;
7332 elements_[i].output = NULL;
7333 }
7334}
7335
7336
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007337void TranscendentalCache::Clear() {
7338 for (int i = 0; i < kNumberOfCaches; i++) {
7339 if (caches_[i] != NULL) {
7340 delete caches_[i];
7341 caches_[i] = NULL;
7342 }
7343 }
7344}
7345
7346
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007347void ExternalStringTable::CleanUp() {
7348 int last = 0;
7349 for (int i = 0; i < new_space_strings_.length(); ++i) {
danno@chromium.org72204d52012-10-31 10:02:10 +00007350 if (new_space_strings_[i] == heap_->the_hole_value()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007351 continue;
7352 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007353 if (heap_->InNewSpace(new_space_strings_[i])) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007354 new_space_strings_[last++] = new_space_strings_[i];
7355 } else {
7356 old_space_strings_.Add(new_space_strings_[i]);
7357 }
7358 }
7359 new_space_strings_.Rewind(last);
7360 last = 0;
7361 for (int i = 0; i < old_space_strings_.length(); ++i) {
danno@chromium.org72204d52012-10-31 10:02:10 +00007362 if (old_space_strings_[i] == heap_->the_hole_value()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007363 continue;
7364 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007365 ASSERT(!heap_->InNewSpace(old_space_strings_[i]));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007366 old_space_strings_[last++] = old_space_strings_[i];
7367 }
7368 old_space_strings_.Rewind(last);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007369#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007370 if (FLAG_verify_heap) {
7371 Verify();
7372 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007373#endif
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007374}
7375
7376
7377void ExternalStringTable::TearDown() {
7378 new_space_strings_.Free();
7379 old_space_strings_.Free();
7380}
7381
7382
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007383void Heap::QueueMemoryChunkForFree(MemoryChunk* chunk) {
7384 chunk->set_next_chunk(chunks_queued_for_free_);
7385 chunks_queued_for_free_ = chunk;
7386}
7387
7388
7389void Heap::FreeQueuedChunks() {
7390 if (chunks_queued_for_free_ == NULL) return;
7391 MemoryChunk* next;
7392 MemoryChunk* chunk;
7393 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
7394 next = chunk->next_chunk();
7395 chunk->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
7396
7397 if (chunk->owner()->identity() == LO_SPACE) {
7398 // StoreBuffer::Filter relies on MemoryChunk::FromAnyPointerAddress.
7399 // If FromAnyPointerAddress encounters a slot that belongs to a large
7400 // chunk queued for deletion it will fail to find the chunk because
7401 // it try to perform a search in the list of pages owned by of the large
7402 // object space and queued chunks were detached from that list.
7403 // To work around this we split large chunk into normal kPageSize aligned
danno@chromium.org2c456792011-11-11 12:00:53 +00007404 // pieces and initialize size, owner and flags field of every piece.
7405 // If FromAnyPointerAddress encounters a slot that belongs to one of
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007406 // these smaller pieces it will treat it as a slot on a normal Page.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007407 Address chunk_end = chunk->address() + chunk->size();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007408 MemoryChunk* inner = MemoryChunk::FromAddress(
7409 chunk->address() + Page::kPageSize);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007410 MemoryChunk* inner_last = MemoryChunk::FromAddress(chunk_end - 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007411 while (inner <= inner_last) {
7412 // Size of a large chunk is always a multiple of
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007413 // OS::AllocateAlignment() so there is always
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007414 // enough space for a fake MemoryChunk header.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007415 Address area_end = Min(inner->address() + Page::kPageSize, chunk_end);
7416 // Guard against overflow.
7417 if (area_end < inner->address()) area_end = chunk_end;
7418 inner->SetArea(inner->address(), area_end);
danno@chromium.org2c456792011-11-11 12:00:53 +00007419 inner->set_size(Page::kPageSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007420 inner->set_owner(lo_space());
7421 inner->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
7422 inner = MemoryChunk::FromAddress(
7423 inner->address() + Page::kPageSize);
7424 }
7425 }
7426 }
7427 isolate_->heap()->store_buffer()->Compact();
7428 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED);
7429 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
7430 next = chunk->next_chunk();
7431 isolate_->memory_allocator()->Free(chunk);
7432 }
7433 chunks_queued_for_free_ = NULL;
7434}
7435
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00007436
7437void Heap::RememberUnmappedPage(Address page, bool compacted) {
7438 uintptr_t p = reinterpret_cast<uintptr_t>(page);
7439 // Tag the page pointer to make it findable in the dump file.
7440 if (compacted) {
7441 p ^= 0xc1ead & (Page::kPageSize - 1); // Cleared.
7442 } else {
7443 p ^= 0x1d1ed & (Page::kPageSize - 1); // I died.
7444 }
7445 remembered_unmapped_pages_[remembered_unmapped_pages_index_] =
7446 reinterpret_cast<Address>(p);
7447 remembered_unmapped_pages_index_++;
7448 remembered_unmapped_pages_index_ %= kRememberedUnmappedPages;
7449}
7450
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00007451
7452void Heap::ClearObjectStats(bool clear_last_time_stats) {
7453 memset(object_counts_, 0, sizeof(object_counts_));
7454 memset(object_sizes_, 0, sizeof(object_sizes_));
7455 if (clear_last_time_stats) {
7456 memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_));
7457 memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_));
7458 }
7459}
7460
7461
7462static LazyMutex checkpoint_object_stats_mutex = LAZY_MUTEX_INITIALIZER;
7463
7464
7465void Heap::CheckpointObjectStats() {
7466 ScopedLock lock(checkpoint_object_stats_mutex.Pointer());
7467 Counters* counters = isolate()->counters();
7468#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7469 counters->count_of_##name()->Increment( \
7470 static_cast<int>(object_counts_[name])); \
7471 counters->count_of_##name()->Decrement( \
7472 static_cast<int>(object_counts_last_time_[name])); \
7473 counters->size_of_##name()->Increment( \
7474 static_cast<int>(object_sizes_[name])); \
7475 counters->size_of_##name()->Decrement( \
7476 static_cast<int>(object_sizes_last_time_[name]));
7477 INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7478#undef ADJUST_LAST_TIME_OBJECT_COUNT
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007479 int index;
7480#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7481 index = FIRST_CODE_KIND_SUB_TYPE + Code::name; \
7482 counters->count_of_CODE_TYPE_##name()->Increment( \
7483 static_cast<int>(object_counts_[index])); \
7484 counters->count_of_CODE_TYPE_##name()->Decrement( \
7485 static_cast<int>(object_counts_last_time_[index])); \
7486 counters->size_of_CODE_TYPE_##name()->Increment( \
7487 static_cast<int>(object_sizes_[index])); \
7488 counters->size_of_CODE_TYPE_##name()->Decrement( \
7489 static_cast<int>(object_sizes_last_time_[index]));
7490 CODE_KIND_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7491#undef ADJUST_LAST_TIME_OBJECT_COUNT
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007492#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7493 index = FIRST_FIXED_ARRAY_SUB_TYPE + name; \
7494 counters->count_of_FIXED_ARRAY_##name()->Increment( \
7495 static_cast<int>(object_counts_[index])); \
7496 counters->count_of_FIXED_ARRAY_##name()->Decrement( \
7497 static_cast<int>(object_counts_last_time_[index])); \
7498 counters->size_of_FIXED_ARRAY_##name()->Increment( \
7499 static_cast<int>(object_sizes_[index])); \
7500 counters->size_of_FIXED_ARRAY_##name()->Decrement( \
7501 static_cast<int>(object_sizes_last_time_[index]));
7502 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7503#undef ADJUST_LAST_TIME_OBJECT_COUNT
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007504
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00007505 memcpy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
7506 memcpy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
7507 ClearObjectStats();
7508}
7509
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007510} } // namespace v8::internal