blob: 307960b737564e495b508be5cc33b70ae9f9c8f5 [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),
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000140 low_survival_rate_period_length_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000141 survival_rate_(0),
142 previous_survival_rate_trend_(Heap::STABLE),
143 survival_rate_trend_(Heap::STABLE),
144 max_gc_pause_(0),
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000145 total_gc_time_ms_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 max_alive_after_gc_(0),
147 min_in_mutator_(kMaxInt),
148 alive_after_last_gc_(0),
149 last_gc_end_timestamp_(0.0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000150 store_buffer_(this),
151 marking_(this),
152 incremental_marking_(this),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000153 number_idle_notifications_(0),
154 last_idle_notification_gc_count_(0),
155 last_idle_notification_gc_count_init_(false),
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +0000156 mark_sweeps_since_idle_round_started_(0),
157 ms_count_at_last_idle_notification_(0),
158 gc_count_at_last_idle_gc_(0),
159 scavenges_since_last_idle_round_(kIdleScavengeThreshold),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000160 promotion_queue_(this),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000161 configured_(false),
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000162 chunks_queued_for_free_(NULL),
163 relocation_mutex_(NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000164 // Allow build-time customization of the max semispace size. Building
165 // V8 with snapshots and a non-default max semispace size is much
166 // easier if you can define it as part of the build environment.
167#if defined(V8_MAX_SEMISPACE_SIZE)
168 max_semispace_size_ = reserved_semispace_size_ = V8_MAX_SEMISPACE_SIZE;
169#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000170
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000171 intptr_t max_virtual = OS::MaxVirtualMemory();
172
173 if (max_virtual > 0) {
174 if (code_range_size_ > 0) {
175 // Reserve no more than 1/8 of the memory for the code range.
176 code_range_size_ = Min(code_range_size_, max_virtual >> 3);
177 }
178 }
179
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000180 memset(roots_, 0, sizeof(roots_[0]) * kRootListLength);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000181 native_contexts_list_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000182 mark_compact_collector_.heap_ = this;
183 external_string_table_.heap_ = this;
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000184 // Put a dummy entry in the remembered pages so we can find the list the
185 // minidump even if there are no real unmapped pages.
186 RememberUnmappedPage(NULL, false);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000187
188 ClearObjectStats(true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000189}
190
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000191
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000192intptr_t Heap::Capacity() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000193 if (!HasBeenSetUp()) return 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000194
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000195 return new_space_.Capacity() +
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000196 old_pointer_space_->Capacity() +
197 old_data_space_->Capacity() +
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000198 code_space_->Capacity() +
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000199 map_space_->Capacity() +
200 cell_space_->Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000201}
202
203
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000204intptr_t Heap::CommittedMemory() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000205 if (!HasBeenSetUp()) return 0;
ager@chromium.org3811b432009-10-28 14:53:37 +0000206
207 return new_space_.CommittedMemory() +
208 old_pointer_space_->CommittedMemory() +
209 old_data_space_->CommittedMemory() +
210 code_space_->CommittedMemory() +
211 map_space_->CommittedMemory() +
212 cell_space_->CommittedMemory() +
213 lo_space_->Size();
214}
215
danno@chromium.org72204d52012-10-31 10:02:10 +0000216
217size_t Heap::CommittedPhysicalMemory() {
218 if (!HasBeenSetUp()) return 0;
219
220 return new_space_.CommittedPhysicalMemory() +
221 old_pointer_space_->CommittedPhysicalMemory() +
222 old_data_space_->CommittedPhysicalMemory() +
223 code_space_->CommittedPhysicalMemory() +
224 map_space_->CommittedPhysicalMemory() +
225 cell_space_->CommittedPhysicalMemory() +
226 lo_space_->CommittedPhysicalMemory();
227}
228
229
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000230intptr_t Heap::CommittedMemoryExecutable() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000231 if (!HasBeenSetUp()) return 0;
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000232
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000233 return isolate()->memory_allocator()->SizeExecutable();
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000234}
235
ager@chromium.org3811b432009-10-28 14:53:37 +0000236
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000237intptr_t Heap::Available() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000238 if (!HasBeenSetUp()) return 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000240 return new_space_.Available() +
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000241 old_pointer_space_->Available() +
242 old_data_space_->Available() +
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000243 code_space_->Available() +
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000244 map_space_->Available() +
245 cell_space_->Available();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000246}
247
248
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000249bool Heap::HasBeenSetUp() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000250 return old_pointer_space_ != NULL &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000251 old_data_space_ != NULL &&
252 code_space_ != NULL &&
253 map_space_ != NULL &&
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000254 cell_space_ != NULL &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000255 lo_space_ != NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000256}
257
258
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000259int Heap::GcSafeSizeOfOldObject(HeapObject* object) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000260 if (IntrusiveMarking::IsMarked(object)) {
261 return IntrusiveMarking::SizeOfMarkedObject(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000262 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000263 return object->SizeFromMap(object->map());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000264}
265
266
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000267GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space,
268 const char** reason) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000269 // Is global GC requested?
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000270 if (space != NEW_SPACE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000271 isolate_->counters()->gc_compactor_caused_by_request()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000272 *reason = "GC in old space requested";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000273 return MARK_COMPACTOR;
274 }
275
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000276 if (FLAG_gc_global || (FLAG_stress_compaction && (gc_count_ & 1) != 0)) {
277 *reason = "GC in old space forced by flags";
278 return MARK_COMPACTOR;
279 }
280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000281 // Is enough data promoted to justify a global GC?
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000282 if (OldGenerationPromotionLimitReached()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000283 isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000284 *reason = "promotion limit reached";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000285 return MARK_COMPACTOR;
286 }
287
288 // Have allocation in OLD and LO failed?
289 if (old_gen_exhausted_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000290 isolate_->counters()->
291 gc_compactor_caused_by_oldspace_exhaustion()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000292 *reason = "old generations exhausted";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000293 return MARK_COMPACTOR;
294 }
295
296 // Is there enough space left in OLD to guarantee that a scavenge can
297 // succeed?
298 //
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000299 // Note that MemoryAllocator->MaxAvailable() undercounts the memory available
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000300 // for object promotion. It counts only the bytes that the memory
301 // allocator has not yet allocated from the OS and assigned to any space,
302 // and does not count available bytes already in the old space or code
303 // space. Undercounting is safe---we may get an unrequested full GC when
304 // a scavenge would have succeeded.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000305 if (isolate_->memory_allocator()->MaxAvailable() <= new_space_.Size()) {
306 isolate_->counters()->
307 gc_compactor_caused_by_oldspace_exhaustion()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000308 *reason = "scavenge might not succeed";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309 return MARK_COMPACTOR;
310 }
311
312 // Default
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000313 *reason = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000314 return SCAVENGER;
315}
316
317
318// TODO(1238405): Combine the infrastructure for --heap-stats and
319// --log-gc to avoid the complicated preprocessor and flag testing.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320void Heap::ReportStatisticsBeforeGC() {
321 // Heap::ReportHeapStatistics will also log NewSpace statistics when
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000322 // compiled --log-gc is set. The following logic is used to avoid
323 // double logging.
324#ifdef DEBUG
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000325 if (FLAG_heap_stats || FLAG_log_gc) new_space_.CollectStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000326 if (FLAG_heap_stats) {
327 ReportHeapStatistics("Before GC");
328 } else if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000329 new_space_.ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000330 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000331 if (FLAG_heap_stats || FLAG_log_gc) new_space_.ClearHistograms();
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000332#else
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000333 if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000334 new_space_.CollectStatistics();
335 new_space_.ReportStatistics();
336 new_space_.ClearHistograms();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000338#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339}
340
341
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000342void Heap::PrintShortHeapStatistics() {
343 if (!FLAG_trace_gc_verbose) return;
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000344 PrintPID("Memory allocator, used: %6" V8_PTR_PREFIX "d KB"
345 ", available: %6" V8_PTR_PREFIX "d KB\n",
346 isolate_->memory_allocator()->Size() / KB,
347 isolate_->memory_allocator()->Available() / KB);
348 PrintPID("New space, used: %6" V8_PTR_PREFIX "d KB"
349 ", available: %6" V8_PTR_PREFIX "d KB"
350 ", committed: %6" V8_PTR_PREFIX "d KB\n",
351 new_space_.Size() / KB,
352 new_space_.Available() / KB,
353 new_space_.CommittedMemory() / KB);
354 PrintPID("Old pointers, used: %6" V8_PTR_PREFIX "d KB"
355 ", available: %6" V8_PTR_PREFIX "d KB"
356 ", committed: %6" V8_PTR_PREFIX "d KB\n",
357 old_pointer_space_->SizeOfObjects() / KB,
358 old_pointer_space_->Available() / KB,
359 old_pointer_space_->CommittedMemory() / KB);
360 PrintPID("Old data space, used: %6" V8_PTR_PREFIX "d KB"
361 ", available: %6" V8_PTR_PREFIX "d KB"
362 ", committed: %6" V8_PTR_PREFIX "d KB\n",
363 old_data_space_->SizeOfObjects() / KB,
364 old_data_space_->Available() / KB,
365 old_data_space_->CommittedMemory() / KB);
366 PrintPID("Code space, used: %6" V8_PTR_PREFIX "d KB"
367 ", available: %6" V8_PTR_PREFIX "d KB"
368 ", committed: %6" V8_PTR_PREFIX "d KB\n",
369 code_space_->SizeOfObjects() / KB,
370 code_space_->Available() / KB,
371 code_space_->CommittedMemory() / KB);
372 PrintPID("Map space, used: %6" V8_PTR_PREFIX "d KB"
373 ", available: %6" V8_PTR_PREFIX "d KB"
374 ", committed: %6" V8_PTR_PREFIX "d KB\n",
375 map_space_->SizeOfObjects() / KB,
376 map_space_->Available() / KB,
377 map_space_->CommittedMemory() / KB);
378 PrintPID("Cell space, used: %6" V8_PTR_PREFIX "d KB"
379 ", available: %6" V8_PTR_PREFIX "d KB"
380 ", committed: %6" V8_PTR_PREFIX "d KB\n",
381 cell_space_->SizeOfObjects() / KB,
382 cell_space_->Available() / KB,
383 cell_space_->CommittedMemory() / KB);
384 PrintPID("Large object space, used: %6" V8_PTR_PREFIX "d KB"
385 ", available: %6" V8_PTR_PREFIX "d KB"
386 ", committed: %6" V8_PTR_PREFIX "d KB\n",
387 lo_space_->SizeOfObjects() / KB,
388 lo_space_->Available() / KB,
389 lo_space_->CommittedMemory() / KB);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000390 PrintPID("All spaces, used: %6" V8_PTR_PREFIX "d KB"
391 ", available: %6" V8_PTR_PREFIX "d KB"
392 ", committed: %6" V8_PTR_PREFIX "d KB\n",
393 this->SizeOfObjects() / KB,
394 this->Available() / KB,
395 this->CommittedMemory() / KB);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000396 PrintPID("Total time spent in GC : %d ms\n", total_gc_time_ms_);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000397}
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000398
399
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400// TODO(1238405): Combine the infrastructure for --heap-stats and
401// --log-gc to avoid the complicated preprocessor and flag testing.
402void Heap::ReportStatisticsAfterGC() {
403 // Similar to the before GC, we use some complicated logic to ensure that
404 // NewSpace statistics are logged exactly once when --log-gc is turned on.
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000405#if defined(DEBUG)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000406 if (FLAG_heap_stats) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000407 new_space_.CollectStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000408 ReportHeapStatistics("After GC");
409 } else if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000410 new_space_.ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000411 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000412#else
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000413 if (FLAG_log_gc) new_space_.ReportStatistics();
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000414#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000415}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000416
417
418void Heap::GarbageCollectionPrologue() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000419 isolate_->transcendental_cache()->Clear();
ager@chromium.orgac091b72010-05-05 07:34:42 +0000420 ClearJSFunctionResultCaches();
kasper.lund7276f142008-07-30 08:49:36 +0000421 gc_count_++;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000422 unflattened_strings_length_ = 0;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000423
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000424 if (FLAG_flush_code && FLAG_flush_code_incrementally) {
425 mark_compact_collector()->EnableCodeFlushing(true);
426 }
427
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000428#ifdef VERIFY_HEAP
429 if (FLAG_verify_heap) {
430 Verify();
431 }
432#endif
433
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000434#ifdef DEBUG
435 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
436 allow_allocation(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000438 if (FLAG_gc_verbose) Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000439
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440 ReportStatisticsBeforeGC();
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000441#endif // DEBUG
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000442
443 LiveObjectList::GCPrologue();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000444 store_buffer()->GCPrologue();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000445}
446
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000447
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000448intptr_t Heap::SizeOfObjects() {
449 intptr_t total = 0;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000450 AllSpaces spaces;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000451 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000452 total += space->SizeOfObjects();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000453 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000454 return total;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000455}
456
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000457
458void Heap::RepairFreeListsAfterBoot() {
459 PagedSpaces spaces;
460 for (PagedSpace* space = spaces.next();
461 space != NULL;
462 space = spaces.next()) {
463 space->RepairFreeListsAfterBoot();
464 }
465}
466
467
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000468void Heap::GarbageCollectionEpilogue() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000469 store_buffer()->GCEpilogue();
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000470 LiveObjectList::GCEpilogue();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000471
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000472 // In release mode, we only zap the from space under heap verification.
473 if (Heap::ShouldZapGarbage()) {
474 ZapFromSpace();
475 }
476
477#ifdef VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000478 if (FLAG_verify_heap) {
479 Verify();
480 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000481#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000482
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000483#ifdef DEBUG
484 allow_allocation(true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000485 if (FLAG_print_global_handles) isolate_->global_handles()->Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000486 if (FLAG_print_handles) PrintHandles();
487 if (FLAG_gc_verbose) Print();
488 if (FLAG_code_stats) ReportCodeStatistics("After GC");
489#endif
490
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000491 isolate_->counters()->alive_after_last_gc()->Set(
492 static_cast<int>(SizeOfObjects()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000493
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000494 isolate_->counters()->symbol_table_capacity()->Set(
495 symbol_table()->Capacity());
496 isolate_->counters()->number_of_symbols()->Set(
497 symbol_table()->NumberOfElements());
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000498
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000499 if (CommittedMemory() > 0) {
500 isolate_->counters()->external_fragmentation_total()->AddSample(
501 static_cast<int>(100 - (SizeOfObjects() * 100.0) / CommittedMemory()));
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000502
503 isolate_->counters()->heap_fraction_map_space()->AddSample(
504 static_cast<int>(
505 (map_space()->CommittedMemory() * 100.0) / CommittedMemory()));
506 isolate_->counters()->heap_fraction_cell_space()->AddSample(
507 static_cast<int>(
508 (cell_space()->CommittedMemory() * 100.0) / CommittedMemory()));
509
510 isolate_->counters()->heap_sample_total_committed()->AddSample(
511 static_cast<int>(CommittedMemory() / KB));
512 isolate_->counters()->heap_sample_total_used()->AddSample(
513 static_cast<int>(SizeOfObjects() / KB));
514 isolate_->counters()->heap_sample_map_space_committed()->AddSample(
515 static_cast<int>(map_space()->CommittedMemory() / KB));
516 isolate_->counters()->heap_sample_cell_space_committed()->AddSample(
517 static_cast<int>(cell_space()->CommittedMemory() / KB));
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000518 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000519
520#define UPDATE_COUNTERS_FOR_SPACE(space) \
521 isolate_->counters()->space##_bytes_available()->Set( \
522 static_cast<int>(space()->Available())); \
523 isolate_->counters()->space##_bytes_committed()->Set( \
524 static_cast<int>(space()->CommittedMemory())); \
525 isolate_->counters()->space##_bytes_used()->Set( \
526 static_cast<int>(space()->SizeOfObjects()));
527#define UPDATE_FRAGMENTATION_FOR_SPACE(space) \
528 if (space()->CommittedMemory() > 0) { \
529 isolate_->counters()->external_fragmentation_##space()->AddSample( \
530 static_cast<int>(100 - \
531 (space()->SizeOfObjects() * 100.0) / space()->CommittedMemory())); \
532 }
533#define UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(space) \
534 UPDATE_COUNTERS_FOR_SPACE(space) \
535 UPDATE_FRAGMENTATION_FOR_SPACE(space)
536
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000537 UPDATE_COUNTERS_FOR_SPACE(new_space)
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000538 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(old_pointer_space)
539 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(old_data_space)
540 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(code_space)
541 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(map_space)
542 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(cell_space)
543 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(lo_space)
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000544#undef UPDATE_COUNTERS_FOR_SPACE
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000545#undef UPDATE_FRAGMENTATION_FOR_SPACE
546#undef UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000547
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000548#if defined(DEBUG)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549 ReportStatisticsAfterGC();
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000550#endif // DEBUG
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000551#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000552 isolate_->debug()->AfterGarbageCollection();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000553#endif // ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000554}
555
556
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000557void Heap::CollectAllGarbage(int flags, const char* gc_reason) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000558 // Since we are ignoring the return value, the exact choice of space does
559 // not matter, so long as we do not specify NEW_SPACE, which would not
560 // cause a full GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000561 mark_compact_collector_.SetFlags(flags);
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000562 CollectGarbage(OLD_POINTER_SPACE, gc_reason);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000563 mark_compact_collector_.SetFlags(kNoGCFlags);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000564}
565
566
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000567void Heap::CollectAllAvailableGarbage(const char* gc_reason) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000568 // Since we are ignoring the return value, the exact choice of space does
569 // not matter, so long as we do not specify NEW_SPACE, which would not
570 // cause a full GC.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000571 // Major GC would invoke weak handle callbacks on weakly reachable
572 // handles, but won't collect weakly reachable objects until next
573 // major GC. Therefore if we collect aggressively and weak handle callback
574 // has been invoked, we rerun major GC to release objects which become
575 // garbage.
576 // Note: as weak callbacks can execute arbitrary code, we cannot
577 // hope that eventually there will be no weak callbacks invocations.
578 // Therefore stop recollecting after several attempts.
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000579 mark_compact_collector()->SetFlags(kMakeHeapIterableMask |
580 kReduceMemoryFootprintMask);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000581 isolate_->compilation_cache()->Clear();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000582 const int kMaxNumberOfAttempts = 7;
583 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000584 if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR, gc_reason, NULL)) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000585 break;
586 }
587 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000588 mark_compact_collector()->SetFlags(kNoGCFlags);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000589 new_space_.Shrink();
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000590 UncommitFromSpace();
591 Shrink();
danno@chromium.orgc612e022011-11-10 11:38:15 +0000592 incremental_marking()->UncommitMarkingDeque();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000593}
594
595
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000596bool Heap::CollectGarbage(AllocationSpace space,
597 GarbageCollector collector,
598 const char* gc_reason,
599 const char* collector_reason) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600 // The VM is in the GC state until exiting this function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000601 VMState state(isolate_, GC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000602
603#ifdef DEBUG
604 // Reset the allocation timeout to the GC interval, but make sure to
605 // allow at least a few allocations after a collection. The reason
606 // for this is that we have a lot of allocation sequences and we
607 // assume that a garbage collection will allow the subsequent
608 // allocation attempts to go through.
609 allocation_timeout_ = Max(6, FLAG_gc_interval);
610#endif
611
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000612 if (collector == SCAVENGER && !incremental_marking()->IsStopped()) {
613 if (FLAG_trace_incremental_marking) {
614 PrintF("[IncrementalMarking] Scavenge during marking.\n");
615 }
616 }
617
618 if (collector == MARK_COMPACTOR &&
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000619 !mark_compact_collector()->abort_incremental_marking_ &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000620 !incremental_marking()->IsStopped() &&
621 !incremental_marking()->should_hurry() &&
622 FLAG_incremental_marking_steps) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000623 // Make progress in incremental marking.
624 const intptr_t kStepSizeWhenDelayedByScavenge = 1 * MB;
625 incremental_marking()->Step(kStepSizeWhenDelayedByScavenge,
626 IncrementalMarking::NO_GC_VIA_STACK_GUARD);
627 if (!incremental_marking()->IsComplete()) {
628 if (FLAG_trace_incremental_marking) {
629 PrintF("[IncrementalMarking] Delaying MarkSweep.\n");
630 }
631 collector = SCAVENGER;
632 collector_reason = "incremental marking delaying mark-sweep";
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000633 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000634 }
635
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000636 bool next_gc_likely_to_collect_more = false;
637
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000638 { GCTracer tracer(this, gc_reason, collector_reason);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000639 GarbageCollectionPrologue();
kasper.lund7276f142008-07-30 08:49:36 +0000640 // The GC count was incremented in the prologue. Tell the tracer about
641 // it.
642 tracer.set_gc_count(gc_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000643
kasper.lund7276f142008-07-30 08:49:36 +0000644 // Tell the tracer which collector we've selected.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000645 tracer.set_collector(collector);
646
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000647 HistogramTimer* rate = (collector == SCAVENGER)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000648 ? isolate_->counters()->gc_scavenger()
649 : isolate_->counters()->gc_compactor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000650 rate->Start();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000651 next_gc_likely_to_collect_more =
652 PerformGarbageCollection(collector, &tracer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000653 rate->Stop();
654
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000655 ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped());
656
657 // This can do debug callbacks and restart incremental marking.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000658 GarbageCollectionEpilogue();
659 }
660
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000661 if (incremental_marking()->IsStopped()) {
662 if (incremental_marking()->WorthActivating() && NextGCIsLikelyToBeFull()) {
663 incremental_marking()->Start();
664 }
665 }
666
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000667 return next_gc_likely_to_collect_more;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000668}
669
670
kasper.lund7276f142008-07-30 08:49:36 +0000671void Heap::PerformScavenge() {
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000672 GCTracer tracer(this, NULL, NULL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000673 if (incremental_marking()->IsStopped()) {
674 PerformGarbageCollection(SCAVENGER, &tracer);
675 } else {
676 PerformGarbageCollection(MARK_COMPACTOR, &tracer);
677 }
kasper.lund7276f142008-07-30 08:49:36 +0000678}
679
680
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000681#ifdef VERIFY_HEAP
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000682// Helper class for verifying the symbol table.
683class SymbolTableVerifier : public ObjectVisitor {
684 public:
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000685 void VisitPointers(Object** start, Object** end) {
686 // Visit all HeapObject pointers in [start, end).
687 for (Object** p = start; p < end; p++) {
688 if ((*p)->IsHeapObject()) {
689 // Check that the symbol is actually a symbol.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000690 CHECK((*p)->IsTheHole() || (*p)->IsUndefined() || (*p)->IsSymbol());
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000691 }
692 }
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000693 }
694};
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000695
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000696
697static void VerifySymbolTable() {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000698 SymbolTableVerifier verifier;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000699 HEAP->symbol_table()->IterateElements(&verifier);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000700}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000701#endif // VERIFY_HEAP
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000702
703
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000704static bool AbortIncrementalMarkingAndCollectGarbage(
705 Heap* heap,
706 AllocationSpace space,
707 const char* gc_reason = NULL) {
708 heap->mark_compact_collector()->SetFlags(Heap::kAbortIncrementalMarkingMask);
709 bool result = heap->CollectGarbage(space, gc_reason);
710 heap->mark_compact_collector()->SetFlags(Heap::kNoGCFlags);
711 return result;
712}
713
714
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000715void Heap::ReserveSpace(
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000716 int *sizes,
717 Address *locations_out) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000718 bool gc_performed = true;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000719 int counter = 0;
720 static const int kThreshold = 20;
721 while (gc_performed && counter++ < kThreshold) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000722 gc_performed = false;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000723 ASSERT(NEW_SPACE == FIRST_PAGED_SPACE - 1);
724 for (int space = NEW_SPACE; space <= LAST_PAGED_SPACE; space++) {
725 if (sizes[space] != 0) {
726 MaybeObject* allocation;
727 if (space == NEW_SPACE) {
728 allocation = new_space()->AllocateRaw(sizes[space]);
729 } else {
730 allocation = paged_space(space)->AllocateRaw(sizes[space]);
731 }
732 FreeListNode* node;
733 if (!allocation->To<FreeListNode>(&node)) {
734 if (space == NEW_SPACE) {
735 Heap::CollectGarbage(NEW_SPACE,
736 "failed to reserve space in the new space");
737 } else {
738 AbortIncrementalMarkingAndCollectGarbage(
739 this,
740 static_cast<AllocationSpace>(space),
741 "failed to reserve space in paged space");
742 }
743 gc_performed = true;
744 break;
745 } else {
746 // Mark with a free list node, in case we have a GC before
747 // deserializing.
748 node->set_size(this, sizes[space]);
749 locations_out[space] = node->address();
750 }
751 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000752 }
753 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000754
755 if (gc_performed) {
756 // Failed to reserve the space after several attempts.
757 V8::FatalProcessOutOfMemory("Heap::ReserveSpace");
758 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000759}
760
761
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000762void Heap::EnsureFromSpaceIsCommitted() {
763 if (new_space_.CommitFromSpaceIfNeeded()) return;
764
765 // Committing memory to from space failed.
766 // Try shrinking and try again.
767 Shrink();
768 if (new_space_.CommitFromSpaceIfNeeded()) return;
769
770 // Committing memory to from space failed again.
771 // Memory is exhausted and we will die.
772 V8::FatalProcessOutOfMemory("Committing semi space failed.");
773}
774
775
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000776void Heap::ClearJSFunctionResultCaches() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000777 if (isolate_->bootstrapper()->IsActive()) return;
ager@chromium.orgac091b72010-05-05 07:34:42 +0000778
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000779 Object* context = native_contexts_list_;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000780 while (!context->IsUndefined()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000781 // Get the caches for this context. GC can happen when the context
782 // is not fully initialized, so the caches can be undefined.
783 Object* caches_or_undefined =
784 Context::cast(context)->get(Context::JSFUNCTION_RESULT_CACHES_INDEX);
785 if (!caches_or_undefined->IsUndefined()) {
786 FixedArray* caches = FixedArray::cast(caches_or_undefined);
787 // Clear the caches:
788 int length = caches->length();
789 for (int i = 0; i < length; i++) {
790 JSFunctionResultCache::cast(caches->get(i))->Clear();
791 }
ager@chromium.orgac091b72010-05-05 07:34:42 +0000792 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000793 // Get the next context:
794 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000795 }
ager@chromium.orgac091b72010-05-05 07:34:42 +0000796}
797
798
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000799
ricow@chromium.org65fae842010-08-25 15:26:24 +0000800void Heap::ClearNormalizedMapCaches() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000801 if (isolate_->bootstrapper()->IsActive() &&
802 !incremental_marking()->IsMarking()) {
803 return;
804 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000805
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000806 Object* context = native_contexts_list_;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000807 while (!context->IsUndefined()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000808 // GC can happen when the context is not fully initialized,
809 // so the cache can be undefined.
810 Object* cache =
811 Context::cast(context)->get(Context::NORMALIZED_MAP_CACHE_INDEX);
812 if (!cache->IsUndefined()) {
813 NormalizedMapCache::cast(cache)->Clear();
814 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000815 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
816 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000817}
818
819
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000820void Heap::UpdateSurvivalRateTrend(int start_new_space_size) {
821 double survival_rate =
822 (static_cast<double>(young_survivors_after_last_gc_) * 100) /
823 start_new_space_size;
824
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000825 if (survival_rate > kYoungSurvivalRateHighThreshold) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000826 high_survival_rate_period_length_++;
827 } else {
828 high_survival_rate_period_length_ = 0;
829 }
830
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000831 if (survival_rate < kYoungSurvivalRateLowThreshold) {
832 low_survival_rate_period_length_++;
833 } else {
834 low_survival_rate_period_length_ = 0;
835 }
836
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000837 double survival_rate_diff = survival_rate_ - survival_rate;
838
839 if (survival_rate_diff > kYoungSurvivalRateAllowedDeviation) {
840 set_survival_rate_trend(DECREASING);
841 } else if (survival_rate_diff < -kYoungSurvivalRateAllowedDeviation) {
842 set_survival_rate_trend(INCREASING);
843 } else {
844 set_survival_rate_trend(STABLE);
845 }
846
847 survival_rate_ = survival_rate;
848}
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000849
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000850bool Heap::PerformGarbageCollection(GarbageCollector collector,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000851 GCTracer* tracer) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000852 bool next_gc_likely_to_collect_more = false;
853
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000854 if (collector != SCAVENGER) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000855 PROFILE(isolate_, CodeMovingGCEvent());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000856 }
857
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000858#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000859 if (FLAG_verify_heap) {
860 VerifySymbolTable();
861 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000862#endif
863
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000864 if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) {
865 ASSERT(!allocation_allowed_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000866 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000867 global_gc_prologue_callback_();
868 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000869
870 GCType gc_type =
871 collector == MARK_COMPACTOR ? kGCTypeMarkSweepCompact : kGCTypeScavenge;
872
873 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
874 if (gc_type & gc_prologue_callbacks_[i].gc_type) {
875 gc_prologue_callbacks_[i].callback(gc_type, kNoGCCallbackFlags);
876 }
877 }
878
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000879 EnsureFromSpaceIsCommitted();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000880
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000881 int start_new_space_size = Heap::new_space()->SizeAsInt();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000882
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000883 if (IsHighSurvivalRate()) {
884 // We speed up the incremental marker if it is running so that it
885 // does not fall behind the rate of promotion, which would cause a
886 // constantly growing old space.
887 incremental_marking()->NotifyOfHighPromotionRate();
888 }
889
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000890 if (collector == MARK_COMPACTOR) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000891 // Perform mark-sweep with optional compaction.
kasper.lund7276f142008-07-30 08:49:36 +0000892 MarkCompact(tracer);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000893 sweep_generation_++;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000894 bool high_survival_rate_during_scavenges = IsHighSurvivalRate() &&
895 IsStableOrIncreasingSurvivalTrend();
896
897 UpdateSurvivalRateTrend(start_new_space_size);
898
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000899 size_of_old_gen_at_last_old_space_gc_ = PromotedSpaceSizeOfObjects();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000900
lrn@chromium.org303ada72010-10-27 09:33:13 +0000901 if (high_survival_rate_during_scavenges &&
902 IsStableOrIncreasingSurvivalTrend()) {
903 // Stable high survival rates of young objects both during partial and
904 // full collection indicate that mutator is either building or modifying
905 // a structure with a long lifetime.
906 // In this case we aggressively raise old generation memory limits to
907 // postpone subsequent mark-sweep collection and thus trade memory
908 // space for the mutation speed.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000909 old_gen_limit_factor_ = 2;
910 } else {
911 old_gen_limit_factor_ = 1;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000912 }
913
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000914 old_gen_promotion_limit_ =
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000915 OldGenPromotionLimit(size_of_old_gen_at_last_old_space_gc_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000916 old_gen_allocation_limit_ =
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000917 OldGenAllocationLimit(size_of_old_gen_at_last_old_space_gc_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000918
lrn@chromium.org303ada72010-10-27 09:33:13 +0000919 old_gen_exhausted_ = false;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000920 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000921 tracer_ = tracer;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000922 Scavenge();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000923 tracer_ = NULL;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000924
925 UpdateSurvivalRateTrend(start_new_space_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926 }
ager@chromium.org439e85a2009-08-26 13:15:29 +0000927
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000928 if (!new_space_high_promotion_mode_active_ &&
929 new_space_.Capacity() == new_space_.MaximumCapacity() &&
930 IsStableOrIncreasingSurvivalTrend() &&
931 IsHighSurvivalRate()) {
932 // Stable high survival rates even though young generation is at
933 // maximum capacity indicates that most objects will be promoted.
934 // To decrease scavenger pauses and final mark-sweep pauses, we
935 // have to limit maximal capacity of the young generation.
936 new_space_high_promotion_mode_active_ = true;
937 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000938 PrintPID("Limited new space size due to high promotion rate: %d MB\n",
939 new_space_.InitialCapacity() / MB);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000940 }
941 } else if (new_space_high_promotion_mode_active_ &&
942 IsStableOrDecreasingSurvivalTrend() &&
943 IsLowSurvivalRate()) {
944 // Decreasing low survival rates might indicate that the above high
945 // promotion mode is over and we should allow the young generation
946 // to grow again.
947 new_space_high_promotion_mode_active_ = false;
948 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000949 PrintPID("Unlimited new space size due to low promotion rate: %d MB\n",
950 new_space_.MaximumCapacity() / MB);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000951 }
952 }
953
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000954 if (new_space_high_promotion_mode_active_ &&
955 new_space_.Capacity() > new_space_.InitialCapacity()) {
956 new_space_.Shrink();
957 }
958
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000959 isolate_->counters()->objs_since_last_young()->Set(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000960
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000961 gc_post_processing_depth_++;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000962 { DisableAssertNoAllocation allow_allocation;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000963 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000964 next_gc_likely_to_collect_more =
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000965 isolate_->global_handles()->PostGarbageCollectionProcessing(collector);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000966 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000967 gc_post_processing_depth_--;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000968
ager@chromium.org3811b432009-10-28 14:53:37 +0000969 // Update relocatables.
970 Relocatable::PostGarbageCollectionProcessing();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000971
kasper.lund7276f142008-07-30 08:49:36 +0000972 if (collector == MARK_COMPACTOR) {
973 // Register the amount of external allocated memory.
974 amount_of_external_allocated_memory_at_last_global_gc_ =
975 amount_of_external_allocated_memory_;
976 }
977
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000978 GCCallbackFlags callback_flags = kNoGCCallbackFlags;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000979 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
980 if (gc_type & gc_epilogue_callbacks_[i].gc_type) {
981 gc_epilogue_callbacks_[i].callback(gc_type, callback_flags);
982 }
983 }
984
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000985 if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) {
986 ASSERT(!allocation_allowed_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000987 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 global_gc_epilogue_callback_();
989 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000990
991#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000992 if (FLAG_verify_heap) {
993 VerifySymbolTable();
994 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000995#endif
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000996
997 return next_gc_likely_to_collect_more;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998}
999
1000
kasper.lund7276f142008-07-30 08:49:36 +00001001void Heap::MarkCompact(GCTracer* tracer) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002 gc_state_ = MARK_COMPACT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001003 LOG(isolate_, ResourceEvent("markcompact", "begin"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001004
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001005 mark_compact_collector_.Prepare(tracer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001007 ms_count_++;
1008 tracer->set_full_gc_count(ms_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001010 MarkCompactPrologue();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001011
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001012 mark_compact_collector_.CollectGarbage();
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001013
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001014 LOG(isolate_, ResourceEvent("markcompact", "end"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015
1016 gc_state_ = NOT_IN_GC;
1017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001018 isolate_->counters()->objs_since_last_full()->Set(0);
kasperl@chromium.org8b2bb262010-03-01 09:46:28 +00001019
1020 contexts_disposed_ = 0;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001021
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001022 flush_monomorphic_ics_ = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023}
1024
1025
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001026void Heap::MarkCompactPrologue() {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001027 // At any old GC clear the keyed lookup cache to enable collection of unused
1028 // maps.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001029 isolate_->keyed_lookup_cache()->Clear();
1030 isolate_->context_slot_cache()->Clear();
1031 isolate_->descriptor_lookup_cache()->Clear();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001032 RegExpResultsCache::Clear(string_split_cache());
1033 RegExpResultsCache::Clear(regexp_multiple_cache());
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001034
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035 isolate_->compilation_cache()->MarkCompactPrologue();
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001036
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001037 CompletelyClearInstanceofCache();
1038
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001039 FlushNumberStringCache();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001040 if (FLAG_cleanup_code_caches_at_gc) {
1041 polymorphic_code_cache()->set_cache(undefined_value());
1042 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001043
1044 ClearNormalizedMapCaches();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001045}
1046
1047
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048Object* Heap::FindCodeObject(Address a) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001049 return isolate()->inner_pointer_to_code_cache()->
1050 GcSafeFindCodeForInnerPointer(a);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051}
1052
1053
1054// Helper class for copying HeapObjects
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001055class ScavengeVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001056 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001057 explicit ScavengeVisitor(Heap* heap) : heap_(heap) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001059 void VisitPointer(Object** p) { ScavengePointer(p); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001060
1061 void VisitPointers(Object** start, Object** end) {
1062 // Copy all HeapObject pointers in [start, end)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001063 for (Object** p = start; p < end; p++) ScavengePointer(p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064 }
1065
1066 private:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001067 void ScavengePointer(Object** p) {
1068 Object* object = *p;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001069 if (!heap_->InNewSpace(object)) return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001070 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
1071 reinterpret_cast<HeapObject*>(object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001072 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001073
1074 Heap* heap_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075};
1076
1077
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001078#ifdef VERIFY_HEAP
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001079// Visitor class to verify pointers in code or data space do not point into
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080// new space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001081class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001082 public:
1083 void VisitPointers(Object** start, Object**end) {
1084 for (Object** current = start; current < end; current++) {
1085 if ((*current)->IsHeapObject()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001086 CHECK(!HEAP->InNewSpace(HeapObject::cast(*current)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001087 }
1088 }
1089 }
1090};
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001091
1092
1093static void VerifyNonPointerSpacePointers() {
1094 // Verify that there are no pointers to new space in spaces where we
1095 // do not expect them.
1096 VerifyNonPointerSpacePointersVisitor v;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001097 HeapObjectIterator code_it(HEAP->code_space());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001098 for (HeapObject* object = code_it.Next();
1099 object != NULL; object = code_it.Next())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001100 object->Iterate(&v);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001101
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001102 // The old data space was normally swept conservatively so that the iterator
1103 // doesn't work, so we normally skip the next bit.
1104 if (!HEAP->old_data_space()->was_swept_conservatively()) {
1105 HeapObjectIterator data_it(HEAP->old_data_space());
1106 for (HeapObject* object = data_it.Next();
1107 object != NULL; object = data_it.Next())
1108 object->Iterate(&v);
1109 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001110}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001111#endif // VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001112
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001113
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001114void Heap::CheckNewSpaceExpansionCriteria() {
1115 if (new_space_.Capacity() < new_space_.MaximumCapacity() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001116 survived_since_last_expansion_ > new_space_.Capacity() &&
1117 !new_space_high_promotion_mode_active_) {
1118 // Grow the size of new space if there is room to grow, enough data
1119 // has survived scavenge since the last expansion and we are not in
1120 // high promotion mode.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001121 new_space_.Grow();
1122 survived_since_last_expansion_ = 0;
1123 }
1124}
1125
1126
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001127static bool IsUnscavengedHeapObject(Heap* heap, Object** p) {
1128 return heap->InNewSpace(*p) &&
1129 !HeapObject::cast(*p)->map_word().IsForwardingAddress();
1130}
1131
1132
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001133void Heap::ScavengeStoreBufferCallback(
1134 Heap* heap,
1135 MemoryChunk* page,
1136 StoreBufferEvent event) {
1137 heap->store_buffer_rebuilder_.Callback(page, event);
1138}
1139
1140
1141void StoreBufferRebuilder::Callback(MemoryChunk* page, StoreBufferEvent event) {
1142 if (event == kStoreBufferStartScanningPagesEvent) {
1143 start_of_current_page_ = NULL;
1144 current_page_ = NULL;
1145 } else if (event == kStoreBufferScanningPageEvent) {
1146 if (current_page_ != NULL) {
1147 // If this page already overflowed the store buffer during this iteration.
1148 if (current_page_->scan_on_scavenge()) {
1149 // Then we should wipe out the entries that have been added for it.
1150 store_buffer_->SetTop(start_of_current_page_);
1151 } else if (store_buffer_->Top() - start_of_current_page_ >=
1152 (store_buffer_->Limit() - store_buffer_->Top()) >> 2) {
1153 // Did we find too many pointers in the previous page? The heuristic is
1154 // that no page can take more then 1/5 the remaining slots in the store
1155 // buffer.
1156 current_page_->set_scan_on_scavenge(true);
1157 store_buffer_->SetTop(start_of_current_page_);
1158 } else {
1159 // In this case the page we scanned took a reasonable number of slots in
1160 // the store buffer. It has now been rehabilitated and is no longer
1161 // marked scan_on_scavenge.
1162 ASSERT(!current_page_->scan_on_scavenge());
1163 }
1164 }
1165 start_of_current_page_ = store_buffer_->Top();
1166 current_page_ = page;
1167 } else if (event == kStoreBufferFullEvent) {
1168 // The current page overflowed the store buffer again. Wipe out its entries
1169 // in the store buffer and mark it scan-on-scavenge again. This may happen
1170 // several times while scanning.
1171 if (current_page_ == NULL) {
1172 // Store Buffer overflowed while scanning promoted objects. These are not
1173 // in any particular page, though they are likely to be clustered by the
1174 // allocation routines.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001175 store_buffer_->EnsureSpace(StoreBuffer::kStoreBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001176 } else {
1177 // Store Buffer overflowed while scanning a particular old space page for
1178 // pointers to new space.
1179 ASSERT(current_page_ == page);
1180 ASSERT(page != NULL);
1181 current_page_->set_scan_on_scavenge(true);
1182 ASSERT(start_of_current_page_ != store_buffer_->Top());
1183 store_buffer_->SetTop(start_of_current_page_);
1184 }
1185 } else {
1186 UNREACHABLE();
1187 }
1188}
1189
1190
danno@chromium.orgc612e022011-11-10 11:38:15 +00001191void PromotionQueue::Initialize() {
1192 // Assumes that a NewSpacePage exactly fits a number of promotion queue
1193 // entries (where each is a pair of intptr_t). This allows us to simplify
1194 // the test fpr when to switch pages.
1195 ASSERT((Page::kPageSize - MemoryChunk::kBodyOffset) % (2 * kPointerSize)
1196 == 0);
1197 limit_ = reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceStart());
1198 front_ = rear_ =
1199 reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceEnd());
1200 emergency_stack_ = NULL;
1201 guard_ = false;
1202}
1203
1204
1205void PromotionQueue::RelocateQueueHead() {
1206 ASSERT(emergency_stack_ == NULL);
1207
1208 Page* p = Page::FromAllocationTop(reinterpret_cast<Address>(rear_));
1209 intptr_t* head_start = rear_;
1210 intptr_t* head_end =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001211 Min(front_, reinterpret_cast<intptr_t*>(p->area_end()));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001212
1213 int entries_count =
1214 static_cast<int>(head_end - head_start) / kEntrySizeInWords;
1215
1216 emergency_stack_ = new List<Entry>(2 * entries_count);
1217
1218 while (head_start != head_end) {
1219 int size = static_cast<int>(*(head_start++));
1220 HeapObject* obj = reinterpret_cast<HeapObject*>(*(head_start++));
1221 emergency_stack_->Add(Entry(obj, size));
1222 }
1223 rear_ = head_end;
1224}
1225
1226
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001227class ScavengeWeakObjectRetainer : public WeakObjectRetainer {
1228 public:
1229 explicit ScavengeWeakObjectRetainer(Heap* heap) : heap_(heap) { }
1230
1231 virtual Object* RetainAs(Object* object) {
1232 if (!heap_->InFromSpace(object)) {
1233 return object;
1234 }
1235
1236 MapWord map_word = HeapObject::cast(object)->map_word();
1237 if (map_word.IsForwardingAddress()) {
1238 return map_word.ToForwardingAddress();
1239 }
1240 return NULL;
1241 }
1242
1243 private:
1244 Heap* heap_;
1245};
1246
1247
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001248void Heap::Scavenge() {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001249 RelocationLock relocation_lock(this);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001250
1251#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001252 if (FLAG_verify_heap) VerifyNonPointerSpacePointers();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001253#endif
1254
1255 gc_state_ = SCAVENGE;
1256
1257 // Implements Cheney's copying algorithm
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001258 LOG(isolate_, ResourceEvent("scavenge", "begin"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001259
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001260 // Clear descriptor cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001261 isolate_->descriptor_lookup_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001262
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001263 // Used for updating survived_since_last_expansion_ at function end.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001264 intptr_t survived_watermark = PromotedSpaceSizeOfObjects();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001265
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001266 CheckNewSpaceExpansionCriteria();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001268 SelectScavengingVisitorsTable();
1269
1270 incremental_marking()->PrepareForScavenge();
1271
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001272 AdvanceSweepers(static_cast<int>(new_space_.Size()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001273
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274 // Flip the semispaces. After flipping, to space is empty, from space has
1275 // live objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001276 new_space_.Flip();
1277 new_space_.ResetAllocationInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001279 // We need to sweep newly copied objects which can be either in the
1280 // to space or promoted to the old generation. For to-space
1281 // objects, we treat the bottom of the to space as a queue. Newly
1282 // copied and unswept objects lie between a 'front' mark and the
1283 // allocation pointer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284 //
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001285 // Promoted objects can go into various old-generation spaces, and
1286 // can be allocated internally in the spaces (from the free list).
1287 // We treat the top of the to space as a queue of addresses of
1288 // promoted objects. The addresses of newly promoted and unswept
1289 // objects lie between a 'front' mark and a 'rear' mark that is
1290 // updated as a side effect of promoting an object.
1291 //
1292 // There is guaranteed to be enough room at the top of the to space
1293 // for the addresses of promoted objects: every object promoted
1294 // frees up its size in bytes from the top of the new space, and
1295 // objects are at least one pointer in size.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001296 Address new_space_front = new_space_.ToSpaceStart();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001297 promotion_queue_.Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001299#ifdef DEBUG
1300 store_buffer()->Clean();
1301#endif
1302
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001303 ScavengeVisitor scavenge_visitor(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304 // Copy roots.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001305 IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001306
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001307 // Copy objects reachable from the old generation.
1308 {
1309 StoreBufferRebuildScope scope(this,
1310 store_buffer(),
1311 &ScavengeStoreBufferCallback);
1312 store_buffer()->IteratePointersToNewSpace(&ScavengeObject);
1313 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001314
1315 // Copy objects reachable from cells by scavenging cell values directly.
1316 HeapObjectIterator cell_iterator(cell_space_);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001317 for (HeapObject* heap_object = cell_iterator.Next();
1318 heap_object != NULL;
1319 heap_object = cell_iterator.Next()) {
1320 if (heap_object->IsJSGlobalPropertyCell()) {
1321 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(heap_object);
1322 Address value_address = cell->ValueAddress();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001323 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address));
1324 }
1325 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001326
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001327 // Copy objects reachable from the code flushing candidates list.
1328 MarkCompactCollector* collector = mark_compact_collector();
1329 if (collector->is_code_flushing_enabled()) {
1330 collector->code_flusher()->IteratePointersToFromSpace(&scavenge_visitor);
1331 }
1332
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001333 // Scavenge object reachable from the native contexts list directly.
1334 scavenge_visitor.VisitPointer(BitCast<Object**>(&native_contexts_list_));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001335
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001336 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001337
1338 while (IterateObjectGroups(&scavenge_visitor)) {
1339 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
1340 }
1341 isolate()->global_handles()->RemoveObjectGroups();
1342
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001343 isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles(
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001344 &IsUnscavengedHeapObject);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001345 isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots(
1346 &scavenge_visitor);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001347 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
1348
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001349 UpdateNewSpaceReferencesInExternalStringTable(
1350 &UpdateNewSpaceReferenceInExternalStringTableEntry);
1351
danno@chromium.orgc612e022011-11-10 11:38:15 +00001352 promotion_queue_.Destroy();
1353
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001354 LiveObjectList::UpdateReferencesForScavengeGC();
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001355 if (!FLAG_watch_ic_patching) {
1356 isolate()->runtime_profiler()->UpdateSamplesAfterScavenge();
1357 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001358 incremental_marking()->UpdateMarkingDequeAfterScavenge();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001359
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001360 ScavengeWeakObjectRetainer weak_object_retainer(this);
1361 ProcessWeakReferences(&weak_object_retainer);
1362
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001363 ASSERT(new_space_front == new_space_.top());
1364
1365 // Set age mark.
1366 new_space_.set_age_mark(new_space_.top());
1367
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001368 new_space_.LowerInlineAllocationLimit(
1369 new_space_.inline_allocation_limit_step());
1370
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001371 // Update how much has survived scavenge.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001372 IncrementYoungSurvivorsCounter(static_cast<int>(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001373 (PromotedSpaceSizeOfObjects() - survived_watermark) + new_space_.Size()));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001374
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001375 LOG(isolate_, ResourceEvent("scavenge", "end"));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001376
1377 gc_state_ = NOT_IN_GC;
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001378
1379 scavenges_since_last_idle_round_++;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001380}
1381
1382
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001383// TODO(mstarzinger): Unify this method with
1384// MarkCompactCollector::MarkObjectGroups().
1385bool Heap::IterateObjectGroups(ObjectVisitor* scavenge_visitor) {
1386 List<ObjectGroup*>* object_groups =
1387 isolate()->global_handles()->object_groups();
1388
1389 int last = 0;
1390 bool changed = false;
1391 for (int i = 0; i < object_groups->length(); i++) {
1392 ObjectGroup* entry = object_groups->at(i);
1393 ASSERT(entry != NULL);
1394
1395 Object*** objects = entry->objects_;
1396 bool group_marked = false;
1397 for (size_t j = 0; j < entry->length_; j++) {
1398 Object* object = *objects[j];
1399 if (object->IsHeapObject()) {
1400 if (!IsUnscavengedHeapObject(this, &object)) {
1401 group_marked = true;
1402 break;
1403 }
1404 }
1405 }
1406
1407 if (!group_marked) {
1408 (*object_groups)[last++] = entry;
1409 continue;
1410 }
1411
1412 for (size_t j = 0; j < entry->length_; ++j) {
1413 Object* object = *objects[j];
1414 if (object->IsHeapObject()) {
1415 scavenge_visitor->VisitPointer(&object);
1416 changed = true;
1417 }
1418 }
1419
1420 entry->Dispose();
1421 object_groups->at(i) = NULL;
1422 }
1423 object_groups->Rewind(last);
1424 return changed;
1425}
1426
1427
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001428String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
1429 Object** p) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001430 MapWord first_word = HeapObject::cast(*p)->map_word();
1431
1432 if (!first_word.IsForwardingAddress()) {
1433 // Unreachable external string can be finalized.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001434 heap->FinalizeExternalString(String::cast(*p));
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001435 return NULL;
1436 }
1437
1438 // String is still reachable.
1439 return String::cast(first_word.ToForwardingAddress());
1440}
1441
1442
1443void Heap::UpdateNewSpaceReferencesInExternalStringTable(
1444 ExternalStringTableUpdaterCallback updater_func) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001445#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001446 if (FLAG_verify_heap) {
1447 external_string_table_.Verify();
1448 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001449#endif
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001450
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001451 if (external_string_table_.new_space_strings_.is_empty()) return;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001452
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001453 Object** start = &external_string_table_.new_space_strings_[0];
1454 Object** end = start + external_string_table_.new_space_strings_.length();
1455 Object** last = start;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001456
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001457 for (Object** p = start; p < end; ++p) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001458 ASSERT(InFromSpace(*p));
1459 String* target = updater_func(this, p);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001460
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001461 if (target == NULL) continue;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001462
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001463 ASSERT(target->IsExternalString());
1464
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001465 if (InNewSpace(target)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001466 // String is still in new space. Update the table entry.
1467 *last = target;
1468 ++last;
1469 } else {
1470 // String got promoted. Move it to the old string list.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001471 external_string_table_.AddOldString(target);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001472 }
1473 }
1474
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001475 ASSERT(last <= end);
1476 external_string_table_.ShrinkNewStrings(static_cast<int>(last - start));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001477}
1478
1479
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001480void Heap::UpdateReferencesInExternalStringTable(
1481 ExternalStringTableUpdaterCallback updater_func) {
1482
1483 // Update old space string references.
1484 if (external_string_table_.old_space_strings_.length() > 0) {
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001485 Object** start = &external_string_table_.old_space_strings_[0];
1486 Object** end = start + external_string_table_.old_space_strings_.length();
1487 for (Object** p = start; p < end; ++p) *p = updater_func(this, p);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001488 }
1489
1490 UpdateNewSpaceReferencesInExternalStringTable(updater_func);
1491}
1492
1493
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001494static Object* ProcessFunctionWeakReferences(Heap* heap,
1495 Object* function,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001496 WeakObjectRetainer* retainer,
1497 bool record_slots) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001498 Object* undefined = heap->undefined_value();
1499 Object* head = undefined;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001500 JSFunction* tail = NULL;
1501 Object* candidate = function;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001502 while (candidate != undefined) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001503 // Check whether to keep the candidate in the list.
1504 JSFunction* candidate_function = reinterpret_cast<JSFunction*>(candidate);
1505 Object* retain = retainer->RetainAs(candidate);
1506 if (retain != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001507 if (head == undefined) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001508 // First element in the list.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001509 head = retain;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001510 } else {
1511 // Subsequent elements in the list.
1512 ASSERT(tail != NULL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001513 tail->set_next_function_link(retain);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001514 if (record_slots) {
1515 Object** next_function =
1516 HeapObject::RawField(tail, JSFunction::kNextFunctionLinkOffset);
1517 heap->mark_compact_collector()->RecordSlot(
1518 next_function, next_function, retain);
1519 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001520 }
1521 // Retained function is new tail.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001522 candidate_function = reinterpret_cast<JSFunction*>(retain);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001523 tail = candidate_function;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001524
1525 ASSERT(retain->IsUndefined() || retain->IsJSFunction());
1526
1527 if (retain == undefined) break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001528 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001529
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001530 // Move to next element in the list.
1531 candidate = candidate_function->next_function_link();
1532 }
1533
1534 // Terminate the list if there is one or more elements.
1535 if (tail != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001536 tail->set_next_function_link(undefined);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001537 }
1538
1539 return head;
1540}
1541
1542
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001543void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001544 Object* undefined = undefined_value();
1545 Object* head = undefined;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001546 Context* tail = NULL;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001547 Object* candidate = native_contexts_list_;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001548
1549 // We don't record weak slots during marking or scavenges.
1550 // Instead we do it once when we complete mark-compact cycle.
1551 // Note that write barrier has no effect if we are already in the middle of
1552 // compacting mark-sweep cycle and we have to record slots manually.
1553 bool record_slots =
1554 gc_state() == MARK_COMPACT &&
1555 mark_compact_collector()->is_compacting();
1556
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001557 while (candidate != undefined) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001558 // Check whether to keep the candidate in the list.
1559 Context* candidate_context = reinterpret_cast<Context*>(candidate);
1560 Object* retain = retainer->RetainAs(candidate);
1561 if (retain != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001562 if (head == undefined) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001563 // First element in the list.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001564 head = retain;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001565 } else {
1566 // Subsequent elements in the list.
1567 ASSERT(tail != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001568 tail->set_unchecked(this,
1569 Context::NEXT_CONTEXT_LINK,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001570 retain,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001571 UPDATE_WRITE_BARRIER);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001572
1573 if (record_slots) {
1574 Object** next_context =
1575 HeapObject::RawField(
1576 tail, FixedArray::SizeFor(Context::NEXT_CONTEXT_LINK));
1577 mark_compact_collector()->RecordSlot(
1578 next_context, next_context, retain);
1579 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001580 }
1581 // Retained context is new tail.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001582 candidate_context = reinterpret_cast<Context*>(retain);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001583 tail = candidate_context;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001584
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001585 if (retain == undefined) break;
1586
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001587 // Process the weak list of optimized functions for the context.
1588 Object* function_list_head =
1589 ProcessFunctionWeakReferences(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001590 this,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001591 candidate_context->get(Context::OPTIMIZED_FUNCTIONS_LIST),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001592 retainer,
1593 record_slots);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001594 candidate_context->set_unchecked(this,
1595 Context::OPTIMIZED_FUNCTIONS_LIST,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001596 function_list_head,
1597 UPDATE_WRITE_BARRIER);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001598 if (record_slots) {
1599 Object** optimized_functions =
1600 HeapObject::RawField(
1601 tail, FixedArray::SizeFor(Context::OPTIMIZED_FUNCTIONS_LIST));
1602 mark_compact_collector()->RecordSlot(
1603 optimized_functions, optimized_functions, function_list_head);
1604 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001605 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001606
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001607 // Move to next element in the list.
1608 candidate = candidate_context->get(Context::NEXT_CONTEXT_LINK);
1609 }
1610
1611 // Terminate the list if there is one or more elements.
1612 if (tail != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001613 tail->set_unchecked(this,
1614 Context::NEXT_CONTEXT_LINK,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001615 Heap::undefined_value(),
1616 UPDATE_WRITE_BARRIER);
1617 }
1618
1619 // Update the head of the list of contexts.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001620 native_contexts_list_ = head;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001621}
1622
1623
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001624void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) {
1625 AssertNoAllocation no_allocation;
1626
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001627 // Both the external string table and the symbol table may contain
1628 // external strings, but neither lists them exhaustively, nor is the
1629 // intersection set empty. Therefore we iterate over the external string
1630 // table first, ignoring symbols, and then over the symbol table.
1631
1632 class ExternalStringTableVisitorAdapter : public ObjectVisitor {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001633 public:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001634 explicit ExternalStringTableVisitorAdapter(
1635 v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001636 virtual void VisitPointers(Object** start, Object** end) {
1637 for (Object** p = start; p < end; p++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001638 // Visit non-symbol external strings,
1639 // since symbols are listed in the symbol table.
1640 if (!(*p)->IsSymbol()) {
1641 ASSERT((*p)->IsExternalString());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001642 visitor_->VisitExternalString(Utils::ToLocal(
1643 Handle<String>(String::cast(*p))));
1644 }
1645 }
1646 }
1647 private:
1648 v8::ExternalResourceVisitor* visitor_;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001649 } external_string_table_visitor(visitor);
1650
1651 external_string_table_.Iterate(&external_string_table_visitor);
1652
1653 class SymbolTableVisitorAdapter : public ObjectVisitor {
1654 public:
1655 explicit SymbolTableVisitorAdapter(
1656 v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
1657 virtual void VisitPointers(Object** start, Object** end) {
1658 for (Object** p = start; p < end; p++) {
1659 if ((*p)->IsExternalString()) {
1660 ASSERT((*p)->IsSymbol());
1661 visitor_->VisitExternalString(Utils::ToLocal(
1662 Handle<String>(String::cast(*p))));
1663 }
1664 }
1665 }
1666 private:
1667 v8::ExternalResourceVisitor* visitor_;
1668 } symbol_table_visitor(visitor);
1669
1670 symbol_table()->IterateElements(&symbol_table_visitor);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001671}
1672
1673
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001674class NewSpaceScavenger : public StaticNewSpaceVisitor<NewSpaceScavenger> {
1675 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001676 static inline void VisitPointer(Heap* heap, Object** p) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001677 Object* object = *p;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001678 if (!heap->InNewSpace(object)) return;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001679 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
1680 reinterpret_cast<HeapObject*>(object));
1681 }
1682};
1683
1684
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001685Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
1686 Address new_space_front) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001687 do {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001688 SemiSpace::AssertValidRange(new_space_front, new_space_.top());
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001689 // The addresses new_space_front and new_space_.top() define a
1690 // queue of unprocessed copied objects. Process them until the
1691 // queue is empty.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001692 while (new_space_front != new_space_.top()) {
1693 if (!NewSpacePage::IsAtEnd(new_space_front)) {
1694 HeapObject* object = HeapObject::FromAddress(new_space_front);
1695 new_space_front +=
1696 NewSpaceScavenger::IterateBody(object->map(), object);
1697 } else {
1698 new_space_front =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001699 NewSpacePage::FromLimit(new_space_front)->next_page()->area_start();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001700 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001701 }
1702
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001703 // Promote and process all the to-be-promoted objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001704 {
1705 StoreBufferRebuildScope scope(this,
1706 store_buffer(),
1707 &ScavengeStoreBufferCallback);
1708 while (!promotion_queue()->is_empty()) {
1709 HeapObject* target;
1710 int size;
1711 promotion_queue()->remove(&target, &size);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001712
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001713 // Promoted object might be already partially visited
1714 // during old space pointer iteration. Thus we search specificly
1715 // for pointers to from semispace instead of looking for pointers
1716 // to new space.
1717 ASSERT(!target->IsMap());
1718 IterateAndMarkPointersToFromSpace(target->address(),
1719 target->address() + size,
1720 &ScavengeObject);
1721 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001722 }
1723
1724 // Take another spin if there are now unswept objects in new space
1725 // (there are currently no more unswept promoted objects).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001726 } while (new_space_front != new_space_.top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001727
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001728 return new_space_front;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001729}
1730
1731
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001732STATIC_ASSERT((FixedDoubleArray::kHeaderSize & kDoubleAlignmentMask) == 0);
1733
1734
1735INLINE(static HeapObject* EnsureDoubleAligned(Heap* heap,
1736 HeapObject* object,
1737 int size));
1738
1739static HeapObject* EnsureDoubleAligned(Heap* heap,
1740 HeapObject* object,
1741 int size) {
1742 if ((OffsetFrom(object->address()) & kDoubleAlignmentMask) != 0) {
1743 heap->CreateFillerObjectAt(object->address(), kPointerSize);
1744 return HeapObject::FromAddress(object->address() + kPointerSize);
1745 } else {
1746 heap->CreateFillerObjectAt(object->address() + size - kPointerSize,
1747 kPointerSize);
1748 return object;
1749 }
1750}
1751
1752
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001753enum LoggingAndProfiling {
1754 LOGGING_AND_PROFILING_ENABLED,
1755 LOGGING_AND_PROFILING_DISABLED
1756};
1757
1758
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001759enum MarksHandling { TRANSFER_MARKS, IGNORE_MARKS };
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001760
1761
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001762template<MarksHandling marks_handling,
1763 LoggingAndProfiling logging_and_profiling_mode>
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001764class ScavengingVisitor : public StaticVisitorBase {
1765 public:
1766 static void Initialize() {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001767 table_.Register(kVisitSeqOneByteString, &EvacuateSeqOneByteString);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001768 table_.Register(kVisitSeqTwoByteString, &EvacuateSeqTwoByteString);
1769 table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate);
1770 table_.Register(kVisitByteArray, &EvacuateByteArray);
1771 table_.Register(kVisitFixedArray, &EvacuateFixedArray);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001772 table_.Register(kVisitFixedDoubleArray, &EvacuateFixedDoubleArray);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001773
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001774 table_.Register(kVisitNativeContext,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001775 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001776 template VisitSpecialized<Context::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001777
1778 table_.Register(kVisitConsString,
1779 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001780 template VisitSpecialized<ConsString::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001781
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001782 table_.Register(kVisitSlicedString,
1783 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1784 template VisitSpecialized<SlicedString::kSize>);
1785
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001786 table_.Register(kVisitSharedFunctionInfo,
1787 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001788 template VisitSpecialized<SharedFunctionInfo::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001789
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001790 table_.Register(kVisitJSWeakMap,
1791 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1792 Visit);
1793
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001794 table_.Register(kVisitJSRegExp,
1795 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1796 Visit);
1797
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001798 if (marks_handling == IGNORE_MARKS) {
1799 table_.Register(kVisitJSFunction,
1800 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1801 template VisitSpecialized<JSFunction::kSize>);
1802 } else {
1803 table_.Register(kVisitJSFunction, &EvacuateJSFunction);
1804 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001805
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001806 table_.RegisterSpecializations<ObjectEvacuationStrategy<DATA_OBJECT>,
1807 kVisitDataObject,
1808 kVisitDataObjectGeneric>();
1809
1810 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>,
1811 kVisitJSObject,
1812 kVisitJSObjectGeneric>();
1813
1814 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>,
1815 kVisitStruct,
1816 kVisitStructGeneric>();
1817 }
1818
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001819 static VisitorDispatchTable<ScavengingCallback>* GetTable() {
1820 return &table_;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001821 }
1822
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001823 private:
1824 enum ObjectContents { DATA_OBJECT, POINTER_OBJECT };
1825 enum SizeRestriction { SMALL, UNKNOWN_SIZE };
1826
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001827 static void RecordCopiedObject(Heap* heap, HeapObject* obj) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001828 bool should_record = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001829#ifdef DEBUG
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001830 should_record = FLAG_heap_stats;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001831#endif
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001832 should_record = should_record || FLAG_log_gc;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001833 if (should_record) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001834 if (heap->new_space()->Contains(obj)) {
1835 heap->new_space()->RecordAllocation(obj);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001836 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001837 heap->new_space()->RecordPromotion(obj);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001838 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001839 }
1840 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001841
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001842 // Helper function used by CopyObject to copy a source object to an
1843 // allocated target object and update the forwarding pointer in the source
1844 // object. Returns the target object.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001845 INLINE(static void MigrateObject(Heap* heap,
1846 HeapObject* source,
1847 HeapObject* target,
1848 int size)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001849 // Copy the content of source to target.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001850 heap->CopyBlock(target->address(), source->address(), size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001851
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001852 // Set the forwarding address.
1853 source->set_map_word(MapWord::FromForwardingAddress(target));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001854
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001855 if (logging_and_profiling_mode == LOGGING_AND_PROFILING_ENABLED) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001856 // Update NewSpace stats if necessary.
1857 RecordCopiedObject(heap, target);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001858 HEAP_PROFILE(heap, ObjectMoveEvent(source->address(), target->address()));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001859 Isolate* isolate = heap->isolate();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001860 if (isolate->logger()->is_logging_code_events() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001861 CpuProfiler::is_profiling(isolate)) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001862 if (target->IsSharedFunctionInfo()) {
1863 PROFILE(isolate, SharedFunctionInfoMoveEvent(
1864 source->address(), target->address()));
1865 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001866 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001867 }
1868
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001869 if (marks_handling == TRANSFER_MARKS) {
1870 if (Marking::TransferColor(source, target)) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001871 MemoryChunk::IncrementLiveBytesFromGC(target->address(), size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001872 }
1873 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001874 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001875
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001876
1877 template<ObjectContents object_contents,
1878 SizeRestriction size_restriction,
1879 int alignment>
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001880 static inline void EvacuateObject(Map* map,
1881 HeapObject** slot,
1882 HeapObject* object,
1883 int object_size) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001884 SLOW_ASSERT((size_restriction != SMALL) ||
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001885 (object_size <= Page::kMaxNonCodeHeapObjectSize));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001886 SLOW_ASSERT(object->Size() == object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001887
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001888 int allocation_size = object_size;
1889 if (alignment != kObjectAlignment) {
1890 ASSERT(alignment == kDoubleAlignment);
1891 allocation_size += kPointerSize;
1892 }
1893
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001894 Heap* heap = map->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001895 if (heap->ShouldBePromoted(object->address(), object_size)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001896 MaybeObject* maybe_result;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001897
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001898 if ((size_restriction != SMALL) &&
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001899 (allocation_size > Page::kMaxNonCodeHeapObjectSize)) {
1900 maybe_result = heap->lo_space()->AllocateRaw(allocation_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001901 NOT_EXECUTABLE);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001902 } else {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001903 if (object_contents == DATA_OBJECT) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001904 maybe_result = heap->old_data_space()->AllocateRaw(allocation_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001905 } else {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001906 maybe_result =
1907 heap->old_pointer_space()->AllocateRaw(allocation_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001908 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001909 }
1910
lrn@chromium.org303ada72010-10-27 09:33:13 +00001911 Object* result = NULL; // Initialization to please compiler.
1912 if (maybe_result->ToObject(&result)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001913 HeapObject* target = HeapObject::cast(result);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001914
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001915 if (alignment != kObjectAlignment) {
1916 target = EnsureDoubleAligned(heap, target, allocation_size);
1917 }
1918
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001919 // Order is important: slot might be inside of the target if target
1920 // was allocated over a dead object and slot comes from the store
1921 // buffer.
1922 *slot = target;
1923 MigrateObject(heap, object, target, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001924
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001925 if (object_contents == POINTER_OBJECT) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001926 if (map->instance_type() == JS_FUNCTION_TYPE) {
1927 heap->promotion_queue()->insert(
1928 target, JSFunction::kNonWeakFieldsEndOffset);
1929 } else {
1930 heap->promotion_queue()->insert(target, object_size);
1931 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001932 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001933
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001934 heap->tracer()->increment_promoted_objects_size(object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001935 return;
1936 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001937 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001938 MaybeObject* allocation = heap->new_space()->AllocateRaw(allocation_size);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001939 heap->promotion_queue()->SetNewLimit(heap->new_space()->top());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001940 Object* result = allocation->ToObjectUnchecked();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001941 HeapObject* target = HeapObject::cast(result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001942
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001943 if (alignment != kObjectAlignment) {
1944 target = EnsureDoubleAligned(heap, target, allocation_size);
1945 }
1946
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001947 // Order is important: slot might be inside of the target if target
1948 // was allocated over a dead object and slot comes from the store
1949 // buffer.
1950 *slot = target;
1951 MigrateObject(heap, object, target, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001952 return;
1953 }
1954
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001955
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001956 static inline void EvacuateJSFunction(Map* map,
1957 HeapObject** slot,
1958 HeapObject* object) {
1959 ObjectEvacuationStrategy<POINTER_OBJECT>::
1960 template VisitSpecialized<JSFunction::kSize>(map, slot, object);
1961
1962 HeapObject* target = *slot;
1963 MarkBit mark_bit = Marking::MarkBitFrom(target);
1964 if (Marking::IsBlack(mark_bit)) {
1965 // This object is black and it might not be rescanned by marker.
1966 // We should explicitly record code entry slot for compaction because
1967 // promotion queue processing (IterateAndMarkPointersToFromSpace) will
1968 // miss it as it is not HeapObject-tagged.
1969 Address code_entry_slot =
1970 target->address() + JSFunction::kCodeEntryOffset;
1971 Code* code = Code::cast(Code::GetObjectFromEntryAddress(code_entry_slot));
1972 map->GetHeap()->mark_compact_collector()->
1973 RecordCodeEntrySlot(code_entry_slot, code);
1974 }
1975 }
1976
1977
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001978 static inline void EvacuateFixedArray(Map* map,
1979 HeapObject** slot,
1980 HeapObject* object) {
1981 int object_size = FixedArray::BodyDescriptor::SizeOf(map, object);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001982 EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(map,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001983 slot,
1984 object,
1985 object_size);
1986 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001987
1988
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001989 static inline void EvacuateFixedDoubleArray(Map* map,
1990 HeapObject** slot,
1991 HeapObject* object) {
1992 int length = reinterpret_cast<FixedDoubleArray*>(object)->length();
1993 int object_size = FixedDoubleArray::SizeFor(length);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001994 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kDoubleAlignment>(
1995 map,
1996 slot,
1997 object,
1998 object_size);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001999 }
2000
2001
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002002 static inline void EvacuateByteArray(Map* map,
2003 HeapObject** slot,
2004 HeapObject* object) {
2005 int object_size = reinterpret_cast<ByteArray*>(object)->ByteArraySize();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002006 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
2007 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002008 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002009
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002010
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002011 static inline void EvacuateSeqOneByteString(Map* map,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002012 HeapObject** slot,
2013 HeapObject* object) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002014 int object_size = SeqOneByteString::cast(object)->
2015 SeqOneByteStringSize(map->instance_type());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002016 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
2017 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002018 }
2019
2020
2021 static inline void EvacuateSeqTwoByteString(Map* map,
2022 HeapObject** slot,
2023 HeapObject* object) {
2024 int object_size = SeqTwoByteString::cast(object)->
2025 SeqTwoByteStringSize(map->instance_type());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002026 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
2027 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002028 }
2029
2030
2031 static inline bool IsShortcutCandidate(int type) {
2032 return ((type & kShortcutTypeMask) == kShortcutTypeTag);
2033 }
2034
2035 static inline void EvacuateShortcutCandidate(Map* map,
2036 HeapObject** slot,
2037 HeapObject* object) {
2038 ASSERT(IsShortcutCandidate(map->instance_type()));
2039
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002040 Heap* heap = map->GetHeap();
2041
2042 if (marks_handling == IGNORE_MARKS &&
2043 ConsString::cast(object)->unchecked_second() ==
2044 heap->empty_string()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002045 HeapObject* first =
2046 HeapObject::cast(ConsString::cast(object)->unchecked_first());
2047
2048 *slot = first;
2049
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002050 if (!heap->InNewSpace(first)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002051 object->set_map_word(MapWord::FromForwardingAddress(first));
2052 return;
2053 }
2054
2055 MapWord first_word = first->map_word();
2056 if (first_word.IsForwardingAddress()) {
2057 HeapObject* target = first_word.ToForwardingAddress();
2058
2059 *slot = target;
2060 object->set_map_word(MapWord::FromForwardingAddress(target));
2061 return;
2062 }
2063
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002064 heap->DoScavengeObject(first->map(), slot, first);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002065 object->set_map_word(MapWord::FromForwardingAddress(*slot));
2066 return;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002067 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002068
2069 int object_size = ConsString::kSize;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002070 EvacuateObject<POINTER_OBJECT, SMALL, kObjectAlignment>(
2071 map, slot, object, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002072 }
2073
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002074 template<ObjectContents object_contents>
2075 class ObjectEvacuationStrategy {
2076 public:
2077 template<int object_size>
2078 static inline void VisitSpecialized(Map* map,
2079 HeapObject** slot,
2080 HeapObject* object) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002081 EvacuateObject<object_contents, SMALL, kObjectAlignment>(
2082 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002083 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002084
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002085 static inline void Visit(Map* map,
2086 HeapObject** slot,
2087 HeapObject* object) {
2088 int object_size = map->instance_size();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002089 EvacuateObject<object_contents, SMALL, kObjectAlignment>(
2090 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002091 }
2092 };
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002093
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002094 static VisitorDispatchTable<ScavengingCallback> table_;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002095};
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002096
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002097
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002098template<MarksHandling marks_handling,
2099 LoggingAndProfiling logging_and_profiling_mode>
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002100VisitorDispatchTable<ScavengingCallback>
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002101 ScavengingVisitor<marks_handling, logging_and_profiling_mode>::table_;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002102
2103
2104static void InitializeScavengingVisitorsTables() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002105 ScavengingVisitor<TRANSFER_MARKS,
2106 LOGGING_AND_PROFILING_DISABLED>::Initialize();
2107 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_DISABLED>::Initialize();
2108 ScavengingVisitor<TRANSFER_MARKS,
2109 LOGGING_AND_PROFILING_ENABLED>::Initialize();
2110 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_ENABLED>::Initialize();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002111}
2112
2113
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002114void Heap::SelectScavengingVisitorsTable() {
2115 bool logging_and_profiling =
2116 isolate()->logger()->is_logging() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002117 CpuProfiler::is_profiling(isolate()) ||
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002118 (isolate()->heap_profiler() != NULL &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002119 isolate()->heap_profiler()->is_profiling());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002120
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002121 if (!incremental_marking()->IsMarking()) {
2122 if (!logging_and_profiling) {
2123 scavenging_visitors_table_.CopyFrom(
2124 ScavengingVisitor<IGNORE_MARKS,
2125 LOGGING_AND_PROFILING_DISABLED>::GetTable());
2126 } else {
2127 scavenging_visitors_table_.CopyFrom(
2128 ScavengingVisitor<IGNORE_MARKS,
2129 LOGGING_AND_PROFILING_ENABLED>::GetTable());
2130 }
2131 } else {
2132 if (!logging_and_profiling) {
2133 scavenging_visitors_table_.CopyFrom(
2134 ScavengingVisitor<TRANSFER_MARKS,
2135 LOGGING_AND_PROFILING_DISABLED>::GetTable());
2136 } else {
2137 scavenging_visitors_table_.CopyFrom(
2138 ScavengingVisitor<TRANSFER_MARKS,
2139 LOGGING_AND_PROFILING_ENABLED>::GetTable());
2140 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002141
2142 if (incremental_marking()->IsCompacting()) {
2143 // When compacting forbid short-circuiting of cons-strings.
2144 // Scavenging code relies on the fact that new space object
2145 // can't be evacuated into evacuation candidate but
2146 // short-circuiting violates this assumption.
2147 scavenging_visitors_table_.Register(
2148 StaticVisitorBase::kVisitShortcutCandidate,
2149 scavenging_visitors_table_.GetVisitorById(
2150 StaticVisitorBase::kVisitConsString));
2151 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002152 }
2153}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002154
2155
2156void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002157 SLOW_ASSERT(HEAP->InFromSpace(object));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002158 MapWord first_word = object->map_word();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002159 SLOW_ASSERT(!first_word.IsForwardingAddress());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002160 Map* map = first_word.ToMap();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002161 map->GetHeap()->DoScavengeObject(map, p, object);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002162}
2163
2164
lrn@chromium.org303ada72010-10-27 09:33:13 +00002165MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type,
2166 int instance_size) {
2167 Object* result;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002168 MaybeObject* maybe_result = AllocateRawMap();
2169 if (!maybe_result->ToObject(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002170
2171 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002172 reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173 reinterpret_cast<Map*>(result)->set_instance_type(instance_type);
2174 reinterpret_cast<Map*>(result)->set_instance_size(instance_size);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002175 reinterpret_cast<Map*>(result)->set_visitor_id(
2176 StaticVisitorBase::GetVisitorId(instance_type, instance_size));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002177 reinterpret_cast<Map*>(result)->set_inobject_properties(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002178 reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002179 reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002180 reinterpret_cast<Map*>(result)->set_bit_field(0);
2181 reinterpret_cast<Map*>(result)->set_bit_field2(0);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002182 int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) |
2183 Map::OwnsDescriptors::encode(true);
2184 reinterpret_cast<Map*>(result)->set_bit_field3(bit_field3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002185 return result;
2186}
2187
2188
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002189MaybeObject* Heap::AllocateMap(InstanceType instance_type,
2190 int instance_size,
2191 ElementsKind elements_kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002192 Object* result;
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002193 MaybeObject* maybe_result = AllocateRawMap();
2194 if (!maybe_result->To(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002195
2196 Map* map = reinterpret_cast<Map*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002197 map->set_map_no_write_barrier(meta_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002198 map->set_instance_type(instance_type);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002199 map->set_visitor_id(
2200 StaticVisitorBase::GetVisitorId(instance_type, instance_size));
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002201 map->set_prototype(null_value(), SKIP_WRITE_BARRIER);
2202 map->set_constructor(null_value(), SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002203 map->set_instance_size(instance_size);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002204 map->set_inobject_properties(0);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002205 map->set_pre_allocated_property_fields(0);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002206 map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002207 map->init_back_pointer(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002208 map->set_unused_property_fields(0);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002209 map->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002210 map->set_bit_field(0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002211 map->set_bit_field2(1 << Map::kIsExtensible);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002212 int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) |
2213 Map::OwnsDescriptors::encode(true);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002214 map->set_bit_field3(bit_field3);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002215 map->set_elements_kind(elements_kind);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002216
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002217 return map;
2218}
2219
2220
lrn@chromium.org303ada72010-10-27 09:33:13 +00002221MaybeObject* Heap::AllocateCodeCache() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002222 CodeCache* code_cache;
2223 { MaybeObject* maybe_code_cache = AllocateStruct(CODE_CACHE_TYPE);
2224 if (!maybe_code_cache->To(&code_cache)) return maybe_code_cache;
lrn@chromium.org303ada72010-10-27 09:33:13 +00002225 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002226 code_cache->set_default_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
2227 code_cache->set_normal_type_cache(undefined_value(), SKIP_WRITE_BARRIER);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002228 return code_cache;
2229}
2230
2231
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002232MaybeObject* Heap::AllocatePolymorphicCodeCache() {
2233 return AllocateStruct(POLYMORPHIC_CODE_CACHE_TYPE);
2234}
2235
2236
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002237MaybeObject* Heap::AllocateAccessorPair() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002238 AccessorPair* accessors;
2239 { MaybeObject* maybe_accessors = AllocateStruct(ACCESSOR_PAIR_TYPE);
2240 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002241 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002242 accessors->set_getter(the_hole_value(), SKIP_WRITE_BARRIER);
2243 accessors->set_setter(the_hole_value(), SKIP_WRITE_BARRIER);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002244 return accessors;
2245}
2246
2247
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002248MaybeObject* Heap::AllocateTypeFeedbackInfo() {
2249 TypeFeedbackInfo* info;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002250 { MaybeObject* maybe_info = AllocateStruct(TYPE_FEEDBACK_INFO_TYPE);
2251 if (!maybe_info->To(&info)) return maybe_info;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002252 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002253 info->initialize_storage();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002254 info->set_type_feedback_cells(TypeFeedbackCells::cast(empty_fixed_array()),
2255 SKIP_WRITE_BARRIER);
2256 return info;
2257}
2258
2259
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002260MaybeObject* Heap::AllocateAliasedArgumentsEntry(int aliased_context_slot) {
2261 AliasedArgumentsEntry* entry;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002262 { MaybeObject* maybe_entry = AllocateStruct(ALIASED_ARGUMENTS_ENTRY_TYPE);
2263 if (!maybe_entry->To(&entry)) return maybe_entry;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002264 }
2265 entry->set_aliased_context_slot(aliased_context_slot);
2266 return entry;
2267}
2268
2269
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002270const Heap::StringTypeTable Heap::string_type_table[] = {
2271#define STRING_TYPE_ELEMENT(type, size, name, camel_name) \
2272 {type, size, k##camel_name##MapRootIndex},
2273 STRING_TYPE_LIST(STRING_TYPE_ELEMENT)
2274#undef STRING_TYPE_ELEMENT
2275};
2276
2277
2278const Heap::ConstantSymbolTable Heap::constant_symbol_table[] = {
2279#define CONSTANT_SYMBOL_ELEMENT(name, contents) \
2280 {contents, k##name##RootIndex},
2281 SYMBOL_LIST(CONSTANT_SYMBOL_ELEMENT)
2282#undef CONSTANT_SYMBOL_ELEMENT
2283};
2284
2285
2286const Heap::StructTable Heap::struct_table[] = {
2287#define STRUCT_TABLE_ELEMENT(NAME, Name, name) \
2288 { NAME##_TYPE, Name::kSize, k##Name##MapRootIndex },
2289 STRUCT_LIST(STRUCT_TABLE_ELEMENT)
2290#undef STRUCT_TABLE_ELEMENT
2291};
2292
2293
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002294bool Heap::CreateInitialMaps() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002295 Object* obj;
2296 { MaybeObject* maybe_obj = AllocatePartialMap(MAP_TYPE, Map::kSize);
2297 if (!maybe_obj->ToObject(&obj)) return false;
2298 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002299 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002300 Map* new_meta_map = reinterpret_cast<Map*>(obj);
2301 set_meta_map(new_meta_map);
2302 new_meta_map->set_map(new_meta_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002303
lrn@chromium.org303ada72010-10-27 09:33:13 +00002304 { MaybeObject* maybe_obj =
2305 AllocatePartialMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2306 if (!maybe_obj->ToObject(&obj)) return false;
2307 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002308 set_fixed_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002309
lrn@chromium.org303ada72010-10-27 09:33:13 +00002310 { MaybeObject* maybe_obj = AllocatePartialMap(ODDBALL_TYPE, Oddball::kSize);
2311 if (!maybe_obj->ToObject(&obj)) return false;
2312 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002313 set_oddball_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002314
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002315 // Allocate the empty array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002316 { MaybeObject* maybe_obj = AllocateEmptyFixedArray();
2317 if (!maybe_obj->ToObject(&obj)) return false;
2318 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002319 set_empty_fixed_array(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002320
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002321 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002322 if (!maybe_obj->ToObject(&obj)) return false;
2323 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002324 set_null_value(Oddball::cast(obj));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002325 Oddball::cast(obj)->set_kind(Oddball::kNull);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002326
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002327 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE);
2328 if (!maybe_obj->ToObject(&obj)) return false;
2329 }
2330 set_undefined_value(Oddball::cast(obj));
2331 Oddball::cast(obj)->set_kind(Oddball::kUndefined);
2332 ASSERT(!InNewSpace(undefined_value()));
2333
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002334 // Allocate the empty descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002335 { MaybeObject* maybe_obj = AllocateEmptyFixedArray();
2336 if (!maybe_obj->ToObject(&obj)) return false;
2337 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002338 set_empty_descriptor_array(DescriptorArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002339
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002340 // Fix the instance_descriptors for the existing maps.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002341 meta_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002342 meta_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002343 meta_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002344
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002345 fixed_array_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002346 fixed_array_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002347 fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002348
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002349 oddball_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002350 oddball_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002351 oddball_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002352
2353 // Fix prototype object for existing maps.
2354 meta_map()->set_prototype(null_value());
2355 meta_map()->set_constructor(null_value());
2356
2357 fixed_array_map()->set_prototype(null_value());
2358 fixed_array_map()->set_constructor(null_value());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002359
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002360 oddball_map()->set_prototype(null_value());
2361 oddball_map()->set_constructor(null_value());
2362
lrn@chromium.org303ada72010-10-27 09:33:13 +00002363 { MaybeObject* maybe_obj =
2364 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2365 if (!maybe_obj->ToObject(&obj)) return false;
2366 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002367 set_fixed_cow_array_map(Map::cast(obj));
2368 ASSERT(fixed_array_map() != fixed_cow_array_map());
2369
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002370 { MaybeObject* maybe_obj =
2371 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2372 if (!maybe_obj->ToObject(&obj)) return false;
2373 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002374 set_scope_info_map(Map::cast(obj));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002375
lrn@chromium.org303ada72010-10-27 09:33:13 +00002376 { MaybeObject* maybe_obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
2377 if (!maybe_obj->ToObject(&obj)) return false;
2378 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002379 set_heap_number_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002380
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002381 { MaybeObject* maybe_obj = AllocateMap(FOREIGN_TYPE, Foreign::kSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002382 if (!maybe_obj->ToObject(&obj)) return false;
2383 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002384 set_foreign_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002385
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002386 for (unsigned i = 0; i < ARRAY_SIZE(string_type_table); i++) {
2387 const StringTypeTable& entry = string_type_table[i];
lrn@chromium.org303ada72010-10-27 09:33:13 +00002388 { MaybeObject* maybe_obj = AllocateMap(entry.type, entry.size);
2389 if (!maybe_obj->ToObject(&obj)) return false;
2390 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002391 roots_[entry.index] = Map::cast(obj);
2392 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002393
lrn@chromium.org303ada72010-10-27 09:33:13 +00002394 { MaybeObject* maybe_obj = AllocateMap(STRING_TYPE, kVariableSizeSentinel);
2395 if (!maybe_obj->ToObject(&obj)) return false;
2396 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002397 set_undetectable_string_map(Map::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002398 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002399
lrn@chromium.org303ada72010-10-27 09:33:13 +00002400 { MaybeObject* maybe_obj =
2401 AllocateMap(ASCII_STRING_TYPE, kVariableSizeSentinel);
2402 if (!maybe_obj->ToObject(&obj)) return false;
2403 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002404 set_undetectable_ascii_string_map(Map::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002405 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002406
lrn@chromium.org303ada72010-10-27 09:33:13 +00002407 { MaybeObject* maybe_obj =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002408 AllocateMap(FIXED_DOUBLE_ARRAY_TYPE, kVariableSizeSentinel);
2409 if (!maybe_obj->ToObject(&obj)) return false;
2410 }
2411 set_fixed_double_array_map(Map::cast(obj));
2412
2413 { MaybeObject* maybe_obj =
lrn@chromium.org303ada72010-10-27 09:33:13 +00002414 AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel);
2415 if (!maybe_obj->ToObject(&obj)) return false;
2416 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002417 set_byte_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002418
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002419 { MaybeObject* maybe_obj =
2420 AllocateMap(FREE_SPACE_TYPE, kVariableSizeSentinel);
2421 if (!maybe_obj->ToObject(&obj)) return false;
2422 }
2423 set_free_space_map(Map::cast(obj));
2424
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002425 { MaybeObject* maybe_obj = AllocateByteArray(0, TENURED);
2426 if (!maybe_obj->ToObject(&obj)) return false;
2427 }
2428 set_empty_byte_array(ByteArray::cast(obj));
2429
lrn@chromium.org303ada72010-10-27 09:33:13 +00002430 { MaybeObject* maybe_obj =
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002431 AllocateMap(EXTERNAL_PIXEL_ARRAY_TYPE, ExternalArray::kAlignedSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002432 if (!maybe_obj->ToObject(&obj)) return false;
2433 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002434 set_external_pixel_array_map(Map::cast(obj));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002435
lrn@chromium.org303ada72010-10-27 09:33:13 +00002436 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_BYTE_ARRAY_TYPE,
2437 ExternalArray::kAlignedSize);
2438 if (!maybe_obj->ToObject(&obj)) return false;
2439 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002440 set_external_byte_array_map(Map::cast(obj));
2441
lrn@chromium.org303ada72010-10-27 09:33:13 +00002442 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE,
2443 ExternalArray::kAlignedSize);
2444 if (!maybe_obj->ToObject(&obj)) return false;
2445 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002446 set_external_unsigned_byte_array_map(Map::cast(obj));
2447
lrn@chromium.org303ada72010-10-27 09:33:13 +00002448 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_SHORT_ARRAY_TYPE,
2449 ExternalArray::kAlignedSize);
2450 if (!maybe_obj->ToObject(&obj)) return false;
2451 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002452 set_external_short_array_map(Map::cast(obj));
2453
lrn@chromium.org303ada72010-10-27 09:33:13 +00002454 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE,
2455 ExternalArray::kAlignedSize);
2456 if (!maybe_obj->ToObject(&obj)) return false;
2457 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002458 set_external_unsigned_short_array_map(Map::cast(obj));
2459
lrn@chromium.org303ada72010-10-27 09:33:13 +00002460 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_INT_ARRAY_TYPE,
2461 ExternalArray::kAlignedSize);
2462 if (!maybe_obj->ToObject(&obj)) return false;
2463 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002464 set_external_int_array_map(Map::cast(obj));
2465
lrn@chromium.org303ada72010-10-27 09:33:13 +00002466 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE,
2467 ExternalArray::kAlignedSize);
2468 if (!maybe_obj->ToObject(&obj)) return false;
2469 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002470 set_external_unsigned_int_array_map(Map::cast(obj));
2471
lrn@chromium.org303ada72010-10-27 09:33:13 +00002472 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_FLOAT_ARRAY_TYPE,
2473 ExternalArray::kAlignedSize);
2474 if (!maybe_obj->ToObject(&obj)) return false;
2475 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002476 set_external_float_array_map(Map::cast(obj));
2477
whesse@chromium.org7b260152011-06-20 15:33:18 +00002478 { MaybeObject* maybe_obj =
2479 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2480 if (!maybe_obj->ToObject(&obj)) return false;
2481 }
2482 set_non_strict_arguments_elements_map(Map::cast(obj));
2483
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002484 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_DOUBLE_ARRAY_TYPE,
2485 ExternalArray::kAlignedSize);
2486 if (!maybe_obj->ToObject(&obj)) return false;
2487 }
2488 set_external_double_array_map(Map::cast(obj));
2489
lrn@chromium.org303ada72010-10-27 09:33:13 +00002490 { MaybeObject* maybe_obj = AllocateMap(CODE_TYPE, kVariableSizeSentinel);
2491 if (!maybe_obj->ToObject(&obj)) return false;
2492 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002493 set_code_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002494
lrn@chromium.org303ada72010-10-27 09:33:13 +00002495 { MaybeObject* maybe_obj = AllocateMap(JS_GLOBAL_PROPERTY_CELL_TYPE,
2496 JSGlobalPropertyCell::kSize);
2497 if (!maybe_obj->ToObject(&obj)) return false;
2498 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002499 set_global_property_cell_map(Map::cast(obj));
2500
lrn@chromium.org303ada72010-10-27 09:33:13 +00002501 { MaybeObject* maybe_obj = AllocateMap(FILLER_TYPE, kPointerSize);
2502 if (!maybe_obj->ToObject(&obj)) return false;
2503 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002504 set_one_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002505
lrn@chromium.org303ada72010-10-27 09:33:13 +00002506 { MaybeObject* maybe_obj = AllocateMap(FILLER_TYPE, 2 * kPointerSize);
2507 if (!maybe_obj->ToObject(&obj)) return false;
2508 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002509 set_two_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002510
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002511 for (unsigned i = 0; i < ARRAY_SIZE(struct_table); i++) {
2512 const StructTable& entry = struct_table[i];
lrn@chromium.org303ada72010-10-27 09:33:13 +00002513 { MaybeObject* maybe_obj = AllocateMap(entry.type, entry.size);
2514 if (!maybe_obj->ToObject(&obj)) return false;
2515 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002516 roots_[entry.index] = Map::cast(obj);
2517 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002518
lrn@chromium.org303ada72010-10-27 09:33:13 +00002519 { MaybeObject* maybe_obj =
2520 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2521 if (!maybe_obj->ToObject(&obj)) return false;
2522 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002523 set_hash_table_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002524
lrn@chromium.org303ada72010-10-27 09:33:13 +00002525 { MaybeObject* maybe_obj =
2526 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2527 if (!maybe_obj->ToObject(&obj)) return false;
2528 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002529 set_function_context_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002530
lrn@chromium.org303ada72010-10-27 09:33:13 +00002531 { MaybeObject* maybe_obj =
2532 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2533 if (!maybe_obj->ToObject(&obj)) return false;
2534 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002535 set_catch_context_map(Map::cast(obj));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002536
lrn@chromium.org303ada72010-10-27 09:33:13 +00002537 { MaybeObject* maybe_obj =
2538 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2539 if (!maybe_obj->ToObject(&obj)) return false;
2540 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002541 set_with_context_map(Map::cast(obj));
2542
2543 { MaybeObject* maybe_obj =
2544 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2545 if (!maybe_obj->ToObject(&obj)) return false;
2546 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002547 set_block_context_map(Map::cast(obj));
2548
2549 { MaybeObject* maybe_obj =
2550 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2551 if (!maybe_obj->ToObject(&obj)) return false;
2552 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002553 set_module_context_map(Map::cast(obj));
2554
2555 { MaybeObject* maybe_obj =
2556 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2557 if (!maybe_obj->ToObject(&obj)) return false;
2558 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002559 set_global_context_map(Map::cast(obj));
2560
2561 { MaybeObject* maybe_obj =
2562 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2563 if (!maybe_obj->ToObject(&obj)) return false;
2564 }
2565 Map* native_context_map = Map::cast(obj);
2566 native_context_map->set_dictionary_map(true);
2567 native_context_map->set_visitor_id(StaticVisitorBase::kVisitNativeContext);
2568 set_native_context_map(native_context_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002569
lrn@chromium.org303ada72010-10-27 09:33:13 +00002570 { MaybeObject* maybe_obj = AllocateMap(SHARED_FUNCTION_INFO_TYPE,
2571 SharedFunctionInfo::kAlignedSize);
2572 if (!maybe_obj->ToObject(&obj)) return false;
2573 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002574 set_shared_function_info_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002575
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002576 { MaybeObject* maybe_obj = AllocateMap(JS_MESSAGE_OBJECT_TYPE,
2577 JSMessageObject::kSize);
2578 if (!maybe_obj->ToObject(&obj)) return false;
2579 }
2580 set_message_object_map(Map::cast(obj));
2581
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002582 Map* external_map;
2583 { MaybeObject* maybe_obj =
2584 AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize + kPointerSize);
2585 if (!maybe_obj->To(&external_map)) return false;
2586 }
2587 external_map->set_is_extensible(false);
2588 set_external_map(external_map);
2589
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002590 ASSERT(!InNewSpace(empty_fixed_array()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002591 return true;
2592}
2593
2594
lrn@chromium.org303ada72010-10-27 09:33:13 +00002595MaybeObject* Heap::AllocateHeapNumber(double value, PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002596 // Statically ensure that it is safe to allocate heap numbers in paged
2597 // spaces.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002598 STATIC_ASSERT(HeapNumber::kSize <= Page::kNonCodeObjectAreaSize);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002599 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002600
lrn@chromium.org303ada72010-10-27 09:33:13 +00002601 Object* result;
2602 { MaybeObject* maybe_result =
2603 AllocateRaw(HeapNumber::kSize, space, OLD_DATA_SPACE);
2604 if (!maybe_result->ToObject(&result)) return maybe_result;
2605 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002606
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002607 HeapObject::cast(result)->set_map_no_write_barrier(heap_number_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002608 HeapNumber::cast(result)->set_value(value);
2609 return result;
2610}
2611
2612
lrn@chromium.org303ada72010-10-27 09:33:13 +00002613MaybeObject* Heap::AllocateHeapNumber(double value) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002614 // Use general version, if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002615 if (always_allocate()) return AllocateHeapNumber(value, TENURED);
2616
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002617 // This version of AllocateHeapNumber is optimized for
2618 // allocation in new space.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002619 STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxNonCodeHeapObjectSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002620 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002621 Object* result;
2622 { MaybeObject* maybe_result = new_space_.AllocateRaw(HeapNumber::kSize);
2623 if (!maybe_result->ToObject(&result)) return maybe_result;
2624 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002625 HeapObject::cast(result)->set_map_no_write_barrier(heap_number_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002626 HeapNumber::cast(result)->set_value(value);
2627 return result;
2628}
2629
2630
lrn@chromium.org303ada72010-10-27 09:33:13 +00002631MaybeObject* Heap::AllocateJSGlobalPropertyCell(Object* value) {
2632 Object* result;
2633 { MaybeObject* maybe_result = AllocateRawCell();
2634 if (!maybe_result->ToObject(&result)) return maybe_result;
2635 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002636 HeapObject::cast(result)->set_map_no_write_barrier(
2637 global_property_cell_map());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002638 JSGlobalPropertyCell::cast(result)->set_value(value);
2639 return result;
2640}
2641
2642
lrn@chromium.org303ada72010-10-27 09:33:13 +00002643MaybeObject* Heap::CreateOddball(const char* to_string,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002644 Object* to_number,
2645 byte kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002646 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002647 { MaybeObject* maybe_result = Allocate(oddball_map(), OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002648 if (!maybe_result->ToObject(&result)) return maybe_result;
2649 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002650 return Oddball::cast(result)->Initialize(to_string, to_number, kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002651}
2652
2653
2654bool Heap::CreateApiObjects() {
2655 Object* obj;
2656
lrn@chromium.org303ada72010-10-27 09:33:13 +00002657 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
2658 if (!maybe_obj->ToObject(&obj)) return false;
2659 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002660 // Don't use Smi-only elements optimizations for objects with the neander
2661 // map. There are too many cases where element values are set directly with a
2662 // bottleneck to trap the Smi-only -> fast elements transition, and there
2663 // appears to be no benefit for optimize this case.
2664 Map* new_neander_map = Map::cast(obj);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002665 new_neander_map->set_elements_kind(TERMINAL_FAST_ELEMENTS_KIND);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002666 set_neander_map(new_neander_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002667
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002668 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(neander_map());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002669 if (!maybe_obj->ToObject(&obj)) return false;
2670 }
2671 Object* elements;
2672 { MaybeObject* maybe_elements = AllocateFixedArray(2);
2673 if (!maybe_elements->ToObject(&elements)) return false;
2674 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002675 FixedArray::cast(elements)->set(0, Smi::FromInt(0));
2676 JSObject::cast(obj)->set_elements(FixedArray::cast(elements));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002677 set_message_listeners(JSObject::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002678
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002679 return true;
2680}
2681
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002682
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002683void Heap::CreateJSEntryStub() {
2684 JSEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002685 set_js_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002686}
2687
2688
2689void Heap::CreateJSConstructEntryStub() {
2690 JSConstructEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002691 set_js_construct_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002692}
2693
2694
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002695void Heap::CreateFixedStubs() {
2696 // Here we create roots for fixed stubs. They are needed at GC
2697 // for cooking and uncooking (check out frames.cc).
2698 // The eliminates the need for doing dictionary lookup in the
2699 // stub cache for these stubs.
2700 HandleScope scope;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002701 // gcc-4.4 has problem generating correct code of following snippet:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002702 // { JSEntryStub stub;
2703 // js_entry_code_ = *stub.GetCode();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002704 // }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002705 // { JSConstructEntryStub stub;
2706 // js_construct_entry_code_ = *stub.GetCode();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002707 // }
2708 // To workaround the problem, make separate functions without inlining.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002709 Heap::CreateJSEntryStub();
2710 Heap::CreateJSConstructEntryStub();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002711
2712 // Create stubs that should be there, so we don't unexpectedly have to
2713 // create them if we need them during the creation of another stub.
2714 // Stub creation mixes raw pointers and handles in an unsafe manner so
2715 // we cannot create stubs while we are creating stubs.
2716 CodeStub::GenerateStubsAheadOfTime();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002717}
2718
2719
2720bool Heap::CreateInitialObjects() {
2721 Object* obj;
2722
2723 // The -0 value must be set before NumberFromDouble works.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002724 { MaybeObject* maybe_obj = AllocateHeapNumber(-0.0, TENURED);
2725 if (!maybe_obj->ToObject(&obj)) return false;
2726 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002727 set_minus_zero_value(HeapNumber::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002728 ASSERT(signbit(minus_zero_value()->Number()) != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002729
lrn@chromium.org303ada72010-10-27 09:33:13 +00002730 { MaybeObject* maybe_obj = AllocateHeapNumber(OS::nan_value(), TENURED);
2731 if (!maybe_obj->ToObject(&obj)) return false;
2732 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002733 set_nan_value(HeapNumber::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002734
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002735 { MaybeObject* maybe_obj = AllocateHeapNumber(V8_INFINITY, TENURED);
2736 if (!maybe_obj->ToObject(&obj)) return false;
2737 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002738 set_infinity_value(HeapNumber::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002739
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00002740 // The hole has not been created yet, but we want to put something
2741 // predictable in the gaps in the symbol table, so lets make that Smi zero.
2742 set_the_hole_value(reinterpret_cast<Oddball*>(Smi::FromInt(0)));
2743
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002744 // Allocate initial symbol table.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002745 { MaybeObject* maybe_obj = SymbolTable::Allocate(kInitialSymbolTableSize);
2746 if (!maybe_obj->ToObject(&obj)) return false;
2747 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002748 // Don't use set_symbol_table() due to asserts.
2749 roots_[kSymbolTableRootIndex] = obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002750
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002751 // Finish initializing oddballs after creating symboltable.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002752 { MaybeObject* maybe_obj =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002753 undefined_value()->Initialize("undefined",
2754 nan_value(),
2755 Oddball::kUndefined);
2756 if (!maybe_obj->ToObject(&obj)) return false;
2757 }
2758
2759 // Initialize the null_value.
2760 { MaybeObject* maybe_obj =
2761 null_value()->Initialize("null", Smi::FromInt(0), Oddball::kNull);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002762 if (!maybe_obj->ToObject(&obj)) return false;
2763 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002764
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002765 { MaybeObject* maybe_obj = CreateOddball("true",
2766 Smi::FromInt(1),
2767 Oddball::kTrue);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002768 if (!maybe_obj->ToObject(&obj)) return false;
2769 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002770 set_true_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002772 { MaybeObject* maybe_obj = CreateOddball("false",
2773 Smi::FromInt(0),
2774 Oddball::kFalse);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002775 if (!maybe_obj->ToObject(&obj)) return false;
2776 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002777 set_false_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002778
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002779 { MaybeObject* maybe_obj = CreateOddball("hole",
2780 Smi::FromInt(-1),
2781 Oddball::kTheHole);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002782 if (!maybe_obj->ToObject(&obj)) return false;
2783 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002784 set_the_hole_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002785
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002786 { MaybeObject* maybe_obj = CreateOddball("arguments_marker",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002787 Smi::FromInt(-4),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002788 Oddball::kArgumentMarker);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002789 if (!maybe_obj->ToObject(&obj)) return false;
2790 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002791 set_arguments_marker(Oddball::cast(obj));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002792
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002793 { MaybeObject* maybe_obj = CreateOddball("no_interceptor_result_sentinel",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002794 Smi::FromInt(-2),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002795 Oddball::kOther);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002796 if (!maybe_obj->ToObject(&obj)) return false;
2797 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002798 set_no_interceptor_result_sentinel(obj);
2799
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002800 { MaybeObject* maybe_obj = CreateOddball("termination_exception",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002801 Smi::FromInt(-3),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002802 Oddball::kOther);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002803 if (!maybe_obj->ToObject(&obj)) return false;
2804 }
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00002805 set_termination_exception(obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002806
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002807 // Allocate the empty string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002808 { MaybeObject* maybe_obj = AllocateRawAsciiString(0, TENURED);
2809 if (!maybe_obj->ToObject(&obj)) return false;
2810 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002811 set_empty_string(String::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002812
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002813 for (unsigned i = 0; i < ARRAY_SIZE(constant_symbol_table); i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002814 { MaybeObject* maybe_obj =
2815 LookupAsciiSymbol(constant_symbol_table[i].contents);
2816 if (!maybe_obj->ToObject(&obj)) return false;
2817 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002818 roots_[constant_symbol_table[i].index] = String::cast(obj);
2819 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002820
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002821 // Allocate the hidden symbol which is used to identify the hidden properties
2822 // in JSObjects. The hash code has a special value so that it will not match
2823 // the empty string when searching for the property. It cannot be part of the
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002824 // loop above because it needs to be allocated manually with the special
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002825 // hash code in place. The hash code for the hidden_symbol is zero to ensure
2826 // that it will always be at the first entry in property descriptors.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002827 { MaybeObject* maybe_obj =
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002828 AllocateSymbol(CStrVector(""), 0, String::kEmptyStringHash);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002829 if (!maybe_obj->ToObject(&obj)) return false;
2830 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002831 hidden_symbol_ = String::cast(obj);
2832
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002833 // Allocate the foreign for __proto__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002834 { MaybeObject* maybe_obj =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002835 AllocateForeign((Address) &Accessors::ObjectPrototype);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002836 if (!maybe_obj->ToObject(&obj)) return false;
2837 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002838 set_prototype_accessors(Foreign::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002839
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002840 // Allocate the code_stubs dictionary. The initial size is set to avoid
2841 // expanding the dictionary during bootstrapping.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002842 { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(128);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002843 if (!maybe_obj->ToObject(&obj)) return false;
2844 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002845 set_code_stubs(UnseededNumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002846
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002847
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002848 // Allocate the non_monomorphic_cache used in stub-cache.cc. The initial size
2849 // is set to avoid expanding the dictionary during bootstrapping.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002850 { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(64);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002851 if (!maybe_obj->ToObject(&obj)) return false;
2852 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002853 set_non_monomorphic_cache(UnseededNumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002854
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002855 { MaybeObject* maybe_obj = AllocatePolymorphicCodeCache();
2856 if (!maybe_obj->ToObject(&obj)) return false;
2857 }
2858 set_polymorphic_code_cache(PolymorphicCodeCache::cast(obj));
2859
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002860 set_instanceof_cache_function(Smi::FromInt(0));
2861 set_instanceof_cache_map(Smi::FromInt(0));
2862 set_instanceof_cache_answer(Smi::FromInt(0));
2863
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002864 CreateFixedStubs();
2865
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002866 // Allocate the dictionary of intrinsic function names.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002867 { MaybeObject* maybe_obj = StringDictionary::Allocate(Runtime::kNumFunctions);
2868 if (!maybe_obj->ToObject(&obj)) return false;
2869 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002870 { MaybeObject* maybe_obj = Runtime::InitializeIntrinsicFunctionNames(this,
2871 obj);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002872 if (!maybe_obj->ToObject(&obj)) return false;
2873 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002874 set_intrinsic_function_names(StringDictionary::cast(obj));
2875
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002876 { MaybeObject* maybe_obj = AllocateInitialNumberStringCache();
2877 if (!maybe_obj->ToObject(&obj)) return false;
2878 }
2879 set_number_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002880
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002881 // Allocate cache for single character ASCII strings.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002882 { MaybeObject* maybe_obj =
2883 AllocateFixedArray(String::kMaxAsciiCharCode + 1, TENURED);
2884 if (!maybe_obj->ToObject(&obj)) return false;
2885 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002886 set_single_character_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002887
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002888 // Allocate cache for string split.
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002889 { MaybeObject* maybe_obj = AllocateFixedArray(
2890 RegExpResultsCache::kRegExpResultsCacheSize, TENURED);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002891 if (!maybe_obj->ToObject(&obj)) return false;
2892 }
2893 set_string_split_cache(FixedArray::cast(obj));
2894
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002895 { MaybeObject* maybe_obj = AllocateFixedArray(
2896 RegExpResultsCache::kRegExpResultsCacheSize, TENURED);
2897 if (!maybe_obj->ToObject(&obj)) return false;
2898 }
2899 set_regexp_multiple_cache(FixedArray::cast(obj));
2900
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002901 // Allocate cache for external strings pointing to native source code.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002902 { MaybeObject* maybe_obj = AllocateFixedArray(Natives::GetBuiltinsCount());
2903 if (!maybe_obj->ToObject(&obj)) return false;
2904 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002905 set_natives_source_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002906
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002907 // Allocate object to hold object observation state.
2908 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
2909 if (!maybe_obj->ToObject(&obj)) return false;
2910 }
2911 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(Map::cast(obj));
2912 if (!maybe_obj->ToObject(&obj)) return false;
2913 }
2914 set_observation_state(JSObject::cast(obj));
2915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002916 // Handling of script id generation is in FACTORY->NewScript.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002917 set_last_script_id(undefined_value());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002918
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002919 // Initialize keyed lookup cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002920 isolate_->keyed_lookup_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002921
2922 // Initialize context slot cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002923 isolate_->context_slot_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002924
2925 // Initialize descriptor cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002926 isolate_->descriptor_lookup_cache()->Clear();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002927
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002928 // Initialize compilation cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002929 isolate_->compilation_cache()->Clear();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002930
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002931 return true;
2932}
2933
2934
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002935bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) {
2936 RootListIndex writable_roots[] = {
2937 kStoreBufferTopRootIndex,
2938 kStackLimitRootIndex,
2939 kInstanceofCacheFunctionRootIndex,
2940 kInstanceofCacheMapRootIndex,
2941 kInstanceofCacheAnswerRootIndex,
2942 kCodeStubsRootIndex,
2943 kNonMonomorphicCacheRootIndex,
2944 kPolymorphicCodeCacheRootIndex,
2945 kLastScriptIdRootIndex,
2946 kEmptyScriptRootIndex,
2947 kRealStackLimitRootIndex,
2948 kArgumentsAdaptorDeoptPCOffsetRootIndex,
2949 kConstructStubDeoptPCOffsetRootIndex,
2950 kGetterStubDeoptPCOffsetRootIndex,
2951 kSetterStubDeoptPCOffsetRootIndex,
2952 kSymbolTableRootIndex,
2953 };
2954
2955 for (unsigned int i = 0; i < ARRAY_SIZE(writable_roots); i++) {
2956 if (root_index == writable_roots[i])
2957 return true;
2958 }
2959 return false;
2960}
2961
2962
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002963Object* RegExpResultsCache::Lookup(Heap* heap,
2964 String* key_string,
2965 Object* key_pattern,
2966 ResultsCacheType type) {
2967 FixedArray* cache;
2968 if (!key_string->IsSymbol()) return Smi::FromInt(0);
2969 if (type == STRING_SPLIT_SUBSTRINGS) {
2970 ASSERT(key_pattern->IsString());
2971 if (!key_pattern->IsSymbol()) return Smi::FromInt(0);
2972 cache = heap->string_split_cache();
2973 } else {
2974 ASSERT(type == REGEXP_MULTIPLE_INDICES);
2975 ASSERT(key_pattern->IsFixedArray());
2976 cache = heap->regexp_multiple_cache();
2977 }
2978
2979 uint32_t hash = key_string->Hash();
2980 uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) &
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002981 ~(kArrayEntriesPerCacheEntry - 1));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002982 if (cache->get(index + kStringOffset) == key_string &&
2983 cache->get(index + kPatternOffset) == key_pattern) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002984 return cache->get(index + kArrayOffset);
2985 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002986 index =
2987 ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1));
2988 if (cache->get(index + kStringOffset) == key_string &&
2989 cache->get(index + kPatternOffset) == key_pattern) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002990 return cache->get(index + kArrayOffset);
2991 }
2992 return Smi::FromInt(0);
2993}
2994
2995
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002996void RegExpResultsCache::Enter(Heap* heap,
2997 String* key_string,
2998 Object* key_pattern,
2999 FixedArray* value_array,
3000 ResultsCacheType type) {
3001 FixedArray* cache;
3002 if (!key_string->IsSymbol()) return;
3003 if (type == STRING_SPLIT_SUBSTRINGS) {
3004 ASSERT(key_pattern->IsString());
3005 if (!key_pattern->IsSymbol()) return;
3006 cache = heap->string_split_cache();
3007 } else {
3008 ASSERT(type == REGEXP_MULTIPLE_INDICES);
3009 ASSERT(key_pattern->IsFixedArray());
3010 cache = heap->regexp_multiple_cache();
3011 }
3012
3013 uint32_t hash = key_string->Hash();
3014 uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) &
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003015 ~(kArrayEntriesPerCacheEntry - 1));
3016 if (cache->get(index + kStringOffset) == Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003017 cache->set(index + kStringOffset, key_string);
3018 cache->set(index + kPatternOffset, key_pattern);
3019 cache->set(index + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003020 } else {
3021 uint32_t index2 =
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003022 ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1));
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003023 if (cache->get(index2 + kStringOffset) == Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003024 cache->set(index2 + kStringOffset, key_string);
3025 cache->set(index2 + kPatternOffset, key_pattern);
3026 cache->set(index2 + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003027 } else {
3028 cache->set(index2 + kStringOffset, Smi::FromInt(0));
3029 cache->set(index2 + kPatternOffset, Smi::FromInt(0));
3030 cache->set(index2 + kArrayOffset, Smi::FromInt(0));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003031 cache->set(index + kStringOffset, key_string);
3032 cache->set(index + kPatternOffset, key_pattern);
3033 cache->set(index + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003034 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003035 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003036 // If the array is a reasonably short list of substrings, convert it into a
3037 // list of symbols.
3038 if (type == STRING_SPLIT_SUBSTRINGS && value_array->length() < 100) {
3039 for (int i = 0; i < value_array->length(); i++) {
3040 String* str = String::cast(value_array->get(i));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003041 Object* symbol;
3042 MaybeObject* maybe_symbol = heap->LookupSymbol(str);
3043 if (maybe_symbol->ToObject(&symbol)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003044 value_array->set(i, symbol);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003045 }
3046 }
3047 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003048 // Convert backing store to a copy-on-write array.
3049 value_array->set_map_no_write_barrier(heap->fixed_cow_array_map());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003050}
3051
3052
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003053void RegExpResultsCache::Clear(FixedArray* cache) {
3054 for (int i = 0; i < kRegExpResultsCacheSize; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003055 cache->set(i, Smi::FromInt(0));
3056 }
3057}
3058
3059
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003060MaybeObject* Heap::AllocateInitialNumberStringCache() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003061 MaybeObject* maybe_obj =
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003062 AllocateFixedArray(kInitialNumberStringCacheSize * 2, TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003063 return maybe_obj;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003064}
3065
3066
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003067int Heap::FullSizeNumberStringCacheLength() {
3068 // Compute the size of the number string cache based on the max newspace size.
3069 // The number string cache has a minimum size based on twice the initial cache
3070 // size to ensure that it is bigger after being made 'full size'.
3071 int number_string_cache_size = max_semispace_size_ / 512;
3072 number_string_cache_size = Max(kInitialNumberStringCacheSize * 2,
3073 Min(0x4000, number_string_cache_size));
3074 // There is a string and a number per entry so the length is twice the number
3075 // of entries.
3076 return number_string_cache_size * 2;
3077}
3078
3079
3080void Heap::AllocateFullSizeNumberStringCache() {
3081 // The idea is to have a small number string cache in the snapshot to keep
3082 // boot-time memory usage down. If we expand the number string cache already
3083 // while creating the snapshot then that didn't work out.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003084 ASSERT(!Serializer::enabled() || FLAG_extra_code != NULL);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003085 MaybeObject* maybe_obj =
3086 AllocateFixedArray(FullSizeNumberStringCacheLength(), TENURED);
3087 Object* new_cache;
3088 if (maybe_obj->ToObject(&new_cache)) {
3089 // We don't bother to repopulate the cache with entries from the old cache.
3090 // It will be repopulated soon enough with new strings.
3091 set_number_string_cache(FixedArray::cast(new_cache));
3092 }
3093 // If allocation fails then we just return without doing anything. It is only
3094 // a cache, so best effort is OK here.
3095}
3096
3097
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003098void Heap::FlushNumberStringCache() {
3099 // Flush the number to string cache.
3100 int len = number_string_cache()->length();
3101 for (int i = 0; i < len; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003102 number_string_cache()->set_undefined(this, i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003103 }
3104}
3105
3106
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003107static inline int double_get_hash(double d) {
3108 DoubleRepresentation rep(d);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003109 return static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003110}
3111
3112
3113static inline int smi_get_hash(Smi* smi) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003114 return smi->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003115}
3116
3117
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003118Object* Heap::GetNumberStringCache(Object* number) {
3119 int hash;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003120 int mask = (number_string_cache()->length() >> 1) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003121 if (number->IsSmi()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003122 hash = smi_get_hash(Smi::cast(number)) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003123 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003124 hash = double_get_hash(number->Number()) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003125 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003126 Object* key = number_string_cache()->get(hash * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003127 if (key == number) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003128 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003129 } else if (key->IsHeapNumber() &&
3130 number->IsHeapNumber() &&
3131 key->Number() == number->Number()) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003132 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003133 }
3134 return undefined_value();
3135}
3136
3137
3138void Heap::SetNumberStringCache(Object* number, String* string) {
3139 int hash;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003140 int mask = (number_string_cache()->length() >> 1) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003141 if (number->IsSmi()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003142 hash = smi_get_hash(Smi::cast(number)) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003143 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003144 hash = double_get_hash(number->Number()) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003145 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003146 if (number_string_cache()->get(hash * 2) != undefined_value() &&
3147 number_string_cache()->length() != FullSizeNumberStringCacheLength()) {
3148 // The first time we have a hash collision, we move to the full sized
3149 // number string cache.
3150 AllocateFullSizeNumberStringCache();
3151 return;
3152 }
3153 number_string_cache()->set(hash * 2, number);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003154 number_string_cache()->set(hash * 2 + 1, string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003155}
3156
3157
lrn@chromium.org303ada72010-10-27 09:33:13 +00003158MaybeObject* Heap::NumberToString(Object* number,
3159 bool check_number_string_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003160 isolate_->counters()->number_to_string_runtime()->Increment();
ager@chromium.org357bf652010-04-12 11:30:10 +00003161 if (check_number_string_cache) {
3162 Object* cached = GetNumberStringCache(number);
3163 if (cached != undefined_value()) {
3164 return cached;
3165 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003166 }
3167
3168 char arr[100];
3169 Vector<char> buffer(arr, ARRAY_SIZE(arr));
3170 const char* str;
3171 if (number->IsSmi()) {
3172 int num = Smi::cast(number)->value();
3173 str = IntToCString(num, buffer);
3174 } else {
3175 double num = HeapNumber::cast(number)->value();
3176 str = DoubleToCString(num, buffer);
3177 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003178
lrn@chromium.org303ada72010-10-27 09:33:13 +00003179 Object* js_string;
3180 MaybeObject* maybe_js_string = AllocateStringFromAscii(CStrVector(str));
3181 if (maybe_js_string->ToObject(&js_string)) {
3182 SetNumberStringCache(number, String::cast(js_string));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003183 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00003184 return maybe_js_string;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003185}
3186
3187
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003188MaybeObject* Heap::Uint32ToString(uint32_t value,
3189 bool check_number_string_cache) {
3190 Object* number;
3191 MaybeObject* maybe = NumberFromUint32(value);
3192 if (!maybe->To<Object>(&number)) return maybe;
3193 return NumberToString(number, check_number_string_cache);
3194}
3195
3196
ager@chromium.org3811b432009-10-28 14:53:37 +00003197Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) {
3198 return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]);
3199}
3200
3201
3202Heap::RootListIndex Heap::RootIndexForExternalArrayType(
3203 ExternalArrayType array_type) {
3204 switch (array_type) {
3205 case kExternalByteArray:
3206 return kExternalByteArrayMapRootIndex;
3207 case kExternalUnsignedByteArray:
3208 return kExternalUnsignedByteArrayMapRootIndex;
3209 case kExternalShortArray:
3210 return kExternalShortArrayMapRootIndex;
3211 case kExternalUnsignedShortArray:
3212 return kExternalUnsignedShortArrayMapRootIndex;
3213 case kExternalIntArray:
3214 return kExternalIntArrayMapRootIndex;
3215 case kExternalUnsignedIntArray:
3216 return kExternalUnsignedIntArrayMapRootIndex;
3217 case kExternalFloatArray:
3218 return kExternalFloatArrayMapRootIndex;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003219 case kExternalDoubleArray:
3220 return kExternalDoubleArrayMapRootIndex;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003221 case kExternalPixelArray:
3222 return kExternalPixelArrayMapRootIndex;
ager@chromium.org3811b432009-10-28 14:53:37 +00003223 default:
3224 UNREACHABLE();
3225 return kUndefinedValueRootIndex;
3226 }
3227}
3228
3229
lrn@chromium.org303ada72010-10-27 09:33:13 +00003230MaybeObject* Heap::NumberFromDouble(double value, PretenureFlag pretenure) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003231 // We need to distinguish the minus zero value and this cannot be
3232 // done after conversion to int. Doing this by comparing bit
3233 // patterns is faster than using fpclassify() et al.
3234 static const DoubleRepresentation minus_zero(-0.0);
3235
3236 DoubleRepresentation rep(value);
3237 if (rep.bits == minus_zero.bits) {
3238 return AllocateHeapNumber(-0.0, pretenure);
3239 }
3240
3241 int int_value = FastD2I(value);
3242 if (value == int_value && Smi::IsValid(int_value)) {
3243 return Smi::FromInt(int_value);
3244 }
3245
3246 // Materialize the value in the heap.
3247 return AllocateHeapNumber(value, pretenure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003248}
3249
3250
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003251MaybeObject* Heap::AllocateForeign(Address address, PretenureFlag pretenure) {
3252 // Statically ensure that it is safe to allocate foreigns in paged spaces.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003253 STATIC_ASSERT(Foreign::kSize <= Page::kMaxNonCodeHeapObjectSize);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003254 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003255 Foreign* result;
3256 MaybeObject* maybe_result = Allocate(foreign_map(), space);
3257 if (!maybe_result->To(&result)) return maybe_result;
3258 result->set_foreign_address(address);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003259 return result;
3260}
3261
3262
lrn@chromium.org303ada72010-10-27 09:33:13 +00003263MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003264 SharedFunctionInfo* share;
3265 MaybeObject* maybe = Allocate(shared_function_info_map(), OLD_POINTER_SPACE);
3266 if (!maybe->To<SharedFunctionInfo>(&share)) return maybe;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003267
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003268 // Set pointer fields.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003269 share->set_name(name);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003270 Code* illegal = isolate_->builtins()->builtin(Builtins::kIllegal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003271 share->set_code(illegal);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003272 share->ClearOptimizedCodeMap();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003273 share->set_scope_info(ScopeInfo::Empty());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003274 Code* construct_stub =
3275 isolate_->builtins()->builtin(Builtins::kJSConstructStubGeneric);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003276 share->set_construct_stub(construct_stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003277 share->set_instance_class_name(Object_symbol());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003278 share->set_function_data(undefined_value(), SKIP_WRITE_BARRIER);
3279 share->set_script(undefined_value(), SKIP_WRITE_BARRIER);
3280 share->set_debug_info(undefined_value(), SKIP_WRITE_BARRIER);
3281 share->set_inferred_name(empty_string(), SKIP_WRITE_BARRIER);
3282 share->set_initial_map(undefined_value(), SKIP_WRITE_BARRIER);
3283 share->set_this_property_assignments(undefined_value(), SKIP_WRITE_BARRIER);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003284 share->set_ast_node_count(0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003285 share->set_stress_deopt_counter(FLAG_deopt_every_n_times);
3286 share->set_counters(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003287
3288 // Set integer fields (smi or int, depending on the architecture).
3289 share->set_length(0);
3290 share->set_formal_parameter_count(0);
3291 share->set_expected_nof_properties(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003292 share->set_num_literals(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003293 share->set_start_position_and_type(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003294 share->set_end_position(0);
3295 share->set_function_token_position(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003296 // All compiler hints default to false or 0.
3297 share->set_compiler_hints(0);
3298 share->set_this_property_assignments_count(0);
3299 share->set_opt_count(0);
3300
3301 return share;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003302}
3303
3304
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003305MaybeObject* Heap::AllocateJSMessageObject(String* type,
3306 JSArray* arguments,
3307 int start_position,
3308 int end_position,
3309 Object* script,
3310 Object* stack_trace,
3311 Object* stack_frames) {
3312 Object* result;
3313 { MaybeObject* maybe_result = Allocate(message_object_map(), NEW_SPACE);
3314 if (!maybe_result->ToObject(&result)) return maybe_result;
3315 }
3316 JSMessageObject* message = JSMessageObject::cast(result);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003317 message->set_properties(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003318 message->initialize_elements();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003319 message->set_elements(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003320 message->set_type(type);
3321 message->set_arguments(arguments);
3322 message->set_start_position(start_position);
3323 message->set_end_position(end_position);
3324 message->set_script(script);
3325 message->set_stack_trace(stack_trace);
3326 message->set_stack_frames(stack_frames);
3327 return result;
3328}
3329
3330
3331
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003332// Returns true for a character in a range. Both limits are inclusive.
3333static inline bool Between(uint32_t character, uint32_t from, uint32_t to) {
3334 // This makes uses of the the unsigned wraparound.
3335 return character - from <= to - from;
3336}
3337
3338
lrn@chromium.org303ada72010-10-27 09:33:13 +00003339MUST_USE_RESULT static inline MaybeObject* MakeOrFindTwoCharacterString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003340 Heap* heap,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003341 uint32_t c1,
3342 uint32_t c2) {
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003343 String* symbol;
3344 // Numeric strings have a different hash algorithm not known by
3345 // LookupTwoCharsSymbolIfExists, so we skip this step for such strings.
3346 if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003347 heap->symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) {
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003348 return symbol;
3349 // Now we know the length is 2, we might as well make use of that fact
3350 // when building the new string.
3351 } else if ((c1 | c2) <= String::kMaxAsciiCharCodeU) { // We can do this
3352 ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1)); // because of this.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003353 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003354 { MaybeObject* maybe_result = heap->AllocateRawAsciiString(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003355 if (!maybe_result->ToObject(&result)) return maybe_result;
3356 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003357 char* dest = SeqOneByteString::cast(result)->GetChars();
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003358 dest[0] = c1;
3359 dest[1] = c2;
3360 return result;
3361 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003362 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003363 { MaybeObject* maybe_result = heap->AllocateRawTwoByteString(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003364 if (!maybe_result->ToObject(&result)) return maybe_result;
3365 }
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003366 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
3367 dest[0] = c1;
3368 dest[1] = c2;
3369 return result;
3370 }
3371}
3372
3373
lrn@chromium.org303ada72010-10-27 09:33:13 +00003374MaybeObject* Heap::AllocateConsString(String* first, String* second) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003375 int first_length = first->length();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003376 if (first_length == 0) {
3377 return second;
3378 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003379
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003380 int second_length = second->length();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003381 if (second_length == 0) {
3382 return first;
3383 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003384
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003385 int length = first_length + second_length;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003386
3387 // Optimization for 2-byte strings often used as keys in a decompression
3388 // dictionary. Check whether we already have the string in the symbol
3389 // table to prevent creation of many unneccesary strings.
3390 if (length == 2) {
3391 unsigned c1 = first->Get(0);
3392 unsigned c2 = second->Get(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003393 return MakeOrFindTwoCharacterString(this, c1, c2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003394 }
3395
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003396 bool first_is_ascii = first->IsAsciiRepresentation();
3397 bool second_is_ascii = second->IsAsciiRepresentation();
3398 bool is_ascii = first_is_ascii && second_is_ascii;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003399
ager@chromium.org3e875802009-06-29 08:26:34 +00003400 // Make sure that an out of memory exception is thrown if the length
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003401 // of the new cons string is too large.
3402 if (length > String::kMaxLength || length < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003403 isolate()->context()->mark_out_of_memory();
ager@chromium.org3e875802009-06-29 08:26:34 +00003404 return Failure::OutOfMemoryException();
3405 }
3406
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003407 bool is_ascii_data_in_two_byte_string = false;
3408 if (!is_ascii) {
3409 // At least one of the strings uses two-byte representation so we
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003410 // can't use the fast case code for short ASCII strings below, but
3411 // we can try to save memory if all chars actually fit in ASCII.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003412 is_ascii_data_in_two_byte_string =
3413 first->HasOnlyAsciiChars() && second->HasOnlyAsciiChars();
3414 if (is_ascii_data_in_two_byte_string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003415 isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003416 }
3417 }
3418
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003419 // If the resulting string is small make a flat string.
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003420 if (length < ConsString::kMinLength) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003421 // Note that neither of the two inputs can be a slice because:
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003422 STATIC_ASSERT(ConsString::kMinLength <= SlicedString::kMinLength);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003423 ASSERT(first->IsFlat());
3424 ASSERT(second->IsFlat());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003425 if (is_ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003426 Object* result;
3427 { MaybeObject* maybe_result = AllocateRawAsciiString(length);
3428 if (!maybe_result->ToObject(&result)) return maybe_result;
3429 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003430 // Copy the characters into the new object.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003431 char* dest = SeqOneByteString::cast(result)->GetChars();
ager@chromium.org3e875802009-06-29 08:26:34 +00003432 // Copy first part.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003433 const char* src;
3434 if (first->IsExternalString()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003435 src = ExternalAsciiString::cast(first)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003436 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003437 src = SeqOneByteString::cast(first)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003438 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003439 for (int i = 0; i < first_length; i++) *dest++ = src[i];
3440 // Copy second part.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003441 if (second->IsExternalString()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003442 src = ExternalAsciiString::cast(second)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003443 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003444 src = SeqOneByteString::cast(second)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003445 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003446 for (int i = 0; i < second_length; i++) *dest++ = src[i];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003447 return result;
3448 } else {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003449 if (is_ascii_data_in_two_byte_string) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003450 Object* result;
3451 { MaybeObject* maybe_result = AllocateRawAsciiString(length);
3452 if (!maybe_result->ToObject(&result)) return maybe_result;
3453 }
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003454 // Copy the characters into the new object.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003455 char* dest = SeqOneByteString::cast(result)->GetChars();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003456 String::WriteToFlat(first, dest, 0, first_length);
3457 String::WriteToFlat(second, dest + first_length, 0, second_length);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003458 isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003459 return result;
3460 }
3461
lrn@chromium.org303ada72010-10-27 09:33:13 +00003462 Object* result;
3463 { MaybeObject* maybe_result = AllocateRawTwoByteString(length);
3464 if (!maybe_result->ToObject(&result)) return maybe_result;
3465 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003466 // Copy the characters into the new object.
3467 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003468 String::WriteToFlat(first, dest, 0, first_length);
3469 String::WriteToFlat(second, dest + first_length, 0, second_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003470 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003471 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003472 }
3473
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003474 Map* map = (is_ascii || is_ascii_data_in_two_byte_string) ?
3475 cons_ascii_string_map() : cons_string_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003476
lrn@chromium.org303ada72010-10-27 09:33:13 +00003477 Object* result;
3478 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3479 if (!maybe_result->ToObject(&result)) return maybe_result;
3480 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003481
3482 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003483 ConsString* cons_string = ConsString::cast(result);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003484 WriteBarrierMode mode = cons_string->GetWriteBarrierMode(no_gc);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003485 cons_string->set_length(length);
3486 cons_string->set_hash_field(String::kEmptyHashField);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003487 cons_string->set_first(first, mode);
3488 cons_string->set_second(second, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003489 return result;
3490}
3491
3492
lrn@chromium.org303ada72010-10-27 09:33:13 +00003493MaybeObject* Heap::AllocateSubString(String* buffer,
ager@chromium.org04921a82011-06-27 13:21:41 +00003494 int start,
3495 int end,
3496 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003497 int length = end - start;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003498 if (length <= 0) {
ager@chromium.org04921a82011-06-27 13:21:41 +00003499 return empty_string();
3500 } else if (length == 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003501 return LookupSingleCharacterStringFromCode(buffer->Get(start));
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003502 } else if (length == 2) {
3503 // Optimization for 2-byte strings often used as keys in a decompression
3504 // dictionary. Check whether we already have the string in the symbol
3505 // table to prevent creation of many unneccesary strings.
3506 unsigned c1 = buffer->Get(start);
3507 unsigned c2 = buffer->Get(start + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003508 return MakeOrFindTwoCharacterString(this, c1, c2);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003509 }
3510
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003511 // Make an attempt to flatten the buffer to reduce access time.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003512 buffer = buffer->TryFlattenGetString();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003513
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003514 if (!FLAG_string_slices ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003515 !buffer->IsFlat() ||
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003516 length < SlicedString::kMinLength ||
3517 pretenure == TENURED) {
3518 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003519 // WriteToFlat takes care of the case when an indirect string has a
3520 // different encoding from its underlying string. These encodings may
3521 // differ because of externalization.
3522 bool is_ascii = buffer->IsAsciiRepresentation();
3523 { MaybeObject* maybe_result = is_ascii
3524 ? AllocateRawAsciiString(length, pretenure)
3525 : AllocateRawTwoByteString(length, pretenure);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003526 if (!maybe_result->ToObject(&result)) return maybe_result;
3527 }
3528 String* string_result = String::cast(result);
3529 // Copy the characters into the new object.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003530 if (is_ascii) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003531 ASSERT(string_result->IsAsciiRepresentation());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003532 char* dest = SeqOneByteString::cast(string_result)->GetChars();
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003533 String::WriteToFlat(buffer, dest, start, end);
3534 } else {
3535 ASSERT(string_result->IsTwoByteRepresentation());
3536 uc16* dest = SeqTwoByteString::cast(string_result)->GetChars();
3537 String::WriteToFlat(buffer, dest, start, end);
3538 }
3539 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003540 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003541
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003542 ASSERT(buffer->IsFlat());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003543#if VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003544 if (FLAG_verify_heap) {
3545 buffer->StringVerify();
3546 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003547#endif
3548
3549 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003550 // When slicing an indirect string we use its encoding for a newly created
3551 // slice and don't check the encoding of the underlying string. This is safe
3552 // even if the encodings are different because of externalization. If an
3553 // indirect ASCII string is pointing to a two-byte string, the two-byte char
3554 // codes of the underlying string must still fit into ASCII (because
3555 // externalization must not change char codes).
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003556 { Map* map = buffer->IsAsciiRepresentation()
3557 ? sliced_ascii_string_map()
3558 : sliced_string_map();
3559 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3560 if (!maybe_result->ToObject(&result)) return maybe_result;
3561 }
3562
3563 AssertNoAllocation no_gc;
3564 SlicedString* sliced_string = SlicedString::cast(result);
3565 sliced_string->set_length(length);
3566 sliced_string->set_hash_field(String::kEmptyHashField);
3567 if (buffer->IsConsString()) {
3568 ConsString* cons = ConsString::cast(buffer);
3569 ASSERT(cons->second()->length() == 0);
3570 sliced_string->set_parent(cons->first());
3571 sliced_string->set_offset(start);
3572 } else if (buffer->IsSlicedString()) {
3573 // Prevent nesting sliced strings.
3574 SlicedString* parent_slice = SlicedString::cast(buffer);
3575 sliced_string->set_parent(parent_slice->parent());
3576 sliced_string->set_offset(start + parent_slice->offset());
3577 } else {
3578 sliced_string->set_parent(buffer);
3579 sliced_string->set_offset(start);
3580 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003581 ASSERT(sliced_string->parent()->IsSeqString() ||
3582 sliced_string->parent()->IsExternalString());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003583 return result;
3584}
3585
3586
lrn@chromium.org303ada72010-10-27 09:33:13 +00003587MaybeObject* Heap::AllocateExternalStringFromAscii(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003588 const ExternalAsciiString::Resource* resource) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003589 size_t length = resource->length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003590 if (length > static_cast<size_t>(String::kMaxLength)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003591 isolate()->context()->mark_out_of_memory();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003592 return Failure::OutOfMemoryException();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003593 }
3594
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00003595 ASSERT(String::IsAscii(resource->data(), static_cast<int>(length)));
3596
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003597 Map* map = external_ascii_string_map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003598 Object* result;
3599 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3600 if (!maybe_result->ToObject(&result)) return maybe_result;
3601 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003602
3603 ExternalAsciiString* external_string = ExternalAsciiString::cast(result);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003604 external_string->set_length(static_cast<int>(length));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003605 external_string->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003606 external_string->set_resource(resource);
3607
3608 return result;
3609}
3610
3611
lrn@chromium.org303ada72010-10-27 09:33:13 +00003612MaybeObject* Heap::AllocateExternalStringFromTwoByte(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003613 const ExternalTwoByteString::Resource* resource) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003614 size_t length = resource->length();
3615 if (length > static_cast<size_t>(String::kMaxLength)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003616 isolate()->context()->mark_out_of_memory();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003617 return Failure::OutOfMemoryException();
3618 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003619
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003620 // For small strings we check whether the resource contains only
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003621 // ASCII characters. If yes, we use a different string map.
3622 static const size_t kAsciiCheckLengthLimit = 32;
3623 bool is_ascii = length <= kAsciiCheckLengthLimit &&
3624 String::IsAscii(resource->data(), static_cast<int>(length));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003625 Map* map = is_ascii ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003626 external_string_with_ascii_data_map() : external_string_map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003627 Object* result;
3628 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3629 if (!maybe_result->ToObject(&result)) return maybe_result;
3630 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003631
3632 ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003633 external_string->set_length(static_cast<int>(length));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003634 external_string->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003635 external_string->set_resource(resource);
3636
3637 return result;
3638}
3639
3640
lrn@chromium.org303ada72010-10-27 09:33:13 +00003641MaybeObject* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003642 if (code <= String::kMaxAsciiCharCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003643 Object* value = single_character_string_cache()->get(code);
3644 if (value != undefined_value()) return value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003645
3646 char buffer[1];
3647 buffer[0] = static_cast<char>(code);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003648 Object* result;
3649 MaybeObject* maybe_result = LookupSymbol(Vector<const char>(buffer, 1));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003650
lrn@chromium.org303ada72010-10-27 09:33:13 +00003651 if (!maybe_result->ToObject(&result)) return maybe_result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003652 single_character_string_cache()->set(code, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003653 return result;
3654 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003655
lrn@chromium.org303ada72010-10-27 09:33:13 +00003656 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003657 { MaybeObject* maybe_result = AllocateRawTwoByteString(1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003658 if (!maybe_result->ToObject(&result)) return maybe_result;
3659 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00003660 String* answer = String::cast(result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003661 answer->Set(0, code);
ager@chromium.org870a0b62008-11-04 11:43:05 +00003662 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003663}
3664
3665
lrn@chromium.org303ada72010-10-27 09:33:13 +00003666MaybeObject* Heap::AllocateByteArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003667 if (length < 0 || length > ByteArray::kMaxLength) {
3668 return Failure::OutOfMemoryException();
3669 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003670 if (pretenure == NOT_TENURED) {
3671 return AllocateByteArray(length);
3672 }
3673 int size = ByteArray::SizeFor(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003674 Object* result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003675 { MaybeObject* maybe_result = (size <= Page::kMaxNonCodeHeapObjectSize)
lrn@chromium.org303ada72010-10-27 09:33:13 +00003676 ? old_data_space_->AllocateRaw(size)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003677 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003678 if (!maybe_result->ToObject(&result)) return maybe_result;
3679 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003680
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003681 reinterpret_cast<ByteArray*>(result)->set_map_no_write_barrier(
3682 byte_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003683 reinterpret_cast<ByteArray*>(result)->set_length(length);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003684 return result;
3685}
3686
3687
lrn@chromium.org303ada72010-10-27 09:33:13 +00003688MaybeObject* Heap::AllocateByteArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003689 if (length < 0 || length > ByteArray::kMaxLength) {
3690 return Failure::OutOfMemoryException();
3691 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003692 int size = ByteArray::SizeFor(length);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003693 AllocationSpace space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003694 (size > Page::kMaxNonCodeHeapObjectSize) ? LO_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003695 Object* result;
3696 { MaybeObject* maybe_result = AllocateRaw(size, space, OLD_DATA_SPACE);
3697 if (!maybe_result->ToObject(&result)) return maybe_result;
3698 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003699
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003700 reinterpret_cast<ByteArray*>(result)->set_map_no_write_barrier(
3701 byte_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003702 reinterpret_cast<ByteArray*>(result)->set_length(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003703 return result;
3704}
3705
3706
ager@chromium.org6f10e412009-02-13 10:11:16 +00003707void Heap::CreateFillerObjectAt(Address addr, int size) {
3708 if (size == 0) return;
3709 HeapObject* filler = HeapObject::FromAddress(addr);
3710 if (size == kPointerSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003711 filler->set_map_no_write_barrier(one_pointer_filler_map());
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00003712 } else if (size == 2 * kPointerSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003713 filler->set_map_no_write_barrier(two_pointer_filler_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +00003714 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003715 filler->set_map_no_write_barrier(free_space_map());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003716 FreeSpace::cast(filler)->set_size(size);
ager@chromium.org6f10e412009-02-13 10:11:16 +00003717 }
3718}
3719
3720
lrn@chromium.org303ada72010-10-27 09:33:13 +00003721MaybeObject* Heap::AllocateExternalArray(int length,
3722 ExternalArrayType array_type,
3723 void* external_pointer,
3724 PretenureFlag pretenure) {
ager@chromium.org3811b432009-10-28 14:53:37 +00003725 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003726 Object* result;
3727 { MaybeObject* maybe_result = AllocateRaw(ExternalArray::kAlignedSize,
3728 space,
3729 OLD_DATA_SPACE);
3730 if (!maybe_result->ToObject(&result)) return maybe_result;
3731 }
ager@chromium.org3811b432009-10-28 14:53:37 +00003732
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003733 reinterpret_cast<ExternalArray*>(result)->set_map_no_write_barrier(
ager@chromium.org3811b432009-10-28 14:53:37 +00003734 MapForExternalArrayType(array_type));
3735 reinterpret_cast<ExternalArray*>(result)->set_length(length);
3736 reinterpret_cast<ExternalArray*>(result)->set_external_pointer(
3737 external_pointer);
3738
3739 return result;
3740}
3741
3742
lrn@chromium.org303ada72010-10-27 09:33:13 +00003743MaybeObject* Heap::CreateCode(const CodeDesc& desc,
3744 Code::Flags flags,
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003745 Handle<Object> self_reference,
3746 bool immovable) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003747 // Allocate ByteArray before the Code object, so that we do not risk
3748 // leaving uninitialized Code object (and breaking the heap).
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003749 ByteArray* reloc_info;
3750 MaybeObject* maybe_reloc_info = AllocateByteArray(desc.reloc_size, TENURED);
3751 if (!maybe_reloc_info->To(&reloc_info)) return maybe_reloc_info;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003752
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003753 // Compute size.
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003754 int body_size = RoundUp(desc.instr_size, kObjectAlignment);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003755 int obj_size = Code::SizeFor(body_size);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003756 ASSERT(IsAligned(static_cast<intptr_t>(obj_size), kCodeAlignment));
lrn@chromium.org303ada72010-10-27 09:33:13 +00003757 MaybeObject* maybe_result;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003758 // Large code objects and code objects which should stay at a fixed address
3759 // are allocated in large object space.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003760 HeapObject* result;
3761 bool force_lo_space = obj_size > code_space()->AreaSize();
3762 if (force_lo_space) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003763 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003764 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003765 maybe_result = code_space_->AllocateRaw(obj_size);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003766 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003767 if (!maybe_result->To<HeapObject>(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003768
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003769 if (immovable && !force_lo_space &&
3770 // Objects on the first page of each space are never moved.
3771 !code_space_->FirstPage()->Contains(result->address())) {
3772 // Discard the first code allocation, which was on a page where it could be
3773 // moved.
3774 CreateFillerObjectAt(result->address(), obj_size);
3775 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
3776 if (!maybe_result->To<HeapObject>(&result)) return maybe_result;
3777 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003778
3779 // Initialize the object
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003780 result->set_map_no_write_barrier(code_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003781 Code* code = Code::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003782 ASSERT(!isolate_->code_range()->exists() ||
3783 isolate_->code_range()->contains(code->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003784 code->set_instruction_size(desc.instr_size);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003785 code->set_relocation_info(reloc_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003786 code->set_flags(flags);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003787 if (code->is_call_stub() || code->is_keyed_call_stub()) {
3788 code->set_check_type(RECEIVER_MAP_CHECK);
3789 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003790 code->set_deoptimization_data(empty_fixed_array(), SKIP_WRITE_BARRIER);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003791 code->InitializeTypeFeedbackInfoNoWriteBarrier(undefined_value());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003792 code->set_handler_table(empty_fixed_array(), SKIP_WRITE_BARRIER);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00003793 code->set_gc_metadata(Smi::FromInt(0));
danno@chromium.org88aa0582012-03-23 15:11:57 +00003794 code->set_ic_age(global_ic_age_);
kasperl@chromium.org061ef742009-02-27 12:16:20 +00003795 // Allow self references to created code object by patching the handle to
3796 // point to the newly allocated Code object.
3797 if (!self_reference.is_null()) {
3798 *(self_reference.location()) = code;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003799 }
3800 // Migrate generated code.
3801 // The generated code can contain Object** values (typically from handles)
3802 // that are dereferenced during the copy to point directly to the actual heap
3803 // objects. These pointers can include references to the code object itself,
3804 // through the self_reference parameter.
3805 code->CopyFrom(desc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003806
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003807#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003808 if (FLAG_verify_heap) {
3809 code->Verify();
3810 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003811#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003812 return code;
3813}
3814
3815
lrn@chromium.org303ada72010-10-27 09:33:13 +00003816MaybeObject* Heap::CopyCode(Code* code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003817 // Allocate an object the same size as the code object.
3818 int obj_size = code->Size();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003819 MaybeObject* maybe_result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003820 if (obj_size > code_space()->AreaSize()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003821 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003822 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003823 maybe_result = code_space_->AllocateRaw(obj_size);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003824 }
3825
lrn@chromium.org303ada72010-10-27 09:33:13 +00003826 Object* result;
3827 if (!maybe_result->ToObject(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003828
3829 // Copy code object.
3830 Address old_addr = code->address();
3831 Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003832 CopyBlock(new_addr, old_addr, obj_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003833 // Relocate the copy.
3834 Code* new_code = Code::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003835 ASSERT(!isolate_->code_range()->exists() ||
3836 isolate_->code_range()->contains(code->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003837 new_code->Relocate(new_addr - old_addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003838 return new_code;
3839}
3840
3841
lrn@chromium.org303ada72010-10-27 09:33:13 +00003842MaybeObject* Heap::CopyCode(Code* code, Vector<byte> reloc_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003843 // Allocate ByteArray before the Code object, so that we do not risk
3844 // leaving uninitialized Code object (and breaking the heap).
lrn@chromium.org303ada72010-10-27 09:33:13 +00003845 Object* reloc_info_array;
3846 { MaybeObject* maybe_reloc_info_array =
3847 AllocateByteArray(reloc_info.length(), TENURED);
3848 if (!maybe_reloc_info_array->ToObject(&reloc_info_array)) {
3849 return maybe_reloc_info_array;
3850 }
3851 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003852
3853 int new_body_size = RoundUp(code->instruction_size(), kObjectAlignment);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003854
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003855 int new_obj_size = Code::SizeFor(new_body_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003856
3857 Address old_addr = code->address();
3858
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00003859 size_t relocation_offset =
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003860 static_cast<size_t>(code->instruction_end() - old_addr);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003861
lrn@chromium.org303ada72010-10-27 09:33:13 +00003862 MaybeObject* maybe_result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003863 if (new_obj_size > code_space()->AreaSize()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003864 maybe_result = lo_space_->AllocateRaw(new_obj_size, EXECUTABLE);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003865 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003866 maybe_result = code_space_->AllocateRaw(new_obj_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003867 }
3868
lrn@chromium.org303ada72010-10-27 09:33:13 +00003869 Object* result;
3870 if (!maybe_result->ToObject(&result)) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003871
3872 // Copy code object.
3873 Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
3874
3875 // Copy header and instructions.
3876 memcpy(new_addr, old_addr, relocation_offset);
3877
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003878 Code* new_code = Code::cast(result);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003879 new_code->set_relocation_info(ByteArray::cast(reloc_info_array));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003880
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003881 // Copy patched rinfo.
3882 memcpy(new_code->relocation_start(), reloc_info.start(), reloc_info.length());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003883
3884 // Relocate the copy.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003885 ASSERT(!isolate_->code_range()->exists() ||
3886 isolate_->code_range()->contains(code->address()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003887 new_code->Relocate(new_addr - old_addr);
3888
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003889#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003890 if (FLAG_verify_heap) {
3891 code->Verify();
3892 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003893#endif
3894 return new_code;
3895}
3896
3897
lrn@chromium.org303ada72010-10-27 09:33:13 +00003898MaybeObject* Heap::Allocate(Map* map, AllocationSpace space) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003899 ASSERT(gc_state_ == NOT_IN_GC);
3900 ASSERT(map->instance_type() != MAP_TYPE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003901 // If allocation failures are disallowed, we may allocate in a different
3902 // space when new space is full and the object is not a large object.
3903 AllocationSpace retry_space =
3904 (space != NEW_SPACE) ? space : TargetSpaceId(map->instance_type());
lrn@chromium.org303ada72010-10-27 09:33:13 +00003905 Object* result;
3906 { MaybeObject* maybe_result =
3907 AllocateRaw(map->instance_size(), space, retry_space);
3908 if (!maybe_result->ToObject(&result)) return maybe_result;
3909 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003910 // No need for write barrier since object is white and map is in old space.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003911 HeapObject::cast(result)->set_map_no_write_barrier(map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003912 return result;
3913}
3914
3915
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003916void Heap::InitializeFunction(JSFunction* function,
3917 SharedFunctionInfo* shared,
3918 Object* prototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003919 ASSERT(!prototype->IsMap());
3920 function->initialize_properties();
3921 function->initialize_elements();
3922 function->set_shared(shared);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00003923 function->set_code(shared->code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003924 function->set_prototype_or_initial_map(prototype);
3925 function->set_context(undefined_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003926 function->set_literals_or_bindings(empty_fixed_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003927 function->set_next_function_link(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003928}
3929
3930
lrn@chromium.org303ada72010-10-27 09:33:13 +00003931MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00003932 // Allocate the prototype. Make sure to use the object function
3933 // from the function's context, since the function can be from a
3934 // different context.
3935 JSFunction* object_function =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003936 function->context()->native_context()->object_function();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003937
3938 // Each function prototype gets a copy of the object function map.
3939 // This avoid unwanted sharing of maps between prototypes of different
3940 // constructors.
3941 Map* new_map;
3942 ASSERT(object_function->has_initial_map());
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003943 MaybeObject* maybe_map = object_function->initial_map()->Copy();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003944 if (!maybe_map->To(&new_map)) return maybe_map;
3945
lrn@chromium.org303ada72010-10-27 09:33:13 +00003946 Object* prototype;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003947 MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map);
3948 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
3949
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003950 // When creating the prototype for the function we must set its
3951 // constructor to the function.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003952 MaybeObject* maybe_failure =
3953 JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
3954 constructor_symbol(), function, DONT_ENUM);
3955 if (maybe_failure->IsFailure()) return maybe_failure;
3956
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003957 return prototype;
3958}
3959
3960
lrn@chromium.org303ada72010-10-27 09:33:13 +00003961MaybeObject* Heap::AllocateFunction(Map* function_map,
3962 SharedFunctionInfo* shared,
3963 Object* prototype,
3964 PretenureFlag pretenure) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003965 AllocationSpace space =
3966 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003967 Object* result;
3968 { MaybeObject* maybe_result = Allocate(function_map, space);
3969 if (!maybe_result->ToObject(&result)) return maybe_result;
3970 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003971 InitializeFunction(JSFunction::cast(result), shared, prototype);
3972 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003973}
3974
3975
lrn@chromium.org303ada72010-10-27 09:33:13 +00003976MaybeObject* Heap::AllocateArgumentsObject(Object* callee, int length) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003977 // To get fast allocation and map sharing for arguments objects we
3978 // allocate them based on an arguments boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003979
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003980 JSObject* boilerplate;
3981 int arguments_object_size;
3982 bool strict_mode_callee = callee->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003983 !JSFunction::cast(callee)->shared()->is_classic_mode();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003984 if (strict_mode_callee) {
3985 boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003986 isolate()->context()->native_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003987 strict_mode_arguments_boilerplate();
3988 arguments_object_size = kArgumentsObjectSizeStrict;
3989 } else {
3990 boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003991 isolate()->context()->native_context()->arguments_boilerplate();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003992 arguments_object_size = kArgumentsObjectSize;
3993 }
3994
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003995 // This calls Copy directly rather than using Heap::AllocateRaw so we
3996 // duplicate the check here.
3997 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
3998
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003999 // Check that the size of the boilerplate matches our
4000 // expectations. The ArgumentsAccessStub::GenerateNewObject relies
4001 // on the size being a known constant.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004002 ASSERT(arguments_object_size == boilerplate->map()->instance_size());
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00004003
4004 // Do the allocation.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004005 Object* result;
4006 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004007 AllocateRaw(arguments_object_size, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004008 if (!maybe_result->ToObject(&result)) return maybe_result;
4009 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004011 // Copy the content. The arguments boilerplate doesn't have any
4012 // fields that point to new space so it's safe to skip the write
4013 // barrier here.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004014 CopyBlock(HeapObject::cast(result)->address(),
4015 boilerplate->address(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004016 JSObject::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004018 // Set the length property.
4019 JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsLengthIndex,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004020 Smi::FromInt(length),
4021 SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004022 // Set the callee property for non-strict mode arguments object only.
4023 if (!strict_mode_callee) {
4024 JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsCalleeIndex,
4025 callee);
4026 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004027
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004028 // Check the state of the object
4029 ASSERT(JSObject::cast(result)->HasFastProperties());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004030 ASSERT(JSObject::cast(result)->HasFastObjectElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004031
4032 return result;
4033}
4034
4035
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004036static bool HasDuplicates(DescriptorArray* descriptors) {
4037 int count = descriptors->number_of_descriptors();
4038 if (count > 1) {
4039 String* prev_key = descriptors->GetKey(0);
4040 for (int i = 1; i != count; i++) {
4041 String* current_key = descriptors->GetKey(i);
4042 if (prev_key == current_key) return true;
4043 prev_key = current_key;
4044 }
4045 }
4046 return false;
4047}
4048
4049
lrn@chromium.org303ada72010-10-27 09:33:13 +00004050MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004051 ASSERT(!fun->has_initial_map());
4052
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004053 // First create a new map with the size and number of in-object properties
4054 // suggested by the function.
4055 int instance_size = fun->shared()->CalculateInstanceSize();
4056 int in_object_properties = fun->shared()->CalculateInObjectProperties();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004057 Map* map;
4058 MaybeObject* maybe_map = AllocateMap(JS_OBJECT_TYPE, instance_size);
4059 if (!maybe_map->To(&map)) return maybe_map;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004060
4061 // Fetch or allocate prototype.
4062 Object* prototype;
4063 if (fun->has_instance_prototype()) {
4064 prototype = fun->instance_prototype();
4065 } else {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004066 MaybeObject* maybe_prototype = AllocateFunctionPrototype(fun);
4067 if (!maybe_prototype->To(&prototype)) return maybe_prototype;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004068 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004069 map->set_inobject_properties(in_object_properties);
4070 map->set_unused_property_fields(in_object_properties);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004071 map->set_prototype(prototype);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004072 ASSERT(map->has_fast_object_elements());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004073
ager@chromium.org5c838252010-02-19 08:53:10 +00004074 // If the function has only simple this property assignments add
4075 // field descriptors for these to the initial map as the object
4076 // cannot be constructed without having these properties. Guard by
4077 // the inline_new flag so we only change the map if we generate a
4078 // specialized construct stub.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004079 ASSERT(in_object_properties <= Map::kMaxPreAllocatedPropertyFields);
ager@chromium.org5c838252010-02-19 08:53:10 +00004080 if (fun->shared()->CanGenerateInlineConstructor(prototype)) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004081 int count = fun->shared()->this_property_assignments_count();
4082 if (count > in_object_properties) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004083 // Inline constructor can only handle inobject properties.
4084 fun->shared()->ForbidInlineConstructor();
4085 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004086 DescriptorArray* descriptors;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00004087 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(count);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004088 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
4089
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004090 DescriptorArray::WhitenessWitness witness(descriptors);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004091 for (int i = 0; i < count; i++) {
4092 String* name = fun->shared()->GetThisPropertyAssignmentName(i);
4093 ASSERT(name->IsSymbol());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004094 FieldDescriptor field(name, i, NONE, i + 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004095 descriptors->Set(i, &field, witness);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004096 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004097 descriptors->Sort();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004098
4099 // The descriptors may contain duplicates because the compiler does not
4100 // guarantee the uniqueness of property names (it would have required
4101 // quadratic time). Once the descriptors are sorted we can check for
4102 // duplicates in linear time.
4103 if (HasDuplicates(descriptors)) {
4104 fun->shared()->ForbidInlineConstructor();
4105 } else {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004106 map->InitializeDescriptors(descriptors);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004107 map->set_pre_allocated_property_fields(count);
4108 map->set_unused_property_fields(in_object_properties - count);
4109 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004110 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004111 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004112
4113 fun->shared()->StartInobjectSlackTracking(map);
4114
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004115 return map;
4116}
4117
4118
4119void Heap::InitializeJSObjectFromMap(JSObject* obj,
4120 FixedArray* properties,
4121 Map* map) {
4122 obj->set_properties(properties);
4123 obj->initialize_elements();
4124 // TODO(1240798): Initialize the object's body using valid initial values
4125 // according to the object's initial map. For example, if the map's
4126 // instance type is JS_ARRAY_TYPE, the length field should be initialized
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004127 // to a number (e.g. Smi::FromInt(0)) and the elements initialized to a
4128 // fixed array (e.g. Heap::empty_fixed_array()). Currently, the object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004129 // verification code has to cope with (temporarily) invalid objects. See
4130 // for example, JSArray::JSArrayVerify).
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004131 Object* filler;
4132 // We cannot always fill with one_pointer_filler_map because objects
4133 // created from API functions expect their internal fields to be initialized
4134 // with undefined_value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004135 // Pre-allocated fields need to be initialized with undefined_value as well
4136 // so that object accesses before the constructor completes (e.g. in the
4137 // debugger) will not cause a crash.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004138 if (map->constructor()->IsJSFunction() &&
4139 JSFunction::cast(map->constructor())->shared()->
4140 IsInobjectSlackTrackingInProgress()) {
4141 // We might want to shrink the object later.
4142 ASSERT(obj->GetInternalFieldCount() == 0);
4143 filler = Heap::one_pointer_filler_map();
4144 } else {
4145 filler = Heap::undefined_value();
4146 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004147 obj->InitializeBody(map, Heap::undefined_value(), filler);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004148}
4149
4150
lrn@chromium.org303ada72010-10-27 09:33:13 +00004151MaybeObject* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004152 // JSFunctions should be allocated using AllocateFunction to be
4153 // properly initialized.
4154 ASSERT(map->instance_type() != JS_FUNCTION_TYPE);
4155
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00004156 // Both types of global objects should be allocated using
4157 // AllocateGlobalObject to be properly initialized.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004158 ASSERT(map->instance_type() != JS_GLOBAL_OBJECT_TYPE);
4159 ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE);
4160
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004161 // Allocate the backing storage for the properties.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004162 int prop_size =
4163 map->pre_allocated_property_fields() +
4164 map->unused_property_fields() -
4165 map->inobject_properties();
4166 ASSERT(prop_size >= 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004167 Object* properties;
4168 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, pretenure);
4169 if (!maybe_properties->ToObject(&properties)) return maybe_properties;
4170 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004171
4172 // Allocate the JSObject.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004173 AllocationSpace space =
4174 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004175 if (map->instance_size() > Page::kMaxNonCodeHeapObjectSize) space = LO_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004176 Object* obj;
4177 { MaybeObject* maybe_obj = Allocate(map, space);
4178 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4179 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004180
4181 // Initialize the JSObject.
4182 InitializeJSObjectFromMap(JSObject::cast(obj),
4183 FixedArray::cast(properties),
4184 map);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004185 ASSERT(JSObject::cast(obj)->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004186 return obj;
4187}
4188
4189
lrn@chromium.org303ada72010-10-27 09:33:13 +00004190MaybeObject* Heap::AllocateJSObject(JSFunction* constructor,
4191 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004192 // Allocate the initial map if absent.
4193 if (!constructor->has_initial_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004194 Object* initial_map;
4195 { MaybeObject* maybe_initial_map = AllocateInitialMap(constructor);
4196 if (!maybe_initial_map->ToObject(&initial_map)) return maybe_initial_map;
4197 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004198 constructor->set_initial_map(Map::cast(initial_map));
4199 Map::cast(initial_map)->set_constructor(constructor);
4200 }
4201 // Allocate the object based on the constructors initial map.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004202 MaybeObject* result = AllocateJSObjectFromMap(
4203 constructor->initial_map(), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004204#ifdef DEBUG
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004205 // Make sure result is NOT a global object if valid.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004206 Object* non_failure;
4207 ASSERT(!result->ToObject(&non_failure) || !non_failure->IsGlobalObject());
4208#endif
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004209 return result;
4210}
4211
4212
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004213MaybeObject* Heap::AllocateJSModule(Context* context, ScopeInfo* scope_info) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004214 // Allocate a fresh map. Modules do not have a prototype.
4215 Map* map;
4216 MaybeObject* maybe_map = AllocateMap(JS_MODULE_TYPE, JSModule::kSize);
4217 if (!maybe_map->To(&map)) return maybe_map;
4218 // Allocate the object based on the map.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004219 JSModule* module;
4220 MaybeObject* maybe_module = AllocateJSObjectFromMap(map, TENURED);
4221 if (!maybe_module->To(&module)) return maybe_module;
4222 module->set_context(context);
4223 module->set_scope_info(scope_info);
4224 return module;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004225}
4226
4227
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004228MaybeObject* Heap::AllocateJSArrayAndStorage(
4229 ElementsKind elements_kind,
4230 int length,
4231 int capacity,
4232 ArrayStorageAllocationMode mode,
4233 PretenureFlag pretenure) {
4234 ASSERT(capacity >= length);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004235 if (length != 0 && mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE) {
4236 elements_kind = GetHoleyElementsKind(elements_kind);
4237 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004238 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
4239 JSArray* array;
4240 if (!maybe_array->To(&array)) return maybe_array;
4241
4242 if (capacity == 0) {
4243 array->set_length(Smi::FromInt(0));
4244 array->set_elements(empty_fixed_array());
4245 return array;
4246 }
4247
4248 FixedArrayBase* elms;
4249 MaybeObject* maybe_elms = NULL;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004250 if (IsFastDoubleElementsKind(elements_kind)) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004251 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
4252 maybe_elms = AllocateUninitializedFixedDoubleArray(capacity);
4253 } else {
4254 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
4255 maybe_elms = AllocateFixedDoubleArrayWithHoles(capacity);
4256 }
4257 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004258 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004259 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
4260 maybe_elms = AllocateUninitializedFixedArray(capacity);
4261 } else {
4262 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
4263 maybe_elms = AllocateFixedArrayWithHoles(capacity);
4264 }
4265 }
4266 if (!maybe_elms->To(&elms)) return maybe_elms;
4267
4268 array->set_elements(elms);
4269 array->set_length(Smi::FromInt(length));
4270 return array;
4271}
4272
4273
4274MaybeObject* Heap::AllocateJSArrayWithElements(
4275 FixedArrayBase* elements,
4276 ElementsKind elements_kind,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004277 int length,
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004278 PretenureFlag pretenure) {
4279 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
4280 JSArray* array;
4281 if (!maybe_array->To(&array)) return maybe_array;
4282
4283 array->set_elements(elements);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004284 array->set_length(Smi::FromInt(length));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004285 array->ValidateElements();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004286 return array;
4287}
4288
4289
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004290MaybeObject* Heap::AllocateJSProxy(Object* handler, Object* prototype) {
4291 // Allocate map.
4292 // TODO(rossberg): Once we optimize proxies, think about a scheme to share
4293 // maps. Will probably depend on the identity of the handler object, too.
danno@chromium.org40cb8782011-05-25 07:58:50 +00004294 Map* map;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004295 MaybeObject* maybe_map_obj = AllocateMap(JS_PROXY_TYPE, JSProxy::kSize);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004296 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004297 map->set_prototype(prototype);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004298
4299 // Allocate the proxy object.
lrn@chromium.org34e60782011-09-15 07:25:40 +00004300 JSProxy* result;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004301 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004302 if (!maybe_result->To<JSProxy>(&result)) return maybe_result;
4303 result->InitializeBody(map->instance_size(), Smi::FromInt(0));
4304 result->set_handler(handler);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004305 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004306 return result;
4307}
4308
4309
4310MaybeObject* Heap::AllocateJSFunctionProxy(Object* handler,
4311 Object* call_trap,
4312 Object* construct_trap,
4313 Object* prototype) {
4314 // Allocate map.
4315 // TODO(rossberg): Once we optimize proxies, think about a scheme to share
4316 // maps. Will probably depend on the identity of the handler object, too.
4317 Map* map;
4318 MaybeObject* maybe_map_obj =
4319 AllocateMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize);
4320 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
4321 map->set_prototype(prototype);
4322
4323 // Allocate the proxy object.
4324 JSFunctionProxy* result;
4325 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
4326 if (!maybe_result->To<JSFunctionProxy>(&result)) return maybe_result;
4327 result->InitializeBody(map->instance_size(), Smi::FromInt(0));
4328 result->set_handler(handler);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004329 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004330 result->set_call_trap(call_trap);
4331 result->set_construct_trap(construct_trap);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004332 return result;
4333}
4334
4335
lrn@chromium.org303ada72010-10-27 09:33:13 +00004336MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004337 ASSERT(constructor->has_initial_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004338 Map* map = constructor->initial_map();
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004339 ASSERT(map->is_dictionary_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004340
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004341 // Make sure no field properties are described in the initial map.
4342 // This guarantees us that normalizing the properties does not
4343 // require us to change property values to JSGlobalPropertyCells.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004344 ASSERT(map->NextFreePropertyIndex() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004345
4346 // Make sure we don't have a ton of pre-allocated slots in the
4347 // global objects. They will be unused once we normalize the object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004348 ASSERT(map->unused_property_fields() == 0);
4349 ASSERT(map->inobject_properties() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004350
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004351 // Initial size of the backing store to avoid resize of the storage during
4352 // bootstrapping. The size differs between the JS global object ad the
4353 // builtins object.
4354 int initial_size = map->instance_type() == JS_GLOBAL_OBJECT_TYPE ? 64 : 512;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004355
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004356 // Allocate a dictionary object for backing storage.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004357 StringDictionary* dictionary;
4358 MaybeObject* maybe_dictionary =
4359 StringDictionary::Allocate(
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004360 map->NumberOfOwnDescriptors() * 2 + initial_size);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004361 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004362
4363 // The global object might be created from an object template with accessors.
4364 // Fill these accessors into the dictionary.
4365 DescriptorArray* descs = map->instance_descriptors();
4366 for (int i = 0; i < descs->number_of_descriptors(); i++) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004367 PropertyDetails details = descs->GetDetails(i);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004368 ASSERT(details.type() == CALLBACKS); // Only accessors are expected.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004369 PropertyDetails d = PropertyDetails(details.attributes(),
4370 CALLBACKS,
4371 details.descriptor_index());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004372 Object* value = descs->GetCallbacksObject(i);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004373 MaybeObject* maybe_value = AllocateJSGlobalPropertyCell(value);
4374 if (!maybe_value->ToObject(&value)) return maybe_value;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004375
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004376 MaybeObject* maybe_added = dictionary->Add(descs->GetKey(i), value, d);
4377 if (!maybe_added->To(&dictionary)) return maybe_added;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004378 }
4379
4380 // Allocate the global object and initialize it with the backing store.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004381 JSObject* global;
4382 MaybeObject* maybe_global = Allocate(map, OLD_POINTER_SPACE);
4383 if (!maybe_global->To(&global)) return maybe_global;
4384
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004385 InitializeJSObjectFromMap(global, dictionary, map);
4386
4387 // Create a new map for the global object.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004388 Map* new_map;
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004389 MaybeObject* maybe_map = map->CopyDropDescriptors();
4390 if (!maybe_map->To(&new_map)) return maybe_map;
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004391 new_map->set_dictionary_map(true);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004392
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004393 // Set up the global object as a normalized object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004394 global->set_map(new_map);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004395 global->set_properties(dictionary);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004396
4397 // Make sure result is a global object with properties in dictionary.
4398 ASSERT(global->IsGlobalObject());
4399 ASSERT(!global->HasFastProperties());
4400 return global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004401}
4402
4403
lrn@chromium.org303ada72010-10-27 09:33:13 +00004404MaybeObject* Heap::CopyJSObject(JSObject* source) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004405 // Never used to copy functions. If functions need to be copied we
4406 // have to be careful to clear the literals array.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004407 SLOW_ASSERT(!source->IsJSFunction());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004408
4409 // Make the clone.
4410 Map* map = source->map();
4411 int object_size = map->instance_size();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004412 Object* clone;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004413
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004414 WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER;
4415
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004416 // If we're forced to always allocate, we use the general allocation
4417 // functions which may leave us with an object in old space.
4418 if (always_allocate()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004419 { MaybeObject* maybe_clone =
4420 AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE);
4421 if (!maybe_clone->ToObject(&clone)) return maybe_clone;
4422 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004423 Address clone_address = HeapObject::cast(clone)->address();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004424 CopyBlock(clone_address,
4425 source->address(),
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004426 object_size);
4427 // Update write barrier for all fields that lie beyond the header.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004428 RecordWrites(clone_address,
4429 JSObject::kHeaderSize,
antonm@chromium.org8e5e3382010-03-24 09:56:30 +00004430 (object_size - JSObject::kHeaderSize) / kPointerSize);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004431 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004432 wb_mode = SKIP_WRITE_BARRIER;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004433 { MaybeObject* maybe_clone = new_space_.AllocateRaw(object_size);
4434 if (!maybe_clone->ToObject(&clone)) return maybe_clone;
4435 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004436 SLOW_ASSERT(InNewSpace(clone));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004437 // Since we know the clone is allocated in new space, we can copy
ager@chromium.org32912102009-01-16 10:38:43 +00004438 // the contents without worrying about updating the write barrier.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004439 CopyBlock(HeapObject::cast(clone)->address(),
4440 source->address(),
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004441 object_size);
4442 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004443
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004444 SLOW_ASSERT(
4445 JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004446 FixedArrayBase* elements = FixedArrayBase::cast(source->elements());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004447 FixedArray* properties = FixedArray::cast(source->properties());
4448 // Update elements if necessary.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00004449 if (elements->length() > 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004450 Object* elem;
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004451 { MaybeObject* maybe_elem;
4452 if (elements->map() == fixed_cow_array_map()) {
4453 maybe_elem = FixedArray::cast(elements);
4454 } else if (source->HasFastDoubleElements()) {
4455 maybe_elem = CopyFixedDoubleArray(FixedDoubleArray::cast(elements));
4456 } else {
4457 maybe_elem = CopyFixedArray(FixedArray::cast(elements));
4458 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004459 if (!maybe_elem->ToObject(&elem)) return maybe_elem;
4460 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004461 JSObject::cast(clone)->set_elements(FixedArrayBase::cast(elem), wb_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004462 }
4463 // Update properties if necessary.
4464 if (properties->length() > 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004465 Object* prop;
4466 { MaybeObject* maybe_prop = CopyFixedArray(properties);
4467 if (!maybe_prop->ToObject(&prop)) return maybe_prop;
4468 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004469 JSObject::cast(clone)->set_properties(FixedArray::cast(prop), wb_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004470 }
4471 // Return the new clone.
4472 return clone;
4473}
4474
4475
lrn@chromium.org34e60782011-09-15 07:25:40 +00004476MaybeObject* Heap::ReinitializeJSReceiver(
4477 JSReceiver* object, InstanceType type, int size) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004478 ASSERT(type >= FIRST_JS_OBJECT_TYPE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004479
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004480 // Allocate fresh map.
4481 // TODO(rossberg): Once we optimize proxies, cache these maps.
4482 Map* map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004483 MaybeObject* maybe = AllocateMap(type, size);
4484 if (!maybe->To<Map>(&map)) return maybe;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004485
lrn@chromium.org34e60782011-09-15 07:25:40 +00004486 // Check that the receiver has at least the size of the fresh object.
4487 int size_difference = object->map()->instance_size() - map->instance_size();
4488 ASSERT(size_difference >= 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004489
4490 map->set_prototype(object->map()->prototype());
4491
4492 // Allocate the backing storage for the properties.
4493 int prop_size = map->unused_property_fields() - map->inobject_properties();
4494 Object* properties;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004495 maybe = AllocateFixedArray(prop_size, TENURED);
4496 if (!maybe->ToObject(&properties)) return maybe;
4497
4498 // Functions require some allocation, which might fail here.
4499 SharedFunctionInfo* shared = NULL;
4500 if (type == JS_FUNCTION_TYPE) {
4501 String* name;
4502 maybe = LookupAsciiSymbol("<freezing call trap>");
4503 if (!maybe->To<String>(&name)) return maybe;
4504 maybe = AllocateSharedFunctionInfo(name);
4505 if (!maybe->To<SharedFunctionInfo>(&shared)) return maybe;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004506 }
4507
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004508 // Because of possible retries of this function after failure,
4509 // we must NOT fail after this point, where we have changed the type!
4510
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004511 // Reset the map for the object.
4512 object->set_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004513 JSObject* jsobj = JSObject::cast(object);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004514
4515 // Reinitialize the object from the constructor map.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004516 InitializeJSObjectFromMap(jsobj, FixedArray::cast(properties), map);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004517
4518 // Functions require some minimal initialization.
4519 if (type == JS_FUNCTION_TYPE) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004520 map->set_function_with_prototype(true);
4521 InitializeFunction(JSFunction::cast(object), shared, the_hole_value());
4522 JSFunction::cast(object)->set_context(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004523 isolate()->context()->native_context());
lrn@chromium.org34e60782011-09-15 07:25:40 +00004524 }
4525
4526 // Put in filler if the new object is smaller than the old.
4527 if (size_difference > 0) {
4528 CreateFillerObjectAt(
4529 object->address() + map->instance_size(), size_difference);
4530 }
4531
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004532 return object;
4533}
4534
4535
lrn@chromium.org303ada72010-10-27 09:33:13 +00004536MaybeObject* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor,
4537 JSGlobalProxy* object) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004538 ASSERT(constructor->has_initial_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004539 Map* map = constructor->initial_map();
4540
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004541 // Check that the already allocated object has the same size and type as
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004542 // objects allocated using the constructor.
4543 ASSERT(map->instance_size() == object->map()->instance_size());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004544 ASSERT(map->instance_type() == object->map()->instance_type());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004545
4546 // Allocate the backing storage for the properties.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004547 int prop_size = map->unused_property_fields() - map->inobject_properties();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004548 Object* properties;
4549 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, TENURED);
4550 if (!maybe_properties->ToObject(&properties)) return maybe_properties;
4551 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004552
4553 // Reset the map for the object.
4554 object->set_map(constructor->initial_map());
4555
4556 // Reinitialize the object from the constructor map.
4557 InitializeJSObjectFromMap(object, FixedArray::cast(properties), map);
4558 return object;
4559}
4560
4561
lrn@chromium.org303ada72010-10-27 09:33:13 +00004562MaybeObject* Heap::AllocateStringFromAscii(Vector<const char> string,
4563 PretenureFlag pretenure) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004564 int length = string.length();
4565 if (length == 1) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004566 return Heap::LookupSingleCharacterStringFromCode(string[0]);
4567 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004568 Object* result;
4569 { MaybeObject* maybe_result =
4570 AllocateRawAsciiString(string.length(), pretenure);
4571 if (!maybe_result->ToObject(&result)) return maybe_result;
4572 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004573
4574 // Copy the characters into the new object.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004575 CopyChars(SeqOneByteString::cast(result)->GetChars(), string.start(), length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004576 return result;
4577}
4578
4579
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004580MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector<const char> string,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004581 int non_ascii_start,
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004582 PretenureFlag pretenure) {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004583 // Continue counting the number of characters in the UTF-8 string, starting
4584 // from the first non-ascii character or word.
4585 int chars = non_ascii_start;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004586 Access<UnicodeCache::Utf8Decoder>
4587 decoder(isolate_->unicode_cache()->utf8_decoder());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004588 decoder->Reset(string.start() + non_ascii_start, string.length() - chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004589 while (decoder->has_more()) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004590 uint32_t r = decoder->GetNext();
4591 if (r <= unibrow::Utf16::kMaxNonSurrogateCharCode) {
4592 chars++;
4593 } else {
4594 chars += 2;
4595 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004596 }
4597
lrn@chromium.org303ada72010-10-27 09:33:13 +00004598 Object* result;
4599 { MaybeObject* maybe_result = AllocateRawTwoByteString(chars, pretenure);
4600 if (!maybe_result->ToObject(&result)) return maybe_result;
4601 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004602
4603 // Convert and copy the characters into the new object.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004604 SeqTwoByteString* twobyte = SeqTwoByteString::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004605 decoder->Reset(string.start(), string.length());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004606 int i = 0;
4607 while (i < chars) {
4608 uint32_t r = decoder->GetNext();
4609 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004610 twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::LeadSurrogate(r));
4611 twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::TrailSurrogate(r));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004612 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004613 twobyte->SeqTwoByteStringSet(i++, r);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004614 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004615 }
4616 return result;
4617}
4618
4619
lrn@chromium.org303ada72010-10-27 09:33:13 +00004620MaybeObject* Heap::AllocateStringFromTwoByte(Vector<const uc16> string,
4621 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004622 // Check if the string is an ASCII string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004623 Object* result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004624 int length = string.length();
4625 const uc16* start = string.start();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004626
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004627 if (String::IsAscii(start, length)) {
4628 MaybeObject* maybe_result = AllocateRawAsciiString(length, pretenure);
4629 if (!maybe_result->ToObject(&result)) return maybe_result;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004630 CopyChars(SeqOneByteString::cast(result)->GetChars(), start, length);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004631 } else { // It's not an ASCII string.
4632 MaybeObject* maybe_result = AllocateRawTwoByteString(length, pretenure);
4633 if (!maybe_result->ToObject(&result)) return maybe_result;
4634 CopyChars(SeqTwoByteString::cast(result)->GetChars(), start, length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004635 }
4636 return result;
4637}
4638
4639
4640Map* Heap::SymbolMapForString(String* string) {
4641 // If the string is in new space it cannot be used as a symbol.
4642 if (InNewSpace(string)) return NULL;
4643
4644 // Find the corresponding symbol map for strings.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004645 switch (string->map()->instance_type()) {
4646 case STRING_TYPE: return symbol_map();
4647 case ASCII_STRING_TYPE: return ascii_symbol_map();
4648 case CONS_STRING_TYPE: return cons_symbol_map();
4649 case CONS_ASCII_STRING_TYPE: return cons_ascii_symbol_map();
4650 case EXTERNAL_STRING_TYPE: return external_symbol_map();
4651 case EXTERNAL_ASCII_STRING_TYPE: return external_ascii_symbol_map();
4652 case EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
4653 return external_symbol_with_ascii_data_map();
4654 case SHORT_EXTERNAL_STRING_TYPE: return short_external_symbol_map();
4655 case SHORT_EXTERNAL_ASCII_STRING_TYPE:
4656 return short_external_ascii_symbol_map();
4657 case SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
4658 return short_external_symbol_with_ascii_data_map();
4659 default: return NULL; // No match found.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004660 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004661}
4662
4663
lrn@chromium.org303ada72010-10-27 09:33:13 +00004664MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
4665 int chars,
4666 uint32_t hash_field) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004667 ASSERT(chars >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004668 // Ensure the chars matches the number of characters in the buffer.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004669 ASSERT(static_cast<unsigned>(chars) == buffer->Utf16Length());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004670 // Determine whether the string is ASCII.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004671 bool is_ascii = true;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004672 while (buffer->has_more()) {
4673 if (buffer->GetNext() > unibrow::Utf8::kMaxOneByteChar) {
4674 is_ascii = false;
4675 break;
4676 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004677 }
4678 buffer->Rewind();
4679
4680 // Compute map and object size.
4681 int size;
4682 Map* map;
4683
4684 if (is_ascii) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004685 if (chars > SeqOneByteString::kMaxLength) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004686 return Failure::OutOfMemoryException();
4687 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004688 map = ascii_symbol_map();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004689 size = SeqOneByteString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004690 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004691 if (chars > SeqTwoByteString::kMaxLength) {
4692 return Failure::OutOfMemoryException();
4693 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004694 map = symbol_map();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004695 size = SeqTwoByteString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004696 }
4697
4698 // Allocate string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004699 Object* result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004700 { MaybeObject* maybe_result = (size > Page::kMaxNonCodeHeapObjectSize)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004701 ? lo_space_->AllocateRaw(size, NOT_EXECUTABLE)
lrn@chromium.org303ada72010-10-27 09:33:13 +00004702 : old_data_space_->AllocateRaw(size);
4703 if (!maybe_result->ToObject(&result)) return maybe_result;
4704 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004705
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004706 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(map);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004707 // Set length and hash fields of the allocated string.
ager@chromium.org870a0b62008-11-04 11:43:05 +00004708 String* answer = String::cast(result);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004709 answer->set_length(chars);
4710 answer->set_hash_field(hash_field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004711
ager@chromium.org870a0b62008-11-04 11:43:05 +00004712 ASSERT_EQ(size, answer->Size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004713
4714 // Fill in the characters.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004715 int i = 0;
4716 while (i < chars) {
4717 uint32_t character = buffer->GetNext();
4718 if (character > unibrow::Utf16::kMaxNonSurrogateCharCode) {
4719 answer->Set(i++, unibrow::Utf16::LeadSurrogate(character));
4720 answer->Set(i++, unibrow::Utf16::TrailSurrogate(character));
4721 } else {
4722 answer->Set(i++, character);
4723 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004724 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00004725 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004726}
4727
4728
lrn@chromium.org303ada72010-10-27 09:33:13 +00004729MaybeObject* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004730 if (length < 0 || length > SeqOneByteString::kMaxLength) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004731 return Failure::OutOfMemoryException();
4732 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004733
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004734 int size = SeqOneByteString::SizeFor(length);
4735 ASSERT(size <= SeqOneByteString::kMaxSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004736
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004737 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
4738 AllocationSpace retry_space = OLD_DATA_SPACE;
4739
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004740 if (space == NEW_SPACE) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004741 if (size > kMaxObjectSizeInNewSpace) {
4742 // Allocate in large object space, retry space will be ignored.
4743 space = LO_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004744 } else if (size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004745 // Allocate in new space, retry in large object space.
4746 retry_space = LO_SPACE;
4747 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004748 } else if (space == OLD_DATA_SPACE &&
4749 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004750 space = LO_SPACE;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004751 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004752 Object* result;
4753 { MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
4754 if (!maybe_result->ToObject(&result)) return maybe_result;
4755 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004756
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004757 // Partially initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004758 HeapObject::cast(result)->set_map_no_write_barrier(ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004759 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004760 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004761 ASSERT_EQ(size, HeapObject::cast(result)->Size());
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004762
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004763#ifdef VERIFY_HEAP
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004764 if (FLAG_verify_heap) {
4765 // Initialize string's content to ensure ASCII-ness (character range 0-127)
4766 // as required when verifying the heap.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004767 char* dest = SeqOneByteString::cast(result)->GetChars();
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004768 memset(dest, 0x0F, length * kCharSize);
4769 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004770#endif
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004771
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004772 return result;
4773}
4774
4775
lrn@chromium.org303ada72010-10-27 09:33:13 +00004776MaybeObject* Heap::AllocateRawTwoByteString(int length,
4777 PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004778 if (length < 0 || length > SeqTwoByteString::kMaxLength) {
4779 return Failure::OutOfMemoryException();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004780 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004781 int size = SeqTwoByteString::SizeFor(length);
4782 ASSERT(size <= SeqTwoByteString::kMaxSize);
4783 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
4784 AllocationSpace retry_space = OLD_DATA_SPACE;
4785
4786 if (space == NEW_SPACE) {
4787 if (size > kMaxObjectSizeInNewSpace) {
4788 // Allocate in large object space, retry space will be ignored.
4789 space = LO_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004790 } else if (size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004791 // Allocate in new space, retry in large object space.
4792 retry_space = LO_SPACE;
4793 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004794 } else if (space == OLD_DATA_SPACE &&
4795 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004796 space = LO_SPACE;
4797 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004798 Object* result;
4799 { MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
4800 if (!maybe_result->ToObject(&result)) return maybe_result;
4801 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004802
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004803 // Partially initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004804 HeapObject::cast(result)->set_map_no_write_barrier(string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004805 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004806 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004807 ASSERT_EQ(size, HeapObject::cast(result)->Size());
4808 return result;
4809}
4810
4811
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004812MaybeObject* Heap::AllocateJSArray(
4813 ElementsKind elements_kind,
4814 PretenureFlag pretenure) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004815 Context* native_context = isolate()->context()->native_context();
4816 JSFunction* array_function = native_context->array_function();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004817 Map* map = array_function->initial_map();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004818 Object* maybe_map_array = native_context->js_array_maps();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004819 if (!maybe_map_array->IsUndefined()) {
4820 Object* maybe_transitioned_map =
4821 FixedArray::cast(maybe_map_array)->get(elements_kind);
4822 if (!maybe_transitioned_map->IsUndefined()) {
4823 map = Map::cast(maybe_transitioned_map);
4824 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004825 }
4826
4827 return AllocateJSObjectFromMap(map, pretenure);
4828}
4829
4830
lrn@chromium.org303ada72010-10-27 09:33:13 +00004831MaybeObject* Heap::AllocateEmptyFixedArray() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004832 int size = FixedArray::SizeFor(0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004833 Object* result;
4834 { MaybeObject* maybe_result =
4835 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
4836 if (!maybe_result->ToObject(&result)) return maybe_result;
4837 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004838 // Initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004839 reinterpret_cast<FixedArray*>(result)->set_map_no_write_barrier(
4840 fixed_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004841 reinterpret_cast<FixedArray*>(result)->set_length(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004842 return result;
4843}
4844
4845
lrn@chromium.org303ada72010-10-27 09:33:13 +00004846MaybeObject* Heap::AllocateRawFixedArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004847 if (length < 0 || length > FixedArray::kMaxLength) {
4848 return Failure::OutOfMemoryException();
4849 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004850 ASSERT(length > 0);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004851 // Use the general function if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004852 if (always_allocate()) return AllocateFixedArray(length, TENURED);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004853 // Allocate the raw data for a fixed array.
4854 int size = FixedArray::SizeFor(length);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004855 return size <= kMaxObjectSizeInNewSpace
4856 ? new_space_.AllocateRaw(size)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004857 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004858}
4859
4860
lrn@chromium.org303ada72010-10-27 09:33:13 +00004861MaybeObject* Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004862 int len = src->length();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004863 Object* obj;
4864 { MaybeObject* maybe_obj = AllocateRawFixedArray(len);
4865 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4866 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004867 if (InNewSpace(obj)) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004868 HeapObject* dst = HeapObject::cast(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004869 dst->set_map_no_write_barrier(map);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004870 CopyBlock(dst->address() + kPointerSize,
4871 src->address() + kPointerSize,
4872 FixedArray::SizeFor(len) - kPointerSize);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004873 return obj;
4874 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004875 HeapObject::cast(obj)->set_map_no_write_barrier(map);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004876 FixedArray* result = FixedArray::cast(obj);
4877 result->set_length(len);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004878
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004879 // Copy the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004880 AssertNoAllocation no_gc;
4881 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004882 for (int i = 0; i < len; i++) result->set(i, src->get(i), mode);
4883 return result;
4884}
4885
4886
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004887MaybeObject* Heap::CopyFixedDoubleArrayWithMap(FixedDoubleArray* src,
4888 Map* map) {
4889 int len = src->length();
4890 Object* obj;
4891 { MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(len, NOT_TENURED);
4892 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4893 }
4894 HeapObject* dst = HeapObject::cast(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004895 dst->set_map_no_write_barrier(map);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004896 CopyBlock(
4897 dst->address() + FixedDoubleArray::kLengthOffset,
4898 src->address() + FixedDoubleArray::kLengthOffset,
4899 FixedDoubleArray::SizeFor(len) - FixedDoubleArray::kLengthOffset);
4900 return obj;
4901}
4902
4903
lrn@chromium.org303ada72010-10-27 09:33:13 +00004904MaybeObject* Heap::AllocateFixedArray(int length) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004905 ASSERT(length >= 0);
ager@chromium.org32912102009-01-16 10:38:43 +00004906 if (length == 0) return empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004907 Object* result;
4908 { MaybeObject* maybe_result = AllocateRawFixedArray(length);
4909 if (!maybe_result->ToObject(&result)) return maybe_result;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004910 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004911 // Initialize header.
4912 FixedArray* array = reinterpret_cast<FixedArray*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004913 array->set_map_no_write_barrier(fixed_array_map());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004914 array->set_length(length);
4915 // Initialize body.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004916 ASSERT(!InNewSpace(undefined_value()));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004917 MemsetPointer(array->data_start(), undefined_value(), length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004918 return result;
4919}
4920
4921
lrn@chromium.org303ada72010-10-27 09:33:13 +00004922MaybeObject* Heap::AllocateRawFixedArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004923 if (length < 0 || length > FixedArray::kMaxLength) {
4924 return Failure::OutOfMemoryException();
4925 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004926
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004927 AllocationSpace space =
4928 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004929 int size = FixedArray::SizeFor(length);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004930 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
4931 // Too big for new space.
4932 space = LO_SPACE;
4933 } else if (space == OLD_POINTER_SPACE &&
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004934 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004935 // Too big for old pointer space.
4936 space = LO_SPACE;
4937 }
4938
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004939 AllocationSpace retry_space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004940 (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_POINTER_SPACE : LO_SPACE;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004941
4942 return AllocateRaw(size, space, retry_space);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004943}
4944
4945
lrn@chromium.org303ada72010-10-27 09:33:13 +00004946MUST_USE_RESULT static MaybeObject* AllocateFixedArrayWithFiller(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004947 Heap* heap,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004948 int length,
4949 PretenureFlag pretenure,
4950 Object* filler) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004951 ASSERT(length >= 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004952 ASSERT(heap->empty_fixed_array()->IsFixedArray());
4953 if (length == 0) return heap->empty_fixed_array();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004954
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004955 ASSERT(!heap->InNewSpace(filler));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004956 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004957 { MaybeObject* maybe_result = heap->AllocateRawFixedArray(length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004958 if (!maybe_result->ToObject(&result)) return maybe_result;
4959 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004960
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004961 HeapObject::cast(result)->set_map_no_write_barrier(heap->fixed_array_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004962 FixedArray* array = FixedArray::cast(result);
4963 array->set_length(length);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004964 MemsetPointer(array->data_start(), filler, length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004965 return array;
4966}
4967
4968
lrn@chromium.org303ada72010-10-27 09:33:13 +00004969MaybeObject* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004970 return AllocateFixedArrayWithFiller(this,
4971 length,
4972 pretenure,
4973 undefined_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004974}
4975
4976
lrn@chromium.org303ada72010-10-27 09:33:13 +00004977MaybeObject* Heap::AllocateFixedArrayWithHoles(int length,
4978 PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004979 return AllocateFixedArrayWithFiller(this,
4980 length,
4981 pretenure,
4982 the_hole_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004983}
4984
4985
lrn@chromium.org303ada72010-10-27 09:33:13 +00004986MaybeObject* Heap::AllocateUninitializedFixedArray(int length) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004987 if (length == 0) return empty_fixed_array();
4988
lrn@chromium.org303ada72010-10-27 09:33:13 +00004989 Object* obj;
4990 { MaybeObject* maybe_obj = AllocateRawFixedArray(length);
4991 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4992 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004993
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004994 reinterpret_cast<FixedArray*>(obj)->set_map_no_write_barrier(
4995 fixed_array_map());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004996 FixedArray::cast(obj)->set_length(length);
4997 return obj;
4998}
4999
5000
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005001MaybeObject* Heap::AllocateEmptyFixedDoubleArray() {
5002 int size = FixedDoubleArray::SizeFor(0);
5003 Object* result;
5004 { MaybeObject* maybe_result =
5005 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
5006 if (!maybe_result->ToObject(&result)) return maybe_result;
5007 }
5008 // Initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005009 reinterpret_cast<FixedDoubleArray*>(result)->set_map_no_write_barrier(
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005010 fixed_double_array_map());
5011 reinterpret_cast<FixedDoubleArray*>(result)->set_length(0);
5012 return result;
5013}
5014
5015
5016MaybeObject* Heap::AllocateUninitializedFixedDoubleArray(
5017 int length,
5018 PretenureFlag pretenure) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005019 if (length == 0) return empty_fixed_array();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005020
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005021 Object* elements_object;
5022 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
5023 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj;
5024 FixedDoubleArray* elements =
5025 reinterpret_cast<FixedDoubleArray*>(elements_object);
5026
5027 elements->set_map_no_write_barrier(fixed_double_array_map());
5028 elements->set_length(length);
5029 return elements;
5030}
5031
5032
5033MaybeObject* Heap::AllocateFixedDoubleArrayWithHoles(
5034 int length,
5035 PretenureFlag pretenure) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005036 if (length == 0) return empty_fixed_array();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005037
5038 Object* elements_object;
5039 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
5040 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj;
5041 FixedDoubleArray* elements =
5042 reinterpret_cast<FixedDoubleArray*>(elements_object);
5043
5044 for (int i = 0; i < length; ++i) {
5045 elements->set_the_hole(i);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005046 }
5047
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005048 elements->set_map_no_write_barrier(fixed_double_array_map());
5049 elements->set_length(length);
5050 return elements;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005051}
5052
5053
5054MaybeObject* Heap::AllocateRawFixedDoubleArray(int length,
5055 PretenureFlag pretenure) {
5056 if (length < 0 || length > FixedDoubleArray::kMaxLength) {
5057 return Failure::OutOfMemoryException();
5058 }
5059
5060 AllocationSpace space =
5061 (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
5062 int size = FixedDoubleArray::SizeFor(length);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005063
5064#ifndef V8_HOST_ARCH_64_BIT
5065 size += kPointerSize;
5066#endif
5067
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005068 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
5069 // Too big for new space.
5070 space = LO_SPACE;
5071 } else if (space == OLD_DATA_SPACE &&
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005072 size > Page::kMaxNonCodeHeapObjectSize) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005073 // Too big for old data space.
5074 space = LO_SPACE;
5075 }
5076
5077 AllocationSpace retry_space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005078 (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_DATA_SPACE : LO_SPACE;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005079
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005080 HeapObject* object;
5081 { MaybeObject* maybe_object = AllocateRaw(size, space, retry_space);
5082 if (!maybe_object->To<HeapObject>(&object)) return maybe_object;
5083 }
5084
5085 return EnsureDoubleAligned(this, object, size);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005086}
5087
5088
lrn@chromium.org303ada72010-10-27 09:33:13 +00005089MaybeObject* Heap::AllocateHashTable(int length, PretenureFlag pretenure) {
5090 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005091 { MaybeObject* maybe_result = AllocateFixedArray(length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005092 if (!maybe_result->ToObject(&result)) return maybe_result;
5093 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005094 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(
5095 hash_table_map());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005096 ASSERT(result->IsHashTable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005097 return result;
5098}
5099
5100
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005101MaybeObject* Heap::AllocateNativeContext() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005102 Object* result;
5103 { MaybeObject* maybe_result =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005104 AllocateFixedArray(Context::NATIVE_CONTEXT_SLOTS);
5105 if (!maybe_result->ToObject(&result)) return maybe_result;
5106 }
5107 Context* context = reinterpret_cast<Context*>(result);
5108 context->set_map_no_write_barrier(native_context_map());
5109 context->set_js_array_maps(undefined_value());
5110 ASSERT(context->IsNativeContext());
5111 ASSERT(result->IsContext());
5112 return result;
5113}
5114
5115
5116MaybeObject* Heap::AllocateGlobalContext(JSFunction* function,
5117 ScopeInfo* scope_info) {
5118 Object* result;
5119 { MaybeObject* maybe_result =
5120 AllocateFixedArray(scope_info->ContextLength(), TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005121 if (!maybe_result->ToObject(&result)) return maybe_result;
5122 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005123 Context* context = reinterpret_cast<Context*>(result);
danno@chromium.orgeb831462012-08-24 11:57:08 +00005124 context->set_map_no_write_barrier(global_context_map());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005125 context->set_closure(function);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005126 context->set_previous(function->context());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005127 context->set_extension(scope_info);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005128 context->set_global_object(function->context()->global_object());
danno@chromium.orgeb831462012-08-24 11:57:08 +00005129 ASSERT(context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005130 ASSERT(result->IsContext());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005131 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005132}
5133
5134
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005135MaybeObject* Heap::AllocateModuleContext(ScopeInfo* scope_info) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005136 Object* result;
5137 { MaybeObject* maybe_result =
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005138 AllocateFixedArray(scope_info->ContextLength(), TENURED);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005139 if (!maybe_result->ToObject(&result)) return maybe_result;
5140 }
5141 Context* context = reinterpret_cast<Context*>(result);
5142 context->set_map_no_write_barrier(module_context_map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005143 // Context links will be set later.
5144 context->set_extension(Smi::FromInt(0));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005145 return context;
5146}
5147
5148
lrn@chromium.org303ada72010-10-27 09:33:13 +00005149MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005150 ASSERT(length >= Context::MIN_CONTEXT_SLOTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005151 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005152 { MaybeObject* maybe_result = AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005153 if (!maybe_result->ToObject(&result)) return maybe_result;
5154 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005155 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005156 context->set_map_no_write_barrier(function_context_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005157 context->set_closure(function);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005158 context->set_previous(function->context());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005159 context->set_extension(Smi::FromInt(0));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005160 context->set_global_object(function->context()->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005161 return context;
5162}
5163
5164
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005165MaybeObject* Heap::AllocateCatchContext(JSFunction* function,
5166 Context* previous,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005167 String* name,
5168 Object* thrown_object) {
5169 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == Context::THROWN_OBJECT_INDEX);
5170 Object* result;
5171 { MaybeObject* maybe_result =
5172 AllocateFixedArray(Context::MIN_CONTEXT_SLOTS + 1);
5173 if (!maybe_result->ToObject(&result)) return maybe_result;
5174 }
5175 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005176 context->set_map_no_write_barrier(catch_context_map());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005177 context->set_closure(function);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005178 context->set_previous(previous);
5179 context->set_extension(name);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005180 context->set_global_object(previous->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005181 context->set(Context::THROWN_OBJECT_INDEX, thrown_object);
5182 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005183}
5184
5185
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005186MaybeObject* Heap::AllocateWithContext(JSFunction* function,
5187 Context* previous,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005188 JSObject* extension) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005189 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005190 { MaybeObject* maybe_result = AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005191 if (!maybe_result->ToObject(&result)) return maybe_result;
5192 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005193 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005194 context->set_map_no_write_barrier(with_context_map());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005195 context->set_closure(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196 context->set_previous(previous);
5197 context->set_extension(extension);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005198 context->set_global_object(previous->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005199 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005200}
5201
5202
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005203MaybeObject* Heap::AllocateBlockContext(JSFunction* function,
5204 Context* previous,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005205 ScopeInfo* scope_info) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005206 Object* result;
5207 { MaybeObject* maybe_result =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005208 AllocateFixedArrayWithHoles(scope_info->ContextLength());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005209 if (!maybe_result->ToObject(&result)) return maybe_result;
5210 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005211 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005212 context->set_map_no_write_barrier(block_context_map());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005213 context->set_closure(function);
5214 context->set_previous(previous);
5215 context->set_extension(scope_info);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005216 context->set_global_object(previous->global_object());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005217 return context;
5218}
5219
5220
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005221MaybeObject* Heap::AllocateScopeInfo(int length) {
5222 FixedArray* scope_info;
5223 MaybeObject* maybe_scope_info = AllocateFixedArray(length, TENURED);
5224 if (!maybe_scope_info->To(&scope_info)) return maybe_scope_info;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005225 scope_info->set_map_no_write_barrier(scope_info_map());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005226 return scope_info;
5227}
5228
5229
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00005230MaybeObject* Heap::AllocateExternal(void* value) {
5231 Foreign* foreign;
5232 { MaybeObject* maybe_result = AllocateForeign(static_cast<Address>(value));
5233 if (!maybe_result->To(&foreign)) return maybe_result;
5234 }
5235 JSObject* external;
5236 { MaybeObject* maybe_result = AllocateJSObjectFromMap(external_map());
5237 if (!maybe_result->To(&external)) return maybe_result;
5238 }
5239 external->SetInternalField(0, foreign);
5240 return external;
5241}
5242
5243
lrn@chromium.org303ada72010-10-27 09:33:13 +00005244MaybeObject* Heap::AllocateStruct(InstanceType type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005245 Map* map;
5246 switch (type) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005247#define MAKE_CASE(NAME, Name, name) \
5248 case NAME##_TYPE: map = name##_map(); break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005249STRUCT_LIST(MAKE_CASE)
5250#undef MAKE_CASE
5251 default:
5252 UNREACHABLE();
5253 return Failure::InternalError();
5254 }
5255 int size = map->instance_size();
5256 AllocationSpace space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005257 (size > Page::kMaxNonCodeHeapObjectSize) ? LO_SPACE : OLD_POINTER_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005258 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005259 { MaybeObject* maybe_result = Allocate(map, space);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005260 if (!maybe_result->ToObject(&result)) return maybe_result;
5261 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005262 Struct::cast(result)->InitializeBody(size);
5263 return result;
5264}
5265
5266
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005267bool Heap::IsHeapIterable() {
5268 return (!old_pointer_space()->was_swept_conservatively() &&
5269 !old_data_space()->was_swept_conservatively());
5270}
5271
5272
5273void Heap::EnsureHeapIsIterable() {
5274 ASSERT(IsAllocationAllowed());
5275 if (!IsHeapIterable()) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005276 CollectAllGarbage(kMakeHeapIterableMask, "Heap::EnsureHeapIsIterable");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005277 }
5278 ASSERT(IsHeapIterable());
5279}
5280
5281
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005282void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005283 incremental_marking()->Step(step_size,
5284 IncrementalMarking::NO_GC_VIA_STACK_GUARD);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005285
5286 if (incremental_marking()->IsComplete()) {
5287 bool uncommit = false;
5288 if (gc_count_at_last_idle_gc_ == gc_count_) {
5289 // No GC since the last full GC, the mutator is probably not active.
5290 isolate_->compilation_cache()->Clear();
5291 uncommit = true;
5292 }
5293 CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental");
5294 gc_count_at_last_idle_gc_ = gc_count_;
5295 if (uncommit) {
5296 new_space_.Shrink();
5297 UncommitFromSpace();
5298 }
5299 }
5300}
5301
5302
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005303bool Heap::IdleNotification(int hint) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005304 // Hints greater than this value indicate that
5305 // the embedder is requesting a lot of GC work.
danno@chromium.org88aa0582012-03-23 15:11:57 +00005306 const int kMaxHint = 1000;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005307 // Minimal hint that allows to do full GC.
5308 const int kMinHintForFullGC = 100;
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005309 intptr_t size_factor = Min(Max(hint, 20), kMaxHint) / 4;
5310 // The size factor is in range [5..250]. The numbers here are chosen from
5311 // experiments. If you changes them, make sure to test with
5312 // chrome/performance_ui_tests --gtest_filter="GeneralMixMemoryTest.*
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00005313 intptr_t step_size =
5314 size_factor * IncrementalMarking::kAllocatedThreshold;
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005315
5316 if (contexts_disposed_ > 0) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005317 if (hint >= kMaxHint) {
5318 // The embedder is requesting a lot of GC work after context disposal,
5319 // we age inline caches so that they don't keep objects from
5320 // the old context alive.
5321 AgeInlineCaches();
5322 }
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005323 int mark_sweep_time = Min(TimeMarkSweepWouldTakeInMs(), 1000);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005324 if (hint >= mark_sweep_time && !FLAG_expose_gc &&
5325 incremental_marking()->IsStopped()) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005326 HistogramTimerScope scope(isolate_->counters()->gc_context());
5327 CollectAllGarbage(kReduceMemoryFootprintMask,
5328 "idle notification: contexts disposed");
5329 } else {
5330 AdvanceIdleIncrementalMarking(step_size);
5331 contexts_disposed_ = 0;
5332 }
5333 // Make sure that we have no pending context disposals.
5334 // Take into account that we might have decided to delay full collection
5335 // because incremental marking is in progress.
5336 ASSERT((contexts_disposed_ == 0) || !incremental_marking()->IsStopped());
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005337 // After context disposal there is likely a lot of garbage remaining, reset
5338 // the idle notification counters in order to trigger more incremental GCs
5339 // on subsequent idle notifications.
5340 StartIdleRound();
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005341 return false;
5342 }
5343
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005344 if (!FLAG_incremental_marking || FLAG_expose_gc || Serializer::enabled()) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005345 return IdleGlobalGC();
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005346 }
5347
5348 // By doing small chunks of GC work in each IdleNotification,
5349 // perform a round of incremental GCs and after that wait until
5350 // the mutator creates enough garbage to justify a new round.
5351 // An incremental GC progresses as follows:
5352 // 1. many incremental marking steps,
5353 // 2. one old space mark-sweep-compact,
5354 // 3. many lazy sweep steps.
5355 // Use mark-sweep-compact events to count incremental GCs in a round.
5356
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005357
5358 if (incremental_marking()->IsStopped()) {
5359 if (!IsSweepingComplete() &&
5360 !AdvanceSweepers(static_cast<int>(step_size))) {
5361 return false;
5362 }
5363 }
5364
5365 if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) {
5366 if (EnoughGarbageSinceLastIdleRound()) {
5367 StartIdleRound();
5368 } else {
5369 return true;
5370 }
5371 }
5372
5373 int new_mark_sweeps = ms_count_ - ms_count_at_last_idle_notification_;
5374 mark_sweeps_since_idle_round_started_ += new_mark_sweeps;
5375 ms_count_at_last_idle_notification_ = ms_count_;
5376
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005377 int remaining_mark_sweeps = kMaxMarkSweepsInIdleRound -
5378 mark_sweeps_since_idle_round_started_;
5379
5380 if (remaining_mark_sweeps <= 0) {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005381 FinishIdleRound();
5382 return true;
5383 }
5384
5385 if (incremental_marking()->IsStopped()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005386 // If there are no more than two GCs left in this idle round and we are
5387 // allowed to do a full GC, then make those GCs full in order to compact
5388 // the code space.
5389 // TODO(ulan): Once we enable code compaction for incremental marking,
5390 // we can get rid of this special case and always start incremental marking.
5391 if (remaining_mark_sweeps <= 2 && hint >= kMinHintForFullGC) {
5392 CollectAllGarbage(kReduceMemoryFootprintMask,
5393 "idle notification: finalize idle round");
5394 } else {
5395 incremental_marking()->Start();
5396 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005397 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005398 if (!incremental_marking()->IsStopped()) {
5399 AdvanceIdleIncrementalMarking(step_size);
5400 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005401 return false;
5402}
5403
5404
5405bool Heap::IdleGlobalGC() {
ager@chromium.orga1645e22009-09-09 19:27:10 +00005406 static const int kIdlesBeforeScavenge = 4;
5407 static const int kIdlesBeforeMarkSweep = 7;
5408 static const int kIdlesBeforeMarkCompact = 8;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005409 static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005410 static const unsigned int kGCsBetweenCleanup = 4;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005411
5412 if (!last_idle_notification_gc_count_init_) {
5413 last_idle_notification_gc_count_ = gc_count_;
5414 last_idle_notification_gc_count_init_ = true;
5415 }
ager@chromium.org96c75b52009-08-26 09:13:16 +00005416
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005417 bool uncommit = true;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005418 bool finished = false;
5419
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005420 // Reset the number of idle notifications received when a number of
5421 // GCs have taken place. This allows another round of cleanup based
5422 // on idle notifications if enough work has been carried out to
5423 // provoke a number of garbage collections.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005424 if (gc_count_ - last_idle_notification_gc_count_ < kGCsBetweenCleanup) {
5425 number_idle_notifications_ =
5426 Min(number_idle_notifications_ + 1, kMaxIdleCount);
ager@chromium.org96c75b52009-08-26 09:13:16 +00005427 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005428 number_idle_notifications_ = 0;
5429 last_idle_notification_gc_count_ = gc_count_;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005430 }
5431
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005432 if (number_idle_notifications_ == kIdlesBeforeScavenge) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005433 CollectGarbage(NEW_SPACE, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005434 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005435 last_idle_notification_gc_count_ = gc_count_;
5436 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005437 // Before doing the mark-sweep collections we clear the
5438 // compilation cache to avoid hanging on to source code and
5439 // generated code for cached functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005440 isolate_->compilation_cache()->Clear();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005441
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005442 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005443 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005444 last_idle_notification_gc_count_ = gc_count_;
ager@chromium.orga1645e22009-09-09 19:27:10 +00005445
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005446 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005447 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005448 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005449 last_idle_notification_gc_count_ = gc_count_;
5450 number_idle_notifications_ = 0;
ager@chromium.orga1645e22009-09-09 19:27:10 +00005451 finished = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005452 } else if (number_idle_notifications_ > kIdlesBeforeMarkCompact) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005453 // If we have received more than kIdlesBeforeMarkCompact idle
5454 // notifications we do not perform any cleanup because we don't
5455 // expect to gain much by doing so.
5456 finished = true;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005457 }
5458
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005459 if (uncommit) UncommitFromSpace();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005460
ager@chromium.org96c75b52009-08-26 09:13:16 +00005461 return finished;
5462}
5463
5464
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005465#ifdef DEBUG
5466
5467void Heap::Print() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005468 if (!HasBeenSetUp()) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005469 isolate()->PrintStack();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005470 AllSpaces spaces;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005471 for (Space* space = spaces.next(); space != NULL; space = spaces.next())
5472 space->Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005473}
5474
5475
5476void Heap::ReportCodeStatistics(const char* title) {
5477 PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title);
5478 PagedSpace::ResetCodeStatistics();
5479 // We do not look for code in new space, map space, or old space. If code
5480 // somehow ends up in those spaces, we would miss it here.
5481 code_space_->CollectCodeStatistics();
5482 lo_space_->CollectCodeStatistics();
5483 PagedSpace::ReportCodeStatistics();
5484}
5485
5486
5487// This function expects that NewSpace's allocated objects histogram is
5488// populated (via a call to CollectStatistics or else as a side effect of a
5489// just-completed scavenge collection).
5490void Heap::ReportHeapStatistics(const char* title) {
5491 USE(title);
5492 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n",
5493 title, gc_count_);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005494 PrintF("old_gen_promotion_limit_ %" V8_PTR_PREFIX "d\n",
5495 old_gen_promotion_limit_);
5496 PrintF("old_gen_allocation_limit_ %" V8_PTR_PREFIX "d\n",
5497 old_gen_allocation_limit_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005498 PrintF("old_gen_limit_factor_ %d\n", old_gen_limit_factor_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005499
5500 PrintF("\n");
5501 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005502 isolate_->global_handles()->PrintStats();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005503 PrintF("\n");
5504
5505 PrintF("Heap statistics : ");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005506 isolate_->memory_allocator()->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005507 PrintF("To space : ");
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005508 new_space_.ReportStatistics();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005509 PrintF("Old pointer space : ");
5510 old_pointer_space_->ReportStatistics();
5511 PrintF("Old data space : ");
5512 old_data_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005513 PrintF("Code space : ");
5514 code_space_->ReportStatistics();
5515 PrintF("Map space : ");
5516 map_space_->ReportStatistics();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005517 PrintF("Cell space : ");
5518 cell_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005519 PrintF("Large object space : ");
5520 lo_space_->ReportStatistics();
5521 PrintF(">>>>>> ========================================= >>>>>>\n");
5522}
5523
5524#endif // DEBUG
5525
5526bool Heap::Contains(HeapObject* value) {
5527 return Contains(value->address());
5528}
5529
5530
5531bool Heap::Contains(Address addr) {
5532 if (OS::IsOutsideAllocatedSpace(addr)) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005533 return HasBeenSetUp() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005534 (new_space_.ToSpaceContains(addr) ||
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005535 old_pointer_space_->Contains(addr) ||
5536 old_data_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005537 code_space_->Contains(addr) ||
5538 map_space_->Contains(addr) ||
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005539 cell_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005540 lo_space_->SlowContains(addr));
5541}
5542
5543
5544bool Heap::InSpace(HeapObject* value, AllocationSpace space) {
5545 return InSpace(value->address(), space);
5546}
5547
5548
5549bool Heap::InSpace(Address addr, AllocationSpace space) {
5550 if (OS::IsOutsideAllocatedSpace(addr)) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005551 if (!HasBeenSetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005552
5553 switch (space) {
5554 case NEW_SPACE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005555 return new_space_.ToSpaceContains(addr);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005556 case OLD_POINTER_SPACE:
5557 return old_pointer_space_->Contains(addr);
5558 case OLD_DATA_SPACE:
5559 return old_data_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005560 case CODE_SPACE:
5561 return code_space_->Contains(addr);
5562 case MAP_SPACE:
5563 return map_space_->Contains(addr);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005564 case CELL_SPACE:
5565 return cell_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005566 case LO_SPACE:
5567 return lo_space_->SlowContains(addr);
5568 }
5569
5570 return false;
5571}
5572
5573
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005574#ifdef VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005575void Heap::Verify() {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005576 CHECK(HasBeenSetUp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005577
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005578 store_buffer()->Verify();
5579
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005580 VerifyPointersVisitor visitor;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005581 IterateRoots(&visitor, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005582
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005583 new_space_.Verify();
5584
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005585 old_pointer_space_->Verify(&visitor);
5586 map_space_->Verify(&visitor);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005587
5588 VerifyPointersVisitor no_dirty_regions_visitor;
5589 old_data_space_->Verify(&no_dirty_regions_visitor);
5590 code_space_->Verify(&no_dirty_regions_visitor);
5591 cell_space_->Verify(&no_dirty_regions_visitor);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005592
5593 lo_space_->Verify();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005594}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005595#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005596
5597
lrn@chromium.org303ada72010-10-27 09:33:13 +00005598MaybeObject* Heap::LookupSymbol(Vector<const char> string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005599 Object* symbol = NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005600 Object* new_table;
5601 { MaybeObject* maybe_new_table =
5602 symbol_table()->LookupSymbol(string, &symbol);
5603 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5604 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005605 // Can't use set_symbol_table because SymbolTable::cast knows that
5606 // SymbolTable is a singleton and checks for identity.
5607 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005608 ASSERT(symbol != NULL);
5609 return symbol;
5610}
5611
5612
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005613MaybeObject* Heap::LookupAsciiSymbol(Vector<const char> string) {
5614 Object* symbol = NULL;
5615 Object* new_table;
5616 { MaybeObject* maybe_new_table =
5617 symbol_table()->LookupAsciiSymbol(string, &symbol);
5618 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5619 }
5620 // Can't use set_symbol_table because SymbolTable::cast knows that
5621 // SymbolTable is a singleton and checks for identity.
5622 roots_[kSymbolTableRootIndex] = new_table;
5623 ASSERT(symbol != NULL);
5624 return symbol;
5625}
5626
5627
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005628MaybeObject* Heap::LookupAsciiSymbol(Handle<SeqOneByteString> string,
danno@chromium.org40cb8782011-05-25 07:58:50 +00005629 int from,
5630 int length) {
5631 Object* symbol = NULL;
5632 Object* new_table;
5633 { MaybeObject* maybe_new_table =
5634 symbol_table()->LookupSubStringAsciiSymbol(string,
5635 from,
5636 length,
5637 &symbol);
5638 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5639 }
5640 // Can't use set_symbol_table because SymbolTable::cast knows that
5641 // SymbolTable is a singleton and checks for identity.
5642 roots_[kSymbolTableRootIndex] = new_table;
5643 ASSERT(symbol != NULL);
5644 return symbol;
5645}
5646
5647
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005648MaybeObject* Heap::LookupTwoByteSymbol(Vector<const uc16> string) {
5649 Object* symbol = NULL;
5650 Object* new_table;
5651 { MaybeObject* maybe_new_table =
5652 symbol_table()->LookupTwoByteSymbol(string, &symbol);
5653 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5654 }
5655 // Can't use set_symbol_table because SymbolTable::cast knows that
5656 // SymbolTable is a singleton and checks for identity.
5657 roots_[kSymbolTableRootIndex] = new_table;
5658 ASSERT(symbol != NULL);
5659 return symbol;
5660}
5661
5662
lrn@chromium.org303ada72010-10-27 09:33:13 +00005663MaybeObject* Heap::LookupSymbol(String* string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005664 if (string->IsSymbol()) return string;
5665 Object* symbol = NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005666 Object* new_table;
5667 { MaybeObject* maybe_new_table =
5668 symbol_table()->LookupString(string, &symbol);
5669 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5670 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005671 // Can't use set_symbol_table because SymbolTable::cast knows that
5672 // SymbolTable is a singleton and checks for identity.
5673 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005674 ASSERT(symbol != NULL);
5675 return symbol;
5676}
5677
5678
ager@chromium.org7c537e22008-10-16 08:43:32 +00005679bool Heap::LookupSymbolIfExists(String* string, String** symbol) {
5680 if (string->IsSymbol()) {
5681 *symbol = string;
5682 return true;
5683 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005684 return symbol_table()->LookupSymbolIfExists(string, symbol);
ager@chromium.org7c537e22008-10-16 08:43:32 +00005685}
5686
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005687
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005688void Heap::ZapFromSpace() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005689 NewSpacePageIterator it(new_space_.FromSpaceStart(),
5690 new_space_.FromSpaceEnd());
5691 while (it.has_next()) {
5692 NewSpacePage* page = it.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005693 for (Address cursor = page->area_start(), limit = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005694 cursor < limit;
5695 cursor += kPointerSize) {
5696 Memory::Address_at(cursor) = kFromSpaceZapValue;
5697 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005698 }
5699}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005700
5701
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005702void Heap::IterateAndMarkPointersToFromSpace(Address start,
5703 Address end,
5704 ObjectSlotCallback callback) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005705 Address slot_address = start;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005706
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005707 // We are not collecting slots on new space objects during mutation
5708 // thus we have to scan for pointers to evacuation candidates when we
5709 // promote objects. But we should not record any slots in non-black
5710 // objects. Grey object's slots would be rescanned.
5711 // White object might not survive until the end of collection
5712 // it would be a violation of the invariant to record it's slots.
5713 bool record_slots = false;
5714 if (incremental_marking()->IsCompacting()) {
5715 MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::FromAddress(start));
5716 record_slots = Marking::IsBlack(mark_bit);
5717 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005718
5719 while (slot_address < end) {
5720 Object** slot = reinterpret_cast<Object**>(slot_address);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005721 Object* object = *slot;
5722 // If the store buffer becomes overfull we mark pages as being exempt from
5723 // the store buffer. These pages are scanned to find pointers that point
5724 // to the new space. In that case we may hit newly promoted objects and
5725 // fix the pointers before the promotion queue gets to them. Thus the 'if'.
5726 if (object->IsHeapObject()) {
5727 if (Heap::InFromSpace(object)) {
5728 callback(reinterpret_cast<HeapObject**>(slot),
5729 HeapObject::cast(object));
5730 Object* new_object = *slot;
5731 if (InNewSpace(new_object)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005732 SLOW_ASSERT(Heap::InToSpace(new_object));
5733 SLOW_ASSERT(new_object->IsHeapObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005734 store_buffer_.EnterDirectlyIntoStoreBuffer(
5735 reinterpret_cast<Address>(slot));
5736 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005737 SLOW_ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_object));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005738 } else if (record_slots &&
5739 MarkCompactCollector::IsOnEvacuationCandidate(object)) {
5740 mark_compact_collector()->RecordSlot(slot, slot, object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005741 }
5742 }
5743 slot_address += kPointerSize;
5744 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005745}
5746
5747
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005748#ifdef DEBUG
5749typedef bool (*CheckStoreBufferFilter)(Object** addr);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005750
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005751
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005752bool IsAMapPointerAddress(Object** addr) {
5753 uintptr_t a = reinterpret_cast<uintptr_t>(addr);
5754 int mod = a % Map::kSize;
5755 return mod >= Map::kPointerFieldsBeginOffset &&
5756 mod < Map::kPointerFieldsEndOffset;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005757}
5758
5759
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005760bool EverythingsAPointer(Object** addr) {
5761 return true;
5762}
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005763
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005764
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005765static void CheckStoreBuffer(Heap* heap,
5766 Object** current,
5767 Object** limit,
5768 Object**** store_buffer_position,
5769 Object*** store_buffer_top,
5770 CheckStoreBufferFilter filter,
5771 Address special_garbage_start,
5772 Address special_garbage_end) {
5773 Map* free_space_map = heap->free_space_map();
5774 for ( ; current < limit; current++) {
5775 Object* o = *current;
5776 Address current_address = reinterpret_cast<Address>(current);
5777 // Skip free space.
5778 if (o == free_space_map) {
5779 Address current_address = reinterpret_cast<Address>(current);
5780 FreeSpace* free_space =
5781 FreeSpace::cast(HeapObject::FromAddress(current_address));
5782 int skip = free_space->Size();
5783 ASSERT(current_address + skip <= reinterpret_cast<Address>(limit));
5784 ASSERT(skip > 0);
5785 current_address += skip - kPointerSize;
5786 current = reinterpret_cast<Object**>(current_address);
5787 continue;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005788 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005789 // Skip the current linear allocation space between top and limit which is
5790 // unmarked with the free space map, but can contain junk.
5791 if (current_address == special_garbage_start &&
5792 special_garbage_end != special_garbage_start) {
5793 current_address = special_garbage_end - kPointerSize;
5794 current = reinterpret_cast<Object**>(current_address);
5795 continue;
5796 }
5797 if (!(*filter)(current)) continue;
5798 ASSERT(current_address < special_garbage_start ||
5799 current_address >= special_garbage_end);
5800 ASSERT(reinterpret_cast<uintptr_t>(o) != kFreeListZapValue);
5801 // We have to check that the pointer does not point into new space
5802 // without trying to cast it to a heap object since the hash field of
5803 // a string can contain values like 1 and 3 which are tagged null
5804 // pointers.
5805 if (!heap->InNewSpace(o)) continue;
5806 while (**store_buffer_position < current &&
5807 *store_buffer_position < store_buffer_top) {
5808 (*store_buffer_position)++;
5809 }
5810 if (**store_buffer_position != current ||
5811 *store_buffer_position == store_buffer_top) {
5812 Object** obj_start = current;
5813 while (!(*obj_start)->IsMap()) obj_start--;
5814 UNREACHABLE();
5815 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005816 }
5817}
5818
5819
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005820// Check that the store buffer contains all intergenerational pointers by
5821// scanning a page and ensuring that all pointers to young space are in the
5822// store buffer.
5823void Heap::OldPointerSpaceCheckStoreBuffer() {
5824 OldSpace* space = old_pointer_space();
5825 PageIterator pages(space);
5826
5827 store_buffer()->SortUniq();
5828
5829 while (pages.has_next()) {
5830 Page* page = pages.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005831 Object** current = reinterpret_cast<Object**>(page->area_start());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005832
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005833 Address end = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005834
5835 Object*** store_buffer_position = store_buffer()->Start();
5836 Object*** store_buffer_top = store_buffer()->Top();
5837
5838 Object** limit = reinterpret_cast<Object**>(end);
5839 CheckStoreBuffer(this,
5840 current,
5841 limit,
5842 &store_buffer_position,
5843 store_buffer_top,
5844 &EverythingsAPointer,
5845 space->top(),
5846 space->limit());
5847 }
5848}
5849
5850
5851void Heap::MapSpaceCheckStoreBuffer() {
5852 MapSpace* space = map_space();
5853 PageIterator pages(space);
5854
5855 store_buffer()->SortUniq();
5856
5857 while (pages.has_next()) {
5858 Page* page = pages.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005859 Object** current = reinterpret_cast<Object**>(page->area_start());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005860
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005861 Address end = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005862
5863 Object*** store_buffer_position = store_buffer()->Start();
5864 Object*** store_buffer_top = store_buffer()->Top();
5865
5866 Object** limit = reinterpret_cast<Object**>(end);
5867 CheckStoreBuffer(this,
5868 current,
5869 limit,
5870 &store_buffer_position,
5871 store_buffer_top,
5872 &IsAMapPointerAddress,
5873 space->top(),
5874 space->limit());
5875 }
5876}
5877
5878
5879void Heap::LargeObjectSpaceCheckStoreBuffer() {
5880 LargeObjectIterator it(lo_space());
5881 for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) {
5882 // We only have code, sequential strings, or fixed arrays in large
5883 // object space, and only fixed arrays can possibly contain pointers to
5884 // the young generation.
5885 if (object->IsFixedArray()) {
5886 Object*** store_buffer_position = store_buffer()->Start();
5887 Object*** store_buffer_top = store_buffer()->Top();
5888 Object** current = reinterpret_cast<Object**>(object->address());
5889 Object** limit =
5890 reinterpret_cast<Object**>(object->address() + object->Size());
5891 CheckStoreBuffer(this,
5892 current,
5893 limit,
5894 &store_buffer_position,
5895 store_buffer_top,
5896 &EverythingsAPointer,
5897 NULL,
5898 NULL);
5899 }
5900 }
5901}
5902#endif
5903
5904
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005905void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) {
5906 IterateStrongRoots(v, mode);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005907 IterateWeakRoots(v, mode);
5908}
5909
5910
5911void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005912 v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex]));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005913 v->Synchronize(VisitorSynchronization::kSymbolTable);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005914 if (mode != VISIT_ALL_IN_SCAVENGE &&
5915 mode != VISIT_ALL_IN_SWEEP_NEWSPACE) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005916 // Scavenge collections have special processing for this.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005917 external_string_table_.Iterate(v);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005918 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005919 v->Synchronize(VisitorSynchronization::kExternalStringsTable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005920}
5921
5922
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005923void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005924 v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005925 v->Synchronize(VisitorSynchronization::kStrongRootList);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005926
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00005927 v->VisitPointer(BitCast<Object**>(&hidden_symbol_));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005928 v->Synchronize(VisitorSynchronization::kSymbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005929
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005930 isolate_->bootstrapper()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005931 v->Synchronize(VisitorSynchronization::kBootstrapper);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005932 isolate_->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005933 v->Synchronize(VisitorSynchronization::kTop);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005934 Relocatable::Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005935 v->Synchronize(VisitorSynchronization::kRelocatable);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005936
5937#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005938 isolate_->debug()->Iterate(v);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005939 if (isolate_->deoptimizer_data() != NULL) {
5940 isolate_->deoptimizer_data()->Iterate(v);
5941 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005942#endif
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005943 v->Synchronize(VisitorSynchronization::kDebug);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005944 isolate_->compilation_cache()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005945 v->Synchronize(VisitorSynchronization::kCompilationCache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005946
5947 // Iterate over local handles in handle scopes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005948 isolate_->handle_scope_implementer()->Iterate(v);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005949 isolate_->IterateDeferredHandles(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005950 v->Synchronize(VisitorSynchronization::kHandleScope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005951
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005952 // Iterate over the builtin code objects and code stubs in the
5953 // heap. Note that it is not necessary to iterate over code objects
5954 // on scavenge collections.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005955 if (mode != VISIT_ALL_IN_SCAVENGE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005956 isolate_->builtins()->IterateBuiltins(v);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005957 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005958 v->Synchronize(VisitorSynchronization::kBuiltins);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005959
5960 // Iterate over global handles.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005961 switch (mode) {
5962 case VISIT_ONLY_STRONG:
5963 isolate_->global_handles()->IterateStrongRoots(v);
5964 break;
5965 case VISIT_ALL_IN_SCAVENGE:
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005966 isolate_->global_handles()->IterateNewSpaceStrongAndDependentRoots(v);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005967 break;
5968 case VISIT_ALL_IN_SWEEP_NEWSPACE:
5969 case VISIT_ALL:
5970 isolate_->global_handles()->IterateAllRoots(v);
5971 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005972 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005973 v->Synchronize(VisitorSynchronization::kGlobalHandles);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005974
5975 // Iterate over pointers being held by inactive threads.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005976 isolate_->thread_manager()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005977 v->Synchronize(VisitorSynchronization::kThreadManager);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005978
5979 // Iterate over the pointers the Serialization/Deserialization code is
5980 // holding.
5981 // During garbage collection this keeps the partial snapshot cache alive.
5982 // During deserialization of the startup snapshot this creates the partial
5983 // snapshot cache and deserializes the objects it refers to. During
5984 // serialization this does nothing, since the partial snapshot cache is
5985 // empty. However the next thing we do is create the partial snapshot,
5986 // filling up the partial snapshot cache with objects it needs as we go.
5987 SerializerDeserializer::Iterate(v);
5988 // We don't do a v->Synchronize call here, because in debug mode that will
5989 // output a flag to the snapshot. However at this point the serializer and
5990 // deserializer are deliberately a little unsynchronized (see above) so the
5991 // checking of the sync flag in the snapshot would fail.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005992}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005993
5994
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995// TODO(1236194): Since the heap size is configurable on the command line
5996// and through the API, we should gracefully handle the case that the heap
5997// size is not big enough to fit all the initial objects.
ager@chromium.org01fe7df2010-11-10 11:59:11 +00005998bool Heap::ConfigureHeap(int max_semispace_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005999 intptr_t max_old_gen_size,
6000 intptr_t max_executable_size) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006001 if (HasBeenSetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006002
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00006003 if (FLAG_stress_compaction) {
6004 // This will cause more frequent GCs when stressing.
6005 max_semispace_size_ = Page::kPageSize;
6006 }
6007
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006008 if (max_semispace_size > 0) {
6009 if (max_semispace_size < Page::kPageSize) {
6010 max_semispace_size = Page::kPageSize;
6011 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006012 PrintPID("Max semispace size cannot be less than %dkbytes\n",
6013 Page::kPageSize >> 10);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006014 }
6015 }
6016 max_semispace_size_ = max_semispace_size;
6017 }
ager@chromium.org3811b432009-10-28 14:53:37 +00006018
6019 if (Snapshot::IsEnabled()) {
6020 // If we are using a snapshot we always reserve the default amount
6021 // of memory for each semispace because code in the snapshot has
6022 // write-barrier code that relies on the size and alignment of new
6023 // space. We therefore cannot use a larger max semispace size
6024 // than the default reserved semispace size.
6025 if (max_semispace_size_ > reserved_semispace_size_) {
6026 max_semispace_size_ = reserved_semispace_size_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006027 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006028 PrintPID("Max semispace size cannot be more than %dkbytes\n",
6029 reserved_semispace_size_ >> 10);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006030 }
ager@chromium.org3811b432009-10-28 14:53:37 +00006031 }
6032 } else {
6033 // If we are not using snapshots we reserve space for the actual
6034 // max semispace size.
6035 reserved_semispace_size_ = max_semispace_size_;
6036 }
6037
6038 if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size;
ager@chromium.org01fe7df2010-11-10 11:59:11 +00006039 if (max_executable_size > 0) {
6040 max_executable_size_ = RoundUp(max_executable_size, Page::kPageSize);
6041 }
6042
6043 // The max executable size must be less than or equal to the max old
6044 // generation size.
6045 if (max_executable_size_ > max_old_generation_size_) {
6046 max_executable_size_ = max_old_generation_size_;
6047 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006048
6049 // The new space size must be a power of two to support single-bit testing
6050 // for containment.
ager@chromium.org3811b432009-10-28 14:53:37 +00006051 max_semispace_size_ = RoundUpToPowerOf2(max_semispace_size_);
6052 reserved_semispace_size_ = RoundUpToPowerOf2(reserved_semispace_size_);
6053 initial_semispace_size_ = Min(initial_semispace_size_, max_semispace_size_);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006054 external_allocation_limit_ = 16 * max_semispace_size_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006055
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006056 // The old generation is paged and needs at least one page for each space.
6057 int paged_space_count = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1;
6058 max_old_generation_size_ = Max(static_cast<intptr_t>(paged_space_count *
6059 Page::kPageSize),
6060 RoundUp(max_old_generation_size_,
6061 Page::kPageSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006062
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006063 configured_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006064 return true;
6065}
6066
6067
kasper.lund7276f142008-07-30 08:49:36 +00006068bool Heap::ConfigureHeapDefault() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006069 return ConfigureHeap(static_cast<intptr_t>(FLAG_max_new_space_size / 2) * KB,
6070 static_cast<intptr_t>(FLAG_max_old_space_size) * MB,
6071 static_cast<intptr_t>(FLAG_max_executable_size) * MB);
kasper.lund7276f142008-07-30 08:49:36 +00006072}
6073
6074
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006075void Heap::RecordStats(HeapStats* stats, bool take_snapshot) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006076 *stats->start_marker = HeapStats::kStartMarker;
6077 *stats->end_marker = HeapStats::kEndMarker;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006078 *stats->new_space_size = new_space_.SizeAsInt();
6079 *stats->new_space_capacity = static_cast<int>(new_space_.Capacity());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006080 *stats->old_pointer_space_size = old_pointer_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006081 *stats->old_pointer_space_capacity = old_pointer_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006082 *stats->old_data_space_size = old_data_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006083 *stats->old_data_space_capacity = old_data_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006084 *stats->code_space_size = code_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006085 *stats->code_space_capacity = code_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006086 *stats->map_space_size = map_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006087 *stats->map_space_capacity = map_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006088 *stats->cell_space_size = cell_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006089 *stats->cell_space_capacity = cell_space_->Capacity();
6090 *stats->lo_space_size = lo_space_->Size();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006091 isolate_->global_handles()->RecordStats(stats);
6092 *stats->memory_allocator_size = isolate()->memory_allocator()->Size();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006093 *stats->memory_allocator_capacity =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006094 isolate()->memory_allocator()->Size() +
6095 isolate()->memory_allocator()->Available();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006096 *stats->os_error = OS::GetLastError();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006097 isolate()->memory_allocator()->Available();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006098 if (take_snapshot) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006099 HeapIterator iterator;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006100 for (HeapObject* obj = iterator.next();
6101 obj != NULL;
6102 obj = iterator.next()) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006103 InstanceType type = obj->map()->instance_type();
6104 ASSERT(0 <= type && type <= LAST_TYPE);
6105 stats->objects_per_type[type]++;
6106 stats->size_per_type[type] += obj->Size();
6107 }
6108 }
ager@chromium.org60121232009-12-03 11:25:37 +00006109}
6110
6111
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00006112intptr_t Heap::PromotedSpaceSizeOfObjects() {
6113 return old_pointer_space_->SizeOfObjects()
6114 + old_data_space_->SizeOfObjects()
6115 + code_space_->SizeOfObjects()
6116 + map_space_->SizeOfObjects()
6117 + cell_space_->SizeOfObjects()
6118 + lo_space_->SizeOfObjects();
6119}
6120
6121
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00006122intptr_t Heap::PromotedExternalMemorySize() {
kasper.lund7276f142008-07-30 08:49:36 +00006123 if (amount_of_external_allocated_memory_
6124 <= amount_of_external_allocated_memory_at_last_global_gc_) return 0;
6125 return amount_of_external_allocated_memory_
6126 - amount_of_external_allocated_memory_at_last_global_gc_;
6127}
6128
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006129#ifdef DEBUG
6130
6131// Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject.
6132static const int kMarkTag = 2;
6133
6134
6135class HeapDebugUtils {
6136 public:
6137 explicit HeapDebugUtils(Heap* heap)
6138 : search_for_any_global_(false),
6139 search_target_(NULL),
6140 found_target_(false),
6141 object_stack_(20),
6142 heap_(heap) {
6143 }
6144
6145 class MarkObjectVisitor : public ObjectVisitor {
6146 public:
6147 explicit MarkObjectVisitor(HeapDebugUtils* utils) : utils_(utils) { }
6148
6149 void VisitPointers(Object** start, Object** end) {
6150 // Copy all HeapObject pointers in [start, end)
6151 for (Object** p = start; p < end; p++) {
6152 if ((*p)->IsHeapObject())
6153 utils_->MarkObjectRecursively(p);
6154 }
6155 }
6156
6157 HeapDebugUtils* utils_;
6158 };
6159
6160 void MarkObjectRecursively(Object** p) {
6161 if (!(*p)->IsHeapObject()) return;
6162
6163 HeapObject* obj = HeapObject::cast(*p);
6164
6165 Object* map = obj->map();
6166
6167 if (!map->IsHeapObject()) return; // visited before
6168
6169 if (found_target_) return; // stop if target found
6170 object_stack_.Add(obj);
6171 if ((search_for_any_global_ && obj->IsJSGlobalObject()) ||
6172 (!search_for_any_global_ && (obj == search_target_))) {
6173 found_target_ = true;
6174 return;
6175 }
6176
6177 // not visited yet
6178 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
6179
6180 Address map_addr = map_p->address();
6181
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006182 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_addr + kMarkTag));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006183
6184 MarkObjectRecursively(&map);
6185
6186 MarkObjectVisitor mark_visitor(this);
6187
6188 obj->IterateBody(map_p->instance_type(), obj->SizeFromMap(map_p),
6189 &mark_visitor);
6190
6191 if (!found_target_) // don't pop if found the target
6192 object_stack_.RemoveLast();
6193 }
6194
6195
6196 class UnmarkObjectVisitor : public ObjectVisitor {
6197 public:
6198 explicit UnmarkObjectVisitor(HeapDebugUtils* utils) : utils_(utils) { }
6199
6200 void VisitPointers(Object** start, Object** end) {
6201 // Copy all HeapObject pointers in [start, end)
6202 for (Object** p = start; p < end; p++) {
6203 if ((*p)->IsHeapObject())
6204 utils_->UnmarkObjectRecursively(p);
6205 }
6206 }
6207
6208 HeapDebugUtils* utils_;
6209 };
6210
6211
6212 void UnmarkObjectRecursively(Object** p) {
6213 if (!(*p)->IsHeapObject()) return;
6214
6215 HeapObject* obj = HeapObject::cast(*p);
6216
6217 Object* map = obj->map();
6218
6219 if (map->IsHeapObject()) return; // unmarked already
6220
6221 Address map_addr = reinterpret_cast<Address>(map);
6222
6223 map_addr -= kMarkTag;
6224
6225 ASSERT_TAG_ALIGNED(map_addr);
6226
6227 HeapObject* map_p = HeapObject::FromAddress(map_addr);
6228
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006229 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_p));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006230
6231 UnmarkObjectRecursively(reinterpret_cast<Object**>(&map_p));
6232
6233 UnmarkObjectVisitor unmark_visitor(this);
6234
6235 obj->IterateBody(Map::cast(map_p)->instance_type(),
6236 obj->SizeFromMap(Map::cast(map_p)),
6237 &unmark_visitor);
6238 }
6239
6240
6241 void MarkRootObjectRecursively(Object** root) {
6242 if (search_for_any_global_) {
6243 ASSERT(search_target_ == NULL);
6244 } else {
6245 ASSERT(search_target_->IsHeapObject());
6246 }
6247 found_target_ = false;
6248 object_stack_.Clear();
6249
6250 MarkObjectRecursively(root);
6251 UnmarkObjectRecursively(root);
6252
6253 if (found_target_) {
6254 PrintF("=====================================\n");
6255 PrintF("==== Path to object ====\n");
6256 PrintF("=====================================\n\n");
6257
6258 ASSERT(!object_stack_.is_empty());
6259 for (int i = 0; i < object_stack_.length(); i++) {
6260 if (i > 0) PrintF("\n |\n |\n V\n\n");
6261 Object* obj = object_stack_[i];
6262 obj->Print();
6263 }
6264 PrintF("=====================================\n");
6265 }
6266 }
6267
6268 // Helper class for visiting HeapObjects recursively.
6269 class MarkRootVisitor: public ObjectVisitor {
6270 public:
6271 explicit MarkRootVisitor(HeapDebugUtils* utils) : utils_(utils) { }
6272
6273 void VisitPointers(Object** start, Object** end) {
6274 // Visit all HeapObject pointers in [start, end)
6275 for (Object** p = start; p < end; p++) {
6276 if ((*p)->IsHeapObject())
6277 utils_->MarkRootObjectRecursively(p);
6278 }
6279 }
6280
6281 HeapDebugUtils* utils_;
6282 };
6283
6284 bool search_for_any_global_;
6285 Object* search_target_;
6286 bool found_target_;
6287 List<Object*> object_stack_;
6288 Heap* heap_;
6289
6290 friend class Heap;
6291};
6292
6293#endif
kasper.lund7276f142008-07-30 08:49:36 +00006294
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00006295
6296V8_DECLARE_ONCE(initialize_gc_once);
6297
6298static void InitializeGCOnce() {
6299 InitializeScavengingVisitorsTables();
6300 NewSpaceScavenger::Initialize();
6301 MarkCompactCollector::Initialize();
6302}
6303
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006304bool Heap::SetUp(bool create_heap_objects) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006305#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006306 allocation_timeout_ = FLAG_gc_interval;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006307 debug_utils_ = new HeapDebugUtils(this);
6308#endif
6309
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006310 // Initialize heap spaces and initial maps and objects. Whenever something
6311 // goes wrong, just return false. The caller should check the results and
6312 // call Heap::TearDown() to release allocated memory.
6313 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006314 // If the heap is not yet configured (e.g. through the API), configure it.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006315 // Configuration is based on the flags new-space-size (really the semispace
6316 // size) and old-space-size if set or the initial values of semispace_size_
6317 // and old_generation_size_ otherwise.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006318 if (!configured_) {
kasper.lund7276f142008-07-30 08:49:36 +00006319 if (!ConfigureHeapDefault()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006320 }
6321
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00006322 CallOnce(&initialize_gc_once, &InitializeGCOnce);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006323
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006324 MarkMapPointersAsEncoded(false);
6325
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006326 // Set up memory allocator.
6327 if (!isolate_->memory_allocator()->SetUp(MaxReserved(), MaxExecutableSize()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006328 return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006329
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006330 // Set up new space.
6331 if (!new_space_.SetUp(reserved_semispace_size_, max_semispace_size_)) {
ager@chromium.org3811b432009-10-28 14:53:37 +00006332 return false;
6333 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006334
ager@chromium.orga1645e22009-09-09 19:27:10 +00006335 // Initialize old pointer space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006336 old_pointer_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006337 new OldSpace(this,
6338 max_old_generation_size_,
6339 OLD_POINTER_SPACE,
6340 NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006341 if (old_pointer_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006342 if (!old_pointer_space_->SetUp()) return false;
ager@chromium.orga1645e22009-09-09 19:27:10 +00006343
6344 // Initialize old data space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006345 old_data_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006346 new OldSpace(this,
6347 max_old_generation_size_,
6348 OLD_DATA_SPACE,
6349 NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006350 if (old_data_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006351 if (!old_data_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006352
6353 // Initialize the code space, set its maximum capacity to the old
kasper.lund7276f142008-07-30 08:49:36 +00006354 // generation size. It needs executable memory.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006355 // On 64-bit platform(s), we put all code objects in a 2 GB range of
6356 // virtual address space, so that they can call each other with near calls.
6357 if (code_range_size_ > 0) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006358 if (!isolate_->code_range()->SetUp(code_range_size_)) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006359 return false;
6360 }
6361 }
6362
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006363 code_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006364 new OldSpace(this, max_old_generation_size_, CODE_SPACE, EXECUTABLE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006365 if (code_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006366 if (!code_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006367
6368 // Initialize map space.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00006369 map_space_ = new MapSpace(this, max_old_generation_size_, MAP_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006370 if (map_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006371 if (!map_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006372
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006373 // Initialize global property cell space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006374 cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006375 if (cell_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006376 if (!cell_space_->SetUp()) return false;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006377
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006378 // The large object code space may contain code or data. We set the memory
6379 // to be non-executable here for safety, but this means we need to enable it
6380 // explicitly when allocating large code objects.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006381 lo_space_ = new LargeObjectSpace(this, max_old_generation_size_, LO_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006382 if (lo_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006383 if (!lo_space_->SetUp()) return false;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006384
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006385 // Set up the seed that is used to randomize the string hash function.
6386 ASSERT(hash_seed() == 0);
6387 if (FLAG_randomize_hashes) {
6388 if (FLAG_hash_seed == 0) {
6389 set_hash_seed(
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006390 Smi::FromInt(V8::RandomPrivate(isolate()) & 0x3fffffff));
6391 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006392 set_hash_seed(Smi::FromInt(FLAG_hash_seed));
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006393 }
6394 }
6395
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006396 if (create_heap_objects) {
6397 // Create initial maps.
6398 if (!CreateInitialMaps()) return false;
6399 if (!CreateApiObjects()) return false;
6400
6401 // Create initial objects
6402 if (!CreateInitialObjects()) return false;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00006403
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006404 native_contexts_list_ = undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006405 }
6406
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006407 LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity()));
6408 LOG(isolate_, IntPtrTEvent("heap-available", Available()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006409
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006410 store_buffer()->SetUp();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006411
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006412 if (FLAG_parallel_recompilation) relocation_mutex_ = OS::CreateMutex();
6413
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006414 return true;
6415}
6416
6417
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006418void Heap::SetStackLimits() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006419 ASSERT(isolate_ != NULL);
6420 ASSERT(isolate_ == isolate());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006421 // On 64 bit machines, pointers are generally out of range of Smis. We write
6422 // something that looks like an out of range Smi to the GC.
6423
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006424 // Set up the special root array entries containing the stack limits.
6425 // These are actually addresses, but the tag makes the GC ignore it.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006426 roots_[kStackLimitRootIndex] =
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006427 reinterpret_cast<Object*>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006428 (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006429 roots_[kRealStackLimitRootIndex] =
6430 reinterpret_cast<Object*>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006431 (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006432}
6433
6434
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006435void Heap::TearDown() {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006436#ifdef VERIFY_HEAP
danno@chromium.org1044a4d2012-04-30 12:34:39 +00006437 if (FLAG_verify_heap) {
6438 Verify();
6439 }
6440#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006441
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006442 if (FLAG_print_cumulative_gc_stat) {
6443 PrintF("\n\n");
6444 PrintF("gc_count=%d ", gc_count_);
6445 PrintF("mark_sweep_count=%d ", ms_count_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006446 PrintF("max_gc_pause=%d ", get_max_gc_pause());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006447 PrintF("total_gc_time=%d ", total_gc_time_ms_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006448 PrintF("min_in_mutator=%d ", get_min_in_mutator());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006449 PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ",
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006450 get_max_alive_after_gc());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006451 PrintF("\n\n");
6452 }
6453
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006454 isolate_->global_handles()->TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006455
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006456 external_string_table_.TearDown();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00006457
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006458 new_space_.TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006459
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006460 if (old_pointer_space_ != NULL) {
6461 old_pointer_space_->TearDown();
6462 delete old_pointer_space_;
6463 old_pointer_space_ = NULL;
6464 }
6465
6466 if (old_data_space_ != NULL) {
6467 old_data_space_->TearDown();
6468 delete old_data_space_;
6469 old_data_space_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006470 }
6471
6472 if (code_space_ != NULL) {
6473 code_space_->TearDown();
6474 delete code_space_;
6475 code_space_ = NULL;
6476 }
6477
6478 if (map_space_ != NULL) {
6479 map_space_->TearDown();
6480 delete map_space_;
6481 map_space_ = NULL;
6482 }
6483
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006484 if (cell_space_ != NULL) {
6485 cell_space_->TearDown();
6486 delete cell_space_;
6487 cell_space_ = NULL;
6488 }
6489
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006490 if (lo_space_ != NULL) {
6491 lo_space_->TearDown();
6492 delete lo_space_;
6493 lo_space_ = NULL;
6494 }
6495
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006496 store_buffer()->TearDown();
6497 incremental_marking()->TearDown();
6498
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006499 isolate_->memory_allocator()->TearDown();
6500
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006501 delete relocation_mutex_;
6502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006503#ifdef DEBUG
6504 delete debug_utils_;
6505 debug_utils_ = NULL;
6506#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006507}
6508
6509
6510void Heap::Shrink() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006511 // Try to shrink all paged spaces.
6512 PagedSpaces spaces;
danno@chromium.org2c456792011-11-11 12:00:53 +00006513 for (PagedSpace* space = spaces.next();
6514 space != NULL;
6515 space = spaces.next()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006516 space->ReleaseAllUnusedPages();
danno@chromium.org2c456792011-11-11 12:00:53 +00006517 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006518}
6519
6520
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006521void Heap::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) {
6522 ASSERT(callback != NULL);
6523 GCPrologueCallbackPair pair(callback, gc_type);
6524 ASSERT(!gc_prologue_callbacks_.Contains(pair));
6525 return gc_prologue_callbacks_.Add(pair);
6526}
6527
6528
6529void Heap::RemoveGCPrologueCallback(GCPrologueCallback callback) {
6530 ASSERT(callback != NULL);
6531 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
6532 if (gc_prologue_callbacks_[i].callback == callback) {
6533 gc_prologue_callbacks_.Remove(i);
6534 return;
6535 }
6536 }
6537 UNREACHABLE();
6538}
6539
6540
6541void Heap::AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type) {
6542 ASSERT(callback != NULL);
6543 GCEpilogueCallbackPair pair(callback, gc_type);
6544 ASSERT(!gc_epilogue_callbacks_.Contains(pair));
6545 return gc_epilogue_callbacks_.Add(pair);
6546}
6547
6548
6549void Heap::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
6550 ASSERT(callback != NULL);
6551 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
6552 if (gc_epilogue_callbacks_[i].callback == callback) {
6553 gc_epilogue_callbacks_.Remove(i);
6554 return;
6555 }
6556 }
6557 UNREACHABLE();
6558}
6559
6560
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006561#ifdef DEBUG
6562
6563class PrintHandleVisitor: public ObjectVisitor {
6564 public:
6565 void VisitPointers(Object** start, Object** end) {
6566 for (Object** p = start; p < end; p++)
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006567 PrintF(" handle %p to %p\n",
6568 reinterpret_cast<void*>(p),
6569 reinterpret_cast<void*>(*p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006570 }
6571};
6572
6573void Heap::PrintHandles() {
6574 PrintF("Handles:\n");
6575 PrintHandleVisitor v;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006576 isolate_->handle_scope_implementer()->Iterate(&v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006577}
6578
6579#endif
6580
6581
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006582Space* AllSpaces::next() {
6583 switch (counter_++) {
6584 case NEW_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006585 return HEAP->new_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006586 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006587 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006588 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006589 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006590 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006591 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006592 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006593 return HEAP->map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006594 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006595 return HEAP->cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006596 case LO_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006597 return HEAP->lo_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006598 default:
6599 return NULL;
6600 }
6601}
6602
6603
6604PagedSpace* PagedSpaces::next() {
6605 switch (counter_++) {
6606 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006607 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006608 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006609 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006610 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006611 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006612 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006613 return HEAP->map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006614 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006615 return HEAP->cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006616 default:
6617 return NULL;
6618 }
6619}
6620
6621
6622
6623OldSpace* OldSpaces::next() {
6624 switch (counter_++) {
6625 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006626 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006627 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006628 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006629 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006630 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006631 default:
6632 return NULL;
6633 }
6634}
6635
6636
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006637SpaceIterator::SpaceIterator()
6638 : current_space_(FIRST_SPACE),
6639 iterator_(NULL),
6640 size_func_(NULL) {
6641}
6642
6643
6644SpaceIterator::SpaceIterator(HeapObjectCallback size_func)
6645 : current_space_(FIRST_SPACE),
6646 iterator_(NULL),
6647 size_func_(size_func) {
kasper.lund7276f142008-07-30 08:49:36 +00006648}
6649
6650
6651SpaceIterator::~SpaceIterator() {
6652 // Delete active iterator if any.
6653 delete iterator_;
6654}
6655
6656
6657bool SpaceIterator::has_next() {
6658 // Iterate until no more spaces.
6659 return current_space_ != LAST_SPACE;
6660}
6661
6662
6663ObjectIterator* SpaceIterator::next() {
6664 if (iterator_ != NULL) {
6665 delete iterator_;
6666 iterator_ = NULL;
6667 // Move to the next space
6668 current_space_++;
6669 if (current_space_ > LAST_SPACE) {
6670 return NULL;
6671 }
6672 }
6673
6674 // Return iterator for the new current space.
6675 return CreateIterator();
6676}
6677
6678
6679// Create an iterator for the space to iterate.
6680ObjectIterator* SpaceIterator::CreateIterator() {
6681 ASSERT(iterator_ == NULL);
6682
6683 switch (current_space_) {
6684 case NEW_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006685 iterator_ = new SemiSpaceIterator(HEAP->new_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006686 break;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006687 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006688 iterator_ = new HeapObjectIterator(HEAP->old_pointer_space(), size_func_);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006689 break;
6690 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006691 iterator_ = new HeapObjectIterator(HEAP->old_data_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006692 break;
6693 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006694 iterator_ = new HeapObjectIterator(HEAP->code_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006695 break;
6696 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006697 iterator_ = new HeapObjectIterator(HEAP->map_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006698 break;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006699 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006700 iterator_ = new HeapObjectIterator(HEAP->cell_space(), size_func_);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006701 break;
kasper.lund7276f142008-07-30 08:49:36 +00006702 case LO_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006703 iterator_ = new LargeObjectIterator(HEAP->lo_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006704 break;
6705 }
6706
6707 // Return the newly allocated iterator;
6708 ASSERT(iterator_ != NULL);
6709 return iterator_;
6710}
6711
6712
whesse@chromium.org023421e2010-12-21 12:19:12 +00006713class HeapObjectsFilter {
6714 public:
6715 virtual ~HeapObjectsFilter() {}
6716 virtual bool SkipObject(HeapObject* object) = 0;
6717};
6718
6719
whesse@chromium.org023421e2010-12-21 12:19:12 +00006720class UnreachableObjectsFilter : public HeapObjectsFilter {
6721 public:
6722 UnreachableObjectsFilter() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006723 MarkReachableObjects();
6724 }
6725
6726 ~UnreachableObjectsFilter() {
6727 Isolate::Current()->heap()->mark_compact_collector()->ClearMarkbits();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006728 }
6729
6730 bool SkipObject(HeapObject* object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006731 MarkBit mark_bit = Marking::MarkBitFrom(object);
6732 return !mark_bit.Get();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006733 }
6734
6735 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006736 class MarkingVisitor : public ObjectVisitor {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006737 public:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006738 MarkingVisitor() : marking_stack_(10) {}
whesse@chromium.org023421e2010-12-21 12:19:12 +00006739
6740 void VisitPointers(Object** start, Object** end) {
6741 for (Object** p = start; p < end; p++) {
6742 if (!(*p)->IsHeapObject()) continue;
6743 HeapObject* obj = HeapObject::cast(*p);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006744 MarkBit mark_bit = Marking::MarkBitFrom(obj);
6745 if (!mark_bit.Get()) {
6746 mark_bit.Set();
6747 marking_stack_.Add(obj);
whesse@chromium.org023421e2010-12-21 12:19:12 +00006748 }
6749 }
6750 }
6751
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006752 void TransitiveClosure() {
6753 while (!marking_stack_.is_empty()) {
6754 HeapObject* obj = marking_stack_.RemoveLast();
6755 obj->Iterate(this);
6756 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00006757 }
6758
6759 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006760 List<HeapObject*> marking_stack_;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006761 };
6762
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006763 void MarkReachableObjects() {
6764 Heap* heap = Isolate::Current()->heap();
6765 MarkingVisitor visitor;
6766 heap->IterateRoots(&visitor, VISIT_ALL);
6767 visitor.TransitiveClosure();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006768 }
6769
6770 AssertNoAllocation no_alloc;
6771};
6772
6773
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006774HeapIterator::HeapIterator()
6775 : filtering_(HeapIterator::kNoFiltering),
6776 filter_(NULL) {
6777 Init();
6778}
6779
6780
whesse@chromium.org023421e2010-12-21 12:19:12 +00006781HeapIterator::HeapIterator(HeapIterator::HeapObjectsFiltering filtering)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006782 : filtering_(filtering),
6783 filter_(NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006784 Init();
6785}
6786
6787
6788HeapIterator::~HeapIterator() {
6789 Shutdown();
6790}
6791
6792
6793void HeapIterator::Init() {
6794 // Start the iteration.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006795 space_iterator_ = new SpaceIterator;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006796 switch (filtering_) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006797 case kFilterUnreachable:
6798 filter_ = new UnreachableObjectsFilter;
6799 break;
6800 default:
6801 break;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006802 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006803 object_iterator_ = space_iterator_->next();
6804}
6805
6806
6807void HeapIterator::Shutdown() {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006808#ifdef DEBUG
whesse@chromium.org023421e2010-12-21 12:19:12 +00006809 // Assert that in filtering mode we have iterated through all
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006810 // objects. Otherwise, heap will be left in an inconsistent state.
whesse@chromium.org023421e2010-12-21 12:19:12 +00006811 if (filtering_ != kNoFiltering) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006812 ASSERT(object_iterator_ == NULL);
6813 }
6814#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006815 // Make sure the last iterator is deallocated.
6816 delete space_iterator_;
6817 space_iterator_ = NULL;
6818 object_iterator_ = NULL;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006819 delete filter_;
6820 filter_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006821}
6822
6823
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006824HeapObject* HeapIterator::next() {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006825 if (filter_ == NULL) return NextObject();
6826
6827 HeapObject* obj = NextObject();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006828 while (obj != NULL && filter_->SkipObject(obj)) obj = NextObject();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006829 return obj;
6830}
6831
6832
6833HeapObject* HeapIterator::NextObject() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006834 // No iterator means we are done.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006835 if (object_iterator_ == NULL) return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006836
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006837 if (HeapObject* obj = object_iterator_->next_object()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006838 // If the current iterator has more objects we are fine.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006839 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006840 } else {
6841 // Go though the spaces looking for one that has objects.
6842 while (space_iterator_->has_next()) {
6843 object_iterator_ = space_iterator_->next();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006844 if (HeapObject* obj = object_iterator_->next_object()) {
6845 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006846 }
6847 }
6848 }
6849 // Done with the last space.
6850 object_iterator_ = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006851 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006852}
6853
6854
6855void HeapIterator::reset() {
6856 // Restart the iterator.
6857 Shutdown();
6858 Init();
6859}
6860
6861
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006862#if defined(DEBUG) || defined(LIVE_OBJECT_LIST)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006863
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006864Object* const PathTracer::kAnyGlobalObject = reinterpret_cast<Object*>(NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006865
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006866class PathTracer::MarkVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006867 public:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006868 explicit MarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006869 void VisitPointers(Object** start, Object** end) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006870 // Scan all HeapObject pointers in [start, end)
6871 for (Object** p = start; !tracer_->found() && (p < end); p++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006872 if ((*p)->IsHeapObject())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006873 tracer_->MarkRecursively(p, this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006874 }
6875 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006876
6877 private:
6878 PathTracer* tracer_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006879};
6880
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006881
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006882class PathTracer::UnmarkVisitor: public ObjectVisitor {
6883 public:
6884 explicit UnmarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
6885 void VisitPointers(Object** start, Object** end) {
6886 // Scan all HeapObject pointers in [start, end)
6887 for (Object** p = start; p < end; p++) {
6888 if ((*p)->IsHeapObject())
6889 tracer_->UnmarkRecursively(p, this);
6890 }
6891 }
6892
6893 private:
6894 PathTracer* tracer_;
6895};
6896
6897
6898void PathTracer::VisitPointers(Object** start, Object** end) {
6899 bool done = ((what_to_find_ == FIND_FIRST) && found_target_);
6900 // Visit all HeapObject pointers in [start, end)
6901 for (Object** p = start; !done && (p < end); p++) {
6902 if ((*p)->IsHeapObject()) {
6903 TracePathFrom(p);
6904 done = ((what_to_find_ == FIND_FIRST) && found_target_);
6905 }
6906 }
6907}
6908
6909
6910void PathTracer::Reset() {
6911 found_target_ = false;
6912 object_stack_.Clear();
6913}
6914
6915
6916void PathTracer::TracePathFrom(Object** root) {
6917 ASSERT((search_target_ == kAnyGlobalObject) ||
6918 search_target_->IsHeapObject());
6919 found_target_in_trace_ = false;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00006920 Reset();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006921
6922 MarkVisitor mark_visitor(this);
6923 MarkRecursively(root, &mark_visitor);
6924
6925 UnmarkVisitor unmark_visitor(this);
6926 UnmarkRecursively(root, &unmark_visitor);
6927
6928 ProcessResults();
6929}
6930
6931
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006932static bool SafeIsNativeContext(HeapObject* obj) {
6933 return obj->map() == obj->GetHeap()->raw_unchecked_native_context_map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006934}
6935
6936
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006937void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006938 if (!(*p)->IsHeapObject()) return;
6939
6940 HeapObject* obj = HeapObject::cast(*p);
6941
6942 Object* map = obj->map();
6943
6944 if (!map->IsHeapObject()) return; // visited before
6945
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006946 if (found_target_in_trace_) return; // stop if target found
6947 object_stack_.Add(obj);
6948 if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) ||
6949 (obj == search_target_)) {
6950 found_target_in_trace_ = true;
6951 found_target_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006952 return;
6953 }
6954
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006955 bool is_native_context = SafeIsNativeContext(obj);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006956
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006957 // not visited yet
6958 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
6959
6960 Address map_addr = map_p->address();
6961
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006962 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_addr + kMarkTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006963
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006964 // Scan the object body.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006965 if (is_native_context && (visit_mode_ == VISIT_ONLY_STRONG)) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006966 // This is specialized to scan Context's properly.
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00006967 Object** start = reinterpret_cast<Object**>(obj->address() +
6968 Context::kHeaderSize);
6969 Object** end = reinterpret_cast<Object**>(obj->address() +
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006970 Context::kHeaderSize + Context::FIRST_WEAK_SLOT * kPointerSize);
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00006971 mark_visitor->VisitPointers(start, end);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006972 } else {
6973 obj->IterateBody(map_p->instance_type(),
6974 obj->SizeFromMap(map_p),
6975 mark_visitor);
6976 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006977
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006978 // Scan the map after the body because the body is a lot more interesting
6979 // when doing leak detection.
6980 MarkRecursively(&map, mark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006981
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006982 if (!found_target_in_trace_) // don't pop if found the target
6983 object_stack_.RemoveLast();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006984}
6985
6986
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006987void PathTracer::UnmarkRecursively(Object** p, UnmarkVisitor* unmark_visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006988 if (!(*p)->IsHeapObject()) return;
6989
6990 HeapObject* obj = HeapObject::cast(*p);
6991
6992 Object* map = obj->map();
6993
6994 if (map->IsHeapObject()) return; // unmarked already
6995
6996 Address map_addr = reinterpret_cast<Address>(map);
6997
6998 map_addr -= kMarkTag;
6999
7000 ASSERT_TAG_ALIGNED(map_addr);
7001
7002 HeapObject* map_p = HeapObject::FromAddress(map_addr);
7003
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007004 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007005
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007006 UnmarkRecursively(reinterpret_cast<Object**>(&map_p), unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007007
7008 obj->IterateBody(Map::cast(map_p)->instance_type(),
7009 obj->SizeFromMap(Map::cast(map_p)),
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007010 unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007011}
7012
7013
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007014void PathTracer::ProcessResults() {
7015 if (found_target_) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007016 PrintF("=====================================\n");
7017 PrintF("==== Path to object ====\n");
7018 PrintF("=====================================\n\n");
7019
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007020 ASSERT(!object_stack_.is_empty());
7021 for (int i = 0; i < object_stack_.length(); i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007022 if (i > 0) PrintF("\n |\n |\n V\n\n");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007023 Object* obj = object_stack_[i];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007024 obj->Print();
7025 }
7026 PrintF("=====================================\n");
7027 }
7028}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007029#endif // DEBUG || LIVE_OBJECT_LIST
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007030
7031
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007032#ifdef DEBUG
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00007033// Triggers a depth-first traversal of reachable objects from one
7034// given root object and finds a path to a specific heap object and
7035// prints it.
7036void Heap::TracePathToObjectFrom(Object* target, Object* root) {
7037 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
7038 tracer.VisitPointer(&root);
7039}
7040
7041
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007042// Triggers a depth-first traversal of reachable objects from roots
7043// and finds a path to a specific heap object and prints it.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007044void Heap::TracePathToObject(Object* target) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007045 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
7046 IterateRoots(&tracer, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007047}
7048
7049
7050// Triggers a depth-first traversal of reachable objects from roots
7051// and finds a path to any global object and prints it. Useful for
7052// determining the source for leaks of global objects.
7053void Heap::TracePathToGlobal() {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007054 PathTracer tracer(PathTracer::kAnyGlobalObject,
7055 PathTracer::FIND_ALL,
7056 VISIT_ALL);
7057 IterateRoots(&tracer, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007058}
7059#endif
7060
7061
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007062static intptr_t CountTotalHolesSize() {
7063 intptr_t holes_size = 0;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007064 OldSpaces spaces;
7065 for (OldSpace* space = spaces.next();
7066 space != NULL;
7067 space = spaces.next()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007068 holes_size += space->Waste() + space->Available();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007069 }
7070 return holes_size;
7071}
7072
7073
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007074GCTracer::GCTracer(Heap* heap,
7075 const char* gc_reason,
7076 const char* collector_reason)
kasper.lund7276f142008-07-30 08:49:36 +00007077 : start_time_(0.0),
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007078 start_object_size_(0),
7079 start_memory_size_(0),
kasper.lund7276f142008-07-30 08:49:36 +00007080 gc_count_(0),
7081 full_gc_count_(0),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007082 allocated_since_last_gc_(0),
7083 spent_in_mutator_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007084 promoted_objects_size_(0),
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007085 heap_(heap),
7086 gc_reason_(gc_reason),
7087 collector_reason_(collector_reason) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007088 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
kasper.lund7276f142008-07-30 08:49:36 +00007089 start_time_ = OS::TimeCurrentMillis();
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007090 start_object_size_ = heap_->SizeOfObjects();
7091 start_memory_size_ = heap_->isolate()->memory_allocator()->Size();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007092
7093 for (int i = 0; i < Scope::kNumberOfScopes; i++) {
7094 scopes_[i] = 0;
7095 }
7096
7097 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize();
7098
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007099 allocated_since_last_gc_ =
7100 heap_->SizeOfObjects() - heap_->alive_after_last_gc_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007101
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007102 if (heap_->last_gc_end_timestamp_ > 0) {
7103 spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007104 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007105
7106 steps_count_ = heap_->incremental_marking()->steps_count();
7107 steps_took_ = heap_->incremental_marking()->steps_took();
7108 longest_step_ = heap_->incremental_marking()->longest_step();
7109 steps_count_since_last_gc_ =
7110 heap_->incremental_marking()->steps_count_since_last_gc();
7111 steps_took_since_last_gc_ =
7112 heap_->incremental_marking()->steps_took_since_last_gc();
kasper.lund7276f142008-07-30 08:49:36 +00007113}
7114
7115
7116GCTracer::~GCTracer() {
kasper.lund7276f142008-07-30 08:49:36 +00007117 // Printf ONE line iff flag is set.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007118 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
7119
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007120 bool first_gc = (heap_->last_gc_end_timestamp_ == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007121
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007122 heap_->alive_after_last_gc_ = heap_->SizeOfObjects();
7123 heap_->last_gc_end_timestamp_ = OS::TimeCurrentMillis();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007124
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007125 int time = static_cast<int>(heap_->last_gc_end_timestamp_ - start_time_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007126
7127 // Update cumulative GC statistics if required.
7128 if (FLAG_print_cumulative_gc_stat) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007129 heap_->total_gc_time_ms_ += time;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007130 heap_->max_gc_pause_ = Max(heap_->max_gc_pause_, time);
7131 heap_->max_alive_after_gc_ = Max(heap_->max_alive_after_gc_,
7132 heap_->alive_after_last_gc_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007133 if (!first_gc) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007134 heap_->min_in_mutator_ = Min(heap_->min_in_mutator_,
7135 static_cast<int>(spent_in_mutator_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007136 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007137 } else if (FLAG_trace_gc_verbose) {
7138 heap_->total_gc_time_ms_ += time;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007139 }
7140
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007141 if (collector_ == SCAVENGER && FLAG_trace_gc_ignore_scavenger) return;
7142
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00007143 PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init());
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007144
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007145 if (!FLAG_trace_gc_nvp) {
7146 int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]);
7147
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007148 double end_memory_size_mb =
7149 static_cast<double>(heap_->isolate()->memory_allocator()->Size()) / MB;
7150
7151 PrintF("%s %.1f (%.1f) -> %.1f (%.1f) MB, ",
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007152 CollectorString(),
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007153 static_cast<double>(start_object_size_) / MB,
7154 static_cast<double>(start_memory_size_) / MB,
7155 SizeOfHeapObjects(),
7156 end_memory_size_mb);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007157
7158 if (external_time > 0) PrintF("%d / ", external_time);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007159 PrintF("%d ms", time);
7160 if (steps_count_ > 0) {
7161 if (collector_ == SCAVENGER) {
7162 PrintF(" (+ %d ms in %d steps since last GC)",
7163 static_cast<int>(steps_took_since_last_gc_),
7164 steps_count_since_last_gc_);
7165 } else {
7166 PrintF(" (+ %d ms in %d steps since start of marking, "
7167 "biggest step %f ms)",
7168 static_cast<int>(steps_took_),
7169 steps_count_,
7170 longest_step_);
7171 }
7172 }
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007173
7174 if (gc_reason_ != NULL) {
7175 PrintF(" [%s]", gc_reason_);
7176 }
7177
7178 if (collector_reason_ != NULL) {
7179 PrintF(" [%s]", collector_reason_);
7180 }
7181
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007182 PrintF(".\n");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007183 } else {
7184 PrintF("pause=%d ", time);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007185 PrintF("mutator=%d ", static_cast<int>(spent_in_mutator_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007186 PrintF("gc=");
7187 switch (collector_) {
7188 case SCAVENGER:
7189 PrintF("s");
7190 break;
7191 case MARK_COMPACTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007192 PrintF("ms");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007193 break;
7194 default:
7195 UNREACHABLE();
7196 }
7197 PrintF(" ");
7198
7199 PrintF("external=%d ", static_cast<int>(scopes_[Scope::EXTERNAL]));
7200 PrintF("mark=%d ", static_cast<int>(scopes_[Scope::MC_MARK]));
7201 PrintF("sweep=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP]));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007202 PrintF("sweepns=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP_NEWSPACE]));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00007203 PrintF("evacuate=%d ", static_cast<int>(scopes_[Scope::MC_EVACUATE_PAGES]));
7204 PrintF("new_new=%d ",
7205 static_cast<int>(scopes_[Scope::MC_UPDATE_NEW_TO_NEW_POINTERS]));
7206 PrintF("root_new=%d ",
7207 static_cast<int>(scopes_[Scope::MC_UPDATE_ROOT_TO_NEW_POINTERS]));
7208 PrintF("old_new=%d ",
7209 static_cast<int>(scopes_[Scope::MC_UPDATE_OLD_TO_NEW_POINTERS]));
7210 PrintF("compaction_ptrs=%d ",
7211 static_cast<int>(scopes_[Scope::MC_UPDATE_POINTERS_TO_EVACUATED]));
7212 PrintF("intracompaction_ptrs=%d ", static_cast<int>(scopes_[
7213 Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED]));
7214 PrintF("misc_compaction=%d ",
7215 static_cast<int>(scopes_[Scope::MC_UPDATE_MISC_POINTERS]));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007216
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007217 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_object_size_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007218 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007219 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ",
7220 in_free_list_or_wasted_before_gc_);
7221 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007222
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007223 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_);
7224 PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007225
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007226 if (collector_ == SCAVENGER) {
7227 PrintF("stepscount=%d ", steps_count_since_last_gc_);
7228 PrintF("stepstook=%d ", static_cast<int>(steps_took_since_last_gc_));
7229 } else {
7230 PrintF("stepscount=%d ", steps_count_);
7231 PrintF("stepstook=%d ", static_cast<int>(steps_took_));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007232 PrintF("longeststep=%.f ", longest_step_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007233 }
7234
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007235 PrintF("\n");
7236 }
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007237
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007238 heap_->PrintShortHeapStatistics();
kasper.lund7276f142008-07-30 08:49:36 +00007239}
7240
7241
7242const char* GCTracer::CollectorString() {
7243 switch (collector_) {
7244 case SCAVENGER:
7245 return "Scavenge";
7246 case MARK_COMPACTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007247 return "Mark-sweep";
kasper.lund7276f142008-07-30 08:49:36 +00007248 }
7249 return "Unknown GC";
7250}
7251
7252
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007253int KeyedLookupCache::Hash(Map* map, String* name) {
7254 // Uses only lower 32 bits if pointers are larger.
7255 uintptr_t addr_hash =
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007256 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00007257 return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007258}
7259
7260
7261int KeyedLookupCache::Lookup(Map* map, String* name) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007262 int index = (Hash(map, name) & kHashMask);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007263 for (int i = 0; i < kEntriesPerBucket; i++) {
7264 Key& key = keys_[index + i];
7265 if ((key.map == map) && key.name->Equals(name)) {
7266 return field_offsets_[index + i];
7267 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007268 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007269 return kNotFound;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007270}
7271
7272
7273void KeyedLookupCache::Update(Map* map, String* name, int field_offset) {
7274 String* symbol;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007275 if (HEAP->LookupSymbolIfExists(name, &symbol)) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007276 int index = (Hash(map, symbol) & kHashMask);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007277 // After a GC there will be free slots, so we use them in order (this may
7278 // help to get the most frequently used one in position 0).
7279 for (int i = 0; i< kEntriesPerBucket; i++) {
7280 Key& key = keys_[index];
7281 Object* free_entry_indicator = NULL;
7282 if (key.map == free_entry_indicator) {
7283 key.map = map;
7284 key.name = symbol;
7285 field_offsets_[index + i] = field_offset;
7286 return;
7287 }
7288 }
7289 // No free entry found in this bucket, so we move them all down one and
7290 // put the new entry at position zero.
7291 for (int i = kEntriesPerBucket - 1; i > 0; i--) {
7292 Key& key = keys_[index + i];
7293 Key& key2 = keys_[index + i - 1];
7294 key = key2;
7295 field_offsets_[index + i] = field_offsets_[index + i - 1];
7296 }
7297
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007298 // Write the new first entry.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007299 Key& key = keys_[index];
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007300 key.map = map;
7301 key.name = symbol;
7302 field_offsets_[index] = field_offset;
7303 }
7304}
7305
7306
7307void KeyedLookupCache::Clear() {
7308 for (int index = 0; index < kLength; index++) keys_[index].map = NULL;
7309}
7310
7311
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007312void DescriptorLookupCache::Clear() {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007313 for (int index = 0; index < kLength; index++) keys_[index].source = NULL;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007314}
7315
7316
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007317#ifdef DEBUG
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007318void Heap::GarbageCollectionGreedyCheck() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007319 ASSERT(FLAG_gc_greedy);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007320 if (isolate_->bootstrapper()->IsActive()) return;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007321 if (disallow_allocation_failure()) return;
7322 CollectGarbage(NEW_SPACE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007323}
7324#endif
7325
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007326
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007327TranscendentalCache::SubCache::SubCache(Type t)
7328 : type_(t),
7329 isolate_(Isolate::Current()) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007330 uint32_t in0 = 0xffffffffu; // Bit-pattern for a NaN that isn't
7331 uint32_t in1 = 0xffffffffu; // generated by the FPU.
7332 for (int i = 0; i < kCacheSize; i++) {
7333 elements_[i].in[0] = in0;
7334 elements_[i].in[1] = in1;
7335 elements_[i].output = NULL;
7336 }
7337}
7338
7339
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007340void TranscendentalCache::Clear() {
7341 for (int i = 0; i < kNumberOfCaches; i++) {
7342 if (caches_[i] != NULL) {
7343 delete caches_[i];
7344 caches_[i] = NULL;
7345 }
7346 }
7347}
7348
7349
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007350void ExternalStringTable::CleanUp() {
7351 int last = 0;
7352 for (int i = 0; i < new_space_strings_.length(); ++i) {
danno@chromium.org72204d52012-10-31 10:02:10 +00007353 if (new_space_strings_[i] == heap_->the_hole_value()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007354 continue;
7355 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007356 if (heap_->InNewSpace(new_space_strings_[i])) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007357 new_space_strings_[last++] = new_space_strings_[i];
7358 } else {
7359 old_space_strings_.Add(new_space_strings_[i]);
7360 }
7361 }
7362 new_space_strings_.Rewind(last);
7363 last = 0;
7364 for (int i = 0; i < old_space_strings_.length(); ++i) {
danno@chromium.org72204d52012-10-31 10:02:10 +00007365 if (old_space_strings_[i] == heap_->the_hole_value()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007366 continue;
7367 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007368 ASSERT(!heap_->InNewSpace(old_space_strings_[i]));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007369 old_space_strings_[last++] = old_space_strings_[i];
7370 }
7371 old_space_strings_.Rewind(last);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007372#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007373 if (FLAG_verify_heap) {
7374 Verify();
7375 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007376#endif
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007377}
7378
7379
7380void ExternalStringTable::TearDown() {
7381 new_space_strings_.Free();
7382 old_space_strings_.Free();
7383}
7384
7385
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007386void Heap::QueueMemoryChunkForFree(MemoryChunk* chunk) {
7387 chunk->set_next_chunk(chunks_queued_for_free_);
7388 chunks_queued_for_free_ = chunk;
7389}
7390
7391
7392void Heap::FreeQueuedChunks() {
7393 if (chunks_queued_for_free_ == NULL) return;
7394 MemoryChunk* next;
7395 MemoryChunk* chunk;
7396 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
7397 next = chunk->next_chunk();
7398 chunk->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
7399
7400 if (chunk->owner()->identity() == LO_SPACE) {
7401 // StoreBuffer::Filter relies on MemoryChunk::FromAnyPointerAddress.
7402 // If FromAnyPointerAddress encounters a slot that belongs to a large
7403 // chunk queued for deletion it will fail to find the chunk because
7404 // it try to perform a search in the list of pages owned by of the large
7405 // object space and queued chunks were detached from that list.
7406 // To work around this we split large chunk into normal kPageSize aligned
danno@chromium.org2c456792011-11-11 12:00:53 +00007407 // pieces and initialize size, owner and flags field of every piece.
7408 // If FromAnyPointerAddress encounters a slot that belongs to one of
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007409 // these smaller pieces it will treat it as a slot on a normal Page.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007410 Address chunk_end = chunk->address() + chunk->size();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007411 MemoryChunk* inner = MemoryChunk::FromAddress(
7412 chunk->address() + Page::kPageSize);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007413 MemoryChunk* inner_last = MemoryChunk::FromAddress(chunk_end - 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007414 while (inner <= inner_last) {
7415 // Size of a large chunk is always a multiple of
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007416 // OS::AllocateAlignment() so there is always
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007417 // enough space for a fake MemoryChunk header.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007418 Address area_end = Min(inner->address() + Page::kPageSize, chunk_end);
7419 // Guard against overflow.
7420 if (area_end < inner->address()) area_end = chunk_end;
7421 inner->SetArea(inner->address(), area_end);
danno@chromium.org2c456792011-11-11 12:00:53 +00007422 inner->set_size(Page::kPageSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007423 inner->set_owner(lo_space());
7424 inner->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
7425 inner = MemoryChunk::FromAddress(
7426 inner->address() + Page::kPageSize);
7427 }
7428 }
7429 }
7430 isolate_->heap()->store_buffer()->Compact();
7431 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED);
7432 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
7433 next = chunk->next_chunk();
7434 isolate_->memory_allocator()->Free(chunk);
7435 }
7436 chunks_queued_for_free_ = NULL;
7437}
7438
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00007439
7440void Heap::RememberUnmappedPage(Address page, bool compacted) {
7441 uintptr_t p = reinterpret_cast<uintptr_t>(page);
7442 // Tag the page pointer to make it findable in the dump file.
7443 if (compacted) {
7444 p ^= 0xc1ead & (Page::kPageSize - 1); // Cleared.
7445 } else {
7446 p ^= 0x1d1ed & (Page::kPageSize - 1); // I died.
7447 }
7448 remembered_unmapped_pages_[remembered_unmapped_pages_index_] =
7449 reinterpret_cast<Address>(p);
7450 remembered_unmapped_pages_index_++;
7451 remembered_unmapped_pages_index_ %= kRememberedUnmappedPages;
7452}
7453
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00007454
7455void Heap::ClearObjectStats(bool clear_last_time_stats) {
7456 memset(object_counts_, 0, sizeof(object_counts_));
7457 memset(object_sizes_, 0, sizeof(object_sizes_));
7458 if (clear_last_time_stats) {
7459 memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_));
7460 memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_));
7461 }
7462}
7463
7464
7465static LazyMutex checkpoint_object_stats_mutex = LAZY_MUTEX_INITIALIZER;
7466
7467
7468void Heap::CheckpointObjectStats() {
7469 ScopedLock lock(checkpoint_object_stats_mutex.Pointer());
7470 Counters* counters = isolate()->counters();
7471#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7472 counters->count_of_##name()->Increment( \
7473 static_cast<int>(object_counts_[name])); \
7474 counters->count_of_##name()->Decrement( \
7475 static_cast<int>(object_counts_last_time_[name])); \
7476 counters->size_of_##name()->Increment( \
7477 static_cast<int>(object_sizes_[name])); \
7478 counters->size_of_##name()->Decrement( \
7479 static_cast<int>(object_sizes_last_time_[name]));
7480 INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7481#undef ADJUST_LAST_TIME_OBJECT_COUNT
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007482 int index;
7483#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7484 index = FIRST_CODE_KIND_SUB_TYPE + Code::name; \
7485 counters->count_of_CODE_TYPE_##name()->Increment( \
7486 static_cast<int>(object_counts_[index])); \
7487 counters->count_of_CODE_TYPE_##name()->Decrement( \
7488 static_cast<int>(object_counts_last_time_[index])); \
7489 counters->size_of_CODE_TYPE_##name()->Increment( \
7490 static_cast<int>(object_sizes_[index])); \
7491 counters->size_of_CODE_TYPE_##name()->Decrement( \
7492 static_cast<int>(object_sizes_last_time_[index]));
7493 CODE_KIND_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7494#undef ADJUST_LAST_TIME_OBJECT_COUNT
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007495#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7496 index = FIRST_FIXED_ARRAY_SUB_TYPE + name; \
7497 counters->count_of_FIXED_ARRAY_##name()->Increment( \
7498 static_cast<int>(object_counts_[index])); \
7499 counters->count_of_FIXED_ARRAY_##name()->Decrement( \
7500 static_cast<int>(object_counts_last_time_[index])); \
7501 counters->size_of_FIXED_ARRAY_##name()->Increment( \
7502 static_cast<int>(object_sizes_[index])); \
7503 counters->size_of_FIXED_ARRAY_##name()->Decrement( \
7504 static_cast<int>(object_sizes_last_time_[index]));
7505 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7506#undef ADJUST_LAST_TIME_OBJECT_COUNT
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007507
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00007508 memcpy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
7509 memcpy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
7510 ClearObjectStats();
7511}
7512
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007513} } // namespace v8::internal