blob: 714fc3566fce8b39ab8eaac0ef9d8fcfb552287a [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
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000647 {
648 HistogramTimerScope histogram_timer_scope(
649 (collector == SCAVENGER) ? isolate_->counters()->gc_scavenger()
650 : isolate_->counters()->gc_compactor());
651 next_gc_likely_to_collect_more =
652 PerformGarbageCollection(collector, &tracer);
653 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000654
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.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002808 { MaybeObject* maybe_obj = AllocateRawOneByteString(0, TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002809 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;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003180 MaybeObject* maybe_js_string = AllocateStringFromOneByte(CStrVector(str));
lrn@chromium.org303ada72010-10-27 09:33:13 +00003181 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;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003354 { MaybeObject* maybe_result = heap->AllocateRawOneByteString(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
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003396 bool first_is_ascii = first->IsOneByteRepresentation();
3397 bool second_is_ascii = second->IsOneByteRepresentation();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003398 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;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003427 { MaybeObject* maybe_result = AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003428 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;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003451 { MaybeObject* maybe_result = AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003452 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.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003522 bool is_ascii = buffer->IsOneByteRepresentation();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003523 { MaybeObject* maybe_result = is_ascii
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003524 ? AllocateRawOneByteString(length, pretenure)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003525 : 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) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003531 ASSERT(string_result->IsOneByteRepresentation());
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).
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003556 { Map* map = buffer->IsOneByteRepresentation()
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003557 ? 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);
4235 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
4236 JSArray* array;
4237 if (!maybe_array->To(&array)) return maybe_array;
4238
4239 if (capacity == 0) {
4240 array->set_length(Smi::FromInt(0));
4241 array->set_elements(empty_fixed_array());
4242 return array;
4243 }
4244
4245 FixedArrayBase* elms;
4246 MaybeObject* maybe_elms = NULL;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004247 if (IsFastDoubleElementsKind(elements_kind)) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004248 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
4249 maybe_elms = AllocateUninitializedFixedDoubleArray(capacity);
4250 } else {
4251 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
4252 maybe_elms = AllocateFixedDoubleArrayWithHoles(capacity);
4253 }
4254 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004255 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004256 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
4257 maybe_elms = AllocateUninitializedFixedArray(capacity);
4258 } else {
4259 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
4260 maybe_elms = AllocateFixedArrayWithHoles(capacity);
4261 }
4262 }
4263 if (!maybe_elms->To(&elms)) return maybe_elms;
4264
4265 array->set_elements(elms);
4266 array->set_length(Smi::FromInt(length));
4267 return array;
4268}
4269
4270
4271MaybeObject* Heap::AllocateJSArrayWithElements(
4272 FixedArrayBase* elements,
4273 ElementsKind elements_kind,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004274 int length,
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004275 PretenureFlag pretenure) {
4276 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
4277 JSArray* array;
4278 if (!maybe_array->To(&array)) return maybe_array;
4279
4280 array->set_elements(elements);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004281 array->set_length(Smi::FromInt(length));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004282 array->ValidateElements();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004283 return array;
4284}
4285
4286
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004287MaybeObject* Heap::AllocateJSProxy(Object* handler, Object* prototype) {
4288 // Allocate map.
4289 // TODO(rossberg): Once we optimize proxies, think about a scheme to share
4290 // maps. Will probably depend on the identity of the handler object, too.
danno@chromium.org40cb8782011-05-25 07:58:50 +00004291 Map* map;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004292 MaybeObject* maybe_map_obj = AllocateMap(JS_PROXY_TYPE, JSProxy::kSize);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004293 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004294 map->set_prototype(prototype);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004295
4296 // Allocate the proxy object.
lrn@chromium.org34e60782011-09-15 07:25:40 +00004297 JSProxy* result;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004298 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004299 if (!maybe_result->To<JSProxy>(&result)) return maybe_result;
4300 result->InitializeBody(map->instance_size(), Smi::FromInt(0));
4301 result->set_handler(handler);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004302 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004303 return result;
4304}
4305
4306
4307MaybeObject* Heap::AllocateJSFunctionProxy(Object* handler,
4308 Object* call_trap,
4309 Object* construct_trap,
4310 Object* prototype) {
4311 // Allocate map.
4312 // TODO(rossberg): Once we optimize proxies, think about a scheme to share
4313 // maps. Will probably depend on the identity of the handler object, too.
4314 Map* map;
4315 MaybeObject* maybe_map_obj =
4316 AllocateMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize);
4317 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
4318 map->set_prototype(prototype);
4319
4320 // Allocate the proxy object.
4321 JSFunctionProxy* result;
4322 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
4323 if (!maybe_result->To<JSFunctionProxy>(&result)) return maybe_result;
4324 result->InitializeBody(map->instance_size(), Smi::FromInt(0));
4325 result->set_handler(handler);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004326 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004327 result->set_call_trap(call_trap);
4328 result->set_construct_trap(construct_trap);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004329 return result;
4330}
4331
4332
lrn@chromium.org303ada72010-10-27 09:33:13 +00004333MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004334 ASSERT(constructor->has_initial_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004335 Map* map = constructor->initial_map();
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004336 ASSERT(map->is_dictionary_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004337
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004338 // Make sure no field properties are described in the initial map.
4339 // This guarantees us that normalizing the properties does not
4340 // require us to change property values to JSGlobalPropertyCells.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004341 ASSERT(map->NextFreePropertyIndex() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004342
4343 // Make sure we don't have a ton of pre-allocated slots in the
4344 // global objects. They will be unused once we normalize the object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004345 ASSERT(map->unused_property_fields() == 0);
4346 ASSERT(map->inobject_properties() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004347
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004348 // Initial size of the backing store to avoid resize of the storage during
4349 // bootstrapping. The size differs between the JS global object ad the
4350 // builtins object.
4351 int initial_size = map->instance_type() == JS_GLOBAL_OBJECT_TYPE ? 64 : 512;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004352
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004353 // Allocate a dictionary object for backing storage.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004354 StringDictionary* dictionary;
4355 MaybeObject* maybe_dictionary =
4356 StringDictionary::Allocate(
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004357 map->NumberOfOwnDescriptors() * 2 + initial_size);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004358 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004359
4360 // The global object might be created from an object template with accessors.
4361 // Fill these accessors into the dictionary.
4362 DescriptorArray* descs = map->instance_descriptors();
4363 for (int i = 0; i < descs->number_of_descriptors(); i++) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004364 PropertyDetails details = descs->GetDetails(i);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004365 ASSERT(details.type() == CALLBACKS); // Only accessors are expected.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004366 PropertyDetails d = PropertyDetails(details.attributes(),
4367 CALLBACKS,
4368 details.descriptor_index());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004369 Object* value = descs->GetCallbacksObject(i);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004370 MaybeObject* maybe_value = AllocateJSGlobalPropertyCell(value);
4371 if (!maybe_value->ToObject(&value)) return maybe_value;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004372
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004373 MaybeObject* maybe_added = dictionary->Add(descs->GetKey(i), value, d);
4374 if (!maybe_added->To(&dictionary)) return maybe_added;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004375 }
4376
4377 // Allocate the global object and initialize it with the backing store.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004378 JSObject* global;
4379 MaybeObject* maybe_global = Allocate(map, OLD_POINTER_SPACE);
4380 if (!maybe_global->To(&global)) return maybe_global;
4381
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004382 InitializeJSObjectFromMap(global, dictionary, map);
4383
4384 // Create a new map for the global object.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004385 Map* new_map;
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004386 MaybeObject* maybe_map = map->CopyDropDescriptors();
4387 if (!maybe_map->To(&new_map)) return maybe_map;
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004388 new_map->set_dictionary_map(true);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004389
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004390 // Set up the global object as a normalized object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004391 global->set_map(new_map);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004392 global->set_properties(dictionary);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004393
4394 // Make sure result is a global object with properties in dictionary.
4395 ASSERT(global->IsGlobalObject());
4396 ASSERT(!global->HasFastProperties());
4397 return global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004398}
4399
4400
lrn@chromium.org303ada72010-10-27 09:33:13 +00004401MaybeObject* Heap::CopyJSObject(JSObject* source) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004402 // Never used to copy functions. If functions need to be copied we
4403 // have to be careful to clear the literals array.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004404 SLOW_ASSERT(!source->IsJSFunction());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004405
4406 // Make the clone.
4407 Map* map = source->map();
4408 int object_size = map->instance_size();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004409 Object* clone;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004410
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004411 WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER;
4412
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004413 // If we're forced to always allocate, we use the general allocation
4414 // functions which may leave us with an object in old space.
4415 if (always_allocate()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004416 { MaybeObject* maybe_clone =
4417 AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE);
4418 if (!maybe_clone->ToObject(&clone)) return maybe_clone;
4419 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004420 Address clone_address = HeapObject::cast(clone)->address();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004421 CopyBlock(clone_address,
4422 source->address(),
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004423 object_size);
4424 // Update write barrier for all fields that lie beyond the header.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004425 RecordWrites(clone_address,
4426 JSObject::kHeaderSize,
antonm@chromium.org8e5e3382010-03-24 09:56:30 +00004427 (object_size - JSObject::kHeaderSize) / kPointerSize);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004428 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004429 wb_mode = SKIP_WRITE_BARRIER;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004430 { MaybeObject* maybe_clone = new_space_.AllocateRaw(object_size);
4431 if (!maybe_clone->ToObject(&clone)) return maybe_clone;
4432 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004433 SLOW_ASSERT(InNewSpace(clone));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004434 // Since we know the clone is allocated in new space, we can copy
ager@chromium.org32912102009-01-16 10:38:43 +00004435 // the contents without worrying about updating the write barrier.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004436 CopyBlock(HeapObject::cast(clone)->address(),
4437 source->address(),
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004438 object_size);
4439 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004440
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004441 SLOW_ASSERT(
4442 JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004443 FixedArrayBase* elements = FixedArrayBase::cast(source->elements());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004444 FixedArray* properties = FixedArray::cast(source->properties());
4445 // Update elements if necessary.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00004446 if (elements->length() > 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004447 Object* elem;
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004448 { MaybeObject* maybe_elem;
4449 if (elements->map() == fixed_cow_array_map()) {
4450 maybe_elem = FixedArray::cast(elements);
4451 } else if (source->HasFastDoubleElements()) {
4452 maybe_elem = CopyFixedDoubleArray(FixedDoubleArray::cast(elements));
4453 } else {
4454 maybe_elem = CopyFixedArray(FixedArray::cast(elements));
4455 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004456 if (!maybe_elem->ToObject(&elem)) return maybe_elem;
4457 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004458 JSObject::cast(clone)->set_elements(FixedArrayBase::cast(elem), wb_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004459 }
4460 // Update properties if necessary.
4461 if (properties->length() > 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004462 Object* prop;
4463 { MaybeObject* maybe_prop = CopyFixedArray(properties);
4464 if (!maybe_prop->ToObject(&prop)) return maybe_prop;
4465 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004466 JSObject::cast(clone)->set_properties(FixedArray::cast(prop), wb_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004467 }
4468 // Return the new clone.
4469 return clone;
4470}
4471
4472
lrn@chromium.org34e60782011-09-15 07:25:40 +00004473MaybeObject* Heap::ReinitializeJSReceiver(
4474 JSReceiver* object, InstanceType type, int size) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004475 ASSERT(type >= FIRST_JS_OBJECT_TYPE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004476
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004477 // Allocate fresh map.
4478 // TODO(rossberg): Once we optimize proxies, cache these maps.
4479 Map* map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004480 MaybeObject* maybe = AllocateMap(type, size);
4481 if (!maybe->To<Map>(&map)) return maybe;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004482
lrn@chromium.org34e60782011-09-15 07:25:40 +00004483 // Check that the receiver has at least the size of the fresh object.
4484 int size_difference = object->map()->instance_size() - map->instance_size();
4485 ASSERT(size_difference >= 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004486
4487 map->set_prototype(object->map()->prototype());
4488
4489 // Allocate the backing storage for the properties.
4490 int prop_size = map->unused_property_fields() - map->inobject_properties();
4491 Object* properties;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004492 maybe = AllocateFixedArray(prop_size, TENURED);
4493 if (!maybe->ToObject(&properties)) return maybe;
4494
4495 // Functions require some allocation, which might fail here.
4496 SharedFunctionInfo* shared = NULL;
4497 if (type == JS_FUNCTION_TYPE) {
4498 String* name;
4499 maybe = LookupAsciiSymbol("<freezing call trap>");
4500 if (!maybe->To<String>(&name)) return maybe;
4501 maybe = AllocateSharedFunctionInfo(name);
4502 if (!maybe->To<SharedFunctionInfo>(&shared)) return maybe;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004503 }
4504
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004505 // Because of possible retries of this function after failure,
4506 // we must NOT fail after this point, where we have changed the type!
4507
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004508 // Reset the map for the object.
4509 object->set_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004510 JSObject* jsobj = JSObject::cast(object);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004511
4512 // Reinitialize the object from the constructor map.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004513 InitializeJSObjectFromMap(jsobj, FixedArray::cast(properties), map);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004514
4515 // Functions require some minimal initialization.
4516 if (type == JS_FUNCTION_TYPE) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004517 map->set_function_with_prototype(true);
4518 InitializeFunction(JSFunction::cast(object), shared, the_hole_value());
4519 JSFunction::cast(object)->set_context(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004520 isolate()->context()->native_context());
lrn@chromium.org34e60782011-09-15 07:25:40 +00004521 }
4522
4523 // Put in filler if the new object is smaller than the old.
4524 if (size_difference > 0) {
4525 CreateFillerObjectAt(
4526 object->address() + map->instance_size(), size_difference);
4527 }
4528
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004529 return object;
4530}
4531
4532
lrn@chromium.org303ada72010-10-27 09:33:13 +00004533MaybeObject* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor,
4534 JSGlobalProxy* object) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004535 ASSERT(constructor->has_initial_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004536 Map* map = constructor->initial_map();
4537
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004538 // Check that the already allocated object has the same size and type as
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004539 // objects allocated using the constructor.
4540 ASSERT(map->instance_size() == object->map()->instance_size());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004541 ASSERT(map->instance_type() == object->map()->instance_type());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004542
4543 // Allocate the backing storage for the properties.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004544 int prop_size = map->unused_property_fields() - map->inobject_properties();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004545 Object* properties;
4546 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, TENURED);
4547 if (!maybe_properties->ToObject(&properties)) return maybe_properties;
4548 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004549
4550 // Reset the map for the object.
4551 object->set_map(constructor->initial_map());
4552
4553 // Reinitialize the object from the constructor map.
4554 InitializeJSObjectFromMap(object, FixedArray::cast(properties), map);
4555 return object;
4556}
4557
4558
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004559MaybeObject* Heap::AllocateStringFromOneByte(Vector<const char> string,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004560 PretenureFlag pretenure) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004561 int length = string.length();
4562 if (length == 1) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004563 return Heap::LookupSingleCharacterStringFromCode(string[0]);
4564 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004565 Object* result;
4566 { MaybeObject* maybe_result =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004567 AllocateRawOneByteString(string.length(), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004568 if (!maybe_result->ToObject(&result)) return maybe_result;
4569 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004570
4571 // Copy the characters into the new object.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004572 CopyChars(SeqOneByteString::cast(result)->GetChars(), string.start(), length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004573 return result;
4574}
4575
4576
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004577MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector<const char> string,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004578 int non_ascii_start,
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004579 PretenureFlag pretenure) {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004580 // Continue counting the number of characters in the UTF-8 string, starting
4581 // from the first non-ascii character or word.
4582 int chars = non_ascii_start;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004583 Access<UnicodeCache::Utf8Decoder>
4584 decoder(isolate_->unicode_cache()->utf8_decoder());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004585 decoder->Reset(string.start() + non_ascii_start, string.length() - chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004586 while (decoder->has_more()) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004587 uint32_t r = decoder->GetNext();
4588 if (r <= unibrow::Utf16::kMaxNonSurrogateCharCode) {
4589 chars++;
4590 } else {
4591 chars += 2;
4592 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004593 }
4594
lrn@chromium.org303ada72010-10-27 09:33:13 +00004595 Object* result;
4596 { MaybeObject* maybe_result = AllocateRawTwoByteString(chars, pretenure);
4597 if (!maybe_result->ToObject(&result)) return maybe_result;
4598 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004599
4600 // Convert and copy the characters into the new object.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004601 SeqTwoByteString* twobyte = SeqTwoByteString::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004602 decoder->Reset(string.start(), string.length());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004603 int i = 0;
4604 while (i < chars) {
4605 uint32_t r = decoder->GetNext();
4606 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004607 twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::LeadSurrogate(r));
4608 twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::TrailSurrogate(r));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004609 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004610 twobyte->SeqTwoByteStringSet(i++, r);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004611 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004612 }
4613 return result;
4614}
4615
4616
lrn@chromium.org303ada72010-10-27 09:33:13 +00004617MaybeObject* Heap::AllocateStringFromTwoByte(Vector<const uc16> string,
4618 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004619 // Check if the string is an ASCII string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004620 Object* result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004621 int length = string.length();
4622 const uc16* start = string.start();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004623
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004624 if (String::IsAscii(start, length)) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004625 MaybeObject* maybe_result = AllocateRawOneByteString(length, pretenure);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004626 if (!maybe_result->ToObject(&result)) return maybe_result;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004627 CopyChars(SeqOneByteString::cast(result)->GetChars(), start, length);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004628 } else { // It's not an ASCII string.
4629 MaybeObject* maybe_result = AllocateRawTwoByteString(length, pretenure);
4630 if (!maybe_result->ToObject(&result)) return maybe_result;
4631 CopyChars(SeqTwoByteString::cast(result)->GetChars(), start, length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004632 }
4633 return result;
4634}
4635
4636
4637Map* Heap::SymbolMapForString(String* string) {
4638 // If the string is in new space it cannot be used as a symbol.
4639 if (InNewSpace(string)) return NULL;
4640
4641 // Find the corresponding symbol map for strings.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004642 switch (string->map()->instance_type()) {
4643 case STRING_TYPE: return symbol_map();
4644 case ASCII_STRING_TYPE: return ascii_symbol_map();
4645 case CONS_STRING_TYPE: return cons_symbol_map();
4646 case CONS_ASCII_STRING_TYPE: return cons_ascii_symbol_map();
4647 case EXTERNAL_STRING_TYPE: return external_symbol_map();
4648 case EXTERNAL_ASCII_STRING_TYPE: return external_ascii_symbol_map();
4649 case EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
4650 return external_symbol_with_ascii_data_map();
4651 case SHORT_EXTERNAL_STRING_TYPE: return short_external_symbol_map();
4652 case SHORT_EXTERNAL_ASCII_STRING_TYPE:
4653 return short_external_ascii_symbol_map();
4654 case SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
4655 return short_external_symbol_with_ascii_data_map();
4656 default: return NULL; // No match found.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004657 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004658}
4659
4660
lrn@chromium.org303ada72010-10-27 09:33:13 +00004661MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
4662 int chars,
4663 uint32_t hash_field) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004664 ASSERT(chars >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004665 // Ensure the chars matches the number of characters in the buffer.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004666 ASSERT(static_cast<unsigned>(chars) == buffer->Utf16Length());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004667 // Determine whether the string is ASCII.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004668 bool is_ascii = true;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004669 while (buffer->has_more()) {
4670 if (buffer->GetNext() > unibrow::Utf8::kMaxOneByteChar) {
4671 is_ascii = false;
4672 break;
4673 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004674 }
4675 buffer->Rewind();
4676
4677 // Compute map and object size.
4678 int size;
4679 Map* map;
4680
4681 if (is_ascii) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004682 if (chars > SeqOneByteString::kMaxLength) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004683 return Failure::OutOfMemoryException();
4684 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004685 map = ascii_symbol_map();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004686 size = SeqOneByteString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004687 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004688 if (chars > SeqTwoByteString::kMaxLength) {
4689 return Failure::OutOfMemoryException();
4690 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004691 map = symbol_map();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004692 size = SeqTwoByteString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004693 }
4694
4695 // Allocate string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004696 Object* result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004697 { MaybeObject* maybe_result = (size > Page::kMaxNonCodeHeapObjectSize)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004698 ? lo_space_->AllocateRaw(size, NOT_EXECUTABLE)
lrn@chromium.org303ada72010-10-27 09:33:13 +00004699 : old_data_space_->AllocateRaw(size);
4700 if (!maybe_result->ToObject(&result)) return maybe_result;
4701 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004702
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004703 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(map);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004704 // Set length and hash fields of the allocated string.
ager@chromium.org870a0b62008-11-04 11:43:05 +00004705 String* answer = String::cast(result);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004706 answer->set_length(chars);
4707 answer->set_hash_field(hash_field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004708
ager@chromium.org870a0b62008-11-04 11:43:05 +00004709 ASSERT_EQ(size, answer->Size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004710
4711 // Fill in the characters.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004712 int i = 0;
4713 while (i < chars) {
4714 uint32_t character = buffer->GetNext();
4715 if (character > unibrow::Utf16::kMaxNonSurrogateCharCode) {
4716 answer->Set(i++, unibrow::Utf16::LeadSurrogate(character));
4717 answer->Set(i++, unibrow::Utf16::TrailSurrogate(character));
4718 } else {
4719 answer->Set(i++, character);
4720 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004721 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00004722 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004723}
4724
4725
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004726MaybeObject* Heap::AllocateRawOneByteString(int length,
4727 PretenureFlag pretenure) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004728 if (length < 0 || length > SeqOneByteString::kMaxLength) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004729 return Failure::OutOfMemoryException();
4730 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004731
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004732 int size = SeqOneByteString::SizeFor(length);
4733 ASSERT(size <= SeqOneByteString::kMaxSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004734
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004735 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
4736 AllocationSpace retry_space = OLD_DATA_SPACE;
4737
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004738 if (space == NEW_SPACE) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004739 if (size > kMaxObjectSizeInNewSpace) {
4740 // Allocate in large object space, retry space will be ignored.
4741 space = LO_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004742 } else if (size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004743 // Allocate in new space, retry in large object space.
4744 retry_space = LO_SPACE;
4745 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004746 } else if (space == OLD_DATA_SPACE &&
4747 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004748 space = LO_SPACE;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004749 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004750 Object* result;
4751 { MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
4752 if (!maybe_result->ToObject(&result)) return maybe_result;
4753 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004754
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004755 // Partially initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004756 HeapObject::cast(result)->set_map_no_write_barrier(ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004757 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004758 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004759 ASSERT_EQ(size, HeapObject::cast(result)->Size());
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004760
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004761#ifdef VERIFY_HEAP
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004762 if (FLAG_verify_heap) {
4763 // Initialize string's content to ensure ASCII-ness (character range 0-127)
4764 // as required when verifying the heap.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004765 char* dest = SeqOneByteString::cast(result)->GetChars();
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004766 memset(dest, 0x0F, length * kCharSize);
4767 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004768#endif
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004769
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004770 return result;
4771}
4772
4773
lrn@chromium.org303ada72010-10-27 09:33:13 +00004774MaybeObject* Heap::AllocateRawTwoByteString(int length,
4775 PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004776 if (length < 0 || length > SeqTwoByteString::kMaxLength) {
4777 return Failure::OutOfMemoryException();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004778 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004779 int size = SeqTwoByteString::SizeFor(length);
4780 ASSERT(size <= SeqTwoByteString::kMaxSize);
4781 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
4782 AllocationSpace retry_space = OLD_DATA_SPACE;
4783
4784 if (space == NEW_SPACE) {
4785 if (size > kMaxObjectSizeInNewSpace) {
4786 // Allocate in large object space, retry space will be ignored.
4787 space = LO_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004788 } else if (size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004789 // Allocate in new space, retry in large object space.
4790 retry_space = LO_SPACE;
4791 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004792 } else if (space == OLD_DATA_SPACE &&
4793 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004794 space = LO_SPACE;
4795 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004796 Object* result;
4797 { MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
4798 if (!maybe_result->ToObject(&result)) return maybe_result;
4799 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004800
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004801 // Partially initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004802 HeapObject::cast(result)->set_map_no_write_barrier(string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004803 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004804 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004805 ASSERT_EQ(size, HeapObject::cast(result)->Size());
4806 return result;
4807}
4808
4809
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004810MaybeObject* Heap::AllocateJSArray(
4811 ElementsKind elements_kind,
4812 PretenureFlag pretenure) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004813 Context* native_context = isolate()->context()->native_context();
4814 JSFunction* array_function = native_context->array_function();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004815 Map* map = array_function->initial_map();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004816 Object* maybe_map_array = native_context->js_array_maps();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004817 if (!maybe_map_array->IsUndefined()) {
4818 Object* maybe_transitioned_map =
4819 FixedArray::cast(maybe_map_array)->get(elements_kind);
4820 if (!maybe_transitioned_map->IsUndefined()) {
4821 map = Map::cast(maybe_transitioned_map);
4822 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004823 }
4824
4825 return AllocateJSObjectFromMap(map, pretenure);
4826}
4827
4828
lrn@chromium.org303ada72010-10-27 09:33:13 +00004829MaybeObject* Heap::AllocateEmptyFixedArray() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004830 int size = FixedArray::SizeFor(0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004831 Object* result;
4832 { MaybeObject* maybe_result =
4833 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
4834 if (!maybe_result->ToObject(&result)) return maybe_result;
4835 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004836 // Initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004837 reinterpret_cast<FixedArray*>(result)->set_map_no_write_barrier(
4838 fixed_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004839 reinterpret_cast<FixedArray*>(result)->set_length(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004840 return result;
4841}
4842
4843
lrn@chromium.org303ada72010-10-27 09:33:13 +00004844MaybeObject* Heap::AllocateRawFixedArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004845 if (length < 0 || length > FixedArray::kMaxLength) {
4846 return Failure::OutOfMemoryException();
4847 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004848 ASSERT(length > 0);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004849 // Use the general function if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004850 if (always_allocate()) return AllocateFixedArray(length, TENURED);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004851 // Allocate the raw data for a fixed array.
4852 int size = FixedArray::SizeFor(length);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004853 return size <= kMaxObjectSizeInNewSpace
4854 ? new_space_.AllocateRaw(size)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004855 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004856}
4857
4858
lrn@chromium.org303ada72010-10-27 09:33:13 +00004859MaybeObject* Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004860 int len = src->length();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004861 Object* obj;
4862 { MaybeObject* maybe_obj = AllocateRawFixedArray(len);
4863 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4864 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004865 if (InNewSpace(obj)) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004866 HeapObject* dst = HeapObject::cast(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004867 dst->set_map_no_write_barrier(map);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004868 CopyBlock(dst->address() + kPointerSize,
4869 src->address() + kPointerSize,
4870 FixedArray::SizeFor(len) - kPointerSize);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004871 return obj;
4872 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004873 HeapObject::cast(obj)->set_map_no_write_barrier(map);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004874 FixedArray* result = FixedArray::cast(obj);
4875 result->set_length(len);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004876
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004877 // Copy the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004878 AssertNoAllocation no_gc;
4879 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004880 for (int i = 0; i < len; i++) result->set(i, src->get(i), mode);
4881 return result;
4882}
4883
4884
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004885MaybeObject* Heap::CopyFixedDoubleArrayWithMap(FixedDoubleArray* src,
4886 Map* map) {
4887 int len = src->length();
4888 Object* obj;
4889 { MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(len, NOT_TENURED);
4890 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4891 }
4892 HeapObject* dst = HeapObject::cast(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004893 dst->set_map_no_write_barrier(map);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004894 CopyBlock(
4895 dst->address() + FixedDoubleArray::kLengthOffset,
4896 src->address() + FixedDoubleArray::kLengthOffset,
4897 FixedDoubleArray::SizeFor(len) - FixedDoubleArray::kLengthOffset);
4898 return obj;
4899}
4900
4901
lrn@chromium.org303ada72010-10-27 09:33:13 +00004902MaybeObject* Heap::AllocateFixedArray(int length) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004903 ASSERT(length >= 0);
ager@chromium.org32912102009-01-16 10:38:43 +00004904 if (length == 0) return empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004905 Object* result;
4906 { MaybeObject* maybe_result = AllocateRawFixedArray(length);
4907 if (!maybe_result->ToObject(&result)) return maybe_result;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004908 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004909 // Initialize header.
4910 FixedArray* array = reinterpret_cast<FixedArray*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004911 array->set_map_no_write_barrier(fixed_array_map());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004912 array->set_length(length);
4913 // Initialize body.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004914 ASSERT(!InNewSpace(undefined_value()));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004915 MemsetPointer(array->data_start(), undefined_value(), length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004916 return result;
4917}
4918
4919
lrn@chromium.org303ada72010-10-27 09:33:13 +00004920MaybeObject* Heap::AllocateRawFixedArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004921 if (length < 0 || length > FixedArray::kMaxLength) {
4922 return Failure::OutOfMemoryException();
4923 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004924
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004925 AllocationSpace space =
4926 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004927 int size = FixedArray::SizeFor(length);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004928 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
4929 // Too big for new space.
4930 space = LO_SPACE;
4931 } else if (space == OLD_POINTER_SPACE &&
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004932 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004933 // Too big for old pointer space.
4934 space = LO_SPACE;
4935 }
4936
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004937 AllocationSpace retry_space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004938 (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_POINTER_SPACE : LO_SPACE;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004939
4940 return AllocateRaw(size, space, retry_space);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004941}
4942
4943
lrn@chromium.org303ada72010-10-27 09:33:13 +00004944MUST_USE_RESULT static MaybeObject* AllocateFixedArrayWithFiller(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004945 Heap* heap,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004946 int length,
4947 PretenureFlag pretenure,
4948 Object* filler) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004949 ASSERT(length >= 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004950 ASSERT(heap->empty_fixed_array()->IsFixedArray());
4951 if (length == 0) return heap->empty_fixed_array();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004952
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004953 ASSERT(!heap->InNewSpace(filler));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004954 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004955 { MaybeObject* maybe_result = heap->AllocateRawFixedArray(length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004956 if (!maybe_result->ToObject(&result)) return maybe_result;
4957 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004958
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004959 HeapObject::cast(result)->set_map_no_write_barrier(heap->fixed_array_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004960 FixedArray* array = FixedArray::cast(result);
4961 array->set_length(length);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004962 MemsetPointer(array->data_start(), filler, length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004963 return array;
4964}
4965
4966
lrn@chromium.org303ada72010-10-27 09:33:13 +00004967MaybeObject* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004968 return AllocateFixedArrayWithFiller(this,
4969 length,
4970 pretenure,
4971 undefined_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004972}
4973
4974
lrn@chromium.org303ada72010-10-27 09:33:13 +00004975MaybeObject* Heap::AllocateFixedArrayWithHoles(int length,
4976 PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004977 return AllocateFixedArrayWithFiller(this,
4978 length,
4979 pretenure,
4980 the_hole_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004981}
4982
4983
lrn@chromium.org303ada72010-10-27 09:33:13 +00004984MaybeObject* Heap::AllocateUninitializedFixedArray(int length) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004985 if (length == 0) return empty_fixed_array();
4986
lrn@chromium.org303ada72010-10-27 09:33:13 +00004987 Object* obj;
4988 { MaybeObject* maybe_obj = AllocateRawFixedArray(length);
4989 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4990 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004991
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004992 reinterpret_cast<FixedArray*>(obj)->set_map_no_write_barrier(
4993 fixed_array_map());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004994 FixedArray::cast(obj)->set_length(length);
4995 return obj;
4996}
4997
4998
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004999MaybeObject* Heap::AllocateEmptyFixedDoubleArray() {
5000 int size = FixedDoubleArray::SizeFor(0);
5001 Object* result;
5002 { MaybeObject* maybe_result =
5003 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
5004 if (!maybe_result->ToObject(&result)) return maybe_result;
5005 }
5006 // Initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005007 reinterpret_cast<FixedDoubleArray*>(result)->set_map_no_write_barrier(
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005008 fixed_double_array_map());
5009 reinterpret_cast<FixedDoubleArray*>(result)->set_length(0);
5010 return result;
5011}
5012
5013
5014MaybeObject* Heap::AllocateUninitializedFixedDoubleArray(
5015 int length,
5016 PretenureFlag pretenure) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005017 if (length == 0) return empty_fixed_array();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005018
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005019 Object* elements_object;
5020 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
5021 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj;
5022 FixedDoubleArray* elements =
5023 reinterpret_cast<FixedDoubleArray*>(elements_object);
5024
5025 elements->set_map_no_write_barrier(fixed_double_array_map());
5026 elements->set_length(length);
5027 return elements;
5028}
5029
5030
5031MaybeObject* Heap::AllocateFixedDoubleArrayWithHoles(
5032 int length,
5033 PretenureFlag pretenure) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005034 if (length == 0) return empty_fixed_array();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005035
5036 Object* elements_object;
5037 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
5038 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj;
5039 FixedDoubleArray* elements =
5040 reinterpret_cast<FixedDoubleArray*>(elements_object);
5041
5042 for (int i = 0; i < length; ++i) {
5043 elements->set_the_hole(i);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005044 }
5045
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005046 elements->set_map_no_write_barrier(fixed_double_array_map());
5047 elements->set_length(length);
5048 return elements;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005049}
5050
5051
5052MaybeObject* Heap::AllocateRawFixedDoubleArray(int length,
5053 PretenureFlag pretenure) {
5054 if (length < 0 || length > FixedDoubleArray::kMaxLength) {
5055 return Failure::OutOfMemoryException();
5056 }
5057
5058 AllocationSpace space =
5059 (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
5060 int size = FixedDoubleArray::SizeFor(length);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005061
5062#ifndef V8_HOST_ARCH_64_BIT
5063 size += kPointerSize;
5064#endif
5065
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005066 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
5067 // Too big for new space.
5068 space = LO_SPACE;
5069 } else if (space == OLD_DATA_SPACE &&
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005070 size > Page::kMaxNonCodeHeapObjectSize) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005071 // Too big for old data space.
5072 space = LO_SPACE;
5073 }
5074
5075 AllocationSpace retry_space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005076 (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_DATA_SPACE : LO_SPACE;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005077
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005078 HeapObject* object;
5079 { MaybeObject* maybe_object = AllocateRaw(size, space, retry_space);
5080 if (!maybe_object->To<HeapObject>(&object)) return maybe_object;
5081 }
5082
5083 return EnsureDoubleAligned(this, object, size);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005084}
5085
5086
lrn@chromium.org303ada72010-10-27 09:33:13 +00005087MaybeObject* Heap::AllocateHashTable(int length, PretenureFlag pretenure) {
5088 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005089 { MaybeObject* maybe_result = AllocateFixedArray(length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005090 if (!maybe_result->ToObject(&result)) return maybe_result;
5091 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005092 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(
5093 hash_table_map());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005094 ASSERT(result->IsHashTable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005095 return result;
5096}
5097
5098
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005099MaybeObject* Heap::AllocateNativeContext() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005100 Object* result;
5101 { MaybeObject* maybe_result =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005102 AllocateFixedArray(Context::NATIVE_CONTEXT_SLOTS);
5103 if (!maybe_result->ToObject(&result)) return maybe_result;
5104 }
5105 Context* context = reinterpret_cast<Context*>(result);
5106 context->set_map_no_write_barrier(native_context_map());
5107 context->set_js_array_maps(undefined_value());
5108 ASSERT(context->IsNativeContext());
5109 ASSERT(result->IsContext());
5110 return result;
5111}
5112
5113
5114MaybeObject* Heap::AllocateGlobalContext(JSFunction* function,
5115 ScopeInfo* scope_info) {
5116 Object* result;
5117 { MaybeObject* maybe_result =
5118 AllocateFixedArray(scope_info->ContextLength(), TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005119 if (!maybe_result->ToObject(&result)) return maybe_result;
5120 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005121 Context* context = reinterpret_cast<Context*>(result);
danno@chromium.orgeb831462012-08-24 11:57:08 +00005122 context->set_map_no_write_barrier(global_context_map());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005123 context->set_closure(function);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005124 context->set_previous(function->context());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005125 context->set_extension(scope_info);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005126 context->set_global_object(function->context()->global_object());
danno@chromium.orgeb831462012-08-24 11:57:08 +00005127 ASSERT(context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005128 ASSERT(result->IsContext());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005129 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005130}
5131
5132
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005133MaybeObject* Heap::AllocateModuleContext(ScopeInfo* scope_info) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005134 Object* result;
5135 { MaybeObject* maybe_result =
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005136 AllocateFixedArray(scope_info->ContextLength(), TENURED);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005137 if (!maybe_result->ToObject(&result)) return maybe_result;
5138 }
5139 Context* context = reinterpret_cast<Context*>(result);
5140 context->set_map_no_write_barrier(module_context_map());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005141 // Instance link will be set later.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005142 context->set_extension(Smi::FromInt(0));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005143 return context;
5144}
5145
5146
lrn@chromium.org303ada72010-10-27 09:33:13 +00005147MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005148 ASSERT(length >= Context::MIN_CONTEXT_SLOTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005149 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005150 { MaybeObject* maybe_result = AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005151 if (!maybe_result->ToObject(&result)) return maybe_result;
5152 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005153 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005154 context->set_map_no_write_barrier(function_context_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005155 context->set_closure(function);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005156 context->set_previous(function->context());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005157 context->set_extension(Smi::FromInt(0));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005158 context->set_global_object(function->context()->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005159 return context;
5160}
5161
5162
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005163MaybeObject* Heap::AllocateCatchContext(JSFunction* function,
5164 Context* previous,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005165 String* name,
5166 Object* thrown_object) {
5167 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == Context::THROWN_OBJECT_INDEX);
5168 Object* result;
5169 { MaybeObject* maybe_result =
5170 AllocateFixedArray(Context::MIN_CONTEXT_SLOTS + 1);
5171 if (!maybe_result->ToObject(&result)) return maybe_result;
5172 }
5173 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005174 context->set_map_no_write_barrier(catch_context_map());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005175 context->set_closure(function);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005176 context->set_previous(previous);
5177 context->set_extension(name);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005178 context->set_global_object(previous->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005179 context->set(Context::THROWN_OBJECT_INDEX, thrown_object);
5180 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005181}
5182
5183
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005184MaybeObject* Heap::AllocateWithContext(JSFunction* function,
5185 Context* previous,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005186 JSObject* extension) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005187 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005188 { MaybeObject* maybe_result = AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005189 if (!maybe_result->ToObject(&result)) return maybe_result;
5190 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005191 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005192 context->set_map_no_write_barrier(with_context_map());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005193 context->set_closure(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005194 context->set_previous(previous);
5195 context->set_extension(extension);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005196 context->set_global_object(previous->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005197 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005198}
5199
5200
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005201MaybeObject* Heap::AllocateBlockContext(JSFunction* function,
5202 Context* previous,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005203 ScopeInfo* scope_info) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005204 Object* result;
5205 { MaybeObject* maybe_result =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005206 AllocateFixedArrayWithHoles(scope_info->ContextLength());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005207 if (!maybe_result->ToObject(&result)) return maybe_result;
5208 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005209 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005210 context->set_map_no_write_barrier(block_context_map());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005211 context->set_closure(function);
5212 context->set_previous(previous);
5213 context->set_extension(scope_info);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005214 context->set_global_object(previous->global_object());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005215 return context;
5216}
5217
5218
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005219MaybeObject* Heap::AllocateScopeInfo(int length) {
5220 FixedArray* scope_info;
5221 MaybeObject* maybe_scope_info = AllocateFixedArray(length, TENURED);
5222 if (!maybe_scope_info->To(&scope_info)) return maybe_scope_info;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005223 scope_info->set_map_no_write_barrier(scope_info_map());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005224 return scope_info;
5225}
5226
5227
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00005228MaybeObject* Heap::AllocateExternal(void* value) {
5229 Foreign* foreign;
5230 { MaybeObject* maybe_result = AllocateForeign(static_cast<Address>(value));
5231 if (!maybe_result->To(&foreign)) return maybe_result;
5232 }
5233 JSObject* external;
5234 { MaybeObject* maybe_result = AllocateJSObjectFromMap(external_map());
5235 if (!maybe_result->To(&external)) return maybe_result;
5236 }
5237 external->SetInternalField(0, foreign);
5238 return external;
5239}
5240
5241
lrn@chromium.org303ada72010-10-27 09:33:13 +00005242MaybeObject* Heap::AllocateStruct(InstanceType type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005243 Map* map;
5244 switch (type) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005245#define MAKE_CASE(NAME, Name, name) \
5246 case NAME##_TYPE: map = name##_map(); break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005247STRUCT_LIST(MAKE_CASE)
5248#undef MAKE_CASE
5249 default:
5250 UNREACHABLE();
5251 return Failure::InternalError();
5252 }
5253 int size = map->instance_size();
5254 AllocationSpace space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005255 (size > Page::kMaxNonCodeHeapObjectSize) ? LO_SPACE : OLD_POINTER_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005256 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005257 { MaybeObject* maybe_result = Allocate(map, space);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005258 if (!maybe_result->ToObject(&result)) return maybe_result;
5259 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005260 Struct::cast(result)->InitializeBody(size);
5261 return result;
5262}
5263
5264
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005265bool Heap::IsHeapIterable() {
5266 return (!old_pointer_space()->was_swept_conservatively() &&
5267 !old_data_space()->was_swept_conservatively());
5268}
5269
5270
5271void Heap::EnsureHeapIsIterable() {
5272 ASSERT(IsAllocationAllowed());
5273 if (!IsHeapIterable()) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005274 CollectAllGarbage(kMakeHeapIterableMask, "Heap::EnsureHeapIsIterable");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005275 }
5276 ASSERT(IsHeapIterable());
5277}
5278
5279
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005280void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005281 incremental_marking()->Step(step_size,
5282 IncrementalMarking::NO_GC_VIA_STACK_GUARD);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005283
5284 if (incremental_marking()->IsComplete()) {
5285 bool uncommit = false;
5286 if (gc_count_at_last_idle_gc_ == gc_count_) {
5287 // No GC since the last full GC, the mutator is probably not active.
5288 isolate_->compilation_cache()->Clear();
5289 uncommit = true;
5290 }
5291 CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental");
5292 gc_count_at_last_idle_gc_ = gc_count_;
5293 if (uncommit) {
5294 new_space_.Shrink();
5295 UncommitFromSpace();
5296 }
5297 }
5298}
5299
5300
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005301bool Heap::IdleNotification(int hint) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005302 // Hints greater than this value indicate that
5303 // the embedder is requesting a lot of GC work.
danno@chromium.org88aa0582012-03-23 15:11:57 +00005304 const int kMaxHint = 1000;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005305 // Minimal hint that allows to do full GC.
5306 const int kMinHintForFullGC = 100;
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005307 intptr_t size_factor = Min(Max(hint, 20), kMaxHint) / 4;
5308 // The size factor is in range [5..250]. The numbers here are chosen from
5309 // experiments. If you changes them, make sure to test with
5310 // chrome/performance_ui_tests --gtest_filter="GeneralMixMemoryTest.*
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00005311 intptr_t step_size =
5312 size_factor * IncrementalMarking::kAllocatedThreshold;
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005313
5314 if (contexts_disposed_ > 0) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005315 if (hint >= kMaxHint) {
5316 // The embedder is requesting a lot of GC work after context disposal,
5317 // we age inline caches so that they don't keep objects from
5318 // the old context alive.
5319 AgeInlineCaches();
5320 }
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005321 int mark_sweep_time = Min(TimeMarkSweepWouldTakeInMs(), 1000);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005322 if (hint >= mark_sweep_time && !FLAG_expose_gc &&
5323 incremental_marking()->IsStopped()) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005324 HistogramTimerScope scope(isolate_->counters()->gc_context());
5325 CollectAllGarbage(kReduceMemoryFootprintMask,
5326 "idle notification: contexts disposed");
5327 } else {
5328 AdvanceIdleIncrementalMarking(step_size);
5329 contexts_disposed_ = 0;
5330 }
5331 // Make sure that we have no pending context disposals.
5332 // Take into account that we might have decided to delay full collection
5333 // because incremental marking is in progress.
5334 ASSERT((contexts_disposed_ == 0) || !incremental_marking()->IsStopped());
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005335 // After context disposal there is likely a lot of garbage remaining, reset
5336 // the idle notification counters in order to trigger more incremental GCs
5337 // on subsequent idle notifications.
5338 StartIdleRound();
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005339 return false;
5340 }
5341
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005342 if (!FLAG_incremental_marking || FLAG_expose_gc || Serializer::enabled()) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005343 return IdleGlobalGC();
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005344 }
5345
5346 // By doing small chunks of GC work in each IdleNotification,
5347 // perform a round of incremental GCs and after that wait until
5348 // the mutator creates enough garbage to justify a new round.
5349 // An incremental GC progresses as follows:
5350 // 1. many incremental marking steps,
5351 // 2. one old space mark-sweep-compact,
5352 // 3. many lazy sweep steps.
5353 // Use mark-sweep-compact events to count incremental GCs in a round.
5354
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005355
5356 if (incremental_marking()->IsStopped()) {
5357 if (!IsSweepingComplete() &&
5358 !AdvanceSweepers(static_cast<int>(step_size))) {
5359 return false;
5360 }
5361 }
5362
5363 if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) {
5364 if (EnoughGarbageSinceLastIdleRound()) {
5365 StartIdleRound();
5366 } else {
5367 return true;
5368 }
5369 }
5370
5371 int new_mark_sweeps = ms_count_ - ms_count_at_last_idle_notification_;
5372 mark_sweeps_since_idle_round_started_ += new_mark_sweeps;
5373 ms_count_at_last_idle_notification_ = ms_count_;
5374
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005375 int remaining_mark_sweeps = kMaxMarkSweepsInIdleRound -
5376 mark_sweeps_since_idle_round_started_;
5377
5378 if (remaining_mark_sweeps <= 0) {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005379 FinishIdleRound();
5380 return true;
5381 }
5382
5383 if (incremental_marking()->IsStopped()) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005384 // If there are no more than two GCs left in this idle round and we are
5385 // allowed to do a full GC, then make those GCs full in order to compact
5386 // the code space.
5387 // TODO(ulan): Once we enable code compaction for incremental marking,
5388 // we can get rid of this special case and always start incremental marking.
5389 if (remaining_mark_sweeps <= 2 && hint >= kMinHintForFullGC) {
5390 CollectAllGarbage(kReduceMemoryFootprintMask,
5391 "idle notification: finalize idle round");
5392 } else {
5393 incremental_marking()->Start();
5394 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005395 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005396 if (!incremental_marking()->IsStopped()) {
5397 AdvanceIdleIncrementalMarking(step_size);
5398 }
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005399 return false;
5400}
5401
5402
5403bool Heap::IdleGlobalGC() {
ager@chromium.orga1645e22009-09-09 19:27:10 +00005404 static const int kIdlesBeforeScavenge = 4;
5405 static const int kIdlesBeforeMarkSweep = 7;
5406 static const int kIdlesBeforeMarkCompact = 8;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005407 static const int kMaxIdleCount = kIdlesBeforeMarkCompact + 1;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005408 static const unsigned int kGCsBetweenCleanup = 4;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005409
5410 if (!last_idle_notification_gc_count_init_) {
5411 last_idle_notification_gc_count_ = gc_count_;
5412 last_idle_notification_gc_count_init_ = true;
5413 }
ager@chromium.org96c75b52009-08-26 09:13:16 +00005414
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005415 bool uncommit = true;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005416 bool finished = false;
5417
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005418 // Reset the number of idle notifications received when a number of
5419 // GCs have taken place. This allows another round of cleanup based
5420 // on idle notifications if enough work has been carried out to
5421 // provoke a number of garbage collections.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005422 if (gc_count_ - last_idle_notification_gc_count_ < kGCsBetweenCleanup) {
5423 number_idle_notifications_ =
5424 Min(number_idle_notifications_ + 1, kMaxIdleCount);
ager@chromium.org96c75b52009-08-26 09:13:16 +00005425 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005426 number_idle_notifications_ = 0;
5427 last_idle_notification_gc_count_ = gc_count_;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005428 }
5429
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005430 if (number_idle_notifications_ == kIdlesBeforeScavenge) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005431 CollectGarbage(NEW_SPACE, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005432 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005433 last_idle_notification_gc_count_ = gc_count_;
5434 } else if (number_idle_notifications_ == kIdlesBeforeMarkSweep) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005435 // Before doing the mark-sweep collections we clear the
5436 // compilation cache to avoid hanging on to source code and
5437 // generated code for cached functions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005438 isolate_->compilation_cache()->Clear();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005439
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005440 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005441 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005442 last_idle_notification_gc_count_ = gc_count_;
ager@chromium.orga1645e22009-09-09 19:27:10 +00005443
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005444 } else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005445 CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification");
ager@chromium.orga1645e22009-09-09 19:27:10 +00005446 new_space_.Shrink();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005447 last_idle_notification_gc_count_ = gc_count_;
5448 number_idle_notifications_ = 0;
ager@chromium.orga1645e22009-09-09 19:27:10 +00005449 finished = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005450 } else if (number_idle_notifications_ > kIdlesBeforeMarkCompact) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005451 // If we have received more than kIdlesBeforeMarkCompact idle
5452 // notifications we do not perform any cleanup because we don't
5453 // expect to gain much by doing so.
5454 finished = true;
ager@chromium.org96c75b52009-08-26 09:13:16 +00005455 }
5456
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005457 if (uncommit) UncommitFromSpace();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005458
ager@chromium.org96c75b52009-08-26 09:13:16 +00005459 return finished;
5460}
5461
5462
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005463#ifdef DEBUG
5464
5465void Heap::Print() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005466 if (!HasBeenSetUp()) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005467 isolate()->PrintStack();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005468 AllSpaces spaces;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005469 for (Space* space = spaces.next(); space != NULL; space = spaces.next())
5470 space->Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005471}
5472
5473
5474void Heap::ReportCodeStatistics(const char* title) {
5475 PrintF(">>>>>> Code Stats (%s) >>>>>>\n", title);
5476 PagedSpace::ResetCodeStatistics();
5477 // We do not look for code in new space, map space, or old space. If code
5478 // somehow ends up in those spaces, we would miss it here.
5479 code_space_->CollectCodeStatistics();
5480 lo_space_->CollectCodeStatistics();
5481 PagedSpace::ReportCodeStatistics();
5482}
5483
5484
5485// This function expects that NewSpace's allocated objects histogram is
5486// populated (via a call to CollectStatistics or else as a side effect of a
5487// just-completed scavenge collection).
5488void Heap::ReportHeapStatistics(const char* title) {
5489 USE(title);
5490 PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n",
5491 title, gc_count_);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005492 PrintF("old_gen_promotion_limit_ %" V8_PTR_PREFIX "d\n",
5493 old_gen_promotion_limit_);
5494 PrintF("old_gen_allocation_limit_ %" V8_PTR_PREFIX "d\n",
5495 old_gen_allocation_limit_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005496 PrintF("old_gen_limit_factor_ %d\n", old_gen_limit_factor_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005497
5498 PrintF("\n");
5499 PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005500 isolate_->global_handles()->PrintStats();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005501 PrintF("\n");
5502
5503 PrintF("Heap statistics : ");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005504 isolate_->memory_allocator()->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005505 PrintF("To space : ");
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005506 new_space_.ReportStatistics();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005507 PrintF("Old pointer space : ");
5508 old_pointer_space_->ReportStatistics();
5509 PrintF("Old data space : ");
5510 old_data_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005511 PrintF("Code space : ");
5512 code_space_->ReportStatistics();
5513 PrintF("Map space : ");
5514 map_space_->ReportStatistics();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005515 PrintF("Cell space : ");
5516 cell_space_->ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005517 PrintF("Large object space : ");
5518 lo_space_->ReportStatistics();
5519 PrintF(">>>>>> ========================================= >>>>>>\n");
5520}
5521
5522#endif // DEBUG
5523
5524bool Heap::Contains(HeapObject* value) {
5525 return Contains(value->address());
5526}
5527
5528
5529bool Heap::Contains(Address addr) {
5530 if (OS::IsOutsideAllocatedSpace(addr)) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005531 return HasBeenSetUp() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005532 (new_space_.ToSpaceContains(addr) ||
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005533 old_pointer_space_->Contains(addr) ||
5534 old_data_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005535 code_space_->Contains(addr) ||
5536 map_space_->Contains(addr) ||
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005537 cell_space_->Contains(addr) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005538 lo_space_->SlowContains(addr));
5539}
5540
5541
5542bool Heap::InSpace(HeapObject* value, AllocationSpace space) {
5543 return InSpace(value->address(), space);
5544}
5545
5546
5547bool Heap::InSpace(Address addr, AllocationSpace space) {
5548 if (OS::IsOutsideAllocatedSpace(addr)) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005549 if (!HasBeenSetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005550
5551 switch (space) {
5552 case NEW_SPACE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005553 return new_space_.ToSpaceContains(addr);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005554 case OLD_POINTER_SPACE:
5555 return old_pointer_space_->Contains(addr);
5556 case OLD_DATA_SPACE:
5557 return old_data_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005558 case CODE_SPACE:
5559 return code_space_->Contains(addr);
5560 case MAP_SPACE:
5561 return map_space_->Contains(addr);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005562 case CELL_SPACE:
5563 return cell_space_->Contains(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005564 case LO_SPACE:
5565 return lo_space_->SlowContains(addr);
5566 }
5567
5568 return false;
5569}
5570
5571
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005572#ifdef VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005573void Heap::Verify() {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005574 CHECK(HasBeenSetUp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005575
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005576 store_buffer()->Verify();
5577
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005578 VerifyPointersVisitor visitor;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005579 IterateRoots(&visitor, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005580
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005581 new_space_.Verify();
5582
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005583 old_pointer_space_->Verify(&visitor);
5584 map_space_->Verify(&visitor);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005585
5586 VerifyPointersVisitor no_dirty_regions_visitor;
5587 old_data_space_->Verify(&no_dirty_regions_visitor);
5588 code_space_->Verify(&no_dirty_regions_visitor);
5589 cell_space_->Verify(&no_dirty_regions_visitor);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005590
5591 lo_space_->Verify();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005592}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005593#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005594
5595
lrn@chromium.org303ada72010-10-27 09:33:13 +00005596MaybeObject* Heap::LookupSymbol(Vector<const char> string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005597 Object* symbol = NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005598 Object* new_table;
5599 { MaybeObject* maybe_new_table =
5600 symbol_table()->LookupSymbol(string, &symbol);
5601 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5602 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005603 // Can't use set_symbol_table because SymbolTable::cast knows that
5604 // SymbolTable is a singleton and checks for identity.
5605 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005606 ASSERT(symbol != NULL);
5607 return symbol;
5608}
5609
5610
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005611MaybeObject* Heap::LookupAsciiSymbol(Vector<const char> string) {
5612 Object* symbol = NULL;
5613 Object* new_table;
5614 { MaybeObject* maybe_new_table =
5615 symbol_table()->LookupAsciiSymbol(string, &symbol);
5616 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5617 }
5618 // Can't use set_symbol_table because SymbolTable::cast knows that
5619 // SymbolTable is a singleton and checks for identity.
5620 roots_[kSymbolTableRootIndex] = new_table;
5621 ASSERT(symbol != NULL);
5622 return symbol;
5623}
5624
5625
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005626MaybeObject* Heap::LookupAsciiSymbol(Handle<SeqOneByteString> string,
danno@chromium.org40cb8782011-05-25 07:58:50 +00005627 int from,
5628 int length) {
5629 Object* symbol = NULL;
5630 Object* new_table;
5631 { MaybeObject* maybe_new_table =
5632 symbol_table()->LookupSubStringAsciiSymbol(string,
5633 from,
5634 length,
5635 &symbol);
5636 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5637 }
5638 // Can't use set_symbol_table because SymbolTable::cast knows that
5639 // SymbolTable is a singleton and checks for identity.
5640 roots_[kSymbolTableRootIndex] = new_table;
5641 ASSERT(symbol != NULL);
5642 return symbol;
5643}
5644
5645
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005646MaybeObject* Heap::LookupTwoByteSymbol(Vector<const uc16> string) {
5647 Object* symbol = NULL;
5648 Object* new_table;
5649 { MaybeObject* maybe_new_table =
5650 symbol_table()->LookupTwoByteSymbol(string, &symbol);
5651 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5652 }
5653 // Can't use set_symbol_table because SymbolTable::cast knows that
5654 // SymbolTable is a singleton and checks for identity.
5655 roots_[kSymbolTableRootIndex] = new_table;
5656 ASSERT(symbol != NULL);
5657 return symbol;
5658}
5659
5660
lrn@chromium.org303ada72010-10-27 09:33:13 +00005661MaybeObject* Heap::LookupSymbol(String* string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005662 if (string->IsSymbol()) return string;
5663 Object* symbol = NULL;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005664 Object* new_table;
5665 { MaybeObject* maybe_new_table =
5666 symbol_table()->LookupString(string, &symbol);
5667 if (!maybe_new_table->ToObject(&new_table)) return maybe_new_table;
5668 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005669 // Can't use set_symbol_table because SymbolTable::cast knows that
5670 // SymbolTable is a singleton and checks for identity.
5671 roots_[kSymbolTableRootIndex] = new_table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005672 ASSERT(symbol != NULL);
5673 return symbol;
5674}
5675
5676
ager@chromium.org7c537e22008-10-16 08:43:32 +00005677bool Heap::LookupSymbolIfExists(String* string, String** symbol) {
5678 if (string->IsSymbol()) {
5679 *symbol = string;
5680 return true;
5681 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005682 return symbol_table()->LookupSymbolIfExists(string, symbol);
ager@chromium.org7c537e22008-10-16 08:43:32 +00005683}
5684
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005685
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005686void Heap::ZapFromSpace() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005687 NewSpacePageIterator it(new_space_.FromSpaceStart(),
5688 new_space_.FromSpaceEnd());
5689 while (it.has_next()) {
5690 NewSpacePage* page = it.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005691 for (Address cursor = page->area_start(), limit = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005692 cursor < limit;
5693 cursor += kPointerSize) {
5694 Memory::Address_at(cursor) = kFromSpaceZapValue;
5695 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005696 }
5697}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005698
5699
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005700void Heap::IterateAndMarkPointersToFromSpace(Address start,
5701 Address end,
5702 ObjectSlotCallback callback) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005703 Address slot_address = start;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005704
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005705 // We are not collecting slots on new space objects during mutation
5706 // thus we have to scan for pointers to evacuation candidates when we
5707 // promote objects. But we should not record any slots in non-black
5708 // objects. Grey object's slots would be rescanned.
5709 // White object might not survive until the end of collection
5710 // it would be a violation of the invariant to record it's slots.
5711 bool record_slots = false;
5712 if (incremental_marking()->IsCompacting()) {
5713 MarkBit mark_bit = Marking::MarkBitFrom(HeapObject::FromAddress(start));
5714 record_slots = Marking::IsBlack(mark_bit);
5715 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005716
5717 while (slot_address < end) {
5718 Object** slot = reinterpret_cast<Object**>(slot_address);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005719 Object* object = *slot;
5720 // If the store buffer becomes overfull we mark pages as being exempt from
5721 // the store buffer. These pages are scanned to find pointers that point
5722 // to the new space. In that case we may hit newly promoted objects and
5723 // fix the pointers before the promotion queue gets to them. Thus the 'if'.
5724 if (object->IsHeapObject()) {
5725 if (Heap::InFromSpace(object)) {
5726 callback(reinterpret_cast<HeapObject**>(slot),
5727 HeapObject::cast(object));
5728 Object* new_object = *slot;
5729 if (InNewSpace(new_object)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005730 SLOW_ASSERT(Heap::InToSpace(new_object));
5731 SLOW_ASSERT(new_object->IsHeapObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005732 store_buffer_.EnterDirectlyIntoStoreBuffer(
5733 reinterpret_cast<Address>(slot));
5734 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005735 SLOW_ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_object));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005736 } else if (record_slots &&
5737 MarkCompactCollector::IsOnEvacuationCandidate(object)) {
5738 mark_compact_collector()->RecordSlot(slot, slot, object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005739 }
5740 }
5741 slot_address += kPointerSize;
5742 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005743}
5744
5745
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005746#ifdef DEBUG
5747typedef bool (*CheckStoreBufferFilter)(Object** addr);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005748
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005749
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005750bool IsAMapPointerAddress(Object** addr) {
5751 uintptr_t a = reinterpret_cast<uintptr_t>(addr);
5752 int mod = a % Map::kSize;
5753 return mod >= Map::kPointerFieldsBeginOffset &&
5754 mod < Map::kPointerFieldsEndOffset;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005755}
5756
5757
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005758bool EverythingsAPointer(Object** addr) {
5759 return true;
5760}
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005761
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005762
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005763static void CheckStoreBuffer(Heap* heap,
5764 Object** current,
5765 Object** limit,
5766 Object**** store_buffer_position,
5767 Object*** store_buffer_top,
5768 CheckStoreBufferFilter filter,
5769 Address special_garbage_start,
5770 Address special_garbage_end) {
5771 Map* free_space_map = heap->free_space_map();
5772 for ( ; current < limit; current++) {
5773 Object* o = *current;
5774 Address current_address = reinterpret_cast<Address>(current);
5775 // Skip free space.
5776 if (o == free_space_map) {
5777 Address current_address = reinterpret_cast<Address>(current);
5778 FreeSpace* free_space =
5779 FreeSpace::cast(HeapObject::FromAddress(current_address));
5780 int skip = free_space->Size();
5781 ASSERT(current_address + skip <= reinterpret_cast<Address>(limit));
5782 ASSERT(skip > 0);
5783 current_address += skip - kPointerSize;
5784 current = reinterpret_cast<Object**>(current_address);
5785 continue;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005786 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005787 // Skip the current linear allocation space between top and limit which is
5788 // unmarked with the free space map, but can contain junk.
5789 if (current_address == special_garbage_start &&
5790 special_garbage_end != special_garbage_start) {
5791 current_address = special_garbage_end - kPointerSize;
5792 current = reinterpret_cast<Object**>(current_address);
5793 continue;
5794 }
5795 if (!(*filter)(current)) continue;
5796 ASSERT(current_address < special_garbage_start ||
5797 current_address >= special_garbage_end);
5798 ASSERT(reinterpret_cast<uintptr_t>(o) != kFreeListZapValue);
5799 // We have to check that the pointer does not point into new space
5800 // without trying to cast it to a heap object since the hash field of
5801 // a string can contain values like 1 and 3 which are tagged null
5802 // pointers.
5803 if (!heap->InNewSpace(o)) continue;
5804 while (**store_buffer_position < current &&
5805 *store_buffer_position < store_buffer_top) {
5806 (*store_buffer_position)++;
5807 }
5808 if (**store_buffer_position != current ||
5809 *store_buffer_position == store_buffer_top) {
5810 Object** obj_start = current;
5811 while (!(*obj_start)->IsMap()) obj_start--;
5812 UNREACHABLE();
5813 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005814 }
5815}
5816
5817
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005818// Check that the store buffer contains all intergenerational pointers by
5819// scanning a page and ensuring that all pointers to young space are in the
5820// store buffer.
5821void Heap::OldPointerSpaceCheckStoreBuffer() {
5822 OldSpace* space = old_pointer_space();
5823 PageIterator pages(space);
5824
5825 store_buffer()->SortUniq();
5826
5827 while (pages.has_next()) {
5828 Page* page = pages.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005829 Object** current = reinterpret_cast<Object**>(page->area_start());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005830
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005831 Address end = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005832
5833 Object*** store_buffer_position = store_buffer()->Start();
5834 Object*** store_buffer_top = store_buffer()->Top();
5835
5836 Object** limit = reinterpret_cast<Object**>(end);
5837 CheckStoreBuffer(this,
5838 current,
5839 limit,
5840 &store_buffer_position,
5841 store_buffer_top,
5842 &EverythingsAPointer,
5843 space->top(),
5844 space->limit());
5845 }
5846}
5847
5848
5849void Heap::MapSpaceCheckStoreBuffer() {
5850 MapSpace* space = map_space();
5851 PageIterator pages(space);
5852
5853 store_buffer()->SortUniq();
5854
5855 while (pages.has_next()) {
5856 Page* page = pages.next();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005857 Object** current = reinterpret_cast<Object**>(page->area_start());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005858
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005859 Address end = page->area_end();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005860
5861 Object*** store_buffer_position = store_buffer()->Start();
5862 Object*** store_buffer_top = store_buffer()->Top();
5863
5864 Object** limit = reinterpret_cast<Object**>(end);
5865 CheckStoreBuffer(this,
5866 current,
5867 limit,
5868 &store_buffer_position,
5869 store_buffer_top,
5870 &IsAMapPointerAddress,
5871 space->top(),
5872 space->limit());
5873 }
5874}
5875
5876
5877void Heap::LargeObjectSpaceCheckStoreBuffer() {
5878 LargeObjectIterator it(lo_space());
5879 for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) {
5880 // We only have code, sequential strings, or fixed arrays in large
5881 // object space, and only fixed arrays can possibly contain pointers to
5882 // the young generation.
5883 if (object->IsFixedArray()) {
5884 Object*** store_buffer_position = store_buffer()->Start();
5885 Object*** store_buffer_top = store_buffer()->Top();
5886 Object** current = reinterpret_cast<Object**>(object->address());
5887 Object** limit =
5888 reinterpret_cast<Object**>(object->address() + object->Size());
5889 CheckStoreBuffer(this,
5890 current,
5891 limit,
5892 &store_buffer_position,
5893 store_buffer_top,
5894 &EverythingsAPointer,
5895 NULL,
5896 NULL);
5897 }
5898 }
5899}
5900#endif
5901
5902
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005903void Heap::IterateRoots(ObjectVisitor* v, VisitMode mode) {
5904 IterateStrongRoots(v, mode);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005905 IterateWeakRoots(v, mode);
5906}
5907
5908
5909void Heap::IterateWeakRoots(ObjectVisitor* v, VisitMode mode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005910 v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex]));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005911 v->Synchronize(VisitorSynchronization::kSymbolTable);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005912 if (mode != VISIT_ALL_IN_SCAVENGE &&
5913 mode != VISIT_ALL_IN_SWEEP_NEWSPACE) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005914 // Scavenge collections have special processing for this.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005915 external_string_table_.Iterate(v);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005916 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005917 v->Synchronize(VisitorSynchronization::kExternalStringsTable);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918}
5919
5920
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005921void Heap::IterateStrongRoots(ObjectVisitor* v, VisitMode mode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005922 v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005923 v->Synchronize(VisitorSynchronization::kStrongRootList);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005924
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00005925 v->VisitPointer(BitCast<Object**>(&hidden_symbol_));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005926 v->Synchronize(VisitorSynchronization::kSymbol);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005927
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005928 isolate_->bootstrapper()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005929 v->Synchronize(VisitorSynchronization::kBootstrapper);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005930 isolate_->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005931 v->Synchronize(VisitorSynchronization::kTop);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005932 Relocatable::Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005933 v->Synchronize(VisitorSynchronization::kRelocatable);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005934
5935#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005936 isolate_->debug()->Iterate(v);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005937 if (isolate_->deoptimizer_data() != NULL) {
5938 isolate_->deoptimizer_data()->Iterate(v);
5939 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005940#endif
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005941 v->Synchronize(VisitorSynchronization::kDebug);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005942 isolate_->compilation_cache()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005943 v->Synchronize(VisitorSynchronization::kCompilationCache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005944
5945 // Iterate over local handles in handle scopes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005946 isolate_->handle_scope_implementer()->Iterate(v);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005947 isolate_->IterateDeferredHandles(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005948 v->Synchronize(VisitorSynchronization::kHandleScope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005949
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005950 // Iterate over the builtin code objects and code stubs in the
5951 // heap. Note that it is not necessary to iterate over code objects
5952 // on scavenge collections.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005953 if (mode != VISIT_ALL_IN_SCAVENGE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005954 isolate_->builtins()->IterateBuiltins(v);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00005955 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005956 v->Synchronize(VisitorSynchronization::kBuiltins);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005957
5958 // Iterate over global handles.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005959 switch (mode) {
5960 case VISIT_ONLY_STRONG:
5961 isolate_->global_handles()->IterateStrongRoots(v);
5962 break;
5963 case VISIT_ALL_IN_SCAVENGE:
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005964 isolate_->global_handles()->IterateNewSpaceStrongAndDependentRoots(v);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005965 break;
5966 case VISIT_ALL_IN_SWEEP_NEWSPACE:
5967 case VISIT_ALL:
5968 isolate_->global_handles()->IterateAllRoots(v);
5969 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005970 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005971 v->Synchronize(VisitorSynchronization::kGlobalHandles);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005972
5973 // Iterate over pointers being held by inactive threads.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005974 isolate_->thread_manager()->Iterate(v);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005975 v->Synchronize(VisitorSynchronization::kThreadManager);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005976
5977 // Iterate over the pointers the Serialization/Deserialization code is
5978 // holding.
5979 // During garbage collection this keeps the partial snapshot cache alive.
5980 // During deserialization of the startup snapshot this creates the partial
5981 // snapshot cache and deserializes the objects it refers to. During
5982 // serialization this does nothing, since the partial snapshot cache is
5983 // empty. However the next thing we do is create the partial snapshot,
5984 // filling up the partial snapshot cache with objects it needs as we go.
5985 SerializerDeserializer::Iterate(v);
5986 // We don't do a v->Synchronize call here, because in debug mode that will
5987 // output a flag to the snapshot. However at this point the serializer and
5988 // deserializer are deliberately a little unsynchronized (see above) so the
5989 // checking of the sync flag in the snapshot would fail.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005990}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005991
5992
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005993// TODO(1236194): Since the heap size is configurable on the command line
5994// and through the API, we should gracefully handle the case that the heap
5995// size is not big enough to fit all the initial objects.
ager@chromium.org01fe7df2010-11-10 11:59:11 +00005996bool Heap::ConfigureHeap(int max_semispace_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005997 intptr_t max_old_gen_size,
5998 intptr_t max_executable_size) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005999 if (HasBeenSetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006000
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00006001 if (FLAG_stress_compaction) {
6002 // This will cause more frequent GCs when stressing.
6003 max_semispace_size_ = Page::kPageSize;
6004 }
6005
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006006 if (max_semispace_size > 0) {
6007 if (max_semispace_size < Page::kPageSize) {
6008 max_semispace_size = Page::kPageSize;
6009 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006010 PrintPID("Max semispace size cannot be less than %dkbytes\n",
6011 Page::kPageSize >> 10);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006012 }
6013 }
6014 max_semispace_size_ = max_semispace_size;
6015 }
ager@chromium.org3811b432009-10-28 14:53:37 +00006016
6017 if (Snapshot::IsEnabled()) {
6018 // If we are using a snapshot we always reserve the default amount
6019 // of memory for each semispace because code in the snapshot has
6020 // write-barrier code that relies on the size and alignment of new
6021 // space. We therefore cannot use a larger max semispace size
6022 // than the default reserved semispace size.
6023 if (max_semispace_size_ > reserved_semispace_size_) {
6024 max_semispace_size_ = reserved_semispace_size_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006025 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006026 PrintPID("Max semispace size cannot be more than %dkbytes\n",
6027 reserved_semispace_size_ >> 10);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006028 }
ager@chromium.org3811b432009-10-28 14:53:37 +00006029 }
6030 } else {
6031 // If we are not using snapshots we reserve space for the actual
6032 // max semispace size.
6033 reserved_semispace_size_ = max_semispace_size_;
6034 }
6035
6036 if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size;
ager@chromium.org01fe7df2010-11-10 11:59:11 +00006037 if (max_executable_size > 0) {
6038 max_executable_size_ = RoundUp(max_executable_size, Page::kPageSize);
6039 }
6040
6041 // The max executable size must be less than or equal to the max old
6042 // generation size.
6043 if (max_executable_size_ > max_old_generation_size_) {
6044 max_executable_size_ = max_old_generation_size_;
6045 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006046
6047 // The new space size must be a power of two to support single-bit testing
6048 // for containment.
ager@chromium.org3811b432009-10-28 14:53:37 +00006049 max_semispace_size_ = RoundUpToPowerOf2(max_semispace_size_);
6050 reserved_semispace_size_ = RoundUpToPowerOf2(reserved_semispace_size_);
6051 initial_semispace_size_ = Min(initial_semispace_size_, max_semispace_size_);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006052 external_allocation_limit_ = 16 * max_semispace_size_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006054 // The old generation is paged and needs at least one page for each space.
6055 int paged_space_count = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1;
6056 max_old_generation_size_ = Max(static_cast<intptr_t>(paged_space_count *
6057 Page::kPageSize),
6058 RoundUp(max_old_generation_size_,
6059 Page::kPageSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006060
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006061 configured_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006062 return true;
6063}
6064
6065
kasper.lund7276f142008-07-30 08:49:36 +00006066bool Heap::ConfigureHeapDefault() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006067 return ConfigureHeap(static_cast<intptr_t>(FLAG_max_new_space_size / 2) * KB,
6068 static_cast<intptr_t>(FLAG_max_old_space_size) * MB,
6069 static_cast<intptr_t>(FLAG_max_executable_size) * MB);
kasper.lund7276f142008-07-30 08:49:36 +00006070}
6071
6072
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006073void Heap::RecordStats(HeapStats* stats, bool take_snapshot) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006074 *stats->start_marker = HeapStats::kStartMarker;
6075 *stats->end_marker = HeapStats::kEndMarker;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006076 *stats->new_space_size = new_space_.SizeAsInt();
6077 *stats->new_space_capacity = static_cast<int>(new_space_.Capacity());
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006078 *stats->old_pointer_space_size = old_pointer_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006079 *stats->old_pointer_space_capacity = old_pointer_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006080 *stats->old_data_space_size = old_data_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006081 *stats->old_data_space_capacity = old_data_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006082 *stats->code_space_size = code_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006083 *stats->code_space_capacity = code_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006084 *stats->map_space_size = map_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006085 *stats->map_space_capacity = map_space_->Capacity();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006086 *stats->cell_space_size = cell_space_->SizeOfObjects();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006087 *stats->cell_space_capacity = cell_space_->Capacity();
6088 *stats->lo_space_size = lo_space_->Size();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006089 isolate_->global_handles()->RecordStats(stats);
6090 *stats->memory_allocator_size = isolate()->memory_allocator()->Size();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006091 *stats->memory_allocator_capacity =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006092 isolate()->memory_allocator()->Size() +
6093 isolate()->memory_allocator()->Available();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006094 *stats->os_error = OS::GetLastError();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006095 isolate()->memory_allocator()->Available();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006096 if (take_snapshot) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006097 HeapIterator iterator;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006098 for (HeapObject* obj = iterator.next();
6099 obj != NULL;
6100 obj = iterator.next()) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00006101 InstanceType type = obj->map()->instance_type();
6102 ASSERT(0 <= type && type <= LAST_TYPE);
6103 stats->objects_per_type[type]++;
6104 stats->size_per_type[type] += obj->Size();
6105 }
6106 }
ager@chromium.org60121232009-12-03 11:25:37 +00006107}
6108
6109
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00006110intptr_t Heap::PromotedSpaceSizeOfObjects() {
6111 return old_pointer_space_->SizeOfObjects()
6112 + old_data_space_->SizeOfObjects()
6113 + code_space_->SizeOfObjects()
6114 + map_space_->SizeOfObjects()
6115 + cell_space_->SizeOfObjects()
6116 + lo_space_->SizeOfObjects();
6117}
6118
6119
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00006120intptr_t Heap::PromotedExternalMemorySize() {
kasper.lund7276f142008-07-30 08:49:36 +00006121 if (amount_of_external_allocated_memory_
6122 <= amount_of_external_allocated_memory_at_last_global_gc_) return 0;
6123 return amount_of_external_allocated_memory_
6124 - amount_of_external_allocated_memory_at_last_global_gc_;
6125}
6126
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006127#ifdef DEBUG
6128
6129// Tags 0, 1, and 3 are used. Use 2 for marking visited HeapObject.
6130static const int kMarkTag = 2;
6131
6132
6133class HeapDebugUtils {
6134 public:
6135 explicit HeapDebugUtils(Heap* heap)
6136 : search_for_any_global_(false),
6137 search_target_(NULL),
6138 found_target_(false),
6139 object_stack_(20),
6140 heap_(heap) {
6141 }
6142
6143 class MarkObjectVisitor : public ObjectVisitor {
6144 public:
6145 explicit MarkObjectVisitor(HeapDebugUtils* utils) : utils_(utils) { }
6146
6147 void VisitPointers(Object** start, Object** end) {
6148 // Copy all HeapObject pointers in [start, end)
6149 for (Object** p = start; p < end; p++) {
6150 if ((*p)->IsHeapObject())
6151 utils_->MarkObjectRecursively(p);
6152 }
6153 }
6154
6155 HeapDebugUtils* utils_;
6156 };
6157
6158 void MarkObjectRecursively(Object** p) {
6159 if (!(*p)->IsHeapObject()) return;
6160
6161 HeapObject* obj = HeapObject::cast(*p);
6162
6163 Object* map = obj->map();
6164
6165 if (!map->IsHeapObject()) return; // visited before
6166
6167 if (found_target_) return; // stop if target found
6168 object_stack_.Add(obj);
6169 if ((search_for_any_global_ && obj->IsJSGlobalObject()) ||
6170 (!search_for_any_global_ && (obj == search_target_))) {
6171 found_target_ = true;
6172 return;
6173 }
6174
6175 // not visited yet
6176 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
6177
6178 Address map_addr = map_p->address();
6179
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006180 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_addr + kMarkTag));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006181
6182 MarkObjectRecursively(&map);
6183
6184 MarkObjectVisitor mark_visitor(this);
6185
6186 obj->IterateBody(map_p->instance_type(), obj->SizeFromMap(map_p),
6187 &mark_visitor);
6188
6189 if (!found_target_) // don't pop if found the target
6190 object_stack_.RemoveLast();
6191 }
6192
6193
6194 class UnmarkObjectVisitor : public ObjectVisitor {
6195 public:
6196 explicit UnmarkObjectVisitor(HeapDebugUtils* utils) : utils_(utils) { }
6197
6198 void VisitPointers(Object** start, Object** end) {
6199 // Copy all HeapObject pointers in [start, end)
6200 for (Object** p = start; p < end; p++) {
6201 if ((*p)->IsHeapObject())
6202 utils_->UnmarkObjectRecursively(p);
6203 }
6204 }
6205
6206 HeapDebugUtils* utils_;
6207 };
6208
6209
6210 void UnmarkObjectRecursively(Object** p) {
6211 if (!(*p)->IsHeapObject()) return;
6212
6213 HeapObject* obj = HeapObject::cast(*p);
6214
6215 Object* map = obj->map();
6216
6217 if (map->IsHeapObject()) return; // unmarked already
6218
6219 Address map_addr = reinterpret_cast<Address>(map);
6220
6221 map_addr -= kMarkTag;
6222
6223 ASSERT_TAG_ALIGNED(map_addr);
6224
6225 HeapObject* map_p = HeapObject::FromAddress(map_addr);
6226
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006227 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_p));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006228
6229 UnmarkObjectRecursively(reinterpret_cast<Object**>(&map_p));
6230
6231 UnmarkObjectVisitor unmark_visitor(this);
6232
6233 obj->IterateBody(Map::cast(map_p)->instance_type(),
6234 obj->SizeFromMap(Map::cast(map_p)),
6235 &unmark_visitor);
6236 }
6237
6238
6239 void MarkRootObjectRecursively(Object** root) {
6240 if (search_for_any_global_) {
6241 ASSERT(search_target_ == NULL);
6242 } else {
6243 ASSERT(search_target_->IsHeapObject());
6244 }
6245 found_target_ = false;
6246 object_stack_.Clear();
6247
6248 MarkObjectRecursively(root);
6249 UnmarkObjectRecursively(root);
6250
6251 if (found_target_) {
6252 PrintF("=====================================\n");
6253 PrintF("==== Path to object ====\n");
6254 PrintF("=====================================\n\n");
6255
6256 ASSERT(!object_stack_.is_empty());
6257 for (int i = 0; i < object_stack_.length(); i++) {
6258 if (i > 0) PrintF("\n |\n |\n V\n\n");
6259 Object* obj = object_stack_[i];
6260 obj->Print();
6261 }
6262 PrintF("=====================================\n");
6263 }
6264 }
6265
6266 // Helper class for visiting HeapObjects recursively.
6267 class MarkRootVisitor: public ObjectVisitor {
6268 public:
6269 explicit MarkRootVisitor(HeapDebugUtils* utils) : utils_(utils) { }
6270
6271 void VisitPointers(Object** start, Object** end) {
6272 // Visit all HeapObject pointers in [start, end)
6273 for (Object** p = start; p < end; p++) {
6274 if ((*p)->IsHeapObject())
6275 utils_->MarkRootObjectRecursively(p);
6276 }
6277 }
6278
6279 HeapDebugUtils* utils_;
6280 };
6281
6282 bool search_for_any_global_;
6283 Object* search_target_;
6284 bool found_target_;
6285 List<Object*> object_stack_;
6286 Heap* heap_;
6287
6288 friend class Heap;
6289};
6290
6291#endif
kasper.lund7276f142008-07-30 08:49:36 +00006292
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00006293
6294V8_DECLARE_ONCE(initialize_gc_once);
6295
6296static void InitializeGCOnce() {
6297 InitializeScavengingVisitorsTables();
6298 NewSpaceScavenger::Initialize();
6299 MarkCompactCollector::Initialize();
6300}
6301
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006302bool Heap::SetUp(bool create_heap_objects) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006303#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006304 allocation_timeout_ = FLAG_gc_interval;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006305 debug_utils_ = new HeapDebugUtils(this);
6306#endif
6307
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006308 // Initialize heap spaces and initial maps and objects. Whenever something
6309 // goes wrong, just return false. The caller should check the results and
6310 // call Heap::TearDown() to release allocated memory.
6311 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006312 // If the heap is not yet configured (e.g. through the API), configure it.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006313 // Configuration is based on the flags new-space-size (really the semispace
6314 // size) and old-space-size if set or the initial values of semispace_size_
6315 // and old_generation_size_ otherwise.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006316 if (!configured_) {
kasper.lund7276f142008-07-30 08:49:36 +00006317 if (!ConfigureHeapDefault()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006318 }
6319
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00006320 CallOnce(&initialize_gc_once, &InitializeGCOnce);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006321
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006322 MarkMapPointersAsEncoded(false);
6323
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006324 // Set up memory allocator.
6325 if (!isolate_->memory_allocator()->SetUp(MaxReserved(), MaxExecutableSize()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006326 return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006327
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006328 // Set up new space.
6329 if (!new_space_.SetUp(reserved_semispace_size_, max_semispace_size_)) {
ager@chromium.org3811b432009-10-28 14:53:37 +00006330 return false;
6331 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006332
ager@chromium.orga1645e22009-09-09 19:27:10 +00006333 // Initialize old pointer space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006334 old_pointer_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006335 new OldSpace(this,
6336 max_old_generation_size_,
6337 OLD_POINTER_SPACE,
6338 NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006339 if (old_pointer_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006340 if (!old_pointer_space_->SetUp()) return false;
ager@chromium.orga1645e22009-09-09 19:27:10 +00006341
6342 // Initialize old data space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006343 old_data_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006344 new OldSpace(this,
6345 max_old_generation_size_,
6346 OLD_DATA_SPACE,
6347 NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006348 if (old_data_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006349 if (!old_data_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006350
6351 // Initialize the code space, set its maximum capacity to the old
kasper.lund7276f142008-07-30 08:49:36 +00006352 // generation size. It needs executable memory.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006353 // On 64-bit platform(s), we put all code objects in a 2 GB range of
6354 // virtual address space, so that they can call each other with near calls.
6355 if (code_range_size_ > 0) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006356 if (!isolate_->code_range()->SetUp(code_range_size_)) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006357 return false;
6358 }
6359 }
6360
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006361 code_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006362 new OldSpace(this, max_old_generation_size_, CODE_SPACE, EXECUTABLE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006363 if (code_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006364 if (!code_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006365
6366 // Initialize map space.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00006367 map_space_ = new MapSpace(this, max_old_generation_size_, MAP_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006368 if (map_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006369 if (!map_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006370
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006371 // Initialize global property cell space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006372 cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006373 if (cell_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006374 if (!cell_space_->SetUp()) return false;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006375
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006376 // The large object code space may contain code or data. We set the memory
6377 // to be non-executable here for safety, but this means we need to enable it
6378 // explicitly when allocating large code objects.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006379 lo_space_ = new LargeObjectSpace(this, max_old_generation_size_, LO_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006380 if (lo_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006381 if (!lo_space_->SetUp()) return false;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006382
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006383 // Set up the seed that is used to randomize the string hash function.
6384 ASSERT(hash_seed() == 0);
6385 if (FLAG_randomize_hashes) {
6386 if (FLAG_hash_seed == 0) {
6387 set_hash_seed(
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006388 Smi::FromInt(V8::RandomPrivate(isolate()) & 0x3fffffff));
6389 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006390 set_hash_seed(Smi::FromInt(FLAG_hash_seed));
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006391 }
6392 }
6393
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006394 if (create_heap_objects) {
6395 // Create initial maps.
6396 if (!CreateInitialMaps()) return false;
6397 if (!CreateApiObjects()) return false;
6398
6399 // Create initial objects
6400 if (!CreateInitialObjects()) return false;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00006401
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006402 native_contexts_list_ = undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006403 }
6404
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006405 LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity()));
6406 LOG(isolate_, IntPtrTEvent("heap-available", Available()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006407
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006408 store_buffer()->SetUp();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006409
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006410 if (FLAG_parallel_recompilation) relocation_mutex_ = OS::CreateMutex();
6411
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006412 return true;
6413}
6414
6415
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006416void Heap::SetStackLimits() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006417 ASSERT(isolate_ != NULL);
6418 ASSERT(isolate_ == isolate());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006419 // On 64 bit machines, pointers are generally out of range of Smis. We write
6420 // something that looks like an out of range Smi to the GC.
6421
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006422 // Set up the special root array entries containing the stack limits.
6423 // These are actually addresses, but the tag makes the GC ignore it.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006424 roots_[kStackLimitRootIndex] =
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006425 reinterpret_cast<Object*>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006426 (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006427 roots_[kRealStackLimitRootIndex] =
6428 reinterpret_cast<Object*>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006429 (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006430}
6431
6432
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006433void Heap::TearDown() {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006434#ifdef VERIFY_HEAP
danno@chromium.org1044a4d2012-04-30 12:34:39 +00006435 if (FLAG_verify_heap) {
6436 Verify();
6437 }
6438#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006439
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006440 if (FLAG_print_cumulative_gc_stat) {
6441 PrintF("\n\n");
6442 PrintF("gc_count=%d ", gc_count_);
6443 PrintF("mark_sweep_count=%d ", ms_count_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006444 PrintF("max_gc_pause=%d ", get_max_gc_pause());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006445 PrintF("total_gc_time=%d ", total_gc_time_ms_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006446 PrintF("min_in_mutator=%d ", get_min_in_mutator());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006447 PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ",
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006448 get_max_alive_after_gc());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006449 PrintF("\n\n");
6450 }
6451
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006452 isolate_->global_handles()->TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006453
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006454 external_string_table_.TearDown();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00006455
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006456 new_space_.TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006457
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006458 if (old_pointer_space_ != NULL) {
6459 old_pointer_space_->TearDown();
6460 delete old_pointer_space_;
6461 old_pointer_space_ = NULL;
6462 }
6463
6464 if (old_data_space_ != NULL) {
6465 old_data_space_->TearDown();
6466 delete old_data_space_;
6467 old_data_space_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006468 }
6469
6470 if (code_space_ != NULL) {
6471 code_space_->TearDown();
6472 delete code_space_;
6473 code_space_ = NULL;
6474 }
6475
6476 if (map_space_ != NULL) {
6477 map_space_->TearDown();
6478 delete map_space_;
6479 map_space_ = NULL;
6480 }
6481
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006482 if (cell_space_ != NULL) {
6483 cell_space_->TearDown();
6484 delete cell_space_;
6485 cell_space_ = NULL;
6486 }
6487
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006488 if (lo_space_ != NULL) {
6489 lo_space_->TearDown();
6490 delete lo_space_;
6491 lo_space_ = NULL;
6492 }
6493
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006494 store_buffer()->TearDown();
6495 incremental_marking()->TearDown();
6496
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006497 isolate_->memory_allocator()->TearDown();
6498
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006499 delete relocation_mutex_;
6500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006501#ifdef DEBUG
6502 delete debug_utils_;
6503 debug_utils_ = NULL;
6504#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006505}
6506
6507
6508void Heap::Shrink() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006509 // Try to shrink all paged spaces.
6510 PagedSpaces spaces;
danno@chromium.org2c456792011-11-11 12:00:53 +00006511 for (PagedSpace* space = spaces.next();
6512 space != NULL;
6513 space = spaces.next()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006514 space->ReleaseAllUnusedPages();
danno@chromium.org2c456792011-11-11 12:00:53 +00006515 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006516}
6517
6518
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006519void Heap::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) {
6520 ASSERT(callback != NULL);
6521 GCPrologueCallbackPair pair(callback, gc_type);
6522 ASSERT(!gc_prologue_callbacks_.Contains(pair));
6523 return gc_prologue_callbacks_.Add(pair);
6524}
6525
6526
6527void Heap::RemoveGCPrologueCallback(GCPrologueCallback callback) {
6528 ASSERT(callback != NULL);
6529 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
6530 if (gc_prologue_callbacks_[i].callback == callback) {
6531 gc_prologue_callbacks_.Remove(i);
6532 return;
6533 }
6534 }
6535 UNREACHABLE();
6536}
6537
6538
6539void Heap::AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type) {
6540 ASSERT(callback != NULL);
6541 GCEpilogueCallbackPair pair(callback, gc_type);
6542 ASSERT(!gc_epilogue_callbacks_.Contains(pair));
6543 return gc_epilogue_callbacks_.Add(pair);
6544}
6545
6546
6547void Heap::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
6548 ASSERT(callback != NULL);
6549 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
6550 if (gc_epilogue_callbacks_[i].callback == callback) {
6551 gc_epilogue_callbacks_.Remove(i);
6552 return;
6553 }
6554 }
6555 UNREACHABLE();
6556}
6557
6558
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006559#ifdef DEBUG
6560
6561class PrintHandleVisitor: public ObjectVisitor {
6562 public:
6563 void VisitPointers(Object** start, Object** end) {
6564 for (Object** p = start; p < end; p++)
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006565 PrintF(" handle %p to %p\n",
6566 reinterpret_cast<void*>(p),
6567 reinterpret_cast<void*>(*p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006568 }
6569};
6570
6571void Heap::PrintHandles() {
6572 PrintF("Handles:\n");
6573 PrintHandleVisitor v;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006574 isolate_->handle_scope_implementer()->Iterate(&v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575}
6576
6577#endif
6578
6579
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006580Space* AllSpaces::next() {
6581 switch (counter_++) {
6582 case NEW_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006583 return HEAP->new_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006584 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006585 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006586 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006587 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006588 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006589 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006590 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006591 return HEAP->map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006592 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006593 return HEAP->cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006594 case LO_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006595 return HEAP->lo_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006596 default:
6597 return NULL;
6598 }
6599}
6600
6601
6602PagedSpace* PagedSpaces::next() {
6603 switch (counter_++) {
6604 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006605 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006606 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006607 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006608 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006609 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006610 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006611 return HEAP->map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006612 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006613 return HEAP->cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006614 default:
6615 return NULL;
6616 }
6617}
6618
6619
6620
6621OldSpace* OldSpaces::next() {
6622 switch (counter_++) {
6623 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006624 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006625 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006626 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006627 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006628 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006629 default:
6630 return NULL;
6631 }
6632}
6633
6634
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006635SpaceIterator::SpaceIterator()
6636 : current_space_(FIRST_SPACE),
6637 iterator_(NULL),
6638 size_func_(NULL) {
6639}
6640
6641
6642SpaceIterator::SpaceIterator(HeapObjectCallback size_func)
6643 : current_space_(FIRST_SPACE),
6644 iterator_(NULL),
6645 size_func_(size_func) {
kasper.lund7276f142008-07-30 08:49:36 +00006646}
6647
6648
6649SpaceIterator::~SpaceIterator() {
6650 // Delete active iterator if any.
6651 delete iterator_;
6652}
6653
6654
6655bool SpaceIterator::has_next() {
6656 // Iterate until no more spaces.
6657 return current_space_ != LAST_SPACE;
6658}
6659
6660
6661ObjectIterator* SpaceIterator::next() {
6662 if (iterator_ != NULL) {
6663 delete iterator_;
6664 iterator_ = NULL;
6665 // Move to the next space
6666 current_space_++;
6667 if (current_space_ > LAST_SPACE) {
6668 return NULL;
6669 }
6670 }
6671
6672 // Return iterator for the new current space.
6673 return CreateIterator();
6674}
6675
6676
6677// Create an iterator for the space to iterate.
6678ObjectIterator* SpaceIterator::CreateIterator() {
6679 ASSERT(iterator_ == NULL);
6680
6681 switch (current_space_) {
6682 case NEW_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006683 iterator_ = new SemiSpaceIterator(HEAP->new_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006684 break;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006685 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006686 iterator_ = new HeapObjectIterator(HEAP->old_pointer_space(), size_func_);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006687 break;
6688 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006689 iterator_ = new HeapObjectIterator(HEAP->old_data_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006690 break;
6691 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006692 iterator_ = new HeapObjectIterator(HEAP->code_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006693 break;
6694 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006695 iterator_ = new HeapObjectIterator(HEAP->map_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006696 break;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006697 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006698 iterator_ = new HeapObjectIterator(HEAP->cell_space(), size_func_);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006699 break;
kasper.lund7276f142008-07-30 08:49:36 +00006700 case LO_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006701 iterator_ = new LargeObjectIterator(HEAP->lo_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006702 break;
6703 }
6704
6705 // Return the newly allocated iterator;
6706 ASSERT(iterator_ != NULL);
6707 return iterator_;
6708}
6709
6710
whesse@chromium.org023421e2010-12-21 12:19:12 +00006711class HeapObjectsFilter {
6712 public:
6713 virtual ~HeapObjectsFilter() {}
6714 virtual bool SkipObject(HeapObject* object) = 0;
6715};
6716
6717
whesse@chromium.org023421e2010-12-21 12:19:12 +00006718class UnreachableObjectsFilter : public HeapObjectsFilter {
6719 public:
6720 UnreachableObjectsFilter() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006721 MarkReachableObjects();
6722 }
6723
6724 ~UnreachableObjectsFilter() {
6725 Isolate::Current()->heap()->mark_compact_collector()->ClearMarkbits();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006726 }
6727
6728 bool SkipObject(HeapObject* object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006729 MarkBit mark_bit = Marking::MarkBitFrom(object);
6730 return !mark_bit.Get();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006731 }
6732
6733 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006734 class MarkingVisitor : public ObjectVisitor {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006735 public:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006736 MarkingVisitor() : marking_stack_(10) {}
whesse@chromium.org023421e2010-12-21 12:19:12 +00006737
6738 void VisitPointers(Object** start, Object** end) {
6739 for (Object** p = start; p < end; p++) {
6740 if (!(*p)->IsHeapObject()) continue;
6741 HeapObject* obj = HeapObject::cast(*p);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006742 MarkBit mark_bit = Marking::MarkBitFrom(obj);
6743 if (!mark_bit.Get()) {
6744 mark_bit.Set();
6745 marking_stack_.Add(obj);
whesse@chromium.org023421e2010-12-21 12:19:12 +00006746 }
6747 }
6748 }
6749
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006750 void TransitiveClosure() {
6751 while (!marking_stack_.is_empty()) {
6752 HeapObject* obj = marking_stack_.RemoveLast();
6753 obj->Iterate(this);
6754 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00006755 }
6756
6757 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006758 List<HeapObject*> marking_stack_;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006759 };
6760
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006761 void MarkReachableObjects() {
6762 Heap* heap = Isolate::Current()->heap();
6763 MarkingVisitor visitor;
6764 heap->IterateRoots(&visitor, VISIT_ALL);
6765 visitor.TransitiveClosure();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006766 }
6767
6768 AssertNoAllocation no_alloc;
6769};
6770
6771
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006772HeapIterator::HeapIterator()
6773 : filtering_(HeapIterator::kNoFiltering),
6774 filter_(NULL) {
6775 Init();
6776}
6777
6778
whesse@chromium.org023421e2010-12-21 12:19:12 +00006779HeapIterator::HeapIterator(HeapIterator::HeapObjectsFiltering filtering)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006780 : filtering_(filtering),
6781 filter_(NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006782 Init();
6783}
6784
6785
6786HeapIterator::~HeapIterator() {
6787 Shutdown();
6788}
6789
6790
6791void HeapIterator::Init() {
6792 // Start the iteration.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006793 space_iterator_ = new SpaceIterator;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006794 switch (filtering_) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006795 case kFilterUnreachable:
6796 filter_ = new UnreachableObjectsFilter;
6797 break;
6798 default:
6799 break;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006800 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006801 object_iterator_ = space_iterator_->next();
6802}
6803
6804
6805void HeapIterator::Shutdown() {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006806#ifdef DEBUG
whesse@chromium.org023421e2010-12-21 12:19:12 +00006807 // Assert that in filtering mode we have iterated through all
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006808 // objects. Otherwise, heap will be left in an inconsistent state.
whesse@chromium.org023421e2010-12-21 12:19:12 +00006809 if (filtering_ != kNoFiltering) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006810 ASSERT(object_iterator_ == NULL);
6811 }
6812#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006813 // Make sure the last iterator is deallocated.
6814 delete space_iterator_;
6815 space_iterator_ = NULL;
6816 object_iterator_ = NULL;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006817 delete filter_;
6818 filter_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006819}
6820
6821
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006822HeapObject* HeapIterator::next() {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006823 if (filter_ == NULL) return NextObject();
6824
6825 HeapObject* obj = NextObject();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006826 while (obj != NULL && filter_->SkipObject(obj)) obj = NextObject();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006827 return obj;
6828}
6829
6830
6831HeapObject* HeapIterator::NextObject() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006832 // No iterator means we are done.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006833 if (object_iterator_ == NULL) return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006834
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006835 if (HeapObject* obj = object_iterator_->next_object()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006836 // If the current iterator has more objects we are fine.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006837 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006838 } else {
6839 // Go though the spaces looking for one that has objects.
6840 while (space_iterator_->has_next()) {
6841 object_iterator_ = space_iterator_->next();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006842 if (HeapObject* obj = object_iterator_->next_object()) {
6843 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006844 }
6845 }
6846 }
6847 // Done with the last space.
6848 object_iterator_ = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006849 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006850}
6851
6852
6853void HeapIterator::reset() {
6854 // Restart the iterator.
6855 Shutdown();
6856 Init();
6857}
6858
6859
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006860#if defined(DEBUG) || defined(LIVE_OBJECT_LIST)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006861
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006862Object* const PathTracer::kAnyGlobalObject = reinterpret_cast<Object*>(NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006863
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006864class PathTracer::MarkVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006865 public:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006866 explicit MarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006867 void VisitPointers(Object** start, Object** end) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006868 // Scan all HeapObject pointers in [start, end)
6869 for (Object** p = start; !tracer_->found() && (p < end); p++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006870 if ((*p)->IsHeapObject())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006871 tracer_->MarkRecursively(p, this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006872 }
6873 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006874
6875 private:
6876 PathTracer* tracer_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006877};
6878
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006879
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006880class PathTracer::UnmarkVisitor: public ObjectVisitor {
6881 public:
6882 explicit UnmarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
6883 void VisitPointers(Object** start, Object** end) {
6884 // Scan all HeapObject pointers in [start, end)
6885 for (Object** p = start; p < end; p++) {
6886 if ((*p)->IsHeapObject())
6887 tracer_->UnmarkRecursively(p, this);
6888 }
6889 }
6890
6891 private:
6892 PathTracer* tracer_;
6893};
6894
6895
6896void PathTracer::VisitPointers(Object** start, Object** end) {
6897 bool done = ((what_to_find_ == FIND_FIRST) && found_target_);
6898 // Visit all HeapObject pointers in [start, end)
6899 for (Object** p = start; !done && (p < end); p++) {
6900 if ((*p)->IsHeapObject()) {
6901 TracePathFrom(p);
6902 done = ((what_to_find_ == FIND_FIRST) && found_target_);
6903 }
6904 }
6905}
6906
6907
6908void PathTracer::Reset() {
6909 found_target_ = false;
6910 object_stack_.Clear();
6911}
6912
6913
6914void PathTracer::TracePathFrom(Object** root) {
6915 ASSERT((search_target_ == kAnyGlobalObject) ||
6916 search_target_->IsHeapObject());
6917 found_target_in_trace_ = false;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00006918 Reset();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006919
6920 MarkVisitor mark_visitor(this);
6921 MarkRecursively(root, &mark_visitor);
6922
6923 UnmarkVisitor unmark_visitor(this);
6924 UnmarkRecursively(root, &unmark_visitor);
6925
6926 ProcessResults();
6927}
6928
6929
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006930static bool SafeIsNativeContext(HeapObject* obj) {
6931 return obj->map() == obj->GetHeap()->raw_unchecked_native_context_map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006932}
6933
6934
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006935void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006936 if (!(*p)->IsHeapObject()) return;
6937
6938 HeapObject* obj = HeapObject::cast(*p);
6939
6940 Object* map = obj->map();
6941
6942 if (!map->IsHeapObject()) return; // visited before
6943
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006944 if (found_target_in_trace_) return; // stop if target found
6945 object_stack_.Add(obj);
6946 if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) ||
6947 (obj == search_target_)) {
6948 found_target_in_trace_ = true;
6949 found_target_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006950 return;
6951 }
6952
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006953 bool is_native_context = SafeIsNativeContext(obj);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006954
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006955 // not visited yet
6956 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
6957
6958 Address map_addr = map_p->address();
6959
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006960 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_addr + kMarkTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006961
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006962 // Scan the object body.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006963 if (is_native_context && (visit_mode_ == VISIT_ONLY_STRONG)) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006964 // This is specialized to scan Context's properly.
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00006965 Object** start = reinterpret_cast<Object**>(obj->address() +
6966 Context::kHeaderSize);
6967 Object** end = reinterpret_cast<Object**>(obj->address() +
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006968 Context::kHeaderSize + Context::FIRST_WEAK_SLOT * kPointerSize);
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00006969 mark_visitor->VisitPointers(start, end);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006970 } else {
6971 obj->IterateBody(map_p->instance_type(),
6972 obj->SizeFromMap(map_p),
6973 mark_visitor);
6974 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006975
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006976 // Scan the map after the body because the body is a lot more interesting
6977 // when doing leak detection.
6978 MarkRecursively(&map, mark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006979
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006980 if (!found_target_in_trace_) // don't pop if found the target
6981 object_stack_.RemoveLast();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006982}
6983
6984
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006985void PathTracer::UnmarkRecursively(Object** p, UnmarkVisitor* unmark_visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006986 if (!(*p)->IsHeapObject()) return;
6987
6988 HeapObject* obj = HeapObject::cast(*p);
6989
6990 Object* map = obj->map();
6991
6992 if (map->IsHeapObject()) return; // unmarked already
6993
6994 Address map_addr = reinterpret_cast<Address>(map);
6995
6996 map_addr -= kMarkTag;
6997
6998 ASSERT_TAG_ALIGNED(map_addr);
6999
7000 HeapObject* map_p = HeapObject::FromAddress(map_addr);
7001
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007002 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007003
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007004 UnmarkRecursively(reinterpret_cast<Object**>(&map_p), unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007005
7006 obj->IterateBody(Map::cast(map_p)->instance_type(),
7007 obj->SizeFromMap(Map::cast(map_p)),
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007008 unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007009}
7010
7011
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007012void PathTracer::ProcessResults() {
7013 if (found_target_) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007014 PrintF("=====================================\n");
7015 PrintF("==== Path to object ====\n");
7016 PrintF("=====================================\n\n");
7017
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007018 ASSERT(!object_stack_.is_empty());
7019 for (int i = 0; i < object_stack_.length(); i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007020 if (i > 0) PrintF("\n |\n |\n V\n\n");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007021 Object* obj = object_stack_[i];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007022 obj->Print();
7023 }
7024 PrintF("=====================================\n");
7025 }
7026}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007027#endif // DEBUG || LIVE_OBJECT_LIST
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007028
7029
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007030#ifdef DEBUG
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00007031// Triggers a depth-first traversal of reachable objects from one
7032// given root object and finds a path to a specific heap object and
7033// prints it.
7034void Heap::TracePathToObjectFrom(Object* target, Object* root) {
7035 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
7036 tracer.VisitPointer(&root);
7037}
7038
7039
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007040// Triggers a depth-first traversal of reachable objects from roots
7041// and finds a path to a specific heap object and prints it.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007042void Heap::TracePathToObject(Object* target) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007043 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
7044 IterateRoots(&tracer, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007045}
7046
7047
7048// Triggers a depth-first traversal of reachable objects from roots
7049// and finds a path to any global object and prints it. Useful for
7050// determining the source for leaks of global objects.
7051void Heap::TracePathToGlobal() {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007052 PathTracer tracer(PathTracer::kAnyGlobalObject,
7053 PathTracer::FIND_ALL,
7054 VISIT_ALL);
7055 IterateRoots(&tracer, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007056}
7057#endif
7058
7059
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007060static intptr_t CountTotalHolesSize() {
7061 intptr_t holes_size = 0;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007062 OldSpaces spaces;
7063 for (OldSpace* space = spaces.next();
7064 space != NULL;
7065 space = spaces.next()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007066 holes_size += space->Waste() + space->Available();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007067 }
7068 return holes_size;
7069}
7070
7071
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007072GCTracer::GCTracer(Heap* heap,
7073 const char* gc_reason,
7074 const char* collector_reason)
kasper.lund7276f142008-07-30 08:49:36 +00007075 : start_time_(0.0),
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007076 start_object_size_(0),
7077 start_memory_size_(0),
kasper.lund7276f142008-07-30 08:49:36 +00007078 gc_count_(0),
7079 full_gc_count_(0),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007080 allocated_since_last_gc_(0),
7081 spent_in_mutator_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007082 promoted_objects_size_(0),
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007083 heap_(heap),
7084 gc_reason_(gc_reason),
7085 collector_reason_(collector_reason) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007086 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
kasper.lund7276f142008-07-30 08:49:36 +00007087 start_time_ = OS::TimeCurrentMillis();
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007088 start_object_size_ = heap_->SizeOfObjects();
7089 start_memory_size_ = heap_->isolate()->memory_allocator()->Size();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007090
7091 for (int i = 0; i < Scope::kNumberOfScopes; i++) {
7092 scopes_[i] = 0;
7093 }
7094
7095 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize();
7096
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007097 allocated_since_last_gc_ =
7098 heap_->SizeOfObjects() - heap_->alive_after_last_gc_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007099
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007100 if (heap_->last_gc_end_timestamp_ > 0) {
7101 spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007102 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007103
7104 steps_count_ = heap_->incremental_marking()->steps_count();
7105 steps_took_ = heap_->incremental_marking()->steps_took();
7106 longest_step_ = heap_->incremental_marking()->longest_step();
7107 steps_count_since_last_gc_ =
7108 heap_->incremental_marking()->steps_count_since_last_gc();
7109 steps_took_since_last_gc_ =
7110 heap_->incremental_marking()->steps_took_since_last_gc();
kasper.lund7276f142008-07-30 08:49:36 +00007111}
7112
7113
7114GCTracer::~GCTracer() {
kasper.lund7276f142008-07-30 08:49:36 +00007115 // Printf ONE line iff flag is set.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007116 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
7117
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007118 bool first_gc = (heap_->last_gc_end_timestamp_ == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007119
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007120 heap_->alive_after_last_gc_ = heap_->SizeOfObjects();
7121 heap_->last_gc_end_timestamp_ = OS::TimeCurrentMillis();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007122
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007123 int time = static_cast<int>(heap_->last_gc_end_timestamp_ - start_time_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007124
7125 // Update cumulative GC statistics if required.
7126 if (FLAG_print_cumulative_gc_stat) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007127 heap_->total_gc_time_ms_ += time;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007128 heap_->max_gc_pause_ = Max(heap_->max_gc_pause_, time);
7129 heap_->max_alive_after_gc_ = Max(heap_->max_alive_after_gc_,
7130 heap_->alive_after_last_gc_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007131 if (!first_gc) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007132 heap_->min_in_mutator_ = Min(heap_->min_in_mutator_,
7133 static_cast<int>(spent_in_mutator_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007134 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007135 } else if (FLAG_trace_gc_verbose) {
7136 heap_->total_gc_time_ms_ += time;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007137 }
7138
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007139 if (collector_ == SCAVENGER && FLAG_trace_gc_ignore_scavenger) return;
7140
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00007141 PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init());
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007142
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007143 if (!FLAG_trace_gc_nvp) {
7144 int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]);
7145
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007146 double end_memory_size_mb =
7147 static_cast<double>(heap_->isolate()->memory_allocator()->Size()) / MB;
7148
7149 PrintF("%s %.1f (%.1f) -> %.1f (%.1f) MB, ",
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007150 CollectorString(),
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007151 static_cast<double>(start_object_size_) / MB,
7152 static_cast<double>(start_memory_size_) / MB,
7153 SizeOfHeapObjects(),
7154 end_memory_size_mb);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007155
7156 if (external_time > 0) PrintF("%d / ", external_time);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007157 PrintF("%d ms", time);
7158 if (steps_count_ > 0) {
7159 if (collector_ == SCAVENGER) {
7160 PrintF(" (+ %d ms in %d steps since last GC)",
7161 static_cast<int>(steps_took_since_last_gc_),
7162 steps_count_since_last_gc_);
7163 } else {
7164 PrintF(" (+ %d ms in %d steps since start of marking, "
7165 "biggest step %f ms)",
7166 static_cast<int>(steps_took_),
7167 steps_count_,
7168 longest_step_);
7169 }
7170 }
rossberg@chromium.org994edf62012-02-06 10:12:55 +00007171
7172 if (gc_reason_ != NULL) {
7173 PrintF(" [%s]", gc_reason_);
7174 }
7175
7176 if (collector_reason_ != NULL) {
7177 PrintF(" [%s]", collector_reason_);
7178 }
7179
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007180 PrintF(".\n");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007181 } else {
7182 PrintF("pause=%d ", time);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007183 PrintF("mutator=%d ", static_cast<int>(spent_in_mutator_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007184 PrintF("gc=");
7185 switch (collector_) {
7186 case SCAVENGER:
7187 PrintF("s");
7188 break;
7189 case MARK_COMPACTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007190 PrintF("ms");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007191 break;
7192 default:
7193 UNREACHABLE();
7194 }
7195 PrintF(" ");
7196
7197 PrintF("external=%d ", static_cast<int>(scopes_[Scope::EXTERNAL]));
7198 PrintF("mark=%d ", static_cast<int>(scopes_[Scope::MC_MARK]));
7199 PrintF("sweep=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP]));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007200 PrintF("sweepns=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP_NEWSPACE]));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00007201 PrintF("evacuate=%d ", static_cast<int>(scopes_[Scope::MC_EVACUATE_PAGES]));
7202 PrintF("new_new=%d ",
7203 static_cast<int>(scopes_[Scope::MC_UPDATE_NEW_TO_NEW_POINTERS]));
7204 PrintF("root_new=%d ",
7205 static_cast<int>(scopes_[Scope::MC_UPDATE_ROOT_TO_NEW_POINTERS]));
7206 PrintF("old_new=%d ",
7207 static_cast<int>(scopes_[Scope::MC_UPDATE_OLD_TO_NEW_POINTERS]));
7208 PrintF("compaction_ptrs=%d ",
7209 static_cast<int>(scopes_[Scope::MC_UPDATE_POINTERS_TO_EVACUATED]));
7210 PrintF("intracompaction_ptrs=%d ", static_cast<int>(scopes_[
7211 Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED]));
7212 PrintF("misc_compaction=%d ",
7213 static_cast<int>(scopes_[Scope::MC_UPDATE_MISC_POINTERS]));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007214
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007215 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_object_size_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007216 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007217 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ",
7218 in_free_list_or_wasted_before_gc_);
7219 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007220
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007221 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_);
7222 PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007223
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007224 if (collector_ == SCAVENGER) {
7225 PrintF("stepscount=%d ", steps_count_since_last_gc_);
7226 PrintF("stepstook=%d ", static_cast<int>(steps_took_since_last_gc_));
7227 } else {
7228 PrintF("stepscount=%d ", steps_count_);
7229 PrintF("stepstook=%d ", static_cast<int>(steps_took_));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007230 PrintF("longeststep=%.f ", longest_step_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007231 }
7232
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007233 PrintF("\n");
7234 }
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007235
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007236 heap_->PrintShortHeapStatistics();
kasper.lund7276f142008-07-30 08:49:36 +00007237}
7238
7239
7240const char* GCTracer::CollectorString() {
7241 switch (collector_) {
7242 case SCAVENGER:
7243 return "Scavenge";
7244 case MARK_COMPACTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007245 return "Mark-sweep";
kasper.lund7276f142008-07-30 08:49:36 +00007246 }
7247 return "Unknown GC";
7248}
7249
7250
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007251int KeyedLookupCache::Hash(Map* map, String* name) {
7252 // Uses only lower 32 bits if pointers are larger.
7253 uintptr_t addr_hash =
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007254 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00007255 return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007256}
7257
7258
7259int KeyedLookupCache::Lookup(Map* map, String* name) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007260 int index = (Hash(map, name) & kHashMask);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007261 for (int i = 0; i < kEntriesPerBucket; i++) {
7262 Key& key = keys_[index + i];
7263 if ((key.map == map) && key.name->Equals(name)) {
7264 return field_offsets_[index + i];
7265 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007266 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007267 return kNotFound;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007268}
7269
7270
7271void KeyedLookupCache::Update(Map* map, String* name, int field_offset) {
7272 String* symbol;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007273 if (HEAP->LookupSymbolIfExists(name, &symbol)) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007274 int index = (Hash(map, symbol) & kHashMask);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007275 // After a GC there will be free slots, so we use them in order (this may
7276 // help to get the most frequently used one in position 0).
7277 for (int i = 0; i< kEntriesPerBucket; i++) {
7278 Key& key = keys_[index];
7279 Object* free_entry_indicator = NULL;
7280 if (key.map == free_entry_indicator) {
7281 key.map = map;
7282 key.name = symbol;
7283 field_offsets_[index + i] = field_offset;
7284 return;
7285 }
7286 }
7287 // No free entry found in this bucket, so we move them all down one and
7288 // put the new entry at position zero.
7289 for (int i = kEntriesPerBucket - 1; i > 0; i--) {
7290 Key& key = keys_[index + i];
7291 Key& key2 = keys_[index + i - 1];
7292 key = key2;
7293 field_offsets_[index + i] = field_offsets_[index + i - 1];
7294 }
7295
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007296 // Write the new first entry.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007297 Key& key = keys_[index];
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007298 key.map = map;
7299 key.name = symbol;
7300 field_offsets_[index] = field_offset;
7301 }
7302}
7303
7304
7305void KeyedLookupCache::Clear() {
7306 for (int index = 0; index < kLength; index++) keys_[index].map = NULL;
7307}
7308
7309
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007310void DescriptorLookupCache::Clear() {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007311 for (int index = 0; index < kLength; index++) keys_[index].source = NULL;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007312}
7313
7314
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007315#ifdef DEBUG
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007316void Heap::GarbageCollectionGreedyCheck() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007317 ASSERT(FLAG_gc_greedy);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007318 if (isolate_->bootstrapper()->IsActive()) return;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007319 if (disallow_allocation_failure()) return;
7320 CollectGarbage(NEW_SPACE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007321}
7322#endif
7323
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007325TranscendentalCache::SubCache::SubCache(Type t)
7326 : type_(t),
7327 isolate_(Isolate::Current()) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007328 uint32_t in0 = 0xffffffffu; // Bit-pattern for a NaN that isn't
7329 uint32_t in1 = 0xffffffffu; // generated by the FPU.
7330 for (int i = 0; i < kCacheSize; i++) {
7331 elements_[i].in[0] = in0;
7332 elements_[i].in[1] = in1;
7333 elements_[i].output = NULL;
7334 }
7335}
7336
7337
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007338void TranscendentalCache::Clear() {
7339 for (int i = 0; i < kNumberOfCaches; i++) {
7340 if (caches_[i] != NULL) {
7341 delete caches_[i];
7342 caches_[i] = NULL;
7343 }
7344 }
7345}
7346
7347
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007348void ExternalStringTable::CleanUp() {
7349 int last = 0;
7350 for (int i = 0; i < new_space_strings_.length(); ++i) {
danno@chromium.org72204d52012-10-31 10:02:10 +00007351 if (new_space_strings_[i] == heap_->the_hole_value()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007352 continue;
7353 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007354 if (heap_->InNewSpace(new_space_strings_[i])) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007355 new_space_strings_[last++] = new_space_strings_[i];
7356 } else {
7357 old_space_strings_.Add(new_space_strings_[i]);
7358 }
7359 }
7360 new_space_strings_.Rewind(last);
7361 last = 0;
7362 for (int i = 0; i < old_space_strings_.length(); ++i) {
danno@chromium.org72204d52012-10-31 10:02:10 +00007363 if (old_space_strings_[i] == heap_->the_hole_value()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007364 continue;
7365 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007366 ASSERT(!heap_->InNewSpace(old_space_strings_[i]));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007367 old_space_strings_[last++] = old_space_strings_[i];
7368 }
7369 old_space_strings_.Rewind(last);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007370#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007371 if (FLAG_verify_heap) {
7372 Verify();
7373 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007374#endif
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007375}
7376
7377
7378void ExternalStringTable::TearDown() {
7379 new_space_strings_.Free();
7380 old_space_strings_.Free();
7381}
7382
7383
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007384void Heap::QueueMemoryChunkForFree(MemoryChunk* chunk) {
7385 chunk->set_next_chunk(chunks_queued_for_free_);
7386 chunks_queued_for_free_ = chunk;
7387}
7388
7389
7390void Heap::FreeQueuedChunks() {
7391 if (chunks_queued_for_free_ == NULL) return;
7392 MemoryChunk* next;
7393 MemoryChunk* chunk;
7394 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
7395 next = chunk->next_chunk();
7396 chunk->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
7397
7398 if (chunk->owner()->identity() == LO_SPACE) {
7399 // StoreBuffer::Filter relies on MemoryChunk::FromAnyPointerAddress.
7400 // If FromAnyPointerAddress encounters a slot that belongs to a large
7401 // chunk queued for deletion it will fail to find the chunk because
7402 // it try to perform a search in the list of pages owned by of the large
7403 // object space and queued chunks were detached from that list.
7404 // To work around this we split large chunk into normal kPageSize aligned
danno@chromium.org2c456792011-11-11 12:00:53 +00007405 // pieces and initialize size, owner and flags field of every piece.
7406 // If FromAnyPointerAddress encounters a slot that belongs to one of
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007407 // these smaller pieces it will treat it as a slot on a normal Page.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007408 Address chunk_end = chunk->address() + chunk->size();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007409 MemoryChunk* inner = MemoryChunk::FromAddress(
7410 chunk->address() + Page::kPageSize);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007411 MemoryChunk* inner_last = MemoryChunk::FromAddress(chunk_end - 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007412 while (inner <= inner_last) {
7413 // Size of a large chunk is always a multiple of
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007414 // OS::AllocateAlignment() so there is always
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007415 // enough space for a fake MemoryChunk header.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007416 Address area_end = Min(inner->address() + Page::kPageSize, chunk_end);
7417 // Guard against overflow.
7418 if (area_end < inner->address()) area_end = chunk_end;
7419 inner->SetArea(inner->address(), area_end);
danno@chromium.org2c456792011-11-11 12:00:53 +00007420 inner->set_size(Page::kPageSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007421 inner->set_owner(lo_space());
7422 inner->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
7423 inner = MemoryChunk::FromAddress(
7424 inner->address() + Page::kPageSize);
7425 }
7426 }
7427 }
7428 isolate_->heap()->store_buffer()->Compact();
7429 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED);
7430 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
7431 next = chunk->next_chunk();
7432 isolate_->memory_allocator()->Free(chunk);
7433 }
7434 chunks_queued_for_free_ = NULL;
7435}
7436
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00007437
7438void Heap::RememberUnmappedPage(Address page, bool compacted) {
7439 uintptr_t p = reinterpret_cast<uintptr_t>(page);
7440 // Tag the page pointer to make it findable in the dump file.
7441 if (compacted) {
7442 p ^= 0xc1ead & (Page::kPageSize - 1); // Cleared.
7443 } else {
7444 p ^= 0x1d1ed & (Page::kPageSize - 1); // I died.
7445 }
7446 remembered_unmapped_pages_[remembered_unmapped_pages_index_] =
7447 reinterpret_cast<Address>(p);
7448 remembered_unmapped_pages_index_++;
7449 remembered_unmapped_pages_index_ %= kRememberedUnmappedPages;
7450}
7451
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00007452
7453void Heap::ClearObjectStats(bool clear_last_time_stats) {
7454 memset(object_counts_, 0, sizeof(object_counts_));
7455 memset(object_sizes_, 0, sizeof(object_sizes_));
7456 if (clear_last_time_stats) {
7457 memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_));
7458 memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_));
7459 }
7460}
7461
7462
7463static LazyMutex checkpoint_object_stats_mutex = LAZY_MUTEX_INITIALIZER;
7464
7465
7466void Heap::CheckpointObjectStats() {
7467 ScopedLock lock(checkpoint_object_stats_mutex.Pointer());
7468 Counters* counters = isolate()->counters();
7469#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7470 counters->count_of_##name()->Increment( \
7471 static_cast<int>(object_counts_[name])); \
7472 counters->count_of_##name()->Decrement( \
7473 static_cast<int>(object_counts_last_time_[name])); \
7474 counters->size_of_##name()->Increment( \
7475 static_cast<int>(object_sizes_[name])); \
7476 counters->size_of_##name()->Decrement( \
7477 static_cast<int>(object_sizes_last_time_[name]));
7478 INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7479#undef ADJUST_LAST_TIME_OBJECT_COUNT
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007480 int index;
7481#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7482 index = FIRST_CODE_KIND_SUB_TYPE + Code::name; \
7483 counters->count_of_CODE_TYPE_##name()->Increment( \
7484 static_cast<int>(object_counts_[index])); \
7485 counters->count_of_CODE_TYPE_##name()->Decrement( \
7486 static_cast<int>(object_counts_last_time_[index])); \
7487 counters->size_of_CODE_TYPE_##name()->Increment( \
7488 static_cast<int>(object_sizes_[index])); \
7489 counters->size_of_CODE_TYPE_##name()->Decrement( \
7490 static_cast<int>(object_sizes_last_time_[index]));
7491 CODE_KIND_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7492#undef ADJUST_LAST_TIME_OBJECT_COUNT
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007493#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7494 index = FIRST_FIXED_ARRAY_SUB_TYPE + name; \
7495 counters->count_of_FIXED_ARRAY_##name()->Increment( \
7496 static_cast<int>(object_counts_[index])); \
7497 counters->count_of_FIXED_ARRAY_##name()->Decrement( \
7498 static_cast<int>(object_counts_last_time_[index])); \
7499 counters->size_of_FIXED_ARRAY_##name()->Increment( \
7500 static_cast<int>(object_sizes_[index])); \
7501 counters->size_of_FIXED_ARRAY_##name()->Decrement( \
7502 static_cast<int>(object_sizes_last_time_[index]));
7503 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7504#undef ADJUST_LAST_TIME_OBJECT_COUNT
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007505
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00007506 memcpy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
7507 memcpy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
7508 ClearObjectStats();
7509}
7510
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007511} } // namespace v8::internal