blob: ff791d83387b6b9dfba56e560633f2163c4a36d3 [file] [log] [blame]
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "accessors.h"
31#include "api.h"
32#include "bootstrapper.h"
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000033#include "codegen.h"
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000034#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include "debug.h"
ricow@chromium.org4f693d62011-07-04 14:01:31 +000036#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "global-handles.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000038#include "heap-profiler.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000039#include "incremental-marking.h"
ager@chromium.org0ee099b2011-01-25 14:06:47 +000040#include "liveobjectlist-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "mark-compact.h"
42#include "natives.h"
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000043#include "objects-visiting.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000044#include "objects-visiting-inl.h"
fschneider@chromium.org7d10be52012-04-10 12:30:14 +000045#include "once.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000046#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047#include "scopeinfo.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000048#include "snapshot.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000049#include "store-buffer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050#include "v8threads.h"
ulan@chromium.org56c14af2012-09-20 12:51:09 +000051#include "v8utils.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000052#include "vm-state-inl.h"
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000053#if V8_TARGET_ARCH_ARM && !V8_INTERPRETED_REGEXP
ager@chromium.org18ad94b2009-09-02 08:22:29 +000054#include "regexp-macro-assembler.h"
ager@chromium.org3811b432009-10-28 14:53:37 +000055#include "arm/regexp-macro-assembler-arm.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000056#endif
lrn@chromium.org7516f052011-03-30 08:52:27 +000057#if V8_TARGET_ARCH_MIPS && !V8_INTERPRETED_REGEXP
58#include "regexp-macro-assembler.h"
59#include "mips/regexp-macro-assembler-mips.h"
60#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
kasper.lund7276f142008-07-30 08:49:36 +000065
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000066Heap::Heap()
67 : isolate_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068// semispace_size_ should be a power of 2 and old_generation_size_ should be
69// a multiple of Page::kPageSize.
mmassi@chromium.org7028c052012-06-13 11:51:58 +000070#if defined(V8_TARGET_ARCH_X64)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000071#define LUMP_OF_MEMORY (2 * MB)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000072 code_range_size_(512*MB),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000073#else
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000074#define LUMP_OF_MEMORY MB
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000075 code_range_size_(0),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000076#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +000077#if defined(ANDROID)
78 reserved_semispace_size_(4 * Max(LUMP_OF_MEMORY, Page::kPageSize)),
79 max_semispace_size_(4 * Max(LUMP_OF_MEMORY, Page::kPageSize)),
80 initial_semispace_size_(Page::kPageSize),
81 max_old_generation_size_(192*MB),
82 max_executable_size_(max_old_generation_size_),
83#else
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000084 reserved_semispace_size_(8 * Max(LUMP_OF_MEMORY, Page::kPageSize)),
85 max_semispace_size_(8 * Max(LUMP_OF_MEMORY, Page::kPageSize)),
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000086 initial_semispace_size_(Page::kPageSize),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000087 max_old_generation_size_(700ul * LUMP_OF_MEMORY),
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000088 max_executable_size_(256l * LUMP_OF_MEMORY),
mmassi@chromium.org7028c052012-06-13 11:51:58 +000089#endif
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000090
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091// Variables set based on semispace_size_ and old_generation_size_ in
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000092// ConfigureHeap (survived_since_last_expansion_, external_allocation_limit_)
ager@chromium.org3811b432009-10-28 14:53:37 +000093// Will be 4 * reserved_semispace_size_ to ensure that young
94// generation can be aligned to its size.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000095 survived_since_last_expansion_(0),
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +000096 sweep_generation_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000097 always_allocate_scope_depth_(0),
98 linear_allocation_scope_depth_(0),
99 contexts_disposed_(0),
danno@chromium.org88aa0582012-03-23 15:11:57 +0000100 global_ic_age_(0),
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000101 flush_monomorphic_ics_(false),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000102 scan_on_scavenge_pages_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000103 new_space_(this),
104 old_pointer_space_(NULL),
105 old_data_space_(NULL),
106 code_space_(NULL),
107 map_space_(NULL),
108 cell_space_(NULL),
109 lo_space_(NULL),
110 gc_state_(NOT_IN_GC),
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000111 gc_post_processing_depth_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000112 ms_count_(0),
113 gc_count_(0),
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000114 remembered_unmapped_pages_index_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000115 unflattened_strings_length_(0),
kasper.lund7276f142008-07-30 08:49:36 +0000116#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000117 allocation_allowed_(true),
118 allocation_timeout_(0),
119 disallow_allocation_failure_(false),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000120#endif // DEBUG
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000121 new_space_high_promotion_mode_active_(false),
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000122 old_gen_promotion_limit_(kMinimumPromotionLimit),
123 old_gen_allocation_limit_(kMinimumAllocationLimit),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000124 old_gen_limit_factor_(1),
125 size_of_old_gen_at_last_old_space_gc_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 external_allocation_limit_(0),
127 amount_of_external_allocated_memory_(0),
128 amount_of_external_allocated_memory_at_last_global_gc_(0),
129 old_gen_exhausted_(false),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000130 store_buffer_rebuilder_(store_buffer()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000131 hidden_symbol_(NULL),
132 global_gc_prologue_callback_(NULL),
133 global_gc_epilogue_callback_(NULL),
134 gc_safe_size_of_old_object_(NULL),
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000135 total_regexp_code_generated_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000136 tracer_(NULL),
137 young_survivors_after_last_gc_(0),
138 high_survival_rate_period_length_(0),
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000139 low_survival_rate_period_length_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000140 survival_rate_(0),
141 previous_survival_rate_trend_(Heap::STABLE),
142 survival_rate_trend_(Heap::STABLE),
143 max_gc_pause_(0),
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000144 total_gc_time_ms_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145 max_alive_after_gc_(0),
146 min_in_mutator_(kMaxInt),
147 alive_after_last_gc_(0),
148 last_gc_end_timestamp_(0.0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000149 store_buffer_(this),
150 marking_(this),
151 incremental_marking_(this),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000152 number_idle_notifications_(0),
153 last_idle_notification_gc_count_(0),
154 last_idle_notification_gc_count_init_(false),
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +0000155 mark_sweeps_since_idle_round_started_(0),
156 ms_count_at_last_idle_notification_(0),
157 gc_count_at_last_idle_gc_(0),
158 scavenges_since_last_idle_round_(kIdleScavengeThreshold),
danno@chromium.orgc612e022011-11-10 11:38:15 +0000159 promotion_queue_(this),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 configured_(false),
yangguo@chromium.org304cc332012-07-24 07:59:48 +0000161 chunks_queued_for_free_(NULL),
162 relocation_mutex_(NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000163 // Allow build-time customization of the max semispace size. Building
164 // V8 with snapshots and a non-default max semispace size is much
165 // easier if you can define it as part of the build environment.
166#if defined(V8_MAX_SEMISPACE_SIZE)
167 max_semispace_size_ = reserved_semispace_size_ = V8_MAX_SEMISPACE_SIZE;
168#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000169
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000170 intptr_t max_virtual = OS::MaxVirtualMemory();
171
172 if (max_virtual > 0) {
173 if (code_range_size_ > 0) {
174 // Reserve no more than 1/8 of the memory for the code range.
175 code_range_size_ = Min(code_range_size_, max_virtual >> 3);
176 }
177 }
178
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000179 memset(roots_, 0, sizeof(roots_[0]) * kRootListLength);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000180 native_contexts_list_ = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000181 mark_compact_collector_.heap_ = this;
182 external_string_table_.heap_ = this;
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +0000183 // Put a dummy entry in the remembered pages so we can find the list the
184 // minidump even if there are no real unmapped pages.
185 RememberUnmappedPage(NULL, false);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000186
187 ClearObjectStats(true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000188}
189
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000190
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000191intptr_t Heap::Capacity() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000192 if (!HasBeenSetUp()) return 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000193
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000194 return new_space_.Capacity() +
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000195 old_pointer_space_->Capacity() +
196 old_data_space_->Capacity() +
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000197 code_space_->Capacity() +
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000198 map_space_->Capacity() +
199 cell_space_->Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000200}
201
202
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000203intptr_t Heap::CommittedMemory() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000204 if (!HasBeenSetUp()) return 0;
ager@chromium.org3811b432009-10-28 14:53:37 +0000205
206 return new_space_.CommittedMemory() +
207 old_pointer_space_->CommittedMemory() +
208 old_data_space_->CommittedMemory() +
209 code_space_->CommittedMemory() +
210 map_space_->CommittedMemory() +
211 cell_space_->CommittedMemory() +
212 lo_space_->Size();
213}
214
danno@chromium.org72204d52012-10-31 10:02:10 +0000215
216size_t Heap::CommittedPhysicalMemory() {
217 if (!HasBeenSetUp()) return 0;
218
219 return new_space_.CommittedPhysicalMemory() +
220 old_pointer_space_->CommittedPhysicalMemory() +
221 old_data_space_->CommittedPhysicalMemory() +
222 code_space_->CommittedPhysicalMemory() +
223 map_space_->CommittedPhysicalMemory() +
224 cell_space_->CommittedPhysicalMemory() +
225 lo_space_->CommittedPhysicalMemory();
226}
227
228
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000229intptr_t Heap::CommittedMemoryExecutable() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000230 if (!HasBeenSetUp()) return 0;
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000231
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000232 return isolate()->memory_allocator()->SizeExecutable();
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000233}
234
ager@chromium.org3811b432009-10-28 14:53:37 +0000235
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000236intptr_t Heap::Available() {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000237 if (!HasBeenSetUp()) return 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000239 return new_space_.Available() +
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000240 old_pointer_space_->Available() +
241 old_data_space_->Available() +
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000242 code_space_->Available() +
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000243 map_space_->Available() +
244 cell_space_->Available();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000245}
246
247
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000248bool Heap::HasBeenSetUp() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000249 return old_pointer_space_ != NULL &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000250 old_data_space_ != NULL &&
251 code_space_ != NULL &&
252 map_space_ != NULL &&
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000253 cell_space_ != NULL &&
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000254 lo_space_ != NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000255}
256
257
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000258int Heap::GcSafeSizeOfOldObject(HeapObject* object) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000259 if (IntrusiveMarking::IsMarked(object)) {
260 return IntrusiveMarking::SizeOfMarkedObject(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000261 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000262 return object->SizeFromMap(object->map());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000263}
264
265
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000266GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space,
267 const char** reason) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000268 // Is global GC requested?
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000269 if (space != NEW_SPACE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000270 isolate_->counters()->gc_compactor_caused_by_request()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000271 *reason = "GC in old space requested";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000272 return MARK_COMPACTOR;
273 }
274
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000275 if (FLAG_gc_global || (FLAG_stress_compaction && (gc_count_ & 1) != 0)) {
276 *reason = "GC in old space forced by flags";
277 return MARK_COMPACTOR;
278 }
279
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000280 // Is enough data promoted to justify a global GC?
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000281 if (OldGenerationPromotionLimitReached()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000282 isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000283 *reason = "promotion limit reached";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000284 return MARK_COMPACTOR;
285 }
286
287 // Have allocation in OLD and LO failed?
288 if (old_gen_exhausted_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000289 isolate_->counters()->
290 gc_compactor_caused_by_oldspace_exhaustion()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000291 *reason = "old generations exhausted";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000292 return MARK_COMPACTOR;
293 }
294
295 // Is there enough space left in OLD to guarantee that a scavenge can
296 // succeed?
297 //
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000298 // Note that MemoryAllocator->MaxAvailable() undercounts the memory available
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000299 // for object promotion. It counts only the bytes that the memory
300 // allocator has not yet allocated from the OS and assigned to any space,
301 // and does not count available bytes already in the old space or code
302 // space. Undercounting is safe---we may get an unrequested full GC when
303 // a scavenge would have succeeded.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 if (isolate_->memory_allocator()->MaxAvailable() <= new_space_.Size()) {
305 isolate_->counters()->
306 gc_compactor_caused_by_oldspace_exhaustion()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000307 *reason = "scavenge might not succeed";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000308 return MARK_COMPACTOR;
309 }
310
311 // Default
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000312 *reason = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000313 return SCAVENGER;
314}
315
316
317// TODO(1238405): Combine the infrastructure for --heap-stats and
318// --log-gc to avoid the complicated preprocessor and flag testing.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000319void Heap::ReportStatisticsBeforeGC() {
320 // Heap::ReportHeapStatistics will also log NewSpace statistics when
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000321 // compiled --log-gc is set. The following logic is used to avoid
322 // double logging.
323#ifdef DEBUG
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000324 if (FLAG_heap_stats || FLAG_log_gc) new_space_.CollectStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325 if (FLAG_heap_stats) {
326 ReportHeapStatistics("Before GC");
327 } else if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000328 new_space_.ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000329 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000330 if (FLAG_heap_stats || FLAG_log_gc) new_space_.ClearHistograms();
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000331#else
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000332 if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000333 new_space_.CollectStatistics();
334 new_space_.ReportStatistics();
335 new_space_.ClearHistograms();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000336 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000337#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338}
339
340
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000341void Heap::PrintShortHeapStatistics() {
342 if (!FLAG_trace_gc_verbose) return;
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000343 PrintPID("Memory allocator, used: %6" V8_PTR_PREFIX "d KB"
344 ", available: %6" V8_PTR_PREFIX "d KB\n",
345 isolate_->memory_allocator()->Size() / KB,
346 isolate_->memory_allocator()->Available() / KB);
347 PrintPID("New space, used: %6" V8_PTR_PREFIX "d KB"
348 ", available: %6" V8_PTR_PREFIX "d KB"
349 ", committed: %6" V8_PTR_PREFIX "d KB\n",
350 new_space_.Size() / KB,
351 new_space_.Available() / KB,
352 new_space_.CommittedMemory() / KB);
353 PrintPID("Old pointers, used: %6" V8_PTR_PREFIX "d KB"
354 ", available: %6" V8_PTR_PREFIX "d KB"
355 ", committed: %6" V8_PTR_PREFIX "d KB\n",
356 old_pointer_space_->SizeOfObjects() / KB,
357 old_pointer_space_->Available() / KB,
358 old_pointer_space_->CommittedMemory() / KB);
359 PrintPID("Old data space, used: %6" V8_PTR_PREFIX "d KB"
360 ", available: %6" V8_PTR_PREFIX "d KB"
361 ", committed: %6" V8_PTR_PREFIX "d KB\n",
362 old_data_space_->SizeOfObjects() / KB,
363 old_data_space_->Available() / KB,
364 old_data_space_->CommittedMemory() / KB);
365 PrintPID("Code space, used: %6" V8_PTR_PREFIX "d KB"
366 ", available: %6" V8_PTR_PREFIX "d KB"
367 ", committed: %6" V8_PTR_PREFIX "d KB\n",
368 code_space_->SizeOfObjects() / KB,
369 code_space_->Available() / KB,
370 code_space_->CommittedMemory() / KB);
371 PrintPID("Map space, used: %6" V8_PTR_PREFIX "d KB"
372 ", available: %6" V8_PTR_PREFIX "d KB"
373 ", committed: %6" V8_PTR_PREFIX "d KB\n",
374 map_space_->SizeOfObjects() / KB,
375 map_space_->Available() / KB,
376 map_space_->CommittedMemory() / KB);
377 PrintPID("Cell space, used: %6" V8_PTR_PREFIX "d KB"
378 ", available: %6" V8_PTR_PREFIX "d KB"
379 ", committed: %6" V8_PTR_PREFIX "d KB\n",
380 cell_space_->SizeOfObjects() / KB,
381 cell_space_->Available() / KB,
382 cell_space_->CommittedMemory() / KB);
383 PrintPID("Large object space, used: %6" V8_PTR_PREFIX "d KB"
384 ", available: %6" V8_PTR_PREFIX "d KB"
385 ", committed: %6" V8_PTR_PREFIX "d KB\n",
386 lo_space_->SizeOfObjects() / KB,
387 lo_space_->Available() / KB,
388 lo_space_->CommittedMemory() / KB);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000389 PrintPID("All spaces, used: %6" V8_PTR_PREFIX "d KB"
390 ", available: %6" V8_PTR_PREFIX "d KB"
391 ", committed: %6" V8_PTR_PREFIX "d KB\n",
392 this->SizeOfObjects() / KB,
393 this->Available() / KB,
394 this->CommittedMemory() / KB);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000395 PrintPID("Total time spent in GC : %d ms\n", total_gc_time_ms_);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000396}
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000397
398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399// TODO(1238405): Combine the infrastructure for --heap-stats and
400// --log-gc to avoid the complicated preprocessor and flag testing.
401void Heap::ReportStatisticsAfterGC() {
402 // Similar to the before GC, we use some complicated logic to ensure that
403 // NewSpace statistics are logged exactly once when --log-gc is turned on.
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000404#if defined(DEBUG)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000405 if (FLAG_heap_stats) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000406 new_space_.CollectStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000407 ReportHeapStatistics("After GC");
408 } else if (FLAG_log_gc) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000409 new_space_.ReportStatistics();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000411#else
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000412 if (FLAG_log_gc) new_space_.ReportStatistics();
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000413#endif // DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000415
416
417void Heap::GarbageCollectionPrologue() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 isolate_->transcendental_cache()->Clear();
ager@chromium.orgac091b72010-05-05 07:34:42 +0000419 ClearJSFunctionResultCaches();
kasper.lund7276f142008-07-30 08:49:36 +0000420 gc_count_++;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000421 unflattened_strings_length_ = 0;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000422
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000423 if (FLAG_flush_code && FLAG_flush_code_incrementally) {
424 mark_compact_collector()->EnableCodeFlushing(true);
425 }
426
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000427#ifdef VERIFY_HEAP
428 if (FLAG_verify_heap) {
429 Verify();
430 }
431#endif
432
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000433#ifdef DEBUG
434 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
435 allow_allocation(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000436
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437 if (FLAG_gc_verbose) Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000439 ReportStatisticsBeforeGC();
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000440#endif // DEBUG
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000441
442 LiveObjectList::GCPrologue();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000443 store_buffer()->GCPrologue();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444}
445
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000446
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000447intptr_t Heap::SizeOfObjects() {
448 intptr_t total = 0;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000449 AllSpaces spaces;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000450 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000451 total += space->SizeOfObjects();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000452 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000453 return total;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000454}
455
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000456
457void Heap::RepairFreeListsAfterBoot() {
458 PagedSpaces spaces;
459 for (PagedSpace* space = spaces.next();
460 space != NULL;
461 space = spaces.next()) {
462 space->RepairFreeListsAfterBoot();
463 }
464}
465
466
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000467void Heap::GarbageCollectionEpilogue() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000468 store_buffer()->GCEpilogue();
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000469 LiveObjectList::GCEpilogue();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000470
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000471 // In release mode, we only zap the from space under heap verification.
472 if (Heap::ShouldZapGarbage()) {
473 ZapFromSpace();
474 }
475
476#ifdef VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000477 if (FLAG_verify_heap) {
478 Verify();
479 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000480#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000481
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000482#ifdef DEBUG
483 allow_allocation(true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000484 if (FLAG_print_global_handles) isolate_->global_handles()->Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485 if (FLAG_print_handles) PrintHandles();
486 if (FLAG_gc_verbose) Print();
487 if (FLAG_code_stats) ReportCodeStatistics("After GC");
488#endif
489
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000490 isolate_->counters()->alive_after_last_gc()->Set(
491 static_cast<int>(SizeOfObjects()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000492
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000493 isolate_->counters()->symbol_table_capacity()->Set(
494 symbol_table()->Capacity());
495 isolate_->counters()->number_of_symbols()->Set(
496 symbol_table()->NumberOfElements());
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000497
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000498 if (CommittedMemory() > 0) {
499 isolate_->counters()->external_fragmentation_total()->AddSample(
500 static_cast<int>(100 - (SizeOfObjects() * 100.0) / CommittedMemory()));
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000501
502 isolate_->counters()->heap_fraction_map_space()->AddSample(
503 static_cast<int>(
504 (map_space()->CommittedMemory() * 100.0) / CommittedMemory()));
505 isolate_->counters()->heap_fraction_cell_space()->AddSample(
506 static_cast<int>(
507 (cell_space()->CommittedMemory() * 100.0) / CommittedMemory()));
508
509 isolate_->counters()->heap_sample_total_committed()->AddSample(
510 static_cast<int>(CommittedMemory() / KB));
511 isolate_->counters()->heap_sample_total_used()->AddSample(
512 static_cast<int>(SizeOfObjects() / KB));
513 isolate_->counters()->heap_sample_map_space_committed()->AddSample(
514 static_cast<int>(map_space()->CommittedMemory() / KB));
515 isolate_->counters()->heap_sample_cell_space_committed()->AddSample(
516 static_cast<int>(cell_space()->CommittedMemory() / KB));
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000517 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000518
519#define UPDATE_COUNTERS_FOR_SPACE(space) \
520 isolate_->counters()->space##_bytes_available()->Set( \
521 static_cast<int>(space()->Available())); \
522 isolate_->counters()->space##_bytes_committed()->Set( \
523 static_cast<int>(space()->CommittedMemory())); \
524 isolate_->counters()->space##_bytes_used()->Set( \
525 static_cast<int>(space()->SizeOfObjects()));
526#define UPDATE_FRAGMENTATION_FOR_SPACE(space) \
527 if (space()->CommittedMemory() > 0) { \
528 isolate_->counters()->external_fragmentation_##space()->AddSample( \
529 static_cast<int>(100 - \
530 (space()->SizeOfObjects() * 100.0) / space()->CommittedMemory())); \
531 }
532#define UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(space) \
533 UPDATE_COUNTERS_FOR_SPACE(space) \
534 UPDATE_FRAGMENTATION_FOR_SPACE(space)
535
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000536 UPDATE_COUNTERS_FOR_SPACE(new_space)
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000537 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(old_pointer_space)
538 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(old_data_space)
539 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(code_space)
540 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(map_space)
541 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(cell_space)
542 UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE(lo_space)
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000543#undef UPDATE_COUNTERS_FOR_SPACE
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000544#undef UPDATE_FRAGMENTATION_FOR_SPACE
545#undef UPDATE_COUNTERS_AND_FRAGMENTATION_FOR_SPACE
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000546
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000547#if defined(DEBUG)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548 ReportStatisticsAfterGC();
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000549#endif // DEBUG
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000550#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 isolate_->debug()->AfterGarbageCollection();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000552#endif // ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000553}
554
555
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000556void Heap::CollectAllGarbage(int flags, const char* gc_reason) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000557 // Since we are ignoring the return value, the exact choice of space does
558 // not matter, so long as we do not specify NEW_SPACE, which would not
559 // cause a full GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000560 mark_compact_collector_.SetFlags(flags);
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000561 CollectGarbage(OLD_POINTER_SPACE, gc_reason);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000562 mark_compact_collector_.SetFlags(kNoGCFlags);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000563}
564
565
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000566void Heap::CollectAllAvailableGarbage(const char* gc_reason) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000567 // Since we are ignoring the return value, the exact choice of space does
568 // not matter, so long as we do not specify NEW_SPACE, which would not
569 // cause a full GC.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000570 // Major GC would invoke weak handle callbacks on weakly reachable
571 // handles, but won't collect weakly reachable objects until next
572 // major GC. Therefore if we collect aggressively and weak handle callback
573 // has been invoked, we rerun major GC to release objects which become
574 // garbage.
575 // Note: as weak callbacks can execute arbitrary code, we cannot
576 // hope that eventually there will be no weak callbacks invocations.
577 // Therefore stop recollecting after several attempts.
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000578 mark_compact_collector()->SetFlags(kMakeHeapIterableMask |
579 kReduceMemoryFootprintMask);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000580 isolate_->compilation_cache()->Clear();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000581 const int kMaxNumberOfAttempts = 7;
582 for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000583 if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR, gc_reason, NULL)) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000584 break;
585 }
586 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000587 mark_compact_collector()->SetFlags(kNoGCFlags);
danno@chromium.orgc612e022011-11-10 11:38:15 +0000588 new_space_.Shrink();
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000589 UncommitFromSpace();
590 Shrink();
danno@chromium.orgc612e022011-11-10 11:38:15 +0000591 incremental_marking()->UncommitMarkingDeque();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000592}
593
594
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000595bool Heap::CollectGarbage(AllocationSpace space,
596 GarbageCollector collector,
597 const char* gc_reason,
598 const char* collector_reason) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599 // The VM is in the GC state until exiting this function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 VMState state(isolate_, GC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000601
602#ifdef DEBUG
603 // Reset the allocation timeout to the GC interval, but make sure to
604 // allow at least a few allocations after a collection. The reason
605 // for this is that we have a lot of allocation sequences and we
606 // assume that a garbage collection will allow the subsequent
607 // allocation attempts to go through.
608 allocation_timeout_ = Max(6, FLAG_gc_interval);
609#endif
610
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000611 if (collector == SCAVENGER && !incremental_marking()->IsStopped()) {
612 if (FLAG_trace_incremental_marking) {
613 PrintF("[IncrementalMarking] Scavenge during marking.\n");
614 }
615 }
616
617 if (collector == MARK_COMPACTOR &&
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000618 !mark_compact_collector()->abort_incremental_marking() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000619 !incremental_marking()->IsStopped() &&
620 !incremental_marking()->should_hurry() &&
621 FLAG_incremental_marking_steps) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000622 // Make progress in incremental marking.
623 const intptr_t kStepSizeWhenDelayedByScavenge = 1 * MB;
624 incremental_marking()->Step(kStepSizeWhenDelayedByScavenge,
625 IncrementalMarking::NO_GC_VIA_STACK_GUARD);
626 if (!incremental_marking()->IsComplete()) {
627 if (FLAG_trace_incremental_marking) {
628 PrintF("[IncrementalMarking] Delaying MarkSweep.\n");
629 }
630 collector = SCAVENGER;
631 collector_reason = "incremental marking delaying mark-sweep";
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000632 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000633 }
634
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000635 bool next_gc_likely_to_collect_more = false;
636
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000637 { GCTracer tracer(this, gc_reason, collector_reason);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000638 GarbageCollectionPrologue();
kasper.lund7276f142008-07-30 08:49:36 +0000639 // The GC count was incremented in the prologue. Tell the tracer about
640 // it.
641 tracer.set_gc_count(gc_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000642
kasper.lund7276f142008-07-30 08:49:36 +0000643 // Tell the tracer which collector we've selected.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000644 tracer.set_collector(collector);
645
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000646 {
647 HistogramTimerScope histogram_timer_scope(
648 (collector == SCAVENGER) ? isolate_->counters()->gc_scavenger()
649 : isolate_->counters()->gc_compactor());
650 next_gc_likely_to_collect_more =
651 PerformGarbageCollection(collector, &tracer);
652 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000653
654 GarbageCollectionEpilogue();
655 }
656
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000657 // Start incremental marking for the next cycle. The heap snapshot
658 // generator needs incremental marking to stay off after it aborted.
659 if (!mark_compact_collector()->abort_incremental_marking() &&
660 incremental_marking()->IsStopped() &&
661 incremental_marking()->WorthActivating() &&
662 NextGCIsLikelyToBeFull()) {
663 incremental_marking()->Start();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000664 }
665
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000666 return next_gc_likely_to_collect_more;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000667}
668
669
kasper.lund7276f142008-07-30 08:49:36 +0000670void Heap::PerformScavenge() {
rossberg@chromium.org994edf62012-02-06 10:12:55 +0000671 GCTracer tracer(this, NULL, NULL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000672 if (incremental_marking()->IsStopped()) {
673 PerformGarbageCollection(SCAVENGER, &tracer);
674 } else {
675 PerformGarbageCollection(MARK_COMPACTOR, &tracer);
676 }
kasper.lund7276f142008-07-30 08:49:36 +0000677}
678
679
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000680#ifdef VERIFY_HEAP
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000681// Helper class for verifying the symbol table.
682class SymbolTableVerifier : public ObjectVisitor {
683 public:
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000684 void VisitPointers(Object** start, Object** end) {
685 // Visit all HeapObject pointers in [start, end).
686 for (Object** p = start; p < end; p++) {
687 if ((*p)->IsHeapObject()) {
688 // Check that the symbol is actually a symbol.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000689 CHECK((*p)->IsTheHole() || (*p)->IsUndefined() || (*p)->IsSymbol());
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000690 }
691 }
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000692 }
693};
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000694
kasperl@chromium.org416c5b02009-04-14 14:03:52 +0000695
696static void VerifySymbolTable() {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000697 SymbolTableVerifier verifier;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000698 HEAP->symbol_table()->IterateElements(&verifier);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000699}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000700#endif // VERIFY_HEAP
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000701
702
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000703static bool AbortIncrementalMarkingAndCollectGarbage(
704 Heap* heap,
705 AllocationSpace space,
706 const char* gc_reason = NULL) {
707 heap->mark_compact_collector()->SetFlags(Heap::kAbortIncrementalMarkingMask);
708 bool result = heap->CollectGarbage(space, gc_reason);
709 heap->mark_compact_collector()->SetFlags(Heap::kNoGCFlags);
710 return result;
711}
712
713
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000714void Heap::ReserveSpace(
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000715 int *sizes,
716 Address *locations_out) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000717 bool gc_performed = true;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000718 int counter = 0;
719 static const int kThreshold = 20;
720 while (gc_performed && counter++ < kThreshold) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000721 gc_performed = false;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000722 ASSERT(NEW_SPACE == FIRST_PAGED_SPACE - 1);
723 for (int space = NEW_SPACE; space <= LAST_PAGED_SPACE; space++) {
724 if (sizes[space] != 0) {
725 MaybeObject* allocation;
726 if (space == NEW_SPACE) {
727 allocation = new_space()->AllocateRaw(sizes[space]);
728 } else {
729 allocation = paged_space(space)->AllocateRaw(sizes[space]);
730 }
731 FreeListNode* node;
732 if (!allocation->To<FreeListNode>(&node)) {
733 if (space == NEW_SPACE) {
734 Heap::CollectGarbage(NEW_SPACE,
735 "failed to reserve space in the new space");
736 } else {
737 AbortIncrementalMarkingAndCollectGarbage(
738 this,
739 static_cast<AllocationSpace>(space),
740 "failed to reserve space in paged space");
741 }
742 gc_performed = true;
743 break;
744 } else {
745 // Mark with a free list node, in case we have a GC before
746 // deserializing.
747 node->set_size(this, sizes[space]);
748 locations_out[space] = node->address();
749 }
750 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000751 }
752 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000753
754 if (gc_performed) {
755 // Failed to reserve the space after several attempts.
756 V8::FatalProcessOutOfMemory("Heap::ReserveSpace");
757 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000758}
759
760
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000761void Heap::EnsureFromSpaceIsCommitted() {
762 if (new_space_.CommitFromSpaceIfNeeded()) return;
763
764 // Committing memory to from space failed.
765 // Try shrinking and try again.
766 Shrink();
767 if (new_space_.CommitFromSpaceIfNeeded()) return;
768
769 // Committing memory to from space failed again.
770 // Memory is exhausted and we will die.
771 V8::FatalProcessOutOfMemory("Committing semi space failed.");
772}
773
774
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000775void Heap::ClearJSFunctionResultCaches() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000776 if (isolate_->bootstrapper()->IsActive()) return;
ager@chromium.orgac091b72010-05-05 07:34:42 +0000777
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000778 Object* context = native_contexts_list_;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000779 while (!context->IsUndefined()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000780 // Get the caches for this context. GC can happen when the context
781 // is not fully initialized, so the caches can be undefined.
782 Object* caches_or_undefined =
783 Context::cast(context)->get(Context::JSFUNCTION_RESULT_CACHES_INDEX);
784 if (!caches_or_undefined->IsUndefined()) {
785 FixedArray* caches = FixedArray::cast(caches_or_undefined);
786 // Clear the caches:
787 int length = caches->length();
788 for (int i = 0; i < length; i++) {
789 JSFunctionResultCache::cast(caches->get(i))->Clear();
790 }
ager@chromium.orgac091b72010-05-05 07:34:42 +0000791 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000792 // Get the next context:
793 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
ager@chromium.orgac091b72010-05-05 07:34:42 +0000794 }
ager@chromium.orgac091b72010-05-05 07:34:42 +0000795}
796
797
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000798
ricow@chromium.org65fae842010-08-25 15:26:24 +0000799void Heap::ClearNormalizedMapCaches() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000800 if (isolate_->bootstrapper()->IsActive() &&
801 !incremental_marking()->IsMarking()) {
802 return;
803 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000804
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000805 Object* context = native_contexts_list_;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000806 while (!context->IsUndefined()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000807 // GC can happen when the context is not fully initialized,
808 // so the cache can be undefined.
809 Object* cache =
810 Context::cast(context)->get(Context::NORMALIZED_MAP_CACHE_INDEX);
811 if (!cache->IsUndefined()) {
812 NormalizedMapCache::cast(cache)->Clear();
813 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000814 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
815 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000816}
817
818
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000819void Heap::UpdateSurvivalRateTrend(int start_new_space_size) {
820 double survival_rate =
821 (static_cast<double>(young_survivors_after_last_gc_) * 100) /
822 start_new_space_size;
823
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000824 if (survival_rate > kYoungSurvivalRateHighThreshold) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000825 high_survival_rate_period_length_++;
826 } else {
827 high_survival_rate_period_length_ = 0;
828 }
829
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000830 if (survival_rate < kYoungSurvivalRateLowThreshold) {
831 low_survival_rate_period_length_++;
832 } else {
833 low_survival_rate_period_length_ = 0;
834 }
835
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000836 double survival_rate_diff = survival_rate_ - survival_rate;
837
838 if (survival_rate_diff > kYoungSurvivalRateAllowedDeviation) {
839 set_survival_rate_trend(DECREASING);
840 } else if (survival_rate_diff < -kYoungSurvivalRateAllowedDeviation) {
841 set_survival_rate_trend(INCREASING);
842 } else {
843 set_survival_rate_trend(STABLE);
844 }
845
846 survival_rate_ = survival_rate;
847}
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000848
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000849bool Heap::PerformGarbageCollection(GarbageCollector collector,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000850 GCTracer* tracer) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000851 bool next_gc_likely_to_collect_more = false;
852
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000853 if (collector != SCAVENGER) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000854 PROFILE(isolate_, CodeMovingGCEvent());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000855 }
856
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000857#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000858 if (FLAG_verify_heap) {
859 VerifySymbolTable();
860 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000861#endif
862
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863 if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) {
864 ASSERT(!allocation_allowed_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000865 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000866 global_gc_prologue_callback_();
867 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000868
869 GCType gc_type =
870 collector == MARK_COMPACTOR ? kGCTypeMarkSweepCompact : kGCTypeScavenge;
871
872 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
873 if (gc_type & gc_prologue_callbacks_[i].gc_type) {
874 gc_prologue_callbacks_[i].callback(gc_type, kNoGCCallbackFlags);
875 }
876 }
877
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000878 EnsureFromSpaceIsCommitted();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000879
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000880 int start_new_space_size = Heap::new_space()->SizeAsInt();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000881
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000882 if (IsHighSurvivalRate()) {
883 // We speed up the incremental marker if it is running so that it
884 // does not fall behind the rate of promotion, which would cause a
885 // constantly growing old space.
886 incremental_marking()->NotifyOfHighPromotionRate();
887 }
888
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889 if (collector == MARK_COMPACTOR) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000890 // Perform mark-sweep with optional compaction.
kasper.lund7276f142008-07-30 08:49:36 +0000891 MarkCompact(tracer);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000892 sweep_generation_++;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000893 bool high_survival_rate_during_scavenges = IsHighSurvivalRate() &&
894 IsStableOrIncreasingSurvivalTrend();
895
896 UpdateSurvivalRateTrend(start_new_space_size);
897
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000898 size_of_old_gen_at_last_old_space_gc_ = PromotedSpaceSizeOfObjects();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000899
lrn@chromium.org303ada72010-10-27 09:33:13 +0000900 if (high_survival_rate_during_scavenges &&
901 IsStableOrIncreasingSurvivalTrend()) {
902 // Stable high survival rates of young objects both during partial and
903 // full collection indicate that mutator is either building or modifying
904 // a structure with a long lifetime.
905 // In this case we aggressively raise old generation memory limits to
906 // postpone subsequent mark-sweep collection and thus trade memory
907 // space for the mutation speed.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000908 old_gen_limit_factor_ = 2;
909 } else {
910 old_gen_limit_factor_ = 1;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000911 }
912
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000913 old_gen_promotion_limit_ =
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000914 OldGenPromotionLimit(size_of_old_gen_at_last_old_space_gc_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000915 old_gen_allocation_limit_ =
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +0000916 OldGenAllocationLimit(size_of_old_gen_at_last_old_space_gc_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000917
lrn@chromium.org303ada72010-10-27 09:33:13 +0000918 old_gen_exhausted_ = false;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000919 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000920 tracer_ = tracer;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000921 Scavenge();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000922 tracer_ = NULL;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000923
924 UpdateSurvivalRateTrend(start_new_space_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000925 }
ager@chromium.org439e85a2009-08-26 13:15:29 +0000926
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000927 if (!new_space_high_promotion_mode_active_ &&
928 new_space_.Capacity() == new_space_.MaximumCapacity() &&
929 IsStableOrIncreasingSurvivalTrend() &&
930 IsHighSurvivalRate()) {
931 // Stable high survival rates even though young generation is at
932 // maximum capacity indicates that most objects will be promoted.
933 // To decrease scavenger pauses and final mark-sweep pauses, we
934 // have to limit maximal capacity of the young generation.
935 new_space_high_promotion_mode_active_ = true;
936 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000937 PrintPID("Limited new space size due to high promotion rate: %d MB\n",
938 new_space_.InitialCapacity() / MB);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000939 }
940 } else if (new_space_high_promotion_mode_active_ &&
941 IsStableOrDecreasingSurvivalTrend() &&
942 IsLowSurvivalRate()) {
943 // Decreasing low survival rates might indicate that the above high
944 // promotion mode is over and we should allow the young generation
945 // to grow again.
946 new_space_high_promotion_mode_active_ = false;
947 if (FLAG_trace_gc) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000948 PrintPID("Unlimited new space size due to low promotion rate: %d MB\n",
949 new_space_.MaximumCapacity() / MB);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000950 }
951 }
952
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000953 if (new_space_high_promotion_mode_active_ &&
954 new_space_.Capacity() > new_space_.InitialCapacity()) {
955 new_space_.Shrink();
956 }
957
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000958 isolate_->counters()->objs_since_last_young()->Set(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000959
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000960 // Callbacks that fire after this point might trigger nested GCs and
961 // restart incremental marking, the assertion can't be moved down.
962 ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped());
963
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000964 gc_post_processing_depth_++;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000965 { DisableAssertNoAllocation allow_allocation;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000966 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000967 next_gc_likely_to_collect_more =
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000968 isolate_->global_handles()->PostGarbageCollectionProcessing(collector);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000969 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000970 gc_post_processing_depth_--;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000971
ager@chromium.org3811b432009-10-28 14:53:37 +0000972 // Update relocatables.
973 Relocatable::PostGarbageCollectionProcessing();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000974
kasper.lund7276f142008-07-30 08:49:36 +0000975 if (collector == MARK_COMPACTOR) {
976 // Register the amount of external allocated memory.
977 amount_of_external_allocated_memory_at_last_global_gc_ =
978 amount_of_external_allocated_memory_;
979 }
980
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000981 GCCallbackFlags callback_flags = kNoGCCallbackFlags;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000982 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
983 if (gc_type & gc_epilogue_callbacks_[i].gc_type) {
984 gc_epilogue_callbacks_[i].callback(gc_type, callback_flags);
985 }
986 }
987
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) {
989 ASSERT(!allocation_allowed_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000990 GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991 global_gc_epilogue_callback_();
992 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000993
994#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000995 if (FLAG_verify_heap) {
996 VerifySymbolTable();
997 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +0000998#endif
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000999
1000 return next_gc_likely_to_collect_more;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001001}
1002
1003
kasper.lund7276f142008-07-30 08:49:36 +00001004void Heap::MarkCompact(GCTracer* tracer) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001005 gc_state_ = MARK_COMPACT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001006 LOG(isolate_, ResourceEvent("markcompact", "begin"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001008 mark_compact_collector_.Prepare(tracer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001010 ms_count_++;
1011 tracer->set_full_gc_count(ms_count_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001013 MarkCompactPrologue();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001014
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001015 mark_compact_collector_.CollectGarbage();
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001016
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001017 LOG(isolate_, ResourceEvent("markcompact", "end"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018
1019 gc_state_ = NOT_IN_GC;
1020
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001021 isolate_->counters()->objs_since_last_full()->Set(0);
kasperl@chromium.org8b2bb262010-03-01 09:46:28 +00001022
1023 contexts_disposed_ = 0;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001024
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001025 flush_monomorphic_ics_ = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001026}
1027
1028
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001029void Heap::MarkCompactPrologue() {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001030 // At any old GC clear the keyed lookup cache to enable collection of unused
1031 // maps.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001032 isolate_->keyed_lookup_cache()->Clear();
1033 isolate_->context_slot_cache()->Clear();
1034 isolate_->descriptor_lookup_cache()->Clear();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001035 RegExpResultsCache::Clear(string_split_cache());
1036 RegExpResultsCache::Clear(regexp_multiple_cache());
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001037
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001038 isolate_->compilation_cache()->MarkCompactPrologue();
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001039
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001040 CompletelyClearInstanceofCache();
1041
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001042 FlushNumberStringCache();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001043 if (FLAG_cleanup_code_caches_at_gc) {
1044 polymorphic_code_cache()->set_cache(undefined_value());
1045 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00001046
1047 ClearNormalizedMapCaches();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048}
1049
1050
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051Object* Heap::FindCodeObject(Address a) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001052 return isolate()->inner_pointer_to_code_cache()->
1053 GcSafeFindCodeForInnerPointer(a);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001054}
1055
1056
1057// Helper class for copying HeapObjects
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001058class ScavengeVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001059 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 explicit ScavengeVisitor(Heap* heap) : heap_(heap) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001061
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001062 void VisitPointer(Object** p) { ScavengePointer(p); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001063
1064 void VisitPointers(Object** start, Object** end) {
1065 // Copy all HeapObject pointers in [start, end)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001066 for (Object** p = start; p < end; p++) ScavengePointer(p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001067 }
1068
1069 private:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001070 void ScavengePointer(Object** p) {
1071 Object* object = *p;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001072 if (!heap_->InNewSpace(object)) return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001073 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
1074 reinterpret_cast<HeapObject*>(object));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001076
1077 Heap* heap_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078};
1079
1080
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001081#ifdef VERIFY_HEAP
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001082// Visitor class to verify pointers in code or data space do not point into
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001083// new space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001084class VerifyNonPointerSpacePointersVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085 public:
1086 void VisitPointers(Object** start, Object**end) {
1087 for (Object** current = start; current < end; current++) {
1088 if ((*current)->IsHeapObject()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001089 CHECK(!HEAP->InNewSpace(HeapObject::cast(*current)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001090 }
1091 }
1092 }
1093};
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001094
1095
1096static void VerifyNonPointerSpacePointers() {
1097 // Verify that there are no pointers to new space in spaces where we
1098 // do not expect them.
1099 VerifyNonPointerSpacePointersVisitor v;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001100 HeapObjectIterator code_it(HEAP->code_space());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001101 for (HeapObject* object = code_it.Next();
1102 object != NULL; object = code_it.Next())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001103 object->Iterate(&v);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001104
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001105 // The old data space was normally swept conservatively so that the iterator
1106 // doesn't work, so we normally skip the next bit.
1107 if (!HEAP->old_data_space()->was_swept_conservatively()) {
1108 HeapObjectIterator data_it(HEAP->old_data_space());
1109 for (HeapObject* object = data_it.Next();
1110 object != NULL; object = data_it.Next())
1111 object->Iterate(&v);
1112 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001113}
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001114#endif // VERIFY_HEAP
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001115
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001116
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001117void Heap::CheckNewSpaceExpansionCriteria() {
1118 if (new_space_.Capacity() < new_space_.MaximumCapacity() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001119 survived_since_last_expansion_ > new_space_.Capacity() &&
1120 !new_space_high_promotion_mode_active_) {
1121 // Grow the size of new space if there is room to grow, enough data
1122 // has survived scavenge since the last expansion and we are not in
1123 // high promotion mode.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001124 new_space_.Grow();
1125 survived_since_last_expansion_ = 0;
1126 }
1127}
1128
1129
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001130static bool IsUnscavengedHeapObject(Heap* heap, Object** p) {
1131 return heap->InNewSpace(*p) &&
1132 !HeapObject::cast(*p)->map_word().IsForwardingAddress();
1133}
1134
1135
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001136void Heap::ScavengeStoreBufferCallback(
1137 Heap* heap,
1138 MemoryChunk* page,
1139 StoreBufferEvent event) {
1140 heap->store_buffer_rebuilder_.Callback(page, event);
1141}
1142
1143
1144void StoreBufferRebuilder::Callback(MemoryChunk* page, StoreBufferEvent event) {
1145 if (event == kStoreBufferStartScanningPagesEvent) {
1146 start_of_current_page_ = NULL;
1147 current_page_ = NULL;
1148 } else if (event == kStoreBufferScanningPageEvent) {
1149 if (current_page_ != NULL) {
1150 // If this page already overflowed the store buffer during this iteration.
1151 if (current_page_->scan_on_scavenge()) {
1152 // Then we should wipe out the entries that have been added for it.
1153 store_buffer_->SetTop(start_of_current_page_);
1154 } else if (store_buffer_->Top() - start_of_current_page_ >=
1155 (store_buffer_->Limit() - store_buffer_->Top()) >> 2) {
1156 // Did we find too many pointers in the previous page? The heuristic is
1157 // that no page can take more then 1/5 the remaining slots in the store
1158 // buffer.
1159 current_page_->set_scan_on_scavenge(true);
1160 store_buffer_->SetTop(start_of_current_page_);
1161 } else {
1162 // In this case the page we scanned took a reasonable number of slots in
1163 // the store buffer. It has now been rehabilitated and is no longer
1164 // marked scan_on_scavenge.
1165 ASSERT(!current_page_->scan_on_scavenge());
1166 }
1167 }
1168 start_of_current_page_ = store_buffer_->Top();
1169 current_page_ = page;
1170 } else if (event == kStoreBufferFullEvent) {
1171 // The current page overflowed the store buffer again. Wipe out its entries
1172 // in the store buffer and mark it scan-on-scavenge again. This may happen
1173 // several times while scanning.
1174 if (current_page_ == NULL) {
1175 // Store Buffer overflowed while scanning promoted objects. These are not
1176 // in any particular page, though they are likely to be clustered by the
1177 // allocation routines.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001178 store_buffer_->EnsureSpace(StoreBuffer::kStoreBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001179 } else {
1180 // Store Buffer overflowed while scanning a particular old space page for
1181 // pointers to new space.
1182 ASSERT(current_page_ == page);
1183 ASSERT(page != NULL);
1184 current_page_->set_scan_on_scavenge(true);
1185 ASSERT(start_of_current_page_ != store_buffer_->Top());
1186 store_buffer_->SetTop(start_of_current_page_);
1187 }
1188 } else {
1189 UNREACHABLE();
1190 }
1191}
1192
1193
danno@chromium.orgc612e022011-11-10 11:38:15 +00001194void PromotionQueue::Initialize() {
1195 // Assumes that a NewSpacePage exactly fits a number of promotion queue
1196 // entries (where each is a pair of intptr_t). This allows us to simplify
1197 // the test fpr when to switch pages.
1198 ASSERT((Page::kPageSize - MemoryChunk::kBodyOffset) % (2 * kPointerSize)
1199 == 0);
1200 limit_ = reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceStart());
1201 front_ = rear_ =
1202 reinterpret_cast<intptr_t*>(heap_->new_space()->ToSpaceEnd());
1203 emergency_stack_ = NULL;
1204 guard_ = false;
1205}
1206
1207
1208void PromotionQueue::RelocateQueueHead() {
1209 ASSERT(emergency_stack_ == NULL);
1210
1211 Page* p = Page::FromAllocationTop(reinterpret_cast<Address>(rear_));
1212 intptr_t* head_start = rear_;
1213 intptr_t* head_end =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001214 Min(front_, reinterpret_cast<intptr_t*>(p->area_end()));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001215
1216 int entries_count =
1217 static_cast<int>(head_end - head_start) / kEntrySizeInWords;
1218
1219 emergency_stack_ = new List<Entry>(2 * entries_count);
1220
1221 while (head_start != head_end) {
1222 int size = static_cast<int>(*(head_start++));
1223 HeapObject* obj = reinterpret_cast<HeapObject*>(*(head_start++));
1224 emergency_stack_->Add(Entry(obj, size));
1225 }
1226 rear_ = head_end;
1227}
1228
1229
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001230class ScavengeWeakObjectRetainer : public WeakObjectRetainer {
1231 public:
1232 explicit ScavengeWeakObjectRetainer(Heap* heap) : heap_(heap) { }
1233
1234 virtual Object* RetainAs(Object* object) {
1235 if (!heap_->InFromSpace(object)) {
1236 return object;
1237 }
1238
1239 MapWord map_word = HeapObject::cast(object)->map_word();
1240 if (map_word.IsForwardingAddress()) {
1241 return map_word.ToForwardingAddress();
1242 }
1243 return NULL;
1244 }
1245
1246 private:
1247 Heap* heap_;
1248};
1249
1250
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001251void Heap::Scavenge() {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001252 RelocationLock relocation_lock(this);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001253
1254#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001255 if (FLAG_verify_heap) VerifyNonPointerSpacePointers();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256#endif
1257
1258 gc_state_ = SCAVENGE;
1259
1260 // Implements Cheney's copying algorithm
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001261 LOG(isolate_, ResourceEvent("scavenge", "begin"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001262
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001263 // Clear descriptor cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001264 isolate_->descriptor_lookup_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001265
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001266 // Used for updating survived_since_last_expansion_ at function end.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001267 intptr_t survived_watermark = PromotedSpaceSizeOfObjects();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001268
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001269 CheckNewSpaceExpansionCriteria();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001271 SelectScavengingVisitorsTable();
1272
1273 incremental_marking()->PrepareForScavenge();
1274
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001275 AdvanceSweepers(static_cast<int>(new_space_.Size()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001276
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 // Flip the semispaces. After flipping, to space is empty, from space has
1278 // live objects.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001279 new_space_.Flip();
1280 new_space_.ResetAllocationInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001282 // We need to sweep newly copied objects which can be either in the
1283 // to space or promoted to the old generation. For to-space
1284 // objects, we treat the bottom of the to space as a queue. Newly
1285 // copied and unswept objects lie between a 'front' mark and the
1286 // allocation pointer.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287 //
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001288 // Promoted objects can go into various old-generation spaces, and
1289 // can be allocated internally in the spaces (from the free list).
1290 // We treat the top of the to space as a queue of addresses of
1291 // promoted objects. The addresses of newly promoted and unswept
1292 // objects lie between a 'front' mark and a 'rear' mark that is
1293 // updated as a side effect of promoting an object.
1294 //
1295 // There is guaranteed to be enough room at the top of the to space
1296 // for the addresses of promoted objects: every object promoted
1297 // frees up its size in bytes from the top of the new space, and
1298 // objects are at least one pointer in size.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001299 Address new_space_front = new_space_.ToSpaceStart();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001300 promotion_queue_.Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001301
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001302#ifdef DEBUG
1303 store_buffer()->Clean();
1304#endif
1305
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001306 ScavengeVisitor scavenge_visitor(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307 // Copy roots.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001308 IterateRoots(&scavenge_visitor, VISIT_ALL_IN_SCAVENGE);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001309
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001310 // Copy objects reachable from the old generation.
1311 {
1312 StoreBufferRebuildScope scope(this,
1313 store_buffer(),
1314 &ScavengeStoreBufferCallback);
1315 store_buffer()->IteratePointersToNewSpace(&ScavengeObject);
1316 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001317
1318 // Copy objects reachable from cells by scavenging cell values directly.
1319 HeapObjectIterator cell_iterator(cell_space_);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001320 for (HeapObject* heap_object = cell_iterator.Next();
1321 heap_object != NULL;
1322 heap_object = cell_iterator.Next()) {
1323 if (heap_object->IsJSGlobalPropertyCell()) {
1324 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(heap_object);
1325 Address value_address = cell->ValueAddress();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001326 scavenge_visitor.VisitPointer(reinterpret_cast<Object**>(value_address));
1327 }
1328 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001330 // Copy objects reachable from the code flushing candidates list.
1331 MarkCompactCollector* collector = mark_compact_collector();
1332 if (collector->is_code_flushing_enabled()) {
1333 collector->code_flusher()->IteratePointersToFromSpace(&scavenge_visitor);
1334 }
1335
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001336 // Scavenge object reachable from the native contexts list directly.
1337 scavenge_visitor.VisitPointer(BitCast<Object**>(&native_contexts_list_));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001338
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001339 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001340
1341 while (IterateObjectGroups(&scavenge_visitor)) {
1342 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
1343 }
1344 isolate()->global_handles()->RemoveObjectGroups();
1345
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001346 isolate_->global_handles()->IdentifyNewSpaceWeakIndependentHandles(
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001347 &IsUnscavengedHeapObject);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001348 isolate_->global_handles()->IterateNewSpaceWeakIndependentRoots(
1349 &scavenge_visitor);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001350 new_space_front = DoScavenge(&scavenge_visitor, new_space_front);
1351
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001352 UpdateNewSpaceReferencesInExternalStringTable(
1353 &UpdateNewSpaceReferenceInExternalStringTableEntry);
1354
danno@chromium.orgc612e022011-11-10 11:38:15 +00001355 promotion_queue_.Destroy();
1356
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001357 LiveObjectList::UpdateReferencesForScavengeGC();
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001358 if (!FLAG_watch_ic_patching) {
1359 isolate()->runtime_profiler()->UpdateSamplesAfterScavenge();
1360 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001361 incremental_marking()->UpdateMarkingDequeAfterScavenge();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001362
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001363 ScavengeWeakObjectRetainer weak_object_retainer(this);
1364 ProcessWeakReferences(&weak_object_retainer);
1365
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001366 ASSERT(new_space_front == new_space_.top());
1367
1368 // Set age mark.
1369 new_space_.set_age_mark(new_space_.top());
1370
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001371 new_space_.LowerInlineAllocationLimit(
1372 new_space_.inline_allocation_limit_step());
1373
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001374 // Update how much has survived scavenge.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001375 IncrementYoungSurvivorsCounter(static_cast<int>(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001376 (PromotedSpaceSizeOfObjects() - survived_watermark) + new_space_.Size()));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001377
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001378 LOG(isolate_, ResourceEvent("scavenge", "end"));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001379
1380 gc_state_ = NOT_IN_GC;
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001381
1382 scavenges_since_last_idle_round_++;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001383}
1384
1385
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001386// TODO(mstarzinger): Unify this method with
1387// MarkCompactCollector::MarkObjectGroups().
1388bool Heap::IterateObjectGroups(ObjectVisitor* scavenge_visitor) {
1389 List<ObjectGroup*>* object_groups =
1390 isolate()->global_handles()->object_groups();
1391
1392 int last = 0;
1393 bool changed = false;
1394 for (int i = 0; i < object_groups->length(); i++) {
1395 ObjectGroup* entry = object_groups->at(i);
1396 ASSERT(entry != NULL);
1397
1398 Object*** objects = entry->objects_;
1399 bool group_marked = false;
1400 for (size_t j = 0; j < entry->length_; j++) {
1401 Object* object = *objects[j];
1402 if (object->IsHeapObject()) {
1403 if (!IsUnscavengedHeapObject(this, &object)) {
1404 group_marked = true;
1405 break;
1406 }
1407 }
1408 }
1409
1410 if (!group_marked) {
1411 (*object_groups)[last++] = entry;
1412 continue;
1413 }
1414
1415 for (size_t j = 0; j < entry->length_; ++j) {
1416 Object* object = *objects[j];
1417 if (object->IsHeapObject()) {
1418 scavenge_visitor->VisitPointer(&object);
1419 changed = true;
1420 }
1421 }
1422
1423 entry->Dispose();
1424 object_groups->at(i) = NULL;
1425 }
1426 object_groups->Rewind(last);
1427 return changed;
1428}
1429
1430
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001431String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
1432 Object** p) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001433 MapWord first_word = HeapObject::cast(*p)->map_word();
1434
1435 if (!first_word.IsForwardingAddress()) {
1436 // Unreachable external string can be finalized.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001437 heap->FinalizeExternalString(String::cast(*p));
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001438 return NULL;
1439 }
1440
1441 // String is still reachable.
1442 return String::cast(first_word.ToForwardingAddress());
1443}
1444
1445
1446void Heap::UpdateNewSpaceReferencesInExternalStringTable(
1447 ExternalStringTableUpdaterCallback updater_func) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001448#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001449 if (FLAG_verify_heap) {
1450 external_string_table_.Verify();
1451 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001452#endif
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001453
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001454 if (external_string_table_.new_space_strings_.is_empty()) return;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001455
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001456 Object** start = &external_string_table_.new_space_strings_[0];
1457 Object** end = start + external_string_table_.new_space_strings_.length();
1458 Object** last = start;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001459
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001460 for (Object** p = start; p < end; ++p) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001461 ASSERT(InFromSpace(*p));
1462 String* target = updater_func(this, p);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001463
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001464 if (target == NULL) continue;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001465
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001466 ASSERT(target->IsExternalString());
1467
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001468 if (InNewSpace(target)) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001469 // String is still in new space. Update the table entry.
1470 *last = target;
1471 ++last;
1472 } else {
1473 // String got promoted. Move it to the old string list.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001474 external_string_table_.AddOldString(target);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001475 }
1476 }
1477
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001478 ASSERT(last <= end);
1479 external_string_table_.ShrinkNewStrings(static_cast<int>(last - start));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001480}
1481
1482
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001483void Heap::UpdateReferencesInExternalStringTable(
1484 ExternalStringTableUpdaterCallback updater_func) {
1485
1486 // Update old space string references.
1487 if (external_string_table_.old_space_strings_.length() > 0) {
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00001488 Object** start = &external_string_table_.old_space_strings_[0];
1489 Object** end = start + external_string_table_.old_space_strings_.length();
1490 for (Object** p = start; p < end; ++p) *p = updater_func(this, p);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001491 }
1492
1493 UpdateNewSpaceReferencesInExternalStringTable(updater_func);
1494}
1495
1496
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001497static Object* ProcessFunctionWeakReferences(Heap* heap,
1498 Object* function,
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001499 WeakObjectRetainer* retainer,
1500 bool record_slots) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 Object* undefined = heap->undefined_value();
1502 Object* head = undefined;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001503 JSFunction* tail = NULL;
1504 Object* candidate = function;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001505 while (candidate != undefined) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001506 // Check whether to keep the candidate in the list.
1507 JSFunction* candidate_function = reinterpret_cast<JSFunction*>(candidate);
1508 Object* retain = retainer->RetainAs(candidate);
1509 if (retain != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001510 if (head == undefined) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001511 // First element in the list.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001512 head = retain;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001513 } else {
1514 // Subsequent elements in the list.
1515 ASSERT(tail != NULL);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001516 tail->set_next_function_link(retain);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001517 if (record_slots) {
1518 Object** next_function =
1519 HeapObject::RawField(tail, JSFunction::kNextFunctionLinkOffset);
1520 heap->mark_compact_collector()->RecordSlot(
1521 next_function, next_function, retain);
1522 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001523 }
1524 // Retained function is new tail.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001525 candidate_function = reinterpret_cast<JSFunction*>(retain);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001526 tail = candidate_function;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001527
1528 ASSERT(retain->IsUndefined() || retain->IsJSFunction());
1529
1530 if (retain == undefined) break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001531 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001532
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001533 // Move to next element in the list.
1534 candidate = candidate_function->next_function_link();
1535 }
1536
1537 // Terminate the list if there is one or more elements.
1538 if (tail != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001539 tail->set_next_function_link(undefined);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001540 }
1541
1542 return head;
1543}
1544
1545
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001546void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001547 Object* undefined = undefined_value();
1548 Object* head = undefined;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001549 Context* tail = NULL;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001550 Object* candidate = native_contexts_list_;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001551
1552 // We don't record weak slots during marking or scavenges.
1553 // Instead we do it once when we complete mark-compact cycle.
1554 // Note that write barrier has no effect if we are already in the middle of
1555 // compacting mark-sweep cycle and we have to record slots manually.
1556 bool record_slots =
1557 gc_state() == MARK_COMPACT &&
1558 mark_compact_collector()->is_compacting();
1559
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001560 while (candidate != undefined) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001561 // Check whether to keep the candidate in the list.
1562 Context* candidate_context = reinterpret_cast<Context*>(candidate);
1563 Object* retain = retainer->RetainAs(candidate);
1564 if (retain != NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001565 if (head == undefined) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001566 // First element in the list.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001567 head = retain;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001568 } else {
1569 // Subsequent elements in the list.
1570 ASSERT(tail != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001571 tail->set_unchecked(this,
1572 Context::NEXT_CONTEXT_LINK,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001573 retain,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001574 UPDATE_WRITE_BARRIER);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001575
1576 if (record_slots) {
1577 Object** next_context =
1578 HeapObject::RawField(
1579 tail, FixedArray::SizeFor(Context::NEXT_CONTEXT_LINK));
1580 mark_compact_collector()->RecordSlot(
1581 next_context, next_context, retain);
1582 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001583 }
1584 // Retained context is new tail.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001585 candidate_context = reinterpret_cast<Context*>(retain);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001586 tail = candidate_context;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001587
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001588 if (retain == undefined) break;
1589
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001590 // Process the weak list of optimized functions for the context.
1591 Object* function_list_head =
1592 ProcessFunctionWeakReferences(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001593 this,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001594 candidate_context->get(Context::OPTIMIZED_FUNCTIONS_LIST),
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001595 retainer,
1596 record_slots);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001597 candidate_context->set_unchecked(this,
1598 Context::OPTIMIZED_FUNCTIONS_LIST,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001599 function_list_head,
1600 UPDATE_WRITE_BARRIER);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001601 if (record_slots) {
1602 Object** optimized_functions =
1603 HeapObject::RawField(
1604 tail, FixedArray::SizeFor(Context::OPTIMIZED_FUNCTIONS_LIST));
1605 mark_compact_collector()->RecordSlot(
1606 optimized_functions, optimized_functions, function_list_head);
1607 }
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001608 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001609
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001610 // Move to next element in the list.
1611 candidate = candidate_context->get(Context::NEXT_CONTEXT_LINK);
1612 }
1613
1614 // Terminate the list if there is one or more elements.
1615 if (tail != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001616 tail->set_unchecked(this,
1617 Context::NEXT_CONTEXT_LINK,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001618 Heap::undefined_value(),
1619 UPDATE_WRITE_BARRIER);
1620 }
1621
1622 // Update the head of the list of contexts.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001623 native_contexts_list_ = head;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001624}
1625
1626
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001627void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) {
1628 AssertNoAllocation no_allocation;
1629
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001630 // Both the external string table and the symbol table may contain
1631 // external strings, but neither lists them exhaustively, nor is the
1632 // intersection set empty. Therefore we iterate over the external string
1633 // table first, ignoring symbols, and then over the symbol table.
1634
1635 class ExternalStringTableVisitorAdapter : public ObjectVisitor {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001636 public:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001637 explicit ExternalStringTableVisitorAdapter(
1638 v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001639 virtual void VisitPointers(Object** start, Object** end) {
1640 for (Object** p = start; p < end; p++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001641 // Visit non-symbol external strings,
1642 // since symbols are listed in the symbol table.
1643 if (!(*p)->IsSymbol()) {
1644 ASSERT((*p)->IsExternalString());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001645 visitor_->VisitExternalString(Utils::ToLocal(
1646 Handle<String>(String::cast(*p))));
1647 }
1648 }
1649 }
1650 private:
1651 v8::ExternalResourceVisitor* visitor_;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001652 } external_string_table_visitor(visitor);
1653
1654 external_string_table_.Iterate(&external_string_table_visitor);
1655
1656 class SymbolTableVisitorAdapter : public ObjectVisitor {
1657 public:
1658 explicit SymbolTableVisitorAdapter(
1659 v8::ExternalResourceVisitor* visitor) : visitor_(visitor) {}
1660 virtual void VisitPointers(Object** start, Object** end) {
1661 for (Object** p = start; p < end; p++) {
1662 if ((*p)->IsExternalString()) {
1663 ASSERT((*p)->IsSymbol());
1664 visitor_->VisitExternalString(Utils::ToLocal(
1665 Handle<String>(String::cast(*p))));
1666 }
1667 }
1668 }
1669 private:
1670 v8::ExternalResourceVisitor* visitor_;
1671 } symbol_table_visitor(visitor);
1672
1673 symbol_table()->IterateElements(&symbol_table_visitor);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001674}
1675
1676
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001677class NewSpaceScavenger : public StaticNewSpaceVisitor<NewSpaceScavenger> {
1678 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001679 static inline void VisitPointer(Heap* heap, Object** p) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001680 Object* object = *p;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 if (!heap->InNewSpace(object)) return;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001682 Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p),
1683 reinterpret_cast<HeapObject*>(object));
1684 }
1685};
1686
1687
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001688Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor,
1689 Address new_space_front) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001690 do {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001691 SemiSpace::AssertValidRange(new_space_front, new_space_.top());
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001692 // The addresses new_space_front and new_space_.top() define a
1693 // queue of unprocessed copied objects. Process them until the
1694 // queue is empty.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001695 while (new_space_front != new_space_.top()) {
1696 if (!NewSpacePage::IsAtEnd(new_space_front)) {
1697 HeapObject* object = HeapObject::FromAddress(new_space_front);
1698 new_space_front +=
1699 NewSpaceScavenger::IterateBody(object->map(), object);
1700 } else {
1701 new_space_front =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001702 NewSpacePage::FromLimit(new_space_front)->next_page()->area_start();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001703 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001704 }
1705
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001706 // Promote and process all the to-be-promoted objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001707 {
1708 StoreBufferRebuildScope scope(this,
1709 store_buffer(),
1710 &ScavengeStoreBufferCallback);
1711 while (!promotion_queue()->is_empty()) {
1712 HeapObject* target;
1713 int size;
1714 promotion_queue()->remove(&target, &size);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001715
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001716 // Promoted object might be already partially visited
1717 // during old space pointer iteration. Thus we search specificly
1718 // for pointers to from semispace instead of looking for pointers
1719 // to new space.
1720 ASSERT(!target->IsMap());
1721 IterateAndMarkPointersToFromSpace(target->address(),
1722 target->address() + size,
1723 &ScavengeObject);
1724 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001725 }
1726
1727 // Take another spin if there are now unswept objects in new space
1728 // (there are currently no more unswept promoted objects).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001729 } while (new_space_front != new_space_.top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001730
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001731 return new_space_front;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001732}
1733
1734
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001735STATIC_ASSERT((FixedDoubleArray::kHeaderSize & kDoubleAlignmentMask) == 0);
1736
1737
1738INLINE(static HeapObject* EnsureDoubleAligned(Heap* heap,
1739 HeapObject* object,
1740 int size));
1741
1742static HeapObject* EnsureDoubleAligned(Heap* heap,
1743 HeapObject* object,
1744 int size) {
1745 if ((OffsetFrom(object->address()) & kDoubleAlignmentMask) != 0) {
1746 heap->CreateFillerObjectAt(object->address(), kPointerSize);
1747 return HeapObject::FromAddress(object->address() + kPointerSize);
1748 } else {
1749 heap->CreateFillerObjectAt(object->address() + size - kPointerSize,
1750 kPointerSize);
1751 return object;
1752 }
1753}
1754
1755
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001756enum LoggingAndProfiling {
1757 LOGGING_AND_PROFILING_ENABLED,
1758 LOGGING_AND_PROFILING_DISABLED
1759};
1760
1761
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001762enum MarksHandling { TRANSFER_MARKS, IGNORE_MARKS };
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001763
1764
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001765template<MarksHandling marks_handling,
1766 LoggingAndProfiling logging_and_profiling_mode>
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001767class ScavengingVisitor : public StaticVisitorBase {
1768 public:
1769 static void Initialize() {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001770 table_.Register(kVisitSeqOneByteString, &EvacuateSeqOneByteString);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001771 table_.Register(kVisitSeqTwoByteString, &EvacuateSeqTwoByteString);
1772 table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate);
1773 table_.Register(kVisitByteArray, &EvacuateByteArray);
1774 table_.Register(kVisitFixedArray, &EvacuateFixedArray);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001775 table_.Register(kVisitFixedDoubleArray, &EvacuateFixedDoubleArray);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001776
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001777 table_.Register(kVisitNativeContext,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001778 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001779 template VisitSpecialized<Context::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001780
1781 table_.Register(kVisitConsString,
1782 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001783 template VisitSpecialized<ConsString::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001784
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001785 table_.Register(kVisitSlicedString,
1786 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1787 template VisitSpecialized<SlicedString::kSize>);
1788
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001789 table_.Register(kVisitSharedFunctionInfo,
1790 &ObjectEvacuationStrategy<POINTER_OBJECT>::
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001791 template VisitSpecialized<SharedFunctionInfo::kSize>);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001792
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001793 table_.Register(kVisitJSWeakMap,
1794 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1795 Visit);
1796
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001797 table_.Register(kVisitJSRegExp,
1798 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1799 Visit);
1800
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001801 if (marks_handling == IGNORE_MARKS) {
1802 table_.Register(kVisitJSFunction,
1803 &ObjectEvacuationStrategy<POINTER_OBJECT>::
1804 template VisitSpecialized<JSFunction::kSize>);
1805 } else {
1806 table_.Register(kVisitJSFunction, &EvacuateJSFunction);
1807 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001808
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001809 table_.RegisterSpecializations<ObjectEvacuationStrategy<DATA_OBJECT>,
1810 kVisitDataObject,
1811 kVisitDataObjectGeneric>();
1812
1813 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>,
1814 kVisitJSObject,
1815 kVisitJSObjectGeneric>();
1816
1817 table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>,
1818 kVisitStruct,
1819 kVisitStructGeneric>();
1820 }
1821
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001822 static VisitorDispatchTable<ScavengingCallback>* GetTable() {
1823 return &table_;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001824 }
1825
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001826 private:
1827 enum ObjectContents { DATA_OBJECT, POINTER_OBJECT };
1828 enum SizeRestriction { SMALL, UNKNOWN_SIZE };
1829
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001830 static void RecordCopiedObject(Heap* heap, HeapObject* obj) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001831 bool should_record = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001832#ifdef DEBUG
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001833 should_record = FLAG_heap_stats;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001834#endif
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001835 should_record = should_record || FLAG_log_gc;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001836 if (should_record) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001837 if (heap->new_space()->Contains(obj)) {
1838 heap->new_space()->RecordAllocation(obj);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001839 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 heap->new_space()->RecordPromotion(obj);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001841 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001842 }
1843 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001844
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001845 // Helper function used by CopyObject to copy a source object to an
1846 // allocated target object and update the forwarding pointer in the source
1847 // object. Returns the target object.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001848 INLINE(static void MigrateObject(Heap* heap,
1849 HeapObject* source,
1850 HeapObject* target,
1851 int size)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001852 // Copy the content of source to target.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001853 heap->CopyBlock(target->address(), source->address(), size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001854
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001855 // Set the forwarding address.
1856 source->set_map_word(MapWord::FromForwardingAddress(target));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001857
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001858 if (logging_and_profiling_mode == LOGGING_AND_PROFILING_ENABLED) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001859 // Update NewSpace stats if necessary.
1860 RecordCopiedObject(heap, target);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001861 HEAP_PROFILE(heap, ObjectMoveEvent(source->address(), target->address()));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001862 Isolate* isolate = heap->isolate();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001863 if (isolate->logger()->is_logging_code_events() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001864 CpuProfiler::is_profiling(isolate)) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001865 if (target->IsSharedFunctionInfo()) {
1866 PROFILE(isolate, SharedFunctionInfoMoveEvent(
1867 source->address(), target->address()));
1868 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001869 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001870 }
1871
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001872 if (marks_handling == TRANSFER_MARKS) {
1873 if (Marking::TransferColor(source, target)) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001874 MemoryChunk::IncrementLiveBytesFromGC(target->address(), size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001875 }
1876 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001877 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001878
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001879
1880 template<ObjectContents object_contents,
1881 SizeRestriction size_restriction,
1882 int alignment>
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001883 static inline void EvacuateObject(Map* map,
1884 HeapObject** slot,
1885 HeapObject* object,
1886 int object_size) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001887 SLOW_ASSERT((size_restriction != SMALL) ||
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001888 (object_size <= Page::kMaxNonCodeHeapObjectSize));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001889 SLOW_ASSERT(object->Size() == object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001890
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001891 int allocation_size = object_size;
1892 if (alignment != kObjectAlignment) {
1893 ASSERT(alignment == kDoubleAlignment);
1894 allocation_size += kPointerSize;
1895 }
1896
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001897 Heap* heap = map->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001898 if (heap->ShouldBePromoted(object->address(), object_size)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001899 MaybeObject* maybe_result;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001900
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001901 if ((size_restriction != SMALL) &&
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001902 (allocation_size > Page::kMaxNonCodeHeapObjectSize)) {
1903 maybe_result = heap->lo_space()->AllocateRaw(allocation_size,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001904 NOT_EXECUTABLE);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001905 } else {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001906 if (object_contents == DATA_OBJECT) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001907 maybe_result = heap->old_data_space()->AllocateRaw(allocation_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001908 } else {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001909 maybe_result =
1910 heap->old_pointer_space()->AllocateRaw(allocation_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001911 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001912 }
1913
lrn@chromium.org303ada72010-10-27 09:33:13 +00001914 Object* result = NULL; // Initialization to please compiler.
1915 if (maybe_result->ToObject(&result)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001916 HeapObject* target = HeapObject::cast(result);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001917
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001918 if (alignment != kObjectAlignment) {
1919 target = EnsureDoubleAligned(heap, target, allocation_size);
1920 }
1921
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001922 // Order is important: slot might be inside of the target if target
1923 // was allocated over a dead object and slot comes from the store
1924 // buffer.
1925 *slot = target;
1926 MigrateObject(heap, object, target, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001927
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001928 if (object_contents == POINTER_OBJECT) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001929 if (map->instance_type() == JS_FUNCTION_TYPE) {
1930 heap->promotion_queue()->insert(
1931 target, JSFunction::kNonWeakFieldsEndOffset);
1932 } else {
1933 heap->promotion_queue()->insert(target, object_size);
1934 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001935 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001936
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001937 heap->tracer()->increment_promoted_objects_size(object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001938 return;
1939 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001940 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001941 MaybeObject* allocation = heap->new_space()->AllocateRaw(allocation_size);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001942 heap->promotion_queue()->SetNewLimit(heap->new_space()->top());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001943 Object* result = allocation->ToObjectUnchecked();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001944 HeapObject* target = HeapObject::cast(result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001945
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001946 if (alignment != kObjectAlignment) {
1947 target = EnsureDoubleAligned(heap, target, allocation_size);
1948 }
1949
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001950 // Order is important: slot might be inside of the target if target
1951 // was allocated over a dead object and slot comes from the store
1952 // buffer.
1953 *slot = target;
1954 MigrateObject(heap, object, target, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001955 return;
1956 }
1957
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001958
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001959 static inline void EvacuateJSFunction(Map* map,
1960 HeapObject** slot,
1961 HeapObject* object) {
1962 ObjectEvacuationStrategy<POINTER_OBJECT>::
1963 template VisitSpecialized<JSFunction::kSize>(map, slot, object);
1964
1965 HeapObject* target = *slot;
1966 MarkBit mark_bit = Marking::MarkBitFrom(target);
1967 if (Marking::IsBlack(mark_bit)) {
1968 // This object is black and it might not be rescanned by marker.
1969 // We should explicitly record code entry slot for compaction because
1970 // promotion queue processing (IterateAndMarkPointersToFromSpace) will
1971 // miss it as it is not HeapObject-tagged.
1972 Address code_entry_slot =
1973 target->address() + JSFunction::kCodeEntryOffset;
1974 Code* code = Code::cast(Code::GetObjectFromEntryAddress(code_entry_slot));
1975 map->GetHeap()->mark_compact_collector()->
1976 RecordCodeEntrySlot(code_entry_slot, code);
1977 }
1978 }
1979
1980
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001981 static inline void EvacuateFixedArray(Map* map,
1982 HeapObject** slot,
1983 HeapObject* object) {
1984 int object_size = FixedArray::BodyDescriptor::SizeOf(map, object);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001985 EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(map,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001986 slot,
1987 object,
1988 object_size);
1989 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001990
1991
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001992 static inline void EvacuateFixedDoubleArray(Map* map,
1993 HeapObject** slot,
1994 HeapObject* object) {
1995 int length = reinterpret_cast<FixedDoubleArray*>(object)->length();
1996 int object_size = FixedDoubleArray::SizeFor(length);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001997 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kDoubleAlignment>(
1998 map,
1999 slot,
2000 object,
2001 object_size);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002002 }
2003
2004
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002005 static inline void EvacuateByteArray(Map* map,
2006 HeapObject** slot,
2007 HeapObject* object) {
2008 int object_size = reinterpret_cast<ByteArray*>(object)->ByteArraySize();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002009 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
2010 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002011 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002012
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002013
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002014 static inline void EvacuateSeqOneByteString(Map* map,
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002015 HeapObject** slot,
2016 HeapObject* object) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002017 int object_size = SeqOneByteString::cast(object)->
2018 SeqOneByteStringSize(map->instance_type());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002019 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
2020 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002021 }
2022
2023
2024 static inline void EvacuateSeqTwoByteString(Map* map,
2025 HeapObject** slot,
2026 HeapObject* object) {
2027 int object_size = SeqTwoByteString::cast(object)->
2028 SeqTwoByteStringSize(map->instance_type());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002029 EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE, kObjectAlignment>(
2030 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002031 }
2032
2033
2034 static inline bool IsShortcutCandidate(int type) {
2035 return ((type & kShortcutTypeMask) == kShortcutTypeTag);
2036 }
2037
2038 static inline void EvacuateShortcutCandidate(Map* map,
2039 HeapObject** slot,
2040 HeapObject* object) {
2041 ASSERT(IsShortcutCandidate(map->instance_type()));
2042
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002043 Heap* heap = map->GetHeap();
2044
2045 if (marks_handling == IGNORE_MARKS &&
2046 ConsString::cast(object)->unchecked_second() ==
2047 heap->empty_string()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002048 HeapObject* first =
2049 HeapObject::cast(ConsString::cast(object)->unchecked_first());
2050
2051 *slot = first;
2052
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002053 if (!heap->InNewSpace(first)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002054 object->set_map_word(MapWord::FromForwardingAddress(first));
2055 return;
2056 }
2057
2058 MapWord first_word = first->map_word();
2059 if (first_word.IsForwardingAddress()) {
2060 HeapObject* target = first_word.ToForwardingAddress();
2061
2062 *slot = target;
2063 object->set_map_word(MapWord::FromForwardingAddress(target));
2064 return;
2065 }
2066
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002067 heap->DoScavengeObject(first->map(), slot, first);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002068 object->set_map_word(MapWord::FromForwardingAddress(*slot));
2069 return;
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002070 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002071
2072 int object_size = ConsString::kSize;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002073 EvacuateObject<POINTER_OBJECT, SMALL, kObjectAlignment>(
2074 map, slot, object, object_size);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002075 }
2076
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002077 template<ObjectContents object_contents>
2078 class ObjectEvacuationStrategy {
2079 public:
2080 template<int object_size>
2081 static inline void VisitSpecialized(Map* map,
2082 HeapObject** slot,
2083 HeapObject* object) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002084 EvacuateObject<object_contents, SMALL, kObjectAlignment>(
2085 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002086 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002087
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002088 static inline void Visit(Map* map,
2089 HeapObject** slot,
2090 HeapObject* object) {
2091 int object_size = map->instance_size();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002092 EvacuateObject<object_contents, SMALL, kObjectAlignment>(
2093 map, slot, object, object_size);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002094 }
2095 };
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002097 static VisitorDispatchTable<ScavengingCallback> table_;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002098};
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002099
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002100
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002101template<MarksHandling marks_handling,
2102 LoggingAndProfiling logging_and_profiling_mode>
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002103VisitorDispatchTable<ScavengingCallback>
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002104 ScavengingVisitor<marks_handling, logging_and_profiling_mode>::table_;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002105
2106
2107static void InitializeScavengingVisitorsTables() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002108 ScavengingVisitor<TRANSFER_MARKS,
2109 LOGGING_AND_PROFILING_DISABLED>::Initialize();
2110 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_DISABLED>::Initialize();
2111 ScavengingVisitor<TRANSFER_MARKS,
2112 LOGGING_AND_PROFILING_ENABLED>::Initialize();
2113 ScavengingVisitor<IGNORE_MARKS, LOGGING_AND_PROFILING_ENABLED>::Initialize();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002114}
2115
2116
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002117void Heap::SelectScavengingVisitorsTable() {
2118 bool logging_and_profiling =
2119 isolate()->logger()->is_logging() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002120 CpuProfiler::is_profiling(isolate()) ||
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002121 (isolate()->heap_profiler() != NULL &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002122 isolate()->heap_profiler()->is_profiling());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002123
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002124 if (!incremental_marking()->IsMarking()) {
2125 if (!logging_and_profiling) {
2126 scavenging_visitors_table_.CopyFrom(
2127 ScavengingVisitor<IGNORE_MARKS,
2128 LOGGING_AND_PROFILING_DISABLED>::GetTable());
2129 } else {
2130 scavenging_visitors_table_.CopyFrom(
2131 ScavengingVisitor<IGNORE_MARKS,
2132 LOGGING_AND_PROFILING_ENABLED>::GetTable());
2133 }
2134 } else {
2135 if (!logging_and_profiling) {
2136 scavenging_visitors_table_.CopyFrom(
2137 ScavengingVisitor<TRANSFER_MARKS,
2138 LOGGING_AND_PROFILING_DISABLED>::GetTable());
2139 } else {
2140 scavenging_visitors_table_.CopyFrom(
2141 ScavengingVisitor<TRANSFER_MARKS,
2142 LOGGING_AND_PROFILING_ENABLED>::GetTable());
2143 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002144
2145 if (incremental_marking()->IsCompacting()) {
2146 // When compacting forbid short-circuiting of cons-strings.
2147 // Scavenging code relies on the fact that new space object
2148 // can't be evacuated into evacuation candidate but
2149 // short-circuiting violates this assumption.
2150 scavenging_visitors_table_.Register(
2151 StaticVisitorBase::kVisitShortcutCandidate,
2152 scavenging_visitors_table_.GetVisitorById(
2153 StaticVisitorBase::kVisitConsString));
2154 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002155 }
2156}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002157
2158
2159void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002160 SLOW_ASSERT(HEAP->InFromSpace(object));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002161 MapWord first_word = object->map_word();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002162 SLOW_ASSERT(!first_word.IsForwardingAddress());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002163 Map* map = first_word.ToMap();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002164 map->GetHeap()->DoScavengeObject(map, p, object);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002165}
2166
2167
lrn@chromium.org303ada72010-10-27 09:33:13 +00002168MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type,
2169 int instance_size) {
2170 Object* result;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002171 MaybeObject* maybe_result = AllocateRawMap();
2172 if (!maybe_result->ToObject(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173
2174 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002175 reinterpret_cast<Map*>(result)->set_map(raw_unchecked_meta_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002176 reinterpret_cast<Map*>(result)->set_instance_type(instance_type);
2177 reinterpret_cast<Map*>(result)->set_instance_size(instance_size);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002178 reinterpret_cast<Map*>(result)->set_visitor_id(
2179 StaticVisitorBase::GetVisitorId(instance_type, instance_size));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002180 reinterpret_cast<Map*>(result)->set_inobject_properties(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002181 reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002182 reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002183 reinterpret_cast<Map*>(result)->set_bit_field(0);
2184 reinterpret_cast<Map*>(result)->set_bit_field2(0);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002185 int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) |
2186 Map::OwnsDescriptors::encode(true);
2187 reinterpret_cast<Map*>(result)->set_bit_field3(bit_field3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002188 return result;
2189}
2190
2191
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002192MaybeObject* Heap::AllocateMap(InstanceType instance_type,
2193 int instance_size,
2194 ElementsKind elements_kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002195 Object* result;
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002196 MaybeObject* maybe_result = AllocateRawMap();
2197 if (!maybe_result->To(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002198
2199 Map* map = reinterpret_cast<Map*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002200 map->set_map_no_write_barrier(meta_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002201 map->set_instance_type(instance_type);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002202 map->set_visitor_id(
2203 StaticVisitorBase::GetVisitorId(instance_type, instance_size));
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002204 map->set_prototype(null_value(), SKIP_WRITE_BARRIER);
2205 map->set_constructor(null_value(), SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002206 map->set_instance_size(instance_size);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002207 map->set_inobject_properties(0);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002208 map->set_pre_allocated_property_fields(0);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002209 map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002210 map->init_back_pointer(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002211 map->set_unused_property_fields(0);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002212 map->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002213 map->set_bit_field(0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002214 map->set_bit_field2(1 << Map::kIsExtensible);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002215 int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) |
2216 Map::OwnsDescriptors::encode(true);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002217 map->set_bit_field3(bit_field3);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002218 map->set_elements_kind(elements_kind);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00002219
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002220 return map;
2221}
2222
2223
lrn@chromium.org303ada72010-10-27 09:33:13 +00002224MaybeObject* Heap::AllocateCodeCache() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002225 CodeCache* code_cache;
2226 { MaybeObject* maybe_code_cache = AllocateStruct(CODE_CACHE_TYPE);
2227 if (!maybe_code_cache->To(&code_cache)) return maybe_code_cache;
lrn@chromium.org303ada72010-10-27 09:33:13 +00002228 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002229 code_cache->set_default_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
2230 code_cache->set_normal_type_cache(undefined_value(), SKIP_WRITE_BARRIER);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002231 return code_cache;
2232}
2233
2234
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002235MaybeObject* Heap::AllocatePolymorphicCodeCache() {
2236 return AllocateStruct(POLYMORPHIC_CODE_CACHE_TYPE);
2237}
2238
2239
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002240MaybeObject* Heap::AllocateAccessorPair() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002241 AccessorPair* accessors;
2242 { MaybeObject* maybe_accessors = AllocateStruct(ACCESSOR_PAIR_TYPE);
2243 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002244 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002245 accessors->set_getter(the_hole_value(), SKIP_WRITE_BARRIER);
2246 accessors->set_setter(the_hole_value(), SKIP_WRITE_BARRIER);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002247 return accessors;
2248}
2249
2250
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002251MaybeObject* Heap::AllocateTypeFeedbackInfo() {
2252 TypeFeedbackInfo* info;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002253 { MaybeObject* maybe_info = AllocateStruct(TYPE_FEEDBACK_INFO_TYPE);
2254 if (!maybe_info->To(&info)) return maybe_info;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002255 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002256 info->initialize_storage();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002257 info->set_type_feedback_cells(TypeFeedbackCells::cast(empty_fixed_array()),
2258 SKIP_WRITE_BARRIER);
2259 return info;
2260}
2261
2262
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002263MaybeObject* Heap::AllocateAliasedArgumentsEntry(int aliased_context_slot) {
2264 AliasedArgumentsEntry* entry;
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002265 { MaybeObject* maybe_entry = AllocateStruct(ALIASED_ARGUMENTS_ENTRY_TYPE);
2266 if (!maybe_entry->To(&entry)) return maybe_entry;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002267 }
2268 entry->set_aliased_context_slot(aliased_context_slot);
2269 return entry;
2270}
2271
2272
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002273const Heap::StringTypeTable Heap::string_type_table[] = {
2274#define STRING_TYPE_ELEMENT(type, size, name, camel_name) \
2275 {type, size, k##camel_name##MapRootIndex},
2276 STRING_TYPE_LIST(STRING_TYPE_ELEMENT)
2277#undef STRING_TYPE_ELEMENT
2278};
2279
2280
2281const Heap::ConstantSymbolTable Heap::constant_symbol_table[] = {
2282#define CONSTANT_SYMBOL_ELEMENT(name, contents) \
2283 {contents, k##name##RootIndex},
2284 SYMBOL_LIST(CONSTANT_SYMBOL_ELEMENT)
2285#undef CONSTANT_SYMBOL_ELEMENT
2286};
2287
2288
2289const Heap::StructTable Heap::struct_table[] = {
2290#define STRUCT_TABLE_ELEMENT(NAME, Name, name) \
2291 { NAME##_TYPE, Name::kSize, k##Name##MapRootIndex },
2292 STRUCT_LIST(STRUCT_TABLE_ELEMENT)
2293#undef STRUCT_TABLE_ELEMENT
2294};
2295
2296
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002297bool Heap::CreateInitialMaps() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002298 Object* obj;
2299 { MaybeObject* maybe_obj = AllocatePartialMap(MAP_TYPE, Map::kSize);
2300 if (!maybe_obj->ToObject(&obj)) return false;
2301 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002302 // Map::cast cannot be used due to uninitialized map field.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002303 Map* new_meta_map = reinterpret_cast<Map*>(obj);
2304 set_meta_map(new_meta_map);
2305 new_meta_map->set_map(new_meta_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002306
lrn@chromium.org303ada72010-10-27 09:33:13 +00002307 { MaybeObject* maybe_obj =
2308 AllocatePartialMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2309 if (!maybe_obj->ToObject(&obj)) return false;
2310 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002311 set_fixed_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002312
lrn@chromium.org303ada72010-10-27 09:33:13 +00002313 { MaybeObject* maybe_obj = AllocatePartialMap(ODDBALL_TYPE, Oddball::kSize);
2314 if (!maybe_obj->ToObject(&obj)) return false;
2315 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002316 set_oddball_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002317
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002318 // Allocate the empty array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002319 { MaybeObject* maybe_obj = AllocateEmptyFixedArray();
2320 if (!maybe_obj->ToObject(&obj)) return false;
2321 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002322 set_empty_fixed_array(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002323
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002324 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002325 if (!maybe_obj->ToObject(&obj)) return false;
2326 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002327 set_null_value(Oddball::cast(obj));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002328 Oddball::cast(obj)->set_kind(Oddball::kNull);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002329
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002330 { MaybeObject* maybe_obj = Allocate(oddball_map(), OLD_POINTER_SPACE);
2331 if (!maybe_obj->ToObject(&obj)) return false;
2332 }
2333 set_undefined_value(Oddball::cast(obj));
2334 Oddball::cast(obj)->set_kind(Oddball::kUndefined);
2335 ASSERT(!InNewSpace(undefined_value()));
2336
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002337 // Allocate the empty descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002338 { MaybeObject* maybe_obj = AllocateEmptyFixedArray();
2339 if (!maybe_obj->ToObject(&obj)) return false;
2340 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002341 set_empty_descriptor_array(DescriptorArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002342
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002343 // Fix the instance_descriptors for the existing maps.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002344 meta_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002345 meta_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002346 meta_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002347
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002348 fixed_array_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002349 fixed_array_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002350 fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002351
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002352 oddball_map()->set_code_cache(empty_fixed_array());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00002353 oddball_map()->init_back_pointer(undefined_value());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002354 oddball_map()->set_instance_descriptors(empty_descriptor_array());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002355
2356 // Fix prototype object for existing maps.
2357 meta_map()->set_prototype(null_value());
2358 meta_map()->set_constructor(null_value());
2359
2360 fixed_array_map()->set_prototype(null_value());
2361 fixed_array_map()->set_constructor(null_value());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002362
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002363 oddball_map()->set_prototype(null_value());
2364 oddball_map()->set_constructor(null_value());
2365
lrn@chromium.org303ada72010-10-27 09:33:13 +00002366 { MaybeObject* maybe_obj =
2367 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2368 if (!maybe_obj->ToObject(&obj)) return false;
2369 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002370 set_fixed_cow_array_map(Map::cast(obj));
2371 ASSERT(fixed_array_map() != fixed_cow_array_map());
2372
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002373 { MaybeObject* maybe_obj =
2374 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2375 if (!maybe_obj->ToObject(&obj)) return false;
2376 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002377 set_scope_info_map(Map::cast(obj));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002378
lrn@chromium.org303ada72010-10-27 09:33:13 +00002379 { MaybeObject* maybe_obj = AllocateMap(HEAP_NUMBER_TYPE, HeapNumber::kSize);
2380 if (!maybe_obj->ToObject(&obj)) return false;
2381 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002382 set_heap_number_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002383
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002384 { MaybeObject* maybe_obj = AllocateMap(FOREIGN_TYPE, Foreign::kSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002385 if (!maybe_obj->ToObject(&obj)) return false;
2386 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002387 set_foreign_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002388
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002389 for (unsigned i = 0; i < ARRAY_SIZE(string_type_table); i++) {
2390 const StringTypeTable& entry = string_type_table[i];
lrn@chromium.org303ada72010-10-27 09:33:13 +00002391 { MaybeObject* maybe_obj = AllocateMap(entry.type, entry.size);
2392 if (!maybe_obj->ToObject(&obj)) return false;
2393 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002394 roots_[entry.index] = Map::cast(obj);
2395 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002396
lrn@chromium.org303ada72010-10-27 09:33:13 +00002397 { MaybeObject* maybe_obj = AllocateMap(STRING_TYPE, kVariableSizeSentinel);
2398 if (!maybe_obj->ToObject(&obj)) return false;
2399 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002400 set_undetectable_string_map(Map::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002401 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002402
lrn@chromium.org303ada72010-10-27 09:33:13 +00002403 { MaybeObject* maybe_obj =
2404 AllocateMap(ASCII_STRING_TYPE, kVariableSizeSentinel);
2405 if (!maybe_obj->ToObject(&obj)) return false;
2406 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00002407 set_undetectable_ascii_string_map(Map::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002408 Map::cast(obj)->set_is_undetectable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002409
lrn@chromium.org303ada72010-10-27 09:33:13 +00002410 { MaybeObject* maybe_obj =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002411 AllocateMap(FIXED_DOUBLE_ARRAY_TYPE, kVariableSizeSentinel);
2412 if (!maybe_obj->ToObject(&obj)) return false;
2413 }
2414 set_fixed_double_array_map(Map::cast(obj));
2415
2416 { MaybeObject* maybe_obj =
lrn@chromium.org303ada72010-10-27 09:33:13 +00002417 AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel);
2418 if (!maybe_obj->ToObject(&obj)) return false;
2419 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002420 set_byte_array_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002421
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002422 { MaybeObject* maybe_obj =
2423 AllocateMap(FREE_SPACE_TYPE, kVariableSizeSentinel);
2424 if (!maybe_obj->ToObject(&obj)) return false;
2425 }
2426 set_free_space_map(Map::cast(obj));
2427
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002428 { MaybeObject* maybe_obj = AllocateByteArray(0, TENURED);
2429 if (!maybe_obj->ToObject(&obj)) return false;
2430 }
2431 set_empty_byte_array(ByteArray::cast(obj));
2432
lrn@chromium.org303ada72010-10-27 09:33:13 +00002433 { MaybeObject* maybe_obj =
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002434 AllocateMap(EXTERNAL_PIXEL_ARRAY_TYPE, ExternalArray::kAlignedSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002435 if (!maybe_obj->ToObject(&obj)) return false;
2436 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002437 set_external_pixel_array_map(Map::cast(obj));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002438
lrn@chromium.org303ada72010-10-27 09:33:13 +00002439 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_BYTE_ARRAY_TYPE,
2440 ExternalArray::kAlignedSize);
2441 if (!maybe_obj->ToObject(&obj)) return false;
2442 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002443 set_external_byte_array_map(Map::cast(obj));
2444
lrn@chromium.org303ada72010-10-27 09:33:13 +00002445 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE,
2446 ExternalArray::kAlignedSize);
2447 if (!maybe_obj->ToObject(&obj)) return false;
2448 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002449 set_external_unsigned_byte_array_map(Map::cast(obj));
2450
lrn@chromium.org303ada72010-10-27 09:33:13 +00002451 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_SHORT_ARRAY_TYPE,
2452 ExternalArray::kAlignedSize);
2453 if (!maybe_obj->ToObject(&obj)) return false;
2454 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002455 set_external_short_array_map(Map::cast(obj));
2456
lrn@chromium.org303ada72010-10-27 09:33:13 +00002457 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE,
2458 ExternalArray::kAlignedSize);
2459 if (!maybe_obj->ToObject(&obj)) return false;
2460 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002461 set_external_unsigned_short_array_map(Map::cast(obj));
2462
lrn@chromium.org303ada72010-10-27 09:33:13 +00002463 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_INT_ARRAY_TYPE,
2464 ExternalArray::kAlignedSize);
2465 if (!maybe_obj->ToObject(&obj)) return false;
2466 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002467 set_external_int_array_map(Map::cast(obj));
2468
lrn@chromium.org303ada72010-10-27 09:33:13 +00002469 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_UNSIGNED_INT_ARRAY_TYPE,
2470 ExternalArray::kAlignedSize);
2471 if (!maybe_obj->ToObject(&obj)) return false;
2472 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002473 set_external_unsigned_int_array_map(Map::cast(obj));
2474
lrn@chromium.org303ada72010-10-27 09:33:13 +00002475 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_FLOAT_ARRAY_TYPE,
2476 ExternalArray::kAlignedSize);
2477 if (!maybe_obj->ToObject(&obj)) return false;
2478 }
ager@chromium.org3811b432009-10-28 14:53:37 +00002479 set_external_float_array_map(Map::cast(obj));
2480
whesse@chromium.org7b260152011-06-20 15:33:18 +00002481 { MaybeObject* maybe_obj =
2482 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2483 if (!maybe_obj->ToObject(&obj)) return false;
2484 }
2485 set_non_strict_arguments_elements_map(Map::cast(obj));
2486
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002487 { MaybeObject* maybe_obj = AllocateMap(EXTERNAL_DOUBLE_ARRAY_TYPE,
2488 ExternalArray::kAlignedSize);
2489 if (!maybe_obj->ToObject(&obj)) return false;
2490 }
2491 set_external_double_array_map(Map::cast(obj));
2492
lrn@chromium.org303ada72010-10-27 09:33:13 +00002493 { MaybeObject* maybe_obj = AllocateMap(CODE_TYPE, kVariableSizeSentinel);
2494 if (!maybe_obj->ToObject(&obj)) return false;
2495 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002496 set_code_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002497
lrn@chromium.org303ada72010-10-27 09:33:13 +00002498 { MaybeObject* maybe_obj = AllocateMap(JS_GLOBAL_PROPERTY_CELL_TYPE,
2499 JSGlobalPropertyCell::kSize);
2500 if (!maybe_obj->ToObject(&obj)) return false;
2501 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002502 set_global_property_cell_map(Map::cast(obj));
2503
lrn@chromium.org303ada72010-10-27 09:33:13 +00002504 { MaybeObject* maybe_obj = AllocateMap(FILLER_TYPE, kPointerSize);
2505 if (!maybe_obj->ToObject(&obj)) return false;
2506 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002507 set_one_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002508
lrn@chromium.org303ada72010-10-27 09:33:13 +00002509 { MaybeObject* maybe_obj = AllocateMap(FILLER_TYPE, 2 * kPointerSize);
2510 if (!maybe_obj->ToObject(&obj)) return false;
2511 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002512 set_two_pointer_filler_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002513
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002514 for (unsigned i = 0; i < ARRAY_SIZE(struct_table); i++) {
2515 const StructTable& entry = struct_table[i];
lrn@chromium.org303ada72010-10-27 09:33:13 +00002516 { MaybeObject* maybe_obj = AllocateMap(entry.type, entry.size);
2517 if (!maybe_obj->ToObject(&obj)) return false;
2518 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002519 roots_[entry.index] = Map::cast(obj);
2520 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002521
lrn@chromium.org303ada72010-10-27 09:33:13 +00002522 { MaybeObject* maybe_obj =
2523 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2524 if (!maybe_obj->ToObject(&obj)) return false;
2525 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002526 set_hash_table_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002527
lrn@chromium.org303ada72010-10-27 09:33:13 +00002528 { MaybeObject* maybe_obj =
2529 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2530 if (!maybe_obj->ToObject(&obj)) return false;
2531 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002532 set_function_context_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002533
lrn@chromium.org303ada72010-10-27 09:33:13 +00002534 { MaybeObject* maybe_obj =
2535 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2536 if (!maybe_obj->ToObject(&obj)) return false;
2537 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002538 set_catch_context_map(Map::cast(obj));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002539
lrn@chromium.org303ada72010-10-27 09:33:13 +00002540 { MaybeObject* maybe_obj =
2541 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2542 if (!maybe_obj->ToObject(&obj)) return false;
2543 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002544 set_with_context_map(Map::cast(obj));
2545
2546 { MaybeObject* maybe_obj =
2547 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2548 if (!maybe_obj->ToObject(&obj)) return false;
2549 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002550 set_block_context_map(Map::cast(obj));
2551
2552 { MaybeObject* maybe_obj =
2553 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2554 if (!maybe_obj->ToObject(&obj)) return false;
2555 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002556 set_module_context_map(Map::cast(obj));
2557
2558 { MaybeObject* maybe_obj =
2559 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2560 if (!maybe_obj->ToObject(&obj)) return false;
2561 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002562 set_global_context_map(Map::cast(obj));
2563
2564 { MaybeObject* maybe_obj =
2565 AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
2566 if (!maybe_obj->ToObject(&obj)) return false;
2567 }
2568 Map* native_context_map = Map::cast(obj);
2569 native_context_map->set_dictionary_map(true);
2570 native_context_map->set_visitor_id(StaticVisitorBase::kVisitNativeContext);
2571 set_native_context_map(native_context_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002572
lrn@chromium.org303ada72010-10-27 09:33:13 +00002573 { MaybeObject* maybe_obj = AllocateMap(SHARED_FUNCTION_INFO_TYPE,
2574 SharedFunctionInfo::kAlignedSize);
2575 if (!maybe_obj->ToObject(&obj)) return false;
2576 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002577 set_shared_function_info_map(Map::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002578
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002579 { MaybeObject* maybe_obj = AllocateMap(JS_MESSAGE_OBJECT_TYPE,
2580 JSMessageObject::kSize);
2581 if (!maybe_obj->ToObject(&obj)) return false;
2582 }
2583 set_message_object_map(Map::cast(obj));
2584
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002585 Map* external_map;
2586 { MaybeObject* maybe_obj =
2587 AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize + kPointerSize);
2588 if (!maybe_obj->To(&external_map)) return false;
2589 }
2590 external_map->set_is_extensible(false);
2591 set_external_map(external_map);
2592
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002593 ASSERT(!InNewSpace(empty_fixed_array()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002594 return true;
2595}
2596
2597
lrn@chromium.org303ada72010-10-27 09:33:13 +00002598MaybeObject* Heap::AllocateHeapNumber(double value, PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002599 // Statically ensure that it is safe to allocate heap numbers in paged
2600 // spaces.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002601 STATIC_ASSERT(HeapNumber::kSize <= Page::kNonCodeObjectAreaSize);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002602 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002603
lrn@chromium.org303ada72010-10-27 09:33:13 +00002604 Object* result;
2605 { MaybeObject* maybe_result =
2606 AllocateRaw(HeapNumber::kSize, space, OLD_DATA_SPACE);
2607 if (!maybe_result->ToObject(&result)) return maybe_result;
2608 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002609
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002610 HeapObject::cast(result)->set_map_no_write_barrier(heap_number_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002611 HeapNumber::cast(result)->set_value(value);
2612 return result;
2613}
2614
2615
lrn@chromium.org303ada72010-10-27 09:33:13 +00002616MaybeObject* Heap::AllocateHeapNumber(double value) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00002617 // Use general version, if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002618 if (always_allocate()) return AllocateHeapNumber(value, TENURED);
2619
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002620 // This version of AllocateHeapNumber is optimized for
2621 // allocation in new space.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00002622 STATIC_ASSERT(HeapNumber::kSize <= Page::kMaxNonCodeHeapObjectSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002623 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002624 Object* result;
2625 { MaybeObject* maybe_result = new_space_.AllocateRaw(HeapNumber::kSize);
2626 if (!maybe_result->ToObject(&result)) return maybe_result;
2627 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002628 HeapObject::cast(result)->set_map_no_write_barrier(heap_number_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002629 HeapNumber::cast(result)->set_value(value);
2630 return result;
2631}
2632
2633
lrn@chromium.org303ada72010-10-27 09:33:13 +00002634MaybeObject* Heap::AllocateJSGlobalPropertyCell(Object* value) {
2635 Object* result;
2636 { MaybeObject* maybe_result = AllocateRawCell();
2637 if (!maybe_result->ToObject(&result)) return maybe_result;
2638 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002639 HeapObject::cast(result)->set_map_no_write_barrier(
2640 global_property_cell_map());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002641 JSGlobalPropertyCell::cast(result)->set_value(value);
2642 return result;
2643}
2644
2645
lrn@chromium.org303ada72010-10-27 09:33:13 +00002646MaybeObject* Heap::CreateOddball(const char* to_string,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002647 Object* to_number,
2648 byte kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002649 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002650 { MaybeObject* maybe_result = Allocate(oddball_map(), OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002651 if (!maybe_result->ToObject(&result)) return maybe_result;
2652 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002653 return Oddball::cast(result)->Initialize(to_string, to_number, kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002654}
2655
2656
2657bool Heap::CreateApiObjects() {
2658 Object* obj;
2659
lrn@chromium.org303ada72010-10-27 09:33:13 +00002660 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
2661 if (!maybe_obj->ToObject(&obj)) return false;
2662 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002663 // Don't use Smi-only elements optimizations for objects with the neander
2664 // map. There are too many cases where element values are set directly with a
2665 // bottleneck to trap the Smi-only -> fast elements transition, and there
2666 // appears to be no benefit for optimize this case.
2667 Map* new_neander_map = Map::cast(obj);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002668 new_neander_map->set_elements_kind(TERMINAL_FAST_ELEMENTS_KIND);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002669 set_neander_map(new_neander_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002670
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002671 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(neander_map());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002672 if (!maybe_obj->ToObject(&obj)) return false;
2673 }
2674 Object* elements;
2675 { MaybeObject* maybe_elements = AllocateFixedArray(2);
2676 if (!maybe_elements->ToObject(&elements)) return false;
2677 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002678 FixedArray::cast(elements)->set(0, Smi::FromInt(0));
2679 JSObject::cast(obj)->set_elements(FixedArray::cast(elements));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002680 set_message_listeners(JSObject::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002681
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002682 return true;
2683}
2684
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002685
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002686void Heap::CreateJSEntryStub() {
2687 JSEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002688 set_js_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002689}
2690
2691
2692void Heap::CreateJSConstructEntryStub() {
2693 JSConstructEntryStub stub;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002694 set_js_construct_entry_code(*stub.GetCode());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002695}
2696
2697
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002698void Heap::CreateFixedStubs() {
2699 // Here we create roots for fixed stubs. They are needed at GC
2700 // for cooking and uncooking (check out frames.cc).
2701 // The eliminates the need for doing dictionary lookup in the
2702 // stub cache for these stubs.
2703 HandleScope scope;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002704 // gcc-4.4 has problem generating correct code of following snippet:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002705 // { JSEntryStub stub;
2706 // js_entry_code_ = *stub.GetCode();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002707 // }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002708 // { JSConstructEntryStub stub;
2709 // js_construct_entry_code_ = *stub.GetCode();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002710 // }
2711 // To workaround the problem, make separate functions without inlining.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002712 Heap::CreateJSEntryStub();
2713 Heap::CreateJSConstructEntryStub();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002714
2715 // Create stubs that should be there, so we don't unexpectedly have to
2716 // create them if we need them during the creation of another stub.
2717 // Stub creation mixes raw pointers and handles in an unsafe manner so
2718 // we cannot create stubs while we are creating stubs.
2719 CodeStub::GenerateStubsAheadOfTime();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002720}
2721
2722
2723bool Heap::CreateInitialObjects() {
2724 Object* obj;
2725
2726 // The -0 value must be set before NumberFromDouble works.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002727 { MaybeObject* maybe_obj = AllocateHeapNumber(-0.0, TENURED);
2728 if (!maybe_obj->ToObject(&obj)) return false;
2729 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002730 set_minus_zero_value(HeapNumber::cast(obj));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002731 ASSERT(signbit(minus_zero_value()->Number()) != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002732
lrn@chromium.org303ada72010-10-27 09:33:13 +00002733 { MaybeObject* maybe_obj = AllocateHeapNumber(OS::nan_value(), TENURED);
2734 if (!maybe_obj->ToObject(&obj)) return false;
2735 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002736 set_nan_value(HeapNumber::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002737
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002738 { MaybeObject* maybe_obj = AllocateHeapNumber(V8_INFINITY, TENURED);
2739 if (!maybe_obj->ToObject(&obj)) return false;
2740 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002741 set_infinity_value(HeapNumber::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002742
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00002743 // The hole has not been created yet, but we want to put something
2744 // predictable in the gaps in the symbol table, so lets make that Smi zero.
2745 set_the_hole_value(reinterpret_cast<Oddball*>(Smi::FromInt(0)));
2746
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002747 // Allocate initial symbol table.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002748 { MaybeObject* maybe_obj = SymbolTable::Allocate(kInitialSymbolTableSize);
2749 if (!maybe_obj->ToObject(&obj)) return false;
2750 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002751 // Don't use set_symbol_table() due to asserts.
2752 roots_[kSymbolTableRootIndex] = obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002753
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002754 // Finish initializing oddballs after creating symboltable.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002755 { MaybeObject* maybe_obj =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002756 undefined_value()->Initialize("undefined",
2757 nan_value(),
2758 Oddball::kUndefined);
2759 if (!maybe_obj->ToObject(&obj)) return false;
2760 }
2761
2762 // Initialize the null_value.
2763 { MaybeObject* maybe_obj =
2764 null_value()->Initialize("null", Smi::FromInt(0), Oddball::kNull);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002765 if (!maybe_obj->ToObject(&obj)) return false;
2766 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002767
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002768 { MaybeObject* maybe_obj = CreateOddball("true",
2769 Smi::FromInt(1),
2770 Oddball::kTrue);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002771 if (!maybe_obj->ToObject(&obj)) return false;
2772 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002773 set_true_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002774
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002775 { MaybeObject* maybe_obj = CreateOddball("false",
2776 Smi::FromInt(0),
2777 Oddball::kFalse);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002778 if (!maybe_obj->ToObject(&obj)) return false;
2779 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002780 set_false_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002781
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002782 { MaybeObject* maybe_obj = CreateOddball("hole",
2783 Smi::FromInt(-1),
2784 Oddball::kTheHole);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002785 if (!maybe_obj->ToObject(&obj)) return false;
2786 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002787 set_the_hole_value(Oddball::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002788
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002789 { MaybeObject* maybe_obj = CreateOddball("arguments_marker",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002790 Smi::FromInt(-4),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002791 Oddball::kArgumentMarker);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002792 if (!maybe_obj->ToObject(&obj)) return false;
2793 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002794 set_arguments_marker(Oddball::cast(obj));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002795
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002796 { MaybeObject* maybe_obj = CreateOddball("no_interceptor_result_sentinel",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002797 Smi::FromInt(-2),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002798 Oddball::kOther);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002799 if (!maybe_obj->ToObject(&obj)) return false;
2800 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002801 set_no_interceptor_result_sentinel(obj);
2802
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002803 { MaybeObject* maybe_obj = CreateOddball("termination_exception",
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00002804 Smi::FromInt(-3),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002805 Oddball::kOther);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002806 if (!maybe_obj->ToObject(&obj)) return false;
2807 }
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +00002808 set_termination_exception(obj);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002809
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002810 // Allocate the empty string.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002811 { MaybeObject* maybe_obj = AllocateRawOneByteString(0, TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002812 if (!maybe_obj->ToObject(&obj)) return false;
2813 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002814 set_empty_string(String::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002815
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002816 for (unsigned i = 0; i < ARRAY_SIZE(constant_symbol_table); i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002817 { MaybeObject* maybe_obj =
2818 LookupAsciiSymbol(constant_symbol_table[i].contents);
2819 if (!maybe_obj->ToObject(&obj)) return false;
2820 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002821 roots_[constant_symbol_table[i].index] = String::cast(obj);
2822 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002823
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002824 // Allocate the hidden symbol which is used to identify the hidden properties
2825 // in JSObjects. The hash code has a special value so that it will not match
2826 // the empty string when searching for the property. It cannot be part of the
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002827 // loop above because it needs to be allocated manually with the special
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002828 // hash code in place. The hash code for the hidden_symbol is zero to ensure
2829 // that it will always be at the first entry in property descriptors.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002830 { MaybeObject* maybe_obj =
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002831 AllocateSymbol(CStrVector(""), 0, String::kEmptyStringHash);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002832 if (!maybe_obj->ToObject(&obj)) return false;
2833 }
ager@chromium.org3b45ab52009-03-19 22:21:34 +00002834 hidden_symbol_ = String::cast(obj);
2835
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002836 // Allocate the foreign for __proto__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002837 { MaybeObject* maybe_obj =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002838 AllocateForeign((Address) &Accessors::ObjectPrototype);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002839 if (!maybe_obj->ToObject(&obj)) return false;
2840 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002841 set_prototype_accessors(Foreign::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002842
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002843 // Allocate the code_stubs dictionary. The initial size is set to avoid
2844 // expanding the dictionary during bootstrapping.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002845 { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(128);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002846 if (!maybe_obj->ToObject(&obj)) return false;
2847 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002848 set_code_stubs(UnseededNumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002849
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002850
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002851 // Allocate the non_monomorphic_cache used in stub-cache.cc. The initial size
2852 // is set to avoid expanding the dictionary during bootstrapping.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002853 { MaybeObject* maybe_obj = UnseededNumberDictionary::Allocate(64);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002854 if (!maybe_obj->ToObject(&obj)) return false;
2855 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002856 set_non_monomorphic_cache(UnseededNumberDictionary::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002857
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002858 { MaybeObject* maybe_obj = AllocatePolymorphicCodeCache();
2859 if (!maybe_obj->ToObject(&obj)) return false;
2860 }
2861 set_polymorphic_code_cache(PolymorphicCodeCache::cast(obj));
2862
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002863 set_instanceof_cache_function(Smi::FromInt(0));
2864 set_instanceof_cache_map(Smi::FromInt(0));
2865 set_instanceof_cache_answer(Smi::FromInt(0));
2866
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002867 CreateFixedStubs();
2868
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002869 // Allocate the dictionary of intrinsic function names.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002870 { MaybeObject* maybe_obj = StringDictionary::Allocate(Runtime::kNumFunctions);
2871 if (!maybe_obj->ToObject(&obj)) return false;
2872 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002873 { MaybeObject* maybe_obj = Runtime::InitializeIntrinsicFunctionNames(this,
2874 obj);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002875 if (!maybe_obj->ToObject(&obj)) return false;
2876 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002877 set_intrinsic_function_names(StringDictionary::cast(obj));
2878
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002879 { MaybeObject* maybe_obj = AllocateInitialNumberStringCache();
2880 if (!maybe_obj->ToObject(&obj)) return false;
2881 }
2882 set_number_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002883
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00002884 // Allocate cache for single character ASCII strings.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002885 { MaybeObject* maybe_obj =
2886 AllocateFixedArray(String::kMaxAsciiCharCode + 1, TENURED);
2887 if (!maybe_obj->ToObject(&obj)) return false;
2888 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002889 set_single_character_string_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002890
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002891 // Allocate cache for string split.
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002892 { MaybeObject* maybe_obj = AllocateFixedArray(
2893 RegExpResultsCache::kRegExpResultsCacheSize, TENURED);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002894 if (!maybe_obj->ToObject(&obj)) return false;
2895 }
2896 set_string_split_cache(FixedArray::cast(obj));
2897
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002898 { MaybeObject* maybe_obj = AllocateFixedArray(
2899 RegExpResultsCache::kRegExpResultsCacheSize, TENURED);
2900 if (!maybe_obj->ToObject(&obj)) return false;
2901 }
2902 set_regexp_multiple_cache(FixedArray::cast(obj));
2903
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002904 // Allocate cache for external strings pointing to native source code.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002905 { MaybeObject* maybe_obj = AllocateFixedArray(Natives::GetBuiltinsCount());
2906 if (!maybe_obj->ToObject(&obj)) return false;
2907 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002908 set_natives_source_cache(FixedArray::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002909
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002910 // Allocate object to hold object observation state.
2911 { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
2912 if (!maybe_obj->ToObject(&obj)) return false;
2913 }
2914 { MaybeObject* maybe_obj = AllocateJSObjectFromMap(Map::cast(obj));
2915 if (!maybe_obj->ToObject(&obj)) return false;
2916 }
2917 set_observation_state(JSObject::cast(obj));
2918
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002919 // Handling of script id generation is in FACTORY->NewScript.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002920 set_last_script_id(undefined_value());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002921
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002922 // Initialize keyed lookup cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002923 isolate_->keyed_lookup_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002924
2925 // Initialize context slot cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002926 isolate_->context_slot_cache()->Clear();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002927
2928 // Initialize descriptor cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002929 isolate_->descriptor_lookup_cache()->Clear();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002930
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002931 // Initialize compilation cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002932 isolate_->compilation_cache()->Clear();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002933
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002934 return true;
2935}
2936
2937
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002938bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) {
2939 RootListIndex writable_roots[] = {
2940 kStoreBufferTopRootIndex,
2941 kStackLimitRootIndex,
2942 kInstanceofCacheFunctionRootIndex,
2943 kInstanceofCacheMapRootIndex,
2944 kInstanceofCacheAnswerRootIndex,
2945 kCodeStubsRootIndex,
2946 kNonMonomorphicCacheRootIndex,
2947 kPolymorphicCodeCacheRootIndex,
2948 kLastScriptIdRootIndex,
2949 kEmptyScriptRootIndex,
2950 kRealStackLimitRootIndex,
2951 kArgumentsAdaptorDeoptPCOffsetRootIndex,
2952 kConstructStubDeoptPCOffsetRootIndex,
2953 kGetterStubDeoptPCOffsetRootIndex,
2954 kSetterStubDeoptPCOffsetRootIndex,
2955 kSymbolTableRootIndex,
2956 };
2957
2958 for (unsigned int i = 0; i < ARRAY_SIZE(writable_roots); i++) {
2959 if (root_index == writable_roots[i])
2960 return true;
2961 }
2962 return false;
2963}
2964
2965
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002966Object* RegExpResultsCache::Lookup(Heap* heap,
2967 String* key_string,
2968 Object* key_pattern,
2969 ResultsCacheType type) {
2970 FixedArray* cache;
2971 if (!key_string->IsSymbol()) return Smi::FromInt(0);
2972 if (type == STRING_SPLIT_SUBSTRINGS) {
2973 ASSERT(key_pattern->IsString());
2974 if (!key_pattern->IsSymbol()) return Smi::FromInt(0);
2975 cache = heap->string_split_cache();
2976 } else {
2977 ASSERT(type == REGEXP_MULTIPLE_INDICES);
2978 ASSERT(key_pattern->IsFixedArray());
2979 cache = heap->regexp_multiple_cache();
2980 }
2981
2982 uint32_t hash = key_string->Hash();
2983 uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) &
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002984 ~(kArrayEntriesPerCacheEntry - 1));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002985 if (cache->get(index + kStringOffset) == key_string &&
2986 cache->get(index + kPatternOffset) == key_pattern) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002987 return cache->get(index + kArrayOffset);
2988 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002989 index =
2990 ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1));
2991 if (cache->get(index + kStringOffset) == key_string &&
2992 cache->get(index + kPatternOffset) == key_pattern) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002993 return cache->get(index + kArrayOffset);
2994 }
2995 return Smi::FromInt(0);
2996}
2997
2998
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002999void RegExpResultsCache::Enter(Heap* heap,
3000 String* key_string,
3001 Object* key_pattern,
3002 FixedArray* value_array,
3003 ResultsCacheType type) {
3004 FixedArray* cache;
3005 if (!key_string->IsSymbol()) return;
3006 if (type == STRING_SPLIT_SUBSTRINGS) {
3007 ASSERT(key_pattern->IsString());
3008 if (!key_pattern->IsSymbol()) return;
3009 cache = heap->string_split_cache();
3010 } else {
3011 ASSERT(type == REGEXP_MULTIPLE_INDICES);
3012 ASSERT(key_pattern->IsFixedArray());
3013 cache = heap->regexp_multiple_cache();
3014 }
3015
3016 uint32_t hash = key_string->Hash();
3017 uint32_t index = ((hash & (kRegExpResultsCacheSize - 1)) &
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003018 ~(kArrayEntriesPerCacheEntry - 1));
3019 if (cache->get(index + kStringOffset) == Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003020 cache->set(index + kStringOffset, key_string);
3021 cache->set(index + kPatternOffset, key_pattern);
3022 cache->set(index + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003023 } else {
3024 uint32_t index2 =
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003025 ((index + kArrayEntriesPerCacheEntry) & (kRegExpResultsCacheSize - 1));
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003026 if (cache->get(index2 + kStringOffset) == Smi::FromInt(0)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003027 cache->set(index2 + kStringOffset, key_string);
3028 cache->set(index2 + kPatternOffset, key_pattern);
3029 cache->set(index2 + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003030 } else {
3031 cache->set(index2 + kStringOffset, Smi::FromInt(0));
3032 cache->set(index2 + kPatternOffset, Smi::FromInt(0));
3033 cache->set(index2 + kArrayOffset, Smi::FromInt(0));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003034 cache->set(index + kStringOffset, key_string);
3035 cache->set(index + kPatternOffset, key_pattern);
3036 cache->set(index + kArrayOffset, value_array);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003037 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003038 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003039 // If the array is a reasonably short list of substrings, convert it into a
3040 // list of symbols.
3041 if (type == STRING_SPLIT_SUBSTRINGS && value_array->length() < 100) {
3042 for (int i = 0; i < value_array->length(); i++) {
3043 String* str = String::cast(value_array->get(i));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003044 Object* symbol;
3045 MaybeObject* maybe_symbol = heap->LookupSymbol(str);
3046 if (maybe_symbol->ToObject(&symbol)) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003047 value_array->set(i, symbol);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003048 }
3049 }
3050 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003051 // Convert backing store to a copy-on-write array.
3052 value_array->set_map_no_write_barrier(heap->fixed_cow_array_map());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003053}
3054
3055
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003056void RegExpResultsCache::Clear(FixedArray* cache) {
3057 for (int i = 0; i < kRegExpResultsCacheSize; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003058 cache->set(i, Smi::FromInt(0));
3059 }
3060}
3061
3062
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003063MaybeObject* Heap::AllocateInitialNumberStringCache() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003064 MaybeObject* maybe_obj =
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003065 AllocateFixedArray(kInitialNumberStringCacheSize * 2, TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003066 return maybe_obj;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003067}
3068
3069
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003070int Heap::FullSizeNumberStringCacheLength() {
3071 // Compute the size of the number string cache based on the max newspace size.
3072 // The number string cache has a minimum size based on twice the initial cache
3073 // size to ensure that it is bigger after being made 'full size'.
3074 int number_string_cache_size = max_semispace_size_ / 512;
3075 number_string_cache_size = Max(kInitialNumberStringCacheSize * 2,
3076 Min(0x4000, number_string_cache_size));
3077 // There is a string and a number per entry so the length is twice the number
3078 // of entries.
3079 return number_string_cache_size * 2;
3080}
3081
3082
3083void Heap::AllocateFullSizeNumberStringCache() {
3084 // The idea is to have a small number string cache in the snapshot to keep
3085 // boot-time memory usage down. If we expand the number string cache already
3086 // while creating the snapshot then that didn't work out.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003087 ASSERT(!Serializer::enabled() || FLAG_extra_code != NULL);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003088 MaybeObject* maybe_obj =
3089 AllocateFixedArray(FullSizeNumberStringCacheLength(), TENURED);
3090 Object* new_cache;
3091 if (maybe_obj->ToObject(&new_cache)) {
3092 // We don't bother to repopulate the cache with entries from the old cache.
3093 // It will be repopulated soon enough with new strings.
3094 set_number_string_cache(FixedArray::cast(new_cache));
3095 }
3096 // If allocation fails then we just return without doing anything. It is only
3097 // a cache, so best effort is OK here.
3098}
3099
3100
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003101void Heap::FlushNumberStringCache() {
3102 // Flush the number to string cache.
3103 int len = number_string_cache()->length();
3104 for (int i = 0; i < len; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003105 number_string_cache()->set_undefined(this, i);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003106 }
3107}
3108
3109
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003110static inline int double_get_hash(double d) {
3111 DoubleRepresentation rep(d);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003112 return static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003113}
3114
3115
3116static inline int smi_get_hash(Smi* smi) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003117 return smi->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003118}
3119
3120
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003121Object* Heap::GetNumberStringCache(Object* number) {
3122 int hash;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003123 int mask = (number_string_cache()->length() >> 1) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003124 if (number->IsSmi()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003125 hash = smi_get_hash(Smi::cast(number)) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003126 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003127 hash = double_get_hash(number->Number()) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003128 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003129 Object* key = number_string_cache()->get(hash * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003130 if (key == number) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003131 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003132 } else if (key->IsHeapNumber() &&
3133 number->IsHeapNumber() &&
3134 key->Number() == number->Number()) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003135 return String::cast(number_string_cache()->get(hash * 2 + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003136 }
3137 return undefined_value();
3138}
3139
3140
3141void Heap::SetNumberStringCache(Object* number, String* string) {
3142 int hash;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003143 int mask = (number_string_cache()->length() >> 1) - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003144 if (number->IsSmi()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003145 hash = smi_get_hash(Smi::cast(number)) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003146 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003147 hash = double_get_hash(number->Number()) & mask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003148 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003149 if (number_string_cache()->get(hash * 2) != undefined_value() &&
3150 number_string_cache()->length() != FullSizeNumberStringCacheLength()) {
3151 // The first time we have a hash collision, we move to the full sized
3152 // number string cache.
3153 AllocateFullSizeNumberStringCache();
3154 return;
3155 }
3156 number_string_cache()->set(hash * 2, number);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003157 number_string_cache()->set(hash * 2 + 1, string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003158}
3159
3160
lrn@chromium.org303ada72010-10-27 09:33:13 +00003161MaybeObject* Heap::NumberToString(Object* number,
3162 bool check_number_string_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003163 isolate_->counters()->number_to_string_runtime()->Increment();
ager@chromium.org357bf652010-04-12 11:30:10 +00003164 if (check_number_string_cache) {
3165 Object* cached = GetNumberStringCache(number);
3166 if (cached != undefined_value()) {
3167 return cached;
3168 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003169 }
3170
3171 char arr[100];
3172 Vector<char> buffer(arr, ARRAY_SIZE(arr));
3173 const char* str;
3174 if (number->IsSmi()) {
3175 int num = Smi::cast(number)->value();
3176 str = IntToCString(num, buffer);
3177 } else {
3178 double num = HeapNumber::cast(number)->value();
3179 str = DoubleToCString(num, buffer);
3180 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003181
lrn@chromium.org303ada72010-10-27 09:33:13 +00003182 Object* js_string;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003183 MaybeObject* maybe_js_string = AllocateStringFromOneByte(CStrVector(str));
lrn@chromium.org303ada72010-10-27 09:33:13 +00003184 if (maybe_js_string->ToObject(&js_string)) {
3185 SetNumberStringCache(number, String::cast(js_string));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003186 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00003187 return maybe_js_string;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003188}
3189
3190
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003191MaybeObject* Heap::Uint32ToString(uint32_t value,
3192 bool check_number_string_cache) {
3193 Object* number;
3194 MaybeObject* maybe = NumberFromUint32(value);
3195 if (!maybe->To<Object>(&number)) return maybe;
3196 return NumberToString(number, check_number_string_cache);
3197}
3198
3199
ager@chromium.org3811b432009-10-28 14:53:37 +00003200Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) {
3201 return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]);
3202}
3203
3204
3205Heap::RootListIndex Heap::RootIndexForExternalArrayType(
3206 ExternalArrayType array_type) {
3207 switch (array_type) {
3208 case kExternalByteArray:
3209 return kExternalByteArrayMapRootIndex;
3210 case kExternalUnsignedByteArray:
3211 return kExternalUnsignedByteArrayMapRootIndex;
3212 case kExternalShortArray:
3213 return kExternalShortArrayMapRootIndex;
3214 case kExternalUnsignedShortArray:
3215 return kExternalUnsignedShortArrayMapRootIndex;
3216 case kExternalIntArray:
3217 return kExternalIntArrayMapRootIndex;
3218 case kExternalUnsignedIntArray:
3219 return kExternalUnsignedIntArrayMapRootIndex;
3220 case kExternalFloatArray:
3221 return kExternalFloatArrayMapRootIndex;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003222 case kExternalDoubleArray:
3223 return kExternalDoubleArrayMapRootIndex;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003224 case kExternalPixelArray:
3225 return kExternalPixelArrayMapRootIndex;
ager@chromium.org3811b432009-10-28 14:53:37 +00003226 default:
3227 UNREACHABLE();
3228 return kUndefinedValueRootIndex;
3229 }
3230}
3231
3232
lrn@chromium.org303ada72010-10-27 09:33:13 +00003233MaybeObject* Heap::NumberFromDouble(double value, PretenureFlag pretenure) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003234 // We need to distinguish the minus zero value and this cannot be
3235 // done after conversion to int. Doing this by comparing bit
3236 // patterns is faster than using fpclassify() et al.
3237 static const DoubleRepresentation minus_zero(-0.0);
3238
3239 DoubleRepresentation rep(value);
3240 if (rep.bits == minus_zero.bits) {
3241 return AllocateHeapNumber(-0.0, pretenure);
3242 }
3243
3244 int int_value = FastD2I(value);
3245 if (value == int_value && Smi::IsValid(int_value)) {
3246 return Smi::FromInt(int_value);
3247 }
3248
3249 // Materialize the value in the heap.
3250 return AllocateHeapNumber(value, pretenure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003251}
3252
3253
ager@chromium.orgea91cc52011-05-23 06:06:11 +00003254MaybeObject* Heap::AllocateForeign(Address address, PretenureFlag pretenure) {
3255 // Statically ensure that it is safe to allocate foreigns in paged spaces.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003256 STATIC_ASSERT(Foreign::kSize <= Page::kMaxNonCodeHeapObjectSize);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003257 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003258 Foreign* result;
3259 MaybeObject* maybe_result = Allocate(foreign_map(), space);
3260 if (!maybe_result->To(&result)) return maybe_result;
3261 result->set_foreign_address(address);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003262 return result;
3263}
3264
3265
lrn@chromium.org303ada72010-10-27 09:33:13 +00003266MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003267 SharedFunctionInfo* share;
3268 MaybeObject* maybe = Allocate(shared_function_info_map(), OLD_POINTER_SPACE);
3269 if (!maybe->To<SharedFunctionInfo>(&share)) return maybe;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003270
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003271 // Set pointer fields.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003272 share->set_name(name);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003273 Code* illegal = isolate_->builtins()->builtin(Builtins::kIllegal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003274 share->set_code(illegal);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003275 share->ClearOptimizedCodeMap();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003276 share->set_scope_info(ScopeInfo::Empty());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003277 Code* construct_stub =
3278 isolate_->builtins()->builtin(Builtins::kJSConstructStubGeneric);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003279 share->set_construct_stub(construct_stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003280 share->set_instance_class_name(Object_symbol());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003281 share->set_function_data(undefined_value(), SKIP_WRITE_BARRIER);
3282 share->set_script(undefined_value(), SKIP_WRITE_BARRIER);
3283 share->set_debug_info(undefined_value(), SKIP_WRITE_BARRIER);
3284 share->set_inferred_name(empty_string(), SKIP_WRITE_BARRIER);
3285 share->set_initial_map(undefined_value(), SKIP_WRITE_BARRIER);
3286 share->set_this_property_assignments(undefined_value(), SKIP_WRITE_BARRIER);
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00003287 share->set_ast_node_count(0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003288 share->set_stress_deopt_counter(FLAG_deopt_every_n_times);
3289 share->set_counters(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003290
3291 // Set integer fields (smi or int, depending on the architecture).
3292 share->set_length(0);
3293 share->set_formal_parameter_count(0);
3294 share->set_expected_nof_properties(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003295 share->set_num_literals(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003296 share->set_start_position_and_type(0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003297 share->set_end_position(0);
3298 share->set_function_token_position(0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003299 // All compiler hints default to false or 0.
3300 share->set_compiler_hints(0);
3301 share->set_this_property_assignments_count(0);
3302 share->set_opt_count(0);
3303
3304 return share;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003305}
3306
3307
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003308MaybeObject* Heap::AllocateJSMessageObject(String* type,
3309 JSArray* arguments,
3310 int start_position,
3311 int end_position,
3312 Object* script,
3313 Object* stack_trace,
3314 Object* stack_frames) {
3315 Object* result;
3316 { MaybeObject* maybe_result = Allocate(message_object_map(), NEW_SPACE);
3317 if (!maybe_result->ToObject(&result)) return maybe_result;
3318 }
3319 JSMessageObject* message = JSMessageObject::cast(result);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003320 message->set_properties(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003321 message->initialize_elements();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003322 message->set_elements(Heap::empty_fixed_array(), SKIP_WRITE_BARRIER);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003323 message->set_type(type);
3324 message->set_arguments(arguments);
3325 message->set_start_position(start_position);
3326 message->set_end_position(end_position);
3327 message->set_script(script);
3328 message->set_stack_trace(stack_trace);
3329 message->set_stack_frames(stack_frames);
3330 return result;
3331}
3332
3333
3334
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003335// Returns true for a character in a range. Both limits are inclusive.
3336static inline bool Between(uint32_t character, uint32_t from, uint32_t to) {
3337 // This makes uses of the the unsigned wraparound.
3338 return character - from <= to - from;
3339}
3340
3341
lrn@chromium.org303ada72010-10-27 09:33:13 +00003342MUST_USE_RESULT static inline MaybeObject* MakeOrFindTwoCharacterString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003343 Heap* heap,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003344 uint32_t c1,
3345 uint32_t c2) {
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003346 String* symbol;
3347 // Numeric strings have a different hash algorithm not known by
3348 // LookupTwoCharsSymbolIfExists, so we skip this step for such strings.
3349 if ((!Between(c1, '0', '9') || !Between(c2, '0', '9')) &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003350 heap->symbol_table()->LookupTwoCharsSymbolIfExists(c1, c2, &symbol)) {
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003351 return symbol;
3352 // Now we know the length is 2, we might as well make use of that fact
3353 // when building the new string.
3354 } else if ((c1 | c2) <= String::kMaxAsciiCharCodeU) { // We can do this
3355 ASSERT(IsPowerOf2(String::kMaxAsciiCharCodeU + 1)); // because of this.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003356 Object* result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003357 { MaybeObject* maybe_result = heap->AllocateRawOneByteString(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003358 if (!maybe_result->ToObject(&result)) return maybe_result;
3359 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003360 char* dest = SeqOneByteString::cast(result)->GetChars();
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003361 dest[0] = c1;
3362 dest[1] = c2;
3363 return result;
3364 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003365 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003366 { MaybeObject* maybe_result = heap->AllocateRawTwoByteString(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003367 if (!maybe_result->ToObject(&result)) return maybe_result;
3368 }
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003369 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
3370 dest[0] = c1;
3371 dest[1] = c2;
3372 return result;
3373 }
3374}
3375
3376
lrn@chromium.org303ada72010-10-27 09:33:13 +00003377MaybeObject* Heap::AllocateConsString(String* first, String* second) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003378 int first_length = first->length();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003379 if (first_length == 0) {
3380 return second;
3381 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003382
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003383 int second_length = second->length();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003384 if (second_length == 0) {
3385 return first;
3386 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003387
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003388 int length = first_length + second_length;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003389
3390 // Optimization for 2-byte strings often used as keys in a decompression
3391 // dictionary. Check whether we already have the string in the symbol
3392 // table to prevent creation of many unneccesary strings.
3393 if (length == 2) {
3394 unsigned c1 = first->Get(0);
3395 unsigned c2 = second->Get(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003396 return MakeOrFindTwoCharacterString(this, c1, c2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003397 }
3398
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003399 bool first_is_ascii = first->IsOneByteRepresentation();
3400 bool second_is_ascii = second->IsOneByteRepresentation();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003401 bool is_ascii = first_is_ascii && second_is_ascii;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003402
ager@chromium.org3e875802009-06-29 08:26:34 +00003403 // Make sure that an out of memory exception is thrown if the length
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003404 // of the new cons string is too large.
3405 if (length > String::kMaxLength || length < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003406 isolate()->context()->mark_out_of_memory();
ager@chromium.org3e875802009-06-29 08:26:34 +00003407 return Failure::OutOfMemoryException();
3408 }
3409
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003410 bool is_ascii_data_in_two_byte_string = false;
3411 if (!is_ascii) {
3412 // At least one of the strings uses two-byte representation so we
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003413 // can't use the fast case code for short ASCII strings below, but
3414 // we can try to save memory if all chars actually fit in ASCII.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003415 is_ascii_data_in_two_byte_string =
3416 first->HasOnlyAsciiChars() && second->HasOnlyAsciiChars();
3417 if (is_ascii_data_in_two_byte_string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003418 isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003419 }
3420 }
3421
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003422 // If the resulting string is small make a flat string.
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003423 if (length < ConsString::kMinLength) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003424 // Note that neither of the two inputs can be a slice because:
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003425 STATIC_ASSERT(ConsString::kMinLength <= SlicedString::kMinLength);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003426 ASSERT(first->IsFlat());
3427 ASSERT(second->IsFlat());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003428 if (is_ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003429 Object* result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003430 { MaybeObject* maybe_result = AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003431 if (!maybe_result->ToObject(&result)) return maybe_result;
3432 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003433 // Copy the characters into the new object.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003434 char* dest = SeqOneByteString::cast(result)->GetChars();
ager@chromium.org3e875802009-06-29 08:26:34 +00003435 // Copy first part.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003436 const char* src;
3437 if (first->IsExternalString()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003438 src = ExternalAsciiString::cast(first)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003439 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003440 src = SeqOneByteString::cast(first)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003441 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003442 for (int i = 0; i < first_length; i++) *dest++ = src[i];
3443 // Copy second part.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003444 if (second->IsExternalString()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003445 src = ExternalAsciiString::cast(second)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003446 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003447 src = SeqOneByteString::cast(second)->GetChars();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003448 }
ager@chromium.org3e875802009-06-29 08:26:34 +00003449 for (int i = 0; i < second_length; i++) *dest++ = src[i];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003450 return result;
3451 } else {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003452 if (is_ascii_data_in_two_byte_string) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003453 Object* result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003454 { MaybeObject* maybe_result = AllocateRawOneByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003455 if (!maybe_result->ToObject(&result)) return maybe_result;
3456 }
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003457 // Copy the characters into the new object.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003458 char* dest = SeqOneByteString::cast(result)->GetChars();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003459 String::WriteToFlat(first, dest, 0, first_length);
3460 String::WriteToFlat(second, dest + first_length, 0, second_length);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003461 isolate_->counters()->string_add_runtime_ext_to_ascii()->Increment();
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00003462 return result;
3463 }
3464
lrn@chromium.org303ada72010-10-27 09:33:13 +00003465 Object* result;
3466 { MaybeObject* maybe_result = AllocateRawTwoByteString(length);
3467 if (!maybe_result->ToObject(&result)) return maybe_result;
3468 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003469 // Copy the characters into the new object.
3470 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003471 String::WriteToFlat(first, dest, 0, first_length);
3472 String::WriteToFlat(second, dest + first_length, 0, second_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003473 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003474 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003475 }
3476
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003477 Map* map = (is_ascii || is_ascii_data_in_two_byte_string) ?
3478 cons_ascii_string_map() : cons_string_map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003479
lrn@chromium.org303ada72010-10-27 09:33:13 +00003480 Object* result;
3481 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3482 if (!maybe_result->ToObject(&result)) return maybe_result;
3483 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003484
3485 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003486 ConsString* cons_string = ConsString::cast(result);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003487 WriteBarrierMode mode = cons_string->GetWriteBarrierMode(no_gc);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003488 cons_string->set_length(length);
3489 cons_string->set_hash_field(String::kEmptyHashField);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003490 cons_string->set_first(first, mode);
3491 cons_string->set_second(second, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003492 return result;
3493}
3494
3495
lrn@chromium.org303ada72010-10-27 09:33:13 +00003496MaybeObject* Heap::AllocateSubString(String* buffer,
ager@chromium.org04921a82011-06-27 13:21:41 +00003497 int start,
3498 int end,
3499 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003500 int length = end - start;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003501 if (length <= 0) {
ager@chromium.org04921a82011-06-27 13:21:41 +00003502 return empty_string();
3503 } else if (length == 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003504 return LookupSingleCharacterStringFromCode(buffer->Get(start));
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003505 } else if (length == 2) {
3506 // Optimization for 2-byte strings often used as keys in a decompression
3507 // dictionary. Check whether we already have the string in the symbol
3508 // table to prevent creation of many unneccesary strings.
3509 unsigned c1 = buffer->Get(start);
3510 unsigned c2 = buffer->Get(start + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003511 return MakeOrFindTwoCharacterString(this, c1, c2);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003512 }
3513
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003514 // Make an attempt to flatten the buffer to reduce access time.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003515 buffer = buffer->TryFlattenGetString();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003516
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003517 if (!FLAG_string_slices ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003518 !buffer->IsFlat() ||
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003519 length < SlicedString::kMinLength ||
3520 pretenure == TENURED) {
3521 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003522 // WriteToFlat takes care of the case when an indirect string has a
3523 // different encoding from its underlying string. These encodings may
3524 // differ because of externalization.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003525 bool is_ascii = buffer->IsOneByteRepresentation();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003526 { MaybeObject* maybe_result = is_ascii
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003527 ? AllocateRawOneByteString(length, pretenure)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003528 : AllocateRawTwoByteString(length, pretenure);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003529 if (!maybe_result->ToObject(&result)) return maybe_result;
3530 }
3531 String* string_result = String::cast(result);
3532 // Copy the characters into the new object.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003533 if (is_ascii) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003534 ASSERT(string_result->IsOneByteRepresentation());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003535 char* dest = SeqOneByteString::cast(string_result)->GetChars();
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003536 String::WriteToFlat(buffer, dest, start, end);
3537 } else {
3538 ASSERT(string_result->IsTwoByteRepresentation());
3539 uc16* dest = SeqTwoByteString::cast(string_result)->GetChars();
3540 String::WriteToFlat(buffer, dest, start, end);
3541 }
3542 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003543 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003544
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003545 ASSERT(buffer->IsFlat());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003546#if VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003547 if (FLAG_verify_heap) {
3548 buffer->StringVerify();
3549 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003550#endif
3551
3552 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003553 // When slicing an indirect string we use its encoding for a newly created
3554 // slice and don't check the encoding of the underlying string. This is safe
3555 // even if the encodings are different because of externalization. If an
3556 // indirect ASCII string is pointing to a two-byte string, the two-byte char
3557 // codes of the underlying string must still fit into ASCII (because
3558 // externalization must not change char codes).
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003559 { Map* map = buffer->IsOneByteRepresentation()
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003560 ? sliced_ascii_string_map()
3561 : sliced_string_map();
3562 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3563 if (!maybe_result->ToObject(&result)) return maybe_result;
3564 }
3565
3566 AssertNoAllocation no_gc;
3567 SlicedString* sliced_string = SlicedString::cast(result);
3568 sliced_string->set_length(length);
3569 sliced_string->set_hash_field(String::kEmptyHashField);
3570 if (buffer->IsConsString()) {
3571 ConsString* cons = ConsString::cast(buffer);
3572 ASSERT(cons->second()->length() == 0);
3573 sliced_string->set_parent(cons->first());
3574 sliced_string->set_offset(start);
3575 } else if (buffer->IsSlicedString()) {
3576 // Prevent nesting sliced strings.
3577 SlicedString* parent_slice = SlicedString::cast(buffer);
3578 sliced_string->set_parent(parent_slice->parent());
3579 sliced_string->set_offset(start + parent_slice->offset());
3580 } else {
3581 sliced_string->set_parent(buffer);
3582 sliced_string->set_offset(start);
3583 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003584 ASSERT(sliced_string->parent()->IsSeqString() ||
3585 sliced_string->parent()->IsExternalString());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003586 return result;
3587}
3588
3589
lrn@chromium.org303ada72010-10-27 09:33:13 +00003590MaybeObject* Heap::AllocateExternalStringFromAscii(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003591 const ExternalAsciiString::Resource* resource) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003592 size_t length = resource->length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003593 if (length > static_cast<size_t>(String::kMaxLength)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003594 isolate()->context()->mark_out_of_memory();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003595 return Failure::OutOfMemoryException();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003596 }
3597
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00003598 ASSERT(String::IsAscii(resource->data(), static_cast<int>(length)));
3599
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003600 Map* map = external_ascii_string_map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003601 Object* result;
3602 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3603 if (!maybe_result->ToObject(&result)) return maybe_result;
3604 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003605
3606 ExternalAsciiString* external_string = ExternalAsciiString::cast(result);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003607 external_string->set_length(static_cast<int>(length));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003608 external_string->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003609 external_string->set_resource(resource);
3610
3611 return result;
3612}
3613
3614
lrn@chromium.org303ada72010-10-27 09:33:13 +00003615MaybeObject* Heap::AllocateExternalStringFromTwoByte(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003616 const ExternalTwoByteString::Resource* resource) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003617 size_t length = resource->length();
3618 if (length > static_cast<size_t>(String::kMaxLength)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 isolate()->context()->mark_out_of_memory();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003620 return Failure::OutOfMemoryException();
3621 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003622
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003623 // For small strings we check whether the resource contains only
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003624 // ASCII characters. If yes, we use a different string map.
3625 static const size_t kAsciiCheckLengthLimit = 32;
3626 bool is_ascii = length <= kAsciiCheckLengthLimit &&
3627 String::IsAscii(resource->data(), static_cast<int>(length));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003628 Map* map = is_ascii ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003629 external_string_with_ascii_data_map() : external_string_map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003630 Object* result;
3631 { MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
3632 if (!maybe_result->ToObject(&result)) return maybe_result;
3633 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003634
3635 ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003636 external_string->set_length(static_cast<int>(length));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003637 external_string->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003638 external_string->set_resource(resource);
3639
3640 return result;
3641}
3642
3643
lrn@chromium.org303ada72010-10-27 09:33:13 +00003644MaybeObject* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003645 if (code <= String::kMaxAsciiCharCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003646 Object* value = single_character_string_cache()->get(code);
3647 if (value != undefined_value()) return value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003648
3649 char buffer[1];
3650 buffer[0] = static_cast<char>(code);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003651 Object* result;
3652 MaybeObject* maybe_result = LookupSymbol(Vector<const char>(buffer, 1));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003653
lrn@chromium.org303ada72010-10-27 09:33:13 +00003654 if (!maybe_result->ToObject(&result)) return maybe_result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003655 single_character_string_cache()->set(code, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003656 return result;
3657 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003658
lrn@chromium.org303ada72010-10-27 09:33:13 +00003659 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003660 { MaybeObject* maybe_result = AllocateRawTwoByteString(1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003661 if (!maybe_result->ToObject(&result)) return maybe_result;
3662 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00003663 String* answer = String::cast(result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003664 answer->Set(0, code);
ager@chromium.org870a0b62008-11-04 11:43:05 +00003665 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003666}
3667
3668
lrn@chromium.org303ada72010-10-27 09:33:13 +00003669MaybeObject* Heap::AllocateByteArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003670 if (length < 0 || length > ByteArray::kMaxLength) {
3671 return Failure::OutOfMemoryException();
3672 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003673 if (pretenure == NOT_TENURED) {
3674 return AllocateByteArray(length);
3675 }
3676 int size = ByteArray::SizeFor(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003677 Object* result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003678 { MaybeObject* maybe_result = (size <= Page::kMaxNonCodeHeapObjectSize)
lrn@chromium.org303ada72010-10-27 09:33:13 +00003679 ? old_data_space_->AllocateRaw(size)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003680 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003681 if (!maybe_result->ToObject(&result)) return maybe_result;
3682 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003683
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003684 reinterpret_cast<ByteArray*>(result)->set_map_no_write_barrier(
3685 byte_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003686 reinterpret_cast<ByteArray*>(result)->set_length(length);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003687 return result;
3688}
3689
3690
lrn@chromium.org303ada72010-10-27 09:33:13 +00003691MaybeObject* Heap::AllocateByteArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003692 if (length < 0 || length > ByteArray::kMaxLength) {
3693 return Failure::OutOfMemoryException();
3694 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003695 int size = ByteArray::SizeFor(length);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003696 AllocationSpace space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003697 (size > Page::kMaxNonCodeHeapObjectSize) ? LO_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003698 Object* result;
3699 { MaybeObject* maybe_result = AllocateRaw(size, space, OLD_DATA_SPACE);
3700 if (!maybe_result->ToObject(&result)) return maybe_result;
3701 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003702
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003703 reinterpret_cast<ByteArray*>(result)->set_map_no_write_barrier(
3704 byte_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003705 reinterpret_cast<ByteArray*>(result)->set_length(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003706 return result;
3707}
3708
3709
ager@chromium.org6f10e412009-02-13 10:11:16 +00003710void Heap::CreateFillerObjectAt(Address addr, int size) {
3711 if (size == 0) return;
3712 HeapObject* filler = HeapObject::FromAddress(addr);
3713 if (size == kPointerSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003714 filler->set_map_no_write_barrier(one_pointer_filler_map());
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00003715 } else if (size == 2 * kPointerSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003716 filler->set_map_no_write_barrier(two_pointer_filler_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +00003717 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003718 filler->set_map_no_write_barrier(free_space_map());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003719 FreeSpace::cast(filler)->set_size(size);
ager@chromium.org6f10e412009-02-13 10:11:16 +00003720 }
3721}
3722
3723
lrn@chromium.org303ada72010-10-27 09:33:13 +00003724MaybeObject* Heap::AllocateExternalArray(int length,
3725 ExternalArrayType array_type,
3726 void* external_pointer,
3727 PretenureFlag pretenure) {
ager@chromium.org3811b432009-10-28 14:53:37 +00003728 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003729 Object* result;
3730 { MaybeObject* maybe_result = AllocateRaw(ExternalArray::kAlignedSize,
3731 space,
3732 OLD_DATA_SPACE);
3733 if (!maybe_result->ToObject(&result)) return maybe_result;
3734 }
ager@chromium.org3811b432009-10-28 14:53:37 +00003735
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003736 reinterpret_cast<ExternalArray*>(result)->set_map_no_write_barrier(
ager@chromium.org3811b432009-10-28 14:53:37 +00003737 MapForExternalArrayType(array_type));
3738 reinterpret_cast<ExternalArray*>(result)->set_length(length);
3739 reinterpret_cast<ExternalArray*>(result)->set_external_pointer(
3740 external_pointer);
3741
3742 return result;
3743}
3744
3745
lrn@chromium.org303ada72010-10-27 09:33:13 +00003746MaybeObject* Heap::CreateCode(const CodeDesc& desc,
3747 Code::Flags flags,
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003748 Handle<Object> self_reference,
3749 bool immovable) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003750 // Allocate ByteArray before the Code object, so that we do not risk
3751 // leaving uninitialized Code object (and breaking the heap).
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003752 ByteArray* reloc_info;
3753 MaybeObject* maybe_reloc_info = AllocateByteArray(desc.reloc_size, TENURED);
3754 if (!maybe_reloc_info->To(&reloc_info)) return maybe_reloc_info;
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003755
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003756 // Compute size.
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003757 int body_size = RoundUp(desc.instr_size, kObjectAlignment);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003758 int obj_size = Code::SizeFor(body_size);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003759 ASSERT(IsAligned(static_cast<intptr_t>(obj_size), kCodeAlignment));
lrn@chromium.org303ada72010-10-27 09:33:13 +00003760 MaybeObject* maybe_result;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003761 // Large code objects and code objects which should stay at a fixed address
3762 // are allocated in large object space.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003763 HeapObject* result;
3764 bool force_lo_space = obj_size > code_space()->AreaSize();
3765 if (force_lo_space) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003766 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003767 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003768 maybe_result = code_space_->AllocateRaw(obj_size);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003769 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003770 if (!maybe_result->To<HeapObject>(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003771
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003772 if (immovable && !force_lo_space &&
3773 // Objects on the first page of each space are never moved.
3774 !code_space_->FirstPage()->Contains(result->address())) {
3775 // Discard the first code allocation, which was on a page where it could be
3776 // moved.
3777 CreateFillerObjectAt(result->address(), obj_size);
3778 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
3779 if (!maybe_result->To<HeapObject>(&result)) return maybe_result;
3780 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003781
3782 // Initialize the object
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003783 result->set_map_no_write_barrier(code_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003784 Code* code = Code::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003785 ASSERT(!isolate_->code_range()->exists() ||
3786 isolate_->code_range()->contains(code->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003787 code->set_instruction_size(desc.instr_size);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00003788 code->set_relocation_info(reloc_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003789 code->set_flags(flags);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003790 if (code->is_call_stub() || code->is_keyed_call_stub()) {
3791 code->set_check_type(RECEIVER_MAP_CHECK);
3792 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003793 code->set_deoptimization_data(empty_fixed_array(), SKIP_WRITE_BARRIER);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003794 code->InitializeTypeFeedbackInfoNoWriteBarrier(undefined_value());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003795 code->set_handler_table(empty_fixed_array(), SKIP_WRITE_BARRIER);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00003796 code->set_gc_metadata(Smi::FromInt(0));
danno@chromium.org88aa0582012-03-23 15:11:57 +00003797 code->set_ic_age(global_ic_age_);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003798 code->set_prologue_offset(kPrologueOffsetNotSet);
kasperl@chromium.org061ef742009-02-27 12:16:20 +00003799 // Allow self references to created code object by patching the handle to
3800 // point to the newly allocated Code object.
3801 if (!self_reference.is_null()) {
3802 *(self_reference.location()) = code;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003803 }
3804 // Migrate generated code.
3805 // The generated code can contain Object** values (typically from handles)
3806 // that are dereferenced during the copy to point directly to the actual heap
3807 // objects. These pointers can include references to the code object itself,
3808 // through the self_reference parameter.
3809 code->CopyFrom(desc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003810
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003811#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003812 if (FLAG_verify_heap) {
3813 code->Verify();
3814 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003815#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003816 return code;
3817}
3818
3819
lrn@chromium.org303ada72010-10-27 09:33:13 +00003820MaybeObject* Heap::CopyCode(Code* code) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003821 // Allocate an object the same size as the code object.
3822 int obj_size = code->Size();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003823 MaybeObject* maybe_result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003824 if (obj_size > code_space()->AreaSize()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003825 maybe_result = lo_space_->AllocateRaw(obj_size, EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003826 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003827 maybe_result = code_space_->AllocateRaw(obj_size);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003828 }
3829
lrn@chromium.org303ada72010-10-27 09:33:13 +00003830 Object* result;
3831 if (!maybe_result->ToObject(&result)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003832
3833 // Copy code object.
3834 Address old_addr = code->address();
3835 Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003836 CopyBlock(new_addr, old_addr, obj_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003837 // Relocate the copy.
3838 Code* new_code = Code::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003839 ASSERT(!isolate_->code_range()->exists() ||
3840 isolate_->code_range()->contains(code->address()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003841 new_code->Relocate(new_addr - old_addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003842 return new_code;
3843}
3844
3845
lrn@chromium.org303ada72010-10-27 09:33:13 +00003846MaybeObject* Heap::CopyCode(Code* code, Vector<byte> reloc_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003847 // Allocate ByteArray before the Code object, so that we do not risk
3848 // leaving uninitialized Code object (and breaking the heap).
lrn@chromium.org303ada72010-10-27 09:33:13 +00003849 Object* reloc_info_array;
3850 { MaybeObject* maybe_reloc_info_array =
3851 AllocateByteArray(reloc_info.length(), TENURED);
3852 if (!maybe_reloc_info_array->ToObject(&reloc_info_array)) {
3853 return maybe_reloc_info_array;
3854 }
3855 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003856
3857 int new_body_size = RoundUp(code->instruction_size(), kObjectAlignment);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003858
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003859 int new_obj_size = Code::SizeFor(new_body_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003860
3861 Address old_addr = code->address();
3862
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00003863 size_t relocation_offset =
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003864 static_cast<size_t>(code->instruction_end() - old_addr);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003865
lrn@chromium.org303ada72010-10-27 09:33:13 +00003866 MaybeObject* maybe_result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00003867 if (new_obj_size > code_space()->AreaSize()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003868 maybe_result = lo_space_->AllocateRaw(new_obj_size, EXECUTABLE);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003869 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003870 maybe_result = code_space_->AllocateRaw(new_obj_size);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003871 }
3872
lrn@chromium.org303ada72010-10-27 09:33:13 +00003873 Object* result;
3874 if (!maybe_result->ToObject(&result)) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003875
3876 // Copy code object.
3877 Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
3878
3879 // Copy header and instructions.
3880 memcpy(new_addr, old_addr, relocation_offset);
3881
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003882 Code* new_code = Code::cast(result);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003883 new_code->set_relocation_info(ByteArray::cast(reloc_info_array));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003884
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003885 // Copy patched rinfo.
3886 memcpy(new_code->relocation_start(), reloc_info.start(), reloc_info.length());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003887
3888 // Relocate the copy.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003889 ASSERT(!isolate_->code_range()->exists() ||
3890 isolate_->code_range()->contains(code->address()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003891 new_code->Relocate(new_addr - old_addr);
3892
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003893#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003894 if (FLAG_verify_heap) {
3895 code->Verify();
3896 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00003897#endif
3898 return new_code;
3899}
3900
3901
lrn@chromium.org303ada72010-10-27 09:33:13 +00003902MaybeObject* Heap::Allocate(Map* map, AllocationSpace space) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003903 ASSERT(gc_state_ == NOT_IN_GC);
3904 ASSERT(map->instance_type() != MAP_TYPE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003905 // If allocation failures are disallowed, we may allocate in a different
3906 // space when new space is full and the object is not a large object.
3907 AllocationSpace retry_space =
3908 (space != NEW_SPACE) ? space : TargetSpaceId(map->instance_type());
lrn@chromium.org303ada72010-10-27 09:33:13 +00003909 Object* result;
3910 { MaybeObject* maybe_result =
3911 AllocateRaw(map->instance_size(), space, retry_space);
3912 if (!maybe_result->ToObject(&result)) return maybe_result;
3913 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003914 // No need for write barrier since object is white and map is in old space.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003915 HeapObject::cast(result)->set_map_no_write_barrier(map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003916 return result;
3917}
3918
3919
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003920void Heap::InitializeFunction(JSFunction* function,
3921 SharedFunctionInfo* shared,
3922 Object* prototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003923 ASSERT(!prototype->IsMap());
3924 function->initialize_properties();
3925 function->initialize_elements();
3926 function->set_shared(shared);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00003927 function->set_code(shared->code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003928 function->set_prototype_or_initial_map(prototype);
3929 function->set_context(undefined_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003930 function->set_literals_or_bindings(empty_fixed_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003931 function->set_next_function_link(undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003932}
3933
3934
lrn@chromium.org303ada72010-10-27 09:33:13 +00003935MaybeObject* Heap::AllocateFunctionPrototype(JSFunction* function) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00003936 // Allocate the prototype. Make sure to use the object function
3937 // from the function's context, since the function can be from a
3938 // different context.
3939 JSFunction* object_function =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003940 function->context()->native_context()->object_function();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003941
3942 // Each function prototype gets a copy of the object function map.
3943 // This avoid unwanted sharing of maps between prototypes of different
3944 // constructors.
3945 Map* new_map;
3946 ASSERT(object_function->has_initial_map());
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003947 MaybeObject* maybe_map = object_function->initial_map()->Copy();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003948 if (!maybe_map->To(&new_map)) return maybe_map;
3949
lrn@chromium.org303ada72010-10-27 09:33:13 +00003950 Object* prototype;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003951 MaybeObject* maybe_prototype = AllocateJSObjectFromMap(new_map);
3952 if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
3953
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003954 // When creating the prototype for the function we must set its
3955 // constructor to the function.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003956 MaybeObject* maybe_failure =
3957 JSObject::cast(prototype)->SetLocalPropertyIgnoreAttributes(
3958 constructor_symbol(), function, DONT_ENUM);
3959 if (maybe_failure->IsFailure()) return maybe_failure;
3960
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003961 return prototype;
3962}
3963
3964
lrn@chromium.org303ada72010-10-27 09:33:13 +00003965MaybeObject* Heap::AllocateFunction(Map* function_map,
3966 SharedFunctionInfo* shared,
3967 Object* prototype,
3968 PretenureFlag pretenure) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00003969 AllocationSpace space =
3970 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003971 Object* result;
3972 { MaybeObject* maybe_result = Allocate(function_map, space);
3973 if (!maybe_result->ToObject(&result)) return maybe_result;
3974 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003975 InitializeFunction(JSFunction::cast(result), shared, prototype);
3976 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977}
3978
3979
lrn@chromium.org303ada72010-10-27 09:33:13 +00003980MaybeObject* Heap::AllocateArgumentsObject(Object* callee, int length) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003981 // To get fast allocation and map sharing for arguments objects we
3982 // allocate them based on an arguments boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003983
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003984 JSObject* boilerplate;
3985 int arguments_object_size;
3986 bool strict_mode_callee = callee->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003987 !JSFunction::cast(callee)->shared()->is_classic_mode();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003988 if (strict_mode_callee) {
3989 boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003990 isolate()->context()->native_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003991 strict_mode_arguments_boilerplate();
3992 arguments_object_size = kArgumentsObjectSizeStrict;
3993 } else {
3994 boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003995 isolate()->context()->native_context()->arguments_boilerplate();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003996 arguments_object_size = kArgumentsObjectSize;
3997 }
3998
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003999 // This calls Copy directly rather than using Heap::AllocateRaw so we
4000 // duplicate the check here.
4001 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
4002
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00004003 // Check that the size of the boilerplate matches our
4004 // expectations. The ArgumentsAccessStub::GenerateNewObject relies
4005 // on the size being a known constant.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004006 ASSERT(arguments_object_size == boilerplate->map()->instance_size());
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00004007
4008 // Do the allocation.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004009 Object* result;
4010 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004011 AllocateRaw(arguments_object_size, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004012 if (!maybe_result->ToObject(&result)) return maybe_result;
4013 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004015 // Copy the content. The arguments boilerplate doesn't have any
4016 // fields that point to new space so it's safe to skip the write
4017 // barrier here.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004018 CopyBlock(HeapObject::cast(result)->address(),
4019 boilerplate->address(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004020 JSObject::kHeaderSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004022 // Set the length property.
4023 JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsLengthIndex,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004024 Smi::FromInt(length),
4025 SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004026 // Set the callee property for non-strict mode arguments object only.
4027 if (!strict_mode_callee) {
4028 JSObject::cast(result)->InObjectPropertyAtPut(kArgumentsCalleeIndex,
4029 callee);
4030 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004031
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 // Check the state of the object
4033 ASSERT(JSObject::cast(result)->HasFastProperties());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004034 ASSERT(JSObject::cast(result)->HasFastObjectElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004035
4036 return result;
4037}
4038
4039
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004040static bool HasDuplicates(DescriptorArray* descriptors) {
4041 int count = descriptors->number_of_descriptors();
4042 if (count > 1) {
4043 String* prev_key = descriptors->GetKey(0);
4044 for (int i = 1; i != count; i++) {
4045 String* current_key = descriptors->GetKey(i);
4046 if (prev_key == current_key) return true;
4047 prev_key = current_key;
4048 }
4049 }
4050 return false;
4051}
4052
4053
lrn@chromium.org303ada72010-10-27 09:33:13 +00004054MaybeObject* Heap::AllocateInitialMap(JSFunction* fun) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004055 ASSERT(!fun->has_initial_map());
4056
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004057 // First create a new map with the size and number of in-object properties
4058 // suggested by the function.
4059 int instance_size = fun->shared()->CalculateInstanceSize();
4060 int in_object_properties = fun->shared()->CalculateInObjectProperties();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004061 Map* map;
4062 MaybeObject* maybe_map = AllocateMap(JS_OBJECT_TYPE, instance_size);
4063 if (!maybe_map->To(&map)) return maybe_map;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004064
4065 // Fetch or allocate prototype.
4066 Object* prototype;
4067 if (fun->has_instance_prototype()) {
4068 prototype = fun->instance_prototype();
4069 } else {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004070 MaybeObject* maybe_prototype = AllocateFunctionPrototype(fun);
4071 if (!maybe_prototype->To(&prototype)) return maybe_prototype;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004073 map->set_inobject_properties(in_object_properties);
4074 map->set_unused_property_fields(in_object_properties);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075 map->set_prototype(prototype);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004076 ASSERT(map->has_fast_object_elements());
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004077
ager@chromium.org5c838252010-02-19 08:53:10 +00004078 // If the function has only simple this property assignments add
4079 // field descriptors for these to the initial map as the object
4080 // cannot be constructed without having these properties. Guard by
4081 // the inline_new flag so we only change the map if we generate a
4082 // specialized construct stub.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004083 ASSERT(in_object_properties <= Map::kMaxPreAllocatedPropertyFields);
ager@chromium.org5c838252010-02-19 08:53:10 +00004084 if (fun->shared()->CanGenerateInlineConstructor(prototype)) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004085 int count = fun->shared()->this_property_assignments_count();
4086 if (count > in_object_properties) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004087 // Inline constructor can only handle inobject properties.
4088 fun->shared()->ForbidInlineConstructor();
4089 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004090 DescriptorArray* descriptors;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00004091 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(count);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004092 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
4093
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004094 DescriptorArray::WhitenessWitness witness(descriptors);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004095 for (int i = 0; i < count; i++) {
4096 String* name = fun->shared()->GetThisPropertyAssignmentName(i);
4097 ASSERT(name->IsSymbol());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004098 FieldDescriptor field(name, i, NONE, i + 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004099 descriptors->Set(i, &field, witness);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004100 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004101 descriptors->Sort();
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004102
4103 // The descriptors may contain duplicates because the compiler does not
4104 // guarantee the uniqueness of property names (it would have required
4105 // quadratic time). Once the descriptors are sorted we can check for
4106 // duplicates in linear time.
4107 if (HasDuplicates(descriptors)) {
4108 fun->shared()->ForbidInlineConstructor();
4109 } else {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004110 map->InitializeDescriptors(descriptors);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004111 map->set_pre_allocated_property_fields(count);
4112 map->set_unused_property_fields(in_object_properties - count);
4113 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004114 }
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004115 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004116
4117 fun->shared()->StartInobjectSlackTracking(map);
4118
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119 return map;
4120}
4121
4122
4123void Heap::InitializeJSObjectFromMap(JSObject* obj,
4124 FixedArray* properties,
4125 Map* map) {
4126 obj->set_properties(properties);
4127 obj->initialize_elements();
4128 // TODO(1240798): Initialize the object's body using valid initial values
4129 // according to the object's initial map. For example, if the map's
4130 // instance type is JS_ARRAY_TYPE, the length field should be initialized
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004131 // to a number (e.g. Smi::FromInt(0)) and the elements initialized to a
4132 // fixed array (e.g. Heap::empty_fixed_array()). Currently, the object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004133 // verification code has to cope with (temporarily) invalid objects. See
4134 // for example, JSArray::JSArrayVerify).
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004135 Object* filler;
4136 // We cannot always fill with one_pointer_filler_map because objects
4137 // created from API functions expect their internal fields to be initialized
4138 // with undefined_value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004139 // Pre-allocated fields need to be initialized with undefined_value as well
4140 // so that object accesses before the constructor completes (e.g. in the
4141 // debugger) will not cause a crash.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004142 if (map->constructor()->IsJSFunction() &&
4143 JSFunction::cast(map->constructor())->shared()->
4144 IsInobjectSlackTrackingInProgress()) {
4145 // We might want to shrink the object later.
4146 ASSERT(obj->GetInternalFieldCount() == 0);
4147 filler = Heap::one_pointer_filler_map();
4148 } else {
4149 filler = Heap::undefined_value();
4150 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004151 obj->InitializeBody(map, Heap::undefined_value(), filler);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004152}
4153
4154
lrn@chromium.org303ada72010-10-27 09:33:13 +00004155MaybeObject* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004156 // JSFunctions should be allocated using AllocateFunction to be
4157 // properly initialized.
4158 ASSERT(map->instance_type() != JS_FUNCTION_TYPE);
4159
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00004160 // Both types of global objects should be allocated using
4161 // AllocateGlobalObject to be properly initialized.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004162 ASSERT(map->instance_type() != JS_GLOBAL_OBJECT_TYPE);
4163 ASSERT(map->instance_type() != JS_BUILTINS_OBJECT_TYPE);
4164
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004165 // Allocate the backing storage for the properties.
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004166 int prop_size =
4167 map->pre_allocated_property_fields() +
4168 map->unused_property_fields() -
4169 map->inobject_properties();
4170 ASSERT(prop_size >= 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004171 Object* properties;
4172 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, pretenure);
4173 if (!maybe_properties->ToObject(&properties)) return maybe_properties;
4174 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004175
4176 // Allocate the JSObject.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004177 AllocationSpace space =
4178 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004179 if (map->instance_size() > Page::kMaxNonCodeHeapObjectSize) space = LO_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004180 Object* obj;
4181 { MaybeObject* maybe_obj = Allocate(map, space);
4182 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4183 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004184
4185 // Initialize the JSObject.
4186 InitializeJSObjectFromMap(JSObject::cast(obj),
4187 FixedArray::cast(properties),
4188 map);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004189 ASSERT(JSObject::cast(obj)->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190 return obj;
4191}
4192
4193
lrn@chromium.org303ada72010-10-27 09:33:13 +00004194MaybeObject* Heap::AllocateJSObject(JSFunction* constructor,
4195 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004196 // Allocate the initial map if absent.
4197 if (!constructor->has_initial_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004198 Object* initial_map;
4199 { MaybeObject* maybe_initial_map = AllocateInitialMap(constructor);
4200 if (!maybe_initial_map->ToObject(&initial_map)) return maybe_initial_map;
4201 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004202 constructor->set_initial_map(Map::cast(initial_map));
4203 Map::cast(initial_map)->set_constructor(constructor);
4204 }
4205 // Allocate the object based on the constructors initial map.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004206 MaybeObject* result = AllocateJSObjectFromMap(
4207 constructor->initial_map(), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004208#ifdef DEBUG
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004209 // Make sure result is NOT a global object if valid.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004210 Object* non_failure;
4211 ASSERT(!result->ToObject(&non_failure) || !non_failure->IsGlobalObject());
4212#endif
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004213 return result;
4214}
4215
4216
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004217MaybeObject* Heap::AllocateJSModule(Context* context, ScopeInfo* scope_info) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004218 // Allocate a fresh map. Modules do not have a prototype.
4219 Map* map;
4220 MaybeObject* maybe_map = AllocateMap(JS_MODULE_TYPE, JSModule::kSize);
4221 if (!maybe_map->To(&map)) return maybe_map;
4222 // Allocate the object based on the map.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00004223 JSModule* module;
4224 MaybeObject* maybe_module = AllocateJSObjectFromMap(map, TENURED);
4225 if (!maybe_module->To(&module)) return maybe_module;
4226 module->set_context(context);
4227 module->set_scope_info(scope_info);
4228 return module;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004229}
4230
4231
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004232MaybeObject* Heap::AllocateJSArrayAndStorage(
4233 ElementsKind elements_kind,
4234 int length,
4235 int capacity,
4236 ArrayStorageAllocationMode mode,
4237 PretenureFlag pretenure) {
4238 ASSERT(capacity >= length);
4239 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
4240 JSArray* array;
4241 if (!maybe_array->To(&array)) return maybe_array;
4242
4243 if (capacity == 0) {
4244 array->set_length(Smi::FromInt(0));
4245 array->set_elements(empty_fixed_array());
4246 return array;
4247 }
4248
4249 FixedArrayBase* elms;
4250 MaybeObject* maybe_elms = NULL;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004251 if (IsFastDoubleElementsKind(elements_kind)) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004252 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
4253 maybe_elms = AllocateUninitializedFixedDoubleArray(capacity);
4254 } else {
4255 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
4256 maybe_elms = AllocateFixedDoubleArrayWithHoles(capacity);
4257 }
4258 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004259 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004260 if (mode == DONT_INITIALIZE_ARRAY_ELEMENTS) {
4261 maybe_elms = AllocateUninitializedFixedArray(capacity);
4262 } else {
4263 ASSERT(mode == INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
4264 maybe_elms = AllocateFixedArrayWithHoles(capacity);
4265 }
4266 }
4267 if (!maybe_elms->To(&elms)) return maybe_elms;
4268
4269 array->set_elements(elms);
4270 array->set_length(Smi::FromInt(length));
4271 return array;
4272}
4273
4274
4275MaybeObject* Heap::AllocateJSArrayWithElements(
4276 FixedArrayBase* elements,
4277 ElementsKind elements_kind,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004278 int length,
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004279 PretenureFlag pretenure) {
4280 MaybeObject* maybe_array = AllocateJSArray(elements_kind, pretenure);
4281 JSArray* array;
4282 if (!maybe_array->To(&array)) return maybe_array;
4283
4284 array->set_elements(elements);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004285 array->set_length(Smi::FromInt(length));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004286 array->ValidateElements();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004287 return array;
4288}
4289
4290
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004291MaybeObject* Heap::AllocateJSProxy(Object* handler, Object* prototype) {
4292 // Allocate map.
4293 // TODO(rossberg): Once we optimize proxies, think about a scheme to share
4294 // maps. Will probably depend on the identity of the handler object, too.
danno@chromium.org40cb8782011-05-25 07:58:50 +00004295 Map* map;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004296 MaybeObject* maybe_map_obj = AllocateMap(JS_PROXY_TYPE, JSProxy::kSize);
danno@chromium.org40cb8782011-05-25 07:58:50 +00004297 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004298 map->set_prototype(prototype);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004299
4300 // Allocate the proxy object.
lrn@chromium.org34e60782011-09-15 07:25:40 +00004301 JSProxy* result;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004302 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004303 if (!maybe_result->To<JSProxy>(&result)) return maybe_result;
4304 result->InitializeBody(map->instance_size(), Smi::FromInt(0));
4305 result->set_handler(handler);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004306 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004307 return result;
4308}
4309
4310
4311MaybeObject* Heap::AllocateJSFunctionProxy(Object* handler,
4312 Object* call_trap,
4313 Object* construct_trap,
4314 Object* prototype) {
4315 // Allocate map.
4316 // TODO(rossberg): Once we optimize proxies, think about a scheme to share
4317 // maps. Will probably depend on the identity of the handler object, too.
4318 Map* map;
4319 MaybeObject* maybe_map_obj =
4320 AllocateMap(JS_FUNCTION_PROXY_TYPE, JSFunctionProxy::kSize);
4321 if (!maybe_map_obj->To<Map>(&map)) return maybe_map_obj;
4322 map->set_prototype(prototype);
4323
4324 // Allocate the proxy object.
4325 JSFunctionProxy* result;
4326 MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
4327 if (!maybe_result->To<JSFunctionProxy>(&result)) return maybe_result;
4328 result->InitializeBody(map->instance_size(), Smi::FromInt(0));
4329 result->set_handler(handler);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004330 result->set_hash(undefined_value(), SKIP_WRITE_BARRIER);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004331 result->set_call_trap(call_trap);
4332 result->set_construct_trap(construct_trap);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004333 return result;
4334}
4335
4336
lrn@chromium.org303ada72010-10-27 09:33:13 +00004337MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004338 ASSERT(constructor->has_initial_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004339 Map* map = constructor->initial_map();
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004340 ASSERT(map->is_dictionary_map());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004341
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004342 // Make sure no field properties are described in the initial map.
4343 // This guarantees us that normalizing the properties does not
4344 // require us to change property values to JSGlobalPropertyCells.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004345 ASSERT(map->NextFreePropertyIndex() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004346
4347 // Make sure we don't have a ton of pre-allocated slots in the
4348 // global objects. They will be unused once we normalize the object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004349 ASSERT(map->unused_property_fields() == 0);
4350 ASSERT(map->inobject_properties() == 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004351
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004352 // Initial size of the backing store to avoid resize of the storage during
4353 // bootstrapping. The size differs between the JS global object ad the
4354 // builtins object.
4355 int initial_size = map->instance_type() == JS_GLOBAL_OBJECT_TYPE ? 64 : 512;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004356
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004357 // Allocate a dictionary object for backing storage.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004358 StringDictionary* dictionary;
4359 MaybeObject* maybe_dictionary =
4360 StringDictionary::Allocate(
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004361 map->NumberOfOwnDescriptors() * 2 + initial_size);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004362 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004363
4364 // The global object might be created from an object template with accessors.
4365 // Fill these accessors into the dictionary.
4366 DescriptorArray* descs = map->instance_descriptors();
4367 for (int i = 0; i < descs->number_of_descriptors(); i++) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004368 PropertyDetails details = descs->GetDetails(i);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004369 ASSERT(details.type() == CALLBACKS); // Only accessors are expected.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004370 PropertyDetails d = PropertyDetails(details.attributes(),
4371 CALLBACKS,
4372 details.descriptor_index());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004373 Object* value = descs->GetCallbacksObject(i);
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004374 MaybeObject* maybe_value = AllocateJSGlobalPropertyCell(value);
4375 if (!maybe_value->ToObject(&value)) return maybe_value;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004376
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004377 MaybeObject* maybe_added = dictionary->Add(descs->GetKey(i), value, d);
4378 if (!maybe_added->To(&dictionary)) return maybe_added;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004379 }
4380
4381 // Allocate the global object and initialize it with the backing store.
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004382 JSObject* global;
4383 MaybeObject* maybe_global = Allocate(map, OLD_POINTER_SPACE);
4384 if (!maybe_global->To(&global)) return maybe_global;
4385
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004386 InitializeJSObjectFromMap(global, dictionary, map);
4387
4388 // Create a new map for the global object.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00004389 Map* new_map;
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00004390 MaybeObject* maybe_map = map->CopyDropDescriptors();
4391 if (!maybe_map->To(&new_map)) return maybe_map;
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004392 new_map->set_dictionary_map(true);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004393
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004394 // Set up the global object as a normalized object.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004395 global->set_map(new_map);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004396 global->set_properties(dictionary);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004397
4398 // Make sure result is a global object with properties in dictionary.
4399 ASSERT(global->IsGlobalObject());
4400 ASSERT(!global->HasFastProperties());
4401 return global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004402}
4403
4404
lrn@chromium.org303ada72010-10-27 09:33:13 +00004405MaybeObject* Heap::CopyJSObject(JSObject* source) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004406 // Never used to copy functions. If functions need to be copied we
4407 // have to be careful to clear the literals array.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004408 SLOW_ASSERT(!source->IsJSFunction());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004409
4410 // Make the clone.
4411 Map* map = source->map();
4412 int object_size = map->instance_size();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004413 Object* clone;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004414
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004415 WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER;
4416
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004417 // If we're forced to always allocate, we use the general allocation
4418 // functions which may leave us with an object in old space.
4419 if (always_allocate()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004420 { MaybeObject* maybe_clone =
4421 AllocateRaw(object_size, NEW_SPACE, OLD_POINTER_SPACE);
4422 if (!maybe_clone->ToObject(&clone)) return maybe_clone;
4423 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004424 Address clone_address = HeapObject::cast(clone)->address();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004425 CopyBlock(clone_address,
4426 source->address(),
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004427 object_size);
4428 // Update write barrier for all fields that lie beyond the header.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00004429 RecordWrites(clone_address,
4430 JSObject::kHeaderSize,
antonm@chromium.org8e5e3382010-03-24 09:56:30 +00004431 (object_size - JSObject::kHeaderSize) / kPointerSize);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004432 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004433 wb_mode = SKIP_WRITE_BARRIER;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004434 { MaybeObject* maybe_clone = new_space_.AllocateRaw(object_size);
4435 if (!maybe_clone->ToObject(&clone)) return maybe_clone;
4436 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004437 SLOW_ASSERT(InNewSpace(clone));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004438 // Since we know the clone is allocated in new space, we can copy
ager@chromium.org32912102009-01-16 10:38:43 +00004439 // the contents without worrying about updating the write barrier.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004440 CopyBlock(HeapObject::cast(clone)->address(),
4441 source->address(),
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004442 object_size);
4443 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004444
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004445 SLOW_ASSERT(
4446 JSObject::cast(clone)->GetElementsKind() == source->GetElementsKind());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004447 FixedArrayBase* elements = FixedArrayBase::cast(source->elements());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004448 FixedArray* properties = FixedArray::cast(source->properties());
4449 // Update elements if necessary.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00004450 if (elements->length() > 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004451 Object* elem;
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004452 { MaybeObject* maybe_elem;
4453 if (elements->map() == fixed_cow_array_map()) {
4454 maybe_elem = FixedArray::cast(elements);
4455 } else if (source->HasFastDoubleElements()) {
4456 maybe_elem = CopyFixedDoubleArray(FixedDoubleArray::cast(elements));
4457 } else {
4458 maybe_elem = CopyFixedArray(FixedArray::cast(elements));
4459 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004460 if (!maybe_elem->ToObject(&elem)) return maybe_elem;
4461 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004462 JSObject::cast(clone)->set_elements(FixedArrayBase::cast(elem), wb_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004463 }
4464 // Update properties if necessary.
4465 if (properties->length() > 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004466 Object* prop;
4467 { MaybeObject* maybe_prop = CopyFixedArray(properties);
4468 if (!maybe_prop->ToObject(&prop)) return maybe_prop;
4469 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004470 JSObject::cast(clone)->set_properties(FixedArray::cast(prop), wb_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004471 }
4472 // Return the new clone.
4473 return clone;
4474}
4475
4476
lrn@chromium.org34e60782011-09-15 07:25:40 +00004477MaybeObject* Heap::ReinitializeJSReceiver(
4478 JSReceiver* object, InstanceType type, int size) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004479 ASSERT(type >= FIRST_JS_OBJECT_TYPE);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004480
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004481 // Allocate fresh map.
4482 // TODO(rossberg): Once we optimize proxies, cache these maps.
4483 Map* map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004484 MaybeObject* maybe = AllocateMap(type, size);
4485 if (!maybe->To<Map>(&map)) return maybe;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004486
lrn@chromium.org34e60782011-09-15 07:25:40 +00004487 // Check that the receiver has at least the size of the fresh object.
4488 int size_difference = object->map()->instance_size() - map->instance_size();
4489 ASSERT(size_difference >= 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004490
4491 map->set_prototype(object->map()->prototype());
4492
4493 // Allocate the backing storage for the properties.
4494 int prop_size = map->unused_property_fields() - map->inobject_properties();
4495 Object* properties;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004496 maybe = AllocateFixedArray(prop_size, TENURED);
4497 if (!maybe->ToObject(&properties)) return maybe;
4498
4499 // Functions require some allocation, which might fail here.
4500 SharedFunctionInfo* shared = NULL;
4501 if (type == JS_FUNCTION_TYPE) {
4502 String* name;
4503 maybe = LookupAsciiSymbol("<freezing call trap>");
4504 if (!maybe->To<String>(&name)) return maybe;
4505 maybe = AllocateSharedFunctionInfo(name);
4506 if (!maybe->To<SharedFunctionInfo>(&shared)) return maybe;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004507 }
4508
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004509 // Because of possible retries of this function after failure,
4510 // we must NOT fail after this point, where we have changed the type!
4511
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004512 // Reset the map for the object.
4513 object->set_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004514 JSObject* jsobj = JSObject::cast(object);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004515
4516 // Reinitialize the object from the constructor map.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004517 InitializeJSObjectFromMap(jsobj, FixedArray::cast(properties), map);
lrn@chromium.org34e60782011-09-15 07:25:40 +00004518
4519 // Functions require some minimal initialization.
4520 if (type == JS_FUNCTION_TYPE) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004521 map->set_function_with_prototype(true);
4522 InitializeFunction(JSFunction::cast(object), shared, the_hole_value());
4523 JSFunction::cast(object)->set_context(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004524 isolate()->context()->native_context());
lrn@chromium.org34e60782011-09-15 07:25:40 +00004525 }
4526
4527 // Put in filler if the new object is smaller than the old.
4528 if (size_difference > 0) {
4529 CreateFillerObjectAt(
4530 object->address() + map->instance_size(), size_difference);
4531 }
4532
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004533 return object;
4534}
4535
4536
lrn@chromium.org303ada72010-10-27 09:33:13 +00004537MaybeObject* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor,
4538 JSGlobalProxy* object) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004539 ASSERT(constructor->has_initial_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004540 Map* map = constructor->initial_map();
4541
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004542 // Check that the already allocated object has the same size and type as
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004543 // objects allocated using the constructor.
4544 ASSERT(map->instance_size() == object->map()->instance_size());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004545 ASSERT(map->instance_type() == object->map()->instance_type());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004546
4547 // Allocate the backing storage for the properties.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004548 int prop_size = map->unused_property_fields() - map->inobject_properties();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004549 Object* properties;
4550 { MaybeObject* maybe_properties = AllocateFixedArray(prop_size, TENURED);
4551 if (!maybe_properties->ToObject(&properties)) return maybe_properties;
4552 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004553
4554 // Reset the map for the object.
4555 object->set_map(constructor->initial_map());
4556
4557 // Reinitialize the object from the constructor map.
4558 InitializeJSObjectFromMap(object, FixedArray::cast(properties), map);
4559 return object;
4560}
4561
4562
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004563MaybeObject* Heap::AllocateStringFromOneByte(Vector<const char> string,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004564 PretenureFlag pretenure) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004565 int length = string.length();
4566 if (length == 1) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00004567 return Heap::LookupSingleCharacterStringFromCode(string[0]);
4568 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004569 Object* result;
4570 { MaybeObject* maybe_result =
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004571 AllocateRawOneByteString(string.length(), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004572 if (!maybe_result->ToObject(&result)) return maybe_result;
4573 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004574
4575 // Copy the characters into the new object.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004576 CopyChars(SeqOneByteString::cast(result)->GetChars(), string.start(), length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004577 return result;
4578}
4579
4580
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004581MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector<const char> string,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004582 int non_ascii_start,
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00004583 PretenureFlag pretenure) {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004584 // Continue counting the number of characters in the UTF-8 string, starting
4585 // from the first non-ascii character or word.
4586 int chars = non_ascii_start;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004587 Access<UnicodeCache::Utf8Decoder>
4588 decoder(isolate_->unicode_cache()->utf8_decoder());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004589 decoder->Reset(string.start() + non_ascii_start, string.length() - chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004590 while (decoder->has_more()) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004591 uint32_t r = decoder->GetNext();
4592 if (r <= unibrow::Utf16::kMaxNonSurrogateCharCode) {
4593 chars++;
4594 } else {
4595 chars += 2;
4596 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004597 }
4598
lrn@chromium.org303ada72010-10-27 09:33:13 +00004599 Object* result;
4600 { MaybeObject* maybe_result = AllocateRawTwoByteString(chars, pretenure);
4601 if (!maybe_result->ToObject(&result)) return maybe_result;
4602 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603
4604 // Convert and copy the characters into the new object.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004605 SeqTwoByteString* twobyte = SeqTwoByteString::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004606 decoder->Reset(string.start(), string.length());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004607 int i = 0;
4608 while (i < chars) {
4609 uint32_t r = decoder->GetNext();
4610 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004611 twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::LeadSurrogate(r));
4612 twobyte->SeqTwoByteStringSet(i++, unibrow::Utf16::TrailSurrogate(r));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004613 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004614 twobyte->SeqTwoByteStringSet(i++, r);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004615 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004616 }
4617 return result;
4618}
4619
4620
lrn@chromium.org303ada72010-10-27 09:33:13 +00004621MaybeObject* Heap::AllocateStringFromTwoByte(Vector<const uc16> string,
4622 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004623 // Check if the string is an ASCII string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004624 Object* result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004625 int length = string.length();
4626 const uc16* start = string.start();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004627
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004628 if (String::IsAscii(start, length)) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004629 MaybeObject* maybe_result = AllocateRawOneByteString(length, pretenure);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004630 if (!maybe_result->ToObject(&result)) return maybe_result;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004631 CopyChars(SeqOneByteString::cast(result)->GetChars(), start, length);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004632 } else { // It's not an ASCII string.
4633 MaybeObject* maybe_result = AllocateRawTwoByteString(length, pretenure);
4634 if (!maybe_result->ToObject(&result)) return maybe_result;
4635 CopyChars(SeqTwoByteString::cast(result)->GetChars(), start, length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004636 }
4637 return result;
4638}
4639
4640
4641Map* Heap::SymbolMapForString(String* string) {
4642 // If the string is in new space it cannot be used as a symbol.
4643 if (InNewSpace(string)) return NULL;
4644
4645 // Find the corresponding symbol map for strings.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004646 switch (string->map()->instance_type()) {
4647 case STRING_TYPE: return symbol_map();
4648 case ASCII_STRING_TYPE: return ascii_symbol_map();
4649 case CONS_STRING_TYPE: return cons_symbol_map();
4650 case CONS_ASCII_STRING_TYPE: return cons_ascii_symbol_map();
4651 case EXTERNAL_STRING_TYPE: return external_symbol_map();
4652 case EXTERNAL_ASCII_STRING_TYPE: return external_ascii_symbol_map();
4653 case EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
4654 return external_symbol_with_ascii_data_map();
4655 case SHORT_EXTERNAL_STRING_TYPE: return short_external_symbol_map();
4656 case SHORT_EXTERNAL_ASCII_STRING_TYPE:
4657 return short_external_ascii_symbol_map();
4658 case SHORT_EXTERNAL_STRING_WITH_ASCII_DATA_TYPE:
4659 return short_external_symbol_with_ascii_data_map();
4660 default: return NULL; // No match found.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004661 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004662}
4663
4664
lrn@chromium.org303ada72010-10-27 09:33:13 +00004665MaybeObject* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
4666 int chars,
4667 uint32_t hash_field) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004668 ASSERT(chars >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004669 // Ensure the chars matches the number of characters in the buffer.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004670 ASSERT(static_cast<unsigned>(chars) == buffer->Utf16Length());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004671 // Determine whether the string is ASCII.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004672 bool is_ascii = true;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004673 while (buffer->has_more()) {
4674 if (buffer->GetNext() > unibrow::Utf8::kMaxOneByteChar) {
4675 is_ascii = false;
4676 break;
4677 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004678 }
4679 buffer->Rewind();
4680
4681 // Compute map and object size.
4682 int size;
4683 Map* map;
4684
4685 if (is_ascii) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004686 if (chars > SeqOneByteString::kMaxLength) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004687 return Failure::OutOfMemoryException();
4688 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004689 map = ascii_symbol_map();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004690 size = SeqOneByteString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004691 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004692 if (chars > SeqTwoByteString::kMaxLength) {
4693 return Failure::OutOfMemoryException();
4694 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004695 map = symbol_map();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004696 size = SeqTwoByteString::SizeFor(chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004697 }
4698
4699 // Allocate string.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004700 Object* result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004701 { MaybeObject* maybe_result = (size > Page::kMaxNonCodeHeapObjectSize)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004702 ? lo_space_->AllocateRaw(size, NOT_EXECUTABLE)
lrn@chromium.org303ada72010-10-27 09:33:13 +00004703 : old_data_space_->AllocateRaw(size);
4704 if (!maybe_result->ToObject(&result)) return maybe_result;
4705 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004706
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004707 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(map);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004708 // Set length and hash fields of the allocated string.
ager@chromium.org870a0b62008-11-04 11:43:05 +00004709 String* answer = String::cast(result);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004710 answer->set_length(chars);
4711 answer->set_hash_field(hash_field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004712
ager@chromium.org870a0b62008-11-04 11:43:05 +00004713 ASSERT_EQ(size, answer->Size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004714
4715 // Fill in the characters.
yangguo@chromium.org154ff992012-03-13 08:09:54 +00004716 int i = 0;
4717 while (i < chars) {
4718 uint32_t character = buffer->GetNext();
4719 if (character > unibrow::Utf16::kMaxNonSurrogateCharCode) {
4720 answer->Set(i++, unibrow::Utf16::LeadSurrogate(character));
4721 answer->Set(i++, unibrow::Utf16::TrailSurrogate(character));
4722 } else {
4723 answer->Set(i++, character);
4724 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004725 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00004726 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004727}
4728
4729
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004730MaybeObject* Heap::AllocateRawOneByteString(int length,
4731 PretenureFlag pretenure) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004732 if (length < 0 || length > SeqOneByteString::kMaxLength) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004733 return Failure::OutOfMemoryException();
4734 }
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004735
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004736 int size = SeqOneByteString::SizeFor(length);
4737 ASSERT(size <= SeqOneByteString::kMaxSize);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004738
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004739 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
4740 AllocationSpace retry_space = OLD_DATA_SPACE;
4741
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004742 if (space == NEW_SPACE) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004743 if (size > kMaxObjectSizeInNewSpace) {
4744 // Allocate in large object space, retry space will be ignored.
4745 space = LO_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004746 } else if (size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004747 // Allocate in new space, retry in large object space.
4748 retry_space = LO_SPACE;
4749 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004750 } else if (space == OLD_DATA_SPACE &&
4751 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004752 space = LO_SPACE;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004753 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004754 Object* result;
4755 { MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
4756 if (!maybe_result->ToObject(&result)) return maybe_result;
4757 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004758
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004759 // Partially initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004760 HeapObject::cast(result)->set_map_no_write_barrier(ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004761 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004762 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004763 ASSERT_EQ(size, HeapObject::cast(result)->Size());
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004764
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004765#ifdef VERIFY_HEAP
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004766 if (FLAG_verify_heap) {
4767 // Initialize string's content to ensure ASCII-ness (character range 0-127)
4768 // as required when verifying the heap.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004769 char* dest = SeqOneByteString::cast(result)->GetChars();
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004770 memset(dest, 0x0F, length * kCharSize);
4771 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004772#endif
mstarzinger@chromium.org15613d02012-05-23 12:04:37 +00004773
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004774 return result;
4775}
4776
4777
lrn@chromium.org303ada72010-10-27 09:33:13 +00004778MaybeObject* Heap::AllocateRawTwoByteString(int length,
4779 PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004780 if (length < 0 || length > SeqTwoByteString::kMaxLength) {
4781 return Failure::OutOfMemoryException();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004782 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004783 int size = SeqTwoByteString::SizeFor(length);
4784 ASSERT(size <= SeqTwoByteString::kMaxSize);
4785 AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
4786 AllocationSpace retry_space = OLD_DATA_SPACE;
4787
4788 if (space == NEW_SPACE) {
4789 if (size > kMaxObjectSizeInNewSpace) {
4790 // Allocate in large object space, retry space will be ignored.
4791 space = LO_SPACE;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004792 } else if (size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004793 // Allocate in new space, retry in large object space.
4794 retry_space = LO_SPACE;
4795 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004796 } else if (space == OLD_DATA_SPACE &&
4797 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004798 space = LO_SPACE;
4799 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004800 Object* result;
4801 { MaybeObject* maybe_result = AllocateRaw(size, space, retry_space);
4802 if (!maybe_result->ToObject(&result)) return maybe_result;
4803 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004804
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004805 // Partially initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004806 HeapObject::cast(result)->set_map_no_write_barrier(string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004807 String::cast(result)->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004808 String::cast(result)->set_hash_field(String::kEmptyHashField);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004809 ASSERT_EQ(size, HeapObject::cast(result)->Size());
4810 return result;
4811}
4812
4813
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004814MaybeObject* Heap::AllocateJSArray(
4815 ElementsKind elements_kind,
4816 PretenureFlag pretenure) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004817 Context* native_context = isolate()->context()->native_context();
4818 JSFunction* array_function = native_context->array_function();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004819 Map* map = array_function->initial_map();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004820 Object* maybe_map_array = native_context->js_array_maps();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004821 if (!maybe_map_array->IsUndefined()) {
4822 Object* maybe_transitioned_map =
4823 FixedArray::cast(maybe_map_array)->get(elements_kind);
4824 if (!maybe_transitioned_map->IsUndefined()) {
4825 map = Map::cast(maybe_transitioned_map);
4826 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004827 }
4828
4829 return AllocateJSObjectFromMap(map, pretenure);
4830}
4831
4832
lrn@chromium.org303ada72010-10-27 09:33:13 +00004833MaybeObject* Heap::AllocateEmptyFixedArray() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004834 int size = FixedArray::SizeFor(0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004835 Object* result;
4836 { MaybeObject* maybe_result =
4837 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
4838 if (!maybe_result->ToObject(&result)) return maybe_result;
4839 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004840 // Initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004841 reinterpret_cast<FixedArray*>(result)->set_map_no_write_barrier(
4842 fixed_array_map());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004843 reinterpret_cast<FixedArray*>(result)->set_length(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004844 return result;
4845}
4846
4847
lrn@chromium.org303ada72010-10-27 09:33:13 +00004848MaybeObject* Heap::AllocateRawFixedArray(int length) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004849 if (length < 0 || length > FixedArray::kMaxLength) {
4850 return Failure::OutOfMemoryException();
4851 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004852 ASSERT(length > 0);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004853 // Use the general function if we're forced to always allocate.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004854 if (always_allocate()) return AllocateFixedArray(length, TENURED);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004855 // Allocate the raw data for a fixed array.
4856 int size = FixedArray::SizeFor(length);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004857 return size <= kMaxObjectSizeInNewSpace
4858 ? new_space_.AllocateRaw(size)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004859 : lo_space_->AllocateRaw(size, NOT_EXECUTABLE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004860}
4861
4862
lrn@chromium.org303ada72010-10-27 09:33:13 +00004863MaybeObject* Heap::CopyFixedArrayWithMap(FixedArray* src, Map* map) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004864 int len = src->length();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004865 Object* obj;
4866 { MaybeObject* maybe_obj = AllocateRawFixedArray(len);
4867 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4868 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004869 if (InNewSpace(obj)) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004870 HeapObject* dst = HeapObject::cast(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004871 dst->set_map_no_write_barrier(map);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004872 CopyBlock(dst->address() + kPointerSize,
4873 src->address() + kPointerSize,
4874 FixedArray::SizeFor(len) - kPointerSize);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004875 return obj;
4876 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004877 HeapObject::cast(obj)->set_map_no_write_barrier(map);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004878 FixedArray* result = FixedArray::cast(obj);
4879 result->set_length(len);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004880
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004881 // Copy the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004882 AssertNoAllocation no_gc;
4883 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004884 for (int i = 0; i < len; i++) result->set(i, src->get(i), mode);
4885 return result;
4886}
4887
4888
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004889MaybeObject* Heap::CopyFixedDoubleArrayWithMap(FixedDoubleArray* src,
4890 Map* map) {
4891 int len = src->length();
4892 Object* obj;
4893 { MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(len, NOT_TENURED);
4894 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4895 }
4896 HeapObject* dst = HeapObject::cast(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004897 dst->set_map_no_write_barrier(map);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004898 CopyBlock(
4899 dst->address() + FixedDoubleArray::kLengthOffset,
4900 src->address() + FixedDoubleArray::kLengthOffset,
4901 FixedDoubleArray::SizeFor(len) - FixedDoubleArray::kLengthOffset);
4902 return obj;
4903}
4904
4905
lrn@chromium.org303ada72010-10-27 09:33:13 +00004906MaybeObject* Heap::AllocateFixedArray(int length) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004907 ASSERT(length >= 0);
ager@chromium.org32912102009-01-16 10:38:43 +00004908 if (length == 0) return empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004909 Object* result;
4910 { MaybeObject* maybe_result = AllocateRawFixedArray(length);
4911 if (!maybe_result->ToObject(&result)) return maybe_result;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004912 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004913 // Initialize header.
4914 FixedArray* array = reinterpret_cast<FixedArray*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004915 array->set_map_no_write_barrier(fixed_array_map());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004916 array->set_length(length);
4917 // Initialize body.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004918 ASSERT(!InNewSpace(undefined_value()));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004919 MemsetPointer(array->data_start(), undefined_value(), length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004920 return result;
4921}
4922
4923
lrn@chromium.org303ada72010-10-27 09:33:13 +00004924MaybeObject* Heap::AllocateRawFixedArray(int length, PretenureFlag pretenure) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004925 if (length < 0 || length > FixedArray::kMaxLength) {
4926 return Failure::OutOfMemoryException();
4927 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004928
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004929 AllocationSpace space =
4930 (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004931 int size = FixedArray::SizeFor(length);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004932 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
4933 // Too big for new space.
4934 space = LO_SPACE;
4935 } else if (space == OLD_POINTER_SPACE &&
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004936 size > Page::kMaxNonCodeHeapObjectSize) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004937 // Too big for old pointer space.
4938 space = LO_SPACE;
4939 }
4940
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004941 AllocationSpace retry_space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004942 (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_POINTER_SPACE : LO_SPACE;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004943
4944 return AllocateRaw(size, space, retry_space);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004945}
4946
4947
lrn@chromium.org303ada72010-10-27 09:33:13 +00004948MUST_USE_RESULT static MaybeObject* AllocateFixedArrayWithFiller(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004949 Heap* heap,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004950 int length,
4951 PretenureFlag pretenure,
4952 Object* filler) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004953 ASSERT(length >= 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004954 ASSERT(heap->empty_fixed_array()->IsFixedArray());
4955 if (length == 0) return heap->empty_fixed_array();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004956
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004957 ASSERT(!heap->InNewSpace(filler));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004958 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004959 { MaybeObject* maybe_result = heap->AllocateRawFixedArray(length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004960 if (!maybe_result->ToObject(&result)) return maybe_result;
4961 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004962
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004963 HeapObject::cast(result)->set_map_no_write_barrier(heap->fixed_array_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004964 FixedArray* array = FixedArray::cast(result);
4965 array->set_length(length);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004966 MemsetPointer(array->data_start(), filler, length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004967 return array;
4968}
4969
4970
lrn@chromium.org303ada72010-10-27 09:33:13 +00004971MaybeObject* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004972 return AllocateFixedArrayWithFiller(this,
4973 length,
4974 pretenure,
4975 undefined_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004976}
4977
4978
lrn@chromium.org303ada72010-10-27 09:33:13 +00004979MaybeObject* Heap::AllocateFixedArrayWithHoles(int length,
4980 PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004981 return AllocateFixedArrayWithFiller(this,
4982 length,
4983 pretenure,
4984 the_hole_value());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004985}
4986
4987
lrn@chromium.org303ada72010-10-27 09:33:13 +00004988MaybeObject* Heap::AllocateUninitializedFixedArray(int length) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004989 if (length == 0) return empty_fixed_array();
4990
lrn@chromium.org303ada72010-10-27 09:33:13 +00004991 Object* obj;
4992 { MaybeObject* maybe_obj = AllocateRawFixedArray(length);
4993 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4994 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004995
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004996 reinterpret_cast<FixedArray*>(obj)->set_map_no_write_barrier(
4997 fixed_array_map());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004998 FixedArray::cast(obj)->set_length(length);
4999 return obj;
5000}
5001
5002
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005003MaybeObject* Heap::AllocateEmptyFixedDoubleArray() {
5004 int size = FixedDoubleArray::SizeFor(0);
5005 Object* result;
5006 { MaybeObject* maybe_result =
5007 AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
5008 if (!maybe_result->ToObject(&result)) return maybe_result;
5009 }
5010 // Initialize the object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005011 reinterpret_cast<FixedDoubleArray*>(result)->set_map_no_write_barrier(
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005012 fixed_double_array_map());
5013 reinterpret_cast<FixedDoubleArray*>(result)->set_length(0);
5014 return result;
5015}
5016
5017
5018MaybeObject* Heap::AllocateUninitializedFixedDoubleArray(
5019 int length,
5020 PretenureFlag pretenure) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005021 if (length == 0) return empty_fixed_array();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005022
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005023 Object* elements_object;
5024 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
5025 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj;
5026 FixedDoubleArray* elements =
5027 reinterpret_cast<FixedDoubleArray*>(elements_object);
5028
5029 elements->set_map_no_write_barrier(fixed_double_array_map());
5030 elements->set_length(length);
5031 return elements;
5032}
5033
5034
5035MaybeObject* Heap::AllocateFixedDoubleArrayWithHoles(
5036 int length,
5037 PretenureFlag pretenure) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005038 if (length == 0) return empty_fixed_array();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005039
5040 Object* elements_object;
5041 MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
5042 if (!maybe_obj->ToObject(&elements_object)) return maybe_obj;
5043 FixedDoubleArray* elements =
5044 reinterpret_cast<FixedDoubleArray*>(elements_object);
5045
5046 for (int i = 0; i < length; ++i) {
5047 elements->set_the_hole(i);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005048 }
5049
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005050 elements->set_map_no_write_barrier(fixed_double_array_map());
5051 elements->set_length(length);
5052 return elements;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005053}
5054
5055
5056MaybeObject* Heap::AllocateRawFixedDoubleArray(int length,
5057 PretenureFlag pretenure) {
5058 if (length < 0 || length > FixedDoubleArray::kMaxLength) {
5059 return Failure::OutOfMemoryException();
5060 }
5061
5062 AllocationSpace space =
5063 (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
5064 int size = FixedDoubleArray::SizeFor(length);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005065
5066#ifndef V8_HOST_ARCH_64_BIT
5067 size += kPointerSize;
5068#endif
5069
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005070 if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
5071 // Too big for new space.
5072 space = LO_SPACE;
5073 } else if (space == OLD_DATA_SPACE &&
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005074 size > Page::kMaxNonCodeHeapObjectSize) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005075 // Too big for old data space.
5076 space = LO_SPACE;
5077 }
5078
5079 AllocationSpace retry_space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005080 (size <= Page::kMaxNonCodeHeapObjectSize) ? OLD_DATA_SPACE : LO_SPACE;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005081
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005082 HeapObject* object;
5083 { MaybeObject* maybe_object = AllocateRaw(size, space, retry_space);
5084 if (!maybe_object->To<HeapObject>(&object)) return maybe_object;
5085 }
5086
5087 return EnsureDoubleAligned(this, object, size);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005088}
5089
5090
lrn@chromium.org303ada72010-10-27 09:33:13 +00005091MaybeObject* Heap::AllocateHashTable(int length, PretenureFlag pretenure) {
5092 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005093 { MaybeObject* maybe_result = AllocateFixedArray(length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005094 if (!maybe_result->ToObject(&result)) return maybe_result;
5095 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005096 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(
5097 hash_table_map());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00005098 ASSERT(result->IsHashTable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005099 return result;
5100}
5101
5102
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005103MaybeObject* Heap::AllocateNativeContext() {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005104 Object* result;
5105 { MaybeObject* maybe_result =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005106 AllocateFixedArray(Context::NATIVE_CONTEXT_SLOTS);
5107 if (!maybe_result->ToObject(&result)) return maybe_result;
5108 }
5109 Context* context = reinterpret_cast<Context*>(result);
5110 context->set_map_no_write_barrier(native_context_map());
5111 context->set_js_array_maps(undefined_value());
5112 ASSERT(context->IsNativeContext());
5113 ASSERT(result->IsContext());
5114 return result;
5115}
5116
5117
5118MaybeObject* Heap::AllocateGlobalContext(JSFunction* function,
5119 ScopeInfo* scope_info) {
5120 Object* result;
5121 { MaybeObject* maybe_result =
5122 AllocateFixedArray(scope_info->ContextLength(), TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005123 if (!maybe_result->ToObject(&result)) return maybe_result;
5124 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005125 Context* context = reinterpret_cast<Context*>(result);
danno@chromium.orgeb831462012-08-24 11:57:08 +00005126 context->set_map_no_write_barrier(global_context_map());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005127 context->set_closure(function);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005128 context->set_previous(function->context());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005129 context->set_extension(scope_info);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005130 context->set_global_object(function->context()->global_object());
danno@chromium.orgeb831462012-08-24 11:57:08 +00005131 ASSERT(context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005132 ASSERT(result->IsContext());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005133 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005134}
5135
5136
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005137MaybeObject* Heap::AllocateModuleContext(ScopeInfo* scope_info) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005138 Object* result;
5139 { MaybeObject* maybe_result =
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005140 AllocateFixedArray(scope_info->ContextLength(), TENURED);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005141 if (!maybe_result->ToObject(&result)) return maybe_result;
5142 }
5143 Context* context = reinterpret_cast<Context*>(result);
5144 context->set_map_no_write_barrier(module_context_map());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005145 // Instance link will be set later.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005146 context->set_extension(Smi::FromInt(0));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005147 return context;
5148}
5149
5150
lrn@chromium.org303ada72010-10-27 09:33:13 +00005151MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005152 ASSERT(length >= Context::MIN_CONTEXT_SLOTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005153 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005154 { MaybeObject* maybe_result = AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005155 if (!maybe_result->ToObject(&result)) return maybe_result;
5156 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005157 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005158 context->set_map_no_write_barrier(function_context_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005159 context->set_closure(function);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005160 context->set_previous(function->context());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00005161 context->set_extension(Smi::FromInt(0));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005162 context->set_global_object(function->context()->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005163 return context;
5164}
5165
5166
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005167MaybeObject* Heap::AllocateCatchContext(JSFunction* function,
5168 Context* previous,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005169 String* name,
5170 Object* thrown_object) {
5171 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == Context::THROWN_OBJECT_INDEX);
5172 Object* result;
5173 { MaybeObject* maybe_result =
5174 AllocateFixedArray(Context::MIN_CONTEXT_SLOTS + 1);
5175 if (!maybe_result->ToObject(&result)) return maybe_result;
5176 }
5177 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005178 context->set_map_no_write_barrier(catch_context_map());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005179 context->set_closure(function);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005180 context->set_previous(previous);
5181 context->set_extension(name);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005182 context->set_global_object(previous->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005183 context->set(Context::THROWN_OBJECT_INDEX, thrown_object);
5184 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005185}
5186
5187
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005188MaybeObject* Heap::AllocateWithContext(JSFunction* function,
5189 Context* previous,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005190 JSObject* extension) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005191 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005192 { MaybeObject* maybe_result = AllocateFixedArray(Context::MIN_CONTEXT_SLOTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005193 if (!maybe_result->ToObject(&result)) return maybe_result;
5194 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005195 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005196 context->set_map_no_write_barrier(with_context_map());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00005197 context->set_closure(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005198 context->set_previous(previous);
5199 context->set_extension(extension);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005200 context->set_global_object(previous->global_object());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005201 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005202}
5203
5204
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005205MaybeObject* Heap::AllocateBlockContext(JSFunction* function,
5206 Context* previous,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005207 ScopeInfo* scope_info) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005208 Object* result;
5209 { MaybeObject* maybe_result =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005210 AllocateFixedArrayWithHoles(scope_info->ContextLength());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005211 if (!maybe_result->ToObject(&result)) return maybe_result;
5212 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005213 Context* context = reinterpret_cast<Context*>(result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005214 context->set_map_no_write_barrier(block_context_map());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005215 context->set_closure(function);
5216 context->set_previous(previous);
5217 context->set_extension(scope_info);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005218 context->set_global_object(previous->global_object());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005219 return context;
5220}
5221
5222
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005223MaybeObject* Heap::AllocateScopeInfo(int length) {
5224 FixedArray* scope_info;
5225 MaybeObject* maybe_scope_info = AllocateFixedArray(length, TENURED);
5226 if (!maybe_scope_info->To(&scope_info)) return maybe_scope_info;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005227 scope_info->set_map_no_write_barrier(scope_info_map());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005228 return scope_info;
5229}
5230
5231
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00005232MaybeObject* Heap::AllocateExternal(void* value) {
5233 Foreign* foreign;
5234 { MaybeObject* maybe_result = AllocateForeign(static_cast<Address>(value));
5235 if (!maybe_result->To(&foreign)) return maybe_result;
5236 }
5237 JSObject* external;
5238 { MaybeObject* maybe_result = AllocateJSObjectFromMap(external_map());
5239 if (!maybe_result->To(&external)) return maybe_result;
5240 }
5241 external->SetInternalField(0, foreign);
5242 return external;
5243}
5244
5245
lrn@chromium.org303ada72010-10-27 09:33:13 +00005246MaybeObject* Heap::AllocateStruct(InstanceType type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005247 Map* map;
5248 switch (type) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005249#define MAKE_CASE(NAME, Name, name) \
5250 case NAME##_TYPE: map = name##_map(); break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005251STRUCT_LIST(MAKE_CASE)
5252#undef MAKE_CASE
5253 default:
5254 UNREACHABLE();
5255 return Failure::InternalError();
5256 }
5257 int size = map->instance_size();
5258 AllocationSpace space =
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005259 (size > Page::kMaxNonCodeHeapObjectSize) ? LO_SPACE : OLD_POINTER_SPACE;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005260 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005261 { MaybeObject* maybe_result = Allocate(map, space);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005262 if (!maybe_result->ToObject(&result)) return maybe_result;
5263 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005264 Struct::cast(result)->InitializeBody(size);
5265 return result;
5266}
5267
5268
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005269bool Heap::IsHeapIterable() {
5270 return (!old_pointer_space()->was_swept_conservatively() &&
5271 !old_data_space()->was_swept_conservatively());
5272}
5273
5274
5275void Heap::EnsureHeapIsIterable() {
5276 ASSERT(IsAllocationAllowed());
5277 if (!IsHeapIterable()) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005278 CollectAllGarbage(kMakeHeapIterableMask, "Heap::EnsureHeapIsIterable");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005279 }
5280 ASSERT(IsHeapIterable());
5281}
5282
5283
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005284void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005285 incremental_marking()->Step(step_size,
5286 IncrementalMarking::NO_GC_VIA_STACK_GUARD);
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005287
5288 if (incremental_marking()->IsComplete()) {
5289 bool uncommit = false;
5290 if (gc_count_at_last_idle_gc_ == gc_count_) {
5291 // No GC since the last full GC, the mutator is probably not active.
5292 isolate_->compilation_cache()->Clear();
5293 uncommit = true;
5294 }
5295 CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental");
5296 gc_count_at_last_idle_gc_ = gc_count_;
5297 if (uncommit) {
5298 new_space_.Shrink();
5299 UncommitFromSpace();
5300 }
5301 }
5302}
5303
5304
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00005305bool Heap::IdleNotification(int hint) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005306 // Hints greater than this value indicate that
5307 // the embedder is requesting a lot of GC work.
danno@chromium.org88aa0582012-03-23 15:11:57 +00005308 const int kMaxHint = 1000;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00005309 // Minimal hint that allows to do full GC.
5310 const int kMinHintForFullGC = 100;
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005311 intptr_t size_factor = Min(Max(hint, 20), kMaxHint) / 4;
5312 // The size factor is in range [5..250]. The numbers here are chosen from
5313 // experiments. If you changes them, make sure to test with
5314 // chrome/performance_ui_tests --gtest_filter="GeneralMixMemoryTest.*
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00005315 intptr_t step_size =
5316 size_factor * IncrementalMarking::kAllocatedThreshold;
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005317
5318 if (contexts_disposed_ > 0) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005319 if (hint >= kMaxHint) {
5320 // The embedder is requesting a lot of GC work after context disposal,
5321 // we age inline caches so that they don't keep objects from
5322 // the old context alive.
5323 AgeInlineCaches();
5324 }
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005325 int mark_sweep_time = Min(TimeMarkSweepWouldTakeInMs(), 1000);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005326 if (hint >= mark_sweep_time && !FLAG_expose_gc &&
5327 incremental_marking()->IsStopped()) {
ulan@chromium.org6ff65142012-03-21 09:52:17 +00005328 HistogramTimerScope scope(isolate_->counters()->gc_context());
5329 CollectAllGarbage(kReduceMemoryFootprintMask,
5330 "idle notification: contexts disposed");
5331 } else {
5332 AdvanceIdleIncrementalMarking(step_size);
5333 contexts_disposed_ = 0;
5334 }
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
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +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
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00006127
6128V8_DECLARE_ONCE(initialize_gc_once);
6129
6130static void InitializeGCOnce() {
6131 InitializeScavengingVisitorsTables();
6132 NewSpaceScavenger::Initialize();
6133 MarkCompactCollector::Initialize();
6134}
6135
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006136bool Heap::SetUp(bool create_heap_objects) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006137#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006138 allocation_timeout_ = FLAG_gc_interval;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006139#endif
6140
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006141 // Initialize heap spaces and initial maps and objects. Whenever something
6142 // goes wrong, just return false. The caller should check the results and
6143 // call Heap::TearDown() to release allocated memory.
6144 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006145 // If the heap is not yet configured (e.g. through the API), configure it.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006146 // Configuration is based on the flags new-space-size (really the semispace
6147 // size) and old-space-size if set or the initial values of semispace_size_
6148 // and old_generation_size_ otherwise.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006149 if (!configured_) {
kasper.lund7276f142008-07-30 08:49:36 +00006150 if (!ConfigureHeapDefault()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006151 }
6152
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00006153 CallOnce(&initialize_gc_once, &InitializeGCOnce);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006154
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006155 MarkMapPointersAsEncoded(false);
6156
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006157 // Set up memory allocator.
6158 if (!isolate_->memory_allocator()->SetUp(MaxReserved(), MaxExecutableSize()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006159 return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006160
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006161 // Set up new space.
6162 if (!new_space_.SetUp(reserved_semispace_size_, max_semispace_size_)) {
ager@chromium.org3811b432009-10-28 14:53:37 +00006163 return false;
6164 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006165
ager@chromium.orga1645e22009-09-09 19:27:10 +00006166 // Initialize old pointer space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006167 old_pointer_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006168 new OldSpace(this,
6169 max_old_generation_size_,
6170 OLD_POINTER_SPACE,
6171 NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006172 if (old_pointer_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006173 if (!old_pointer_space_->SetUp()) return false;
ager@chromium.orga1645e22009-09-09 19:27:10 +00006174
6175 // Initialize old data space.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006176 old_data_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006177 new OldSpace(this,
6178 max_old_generation_size_,
6179 OLD_DATA_SPACE,
6180 NOT_EXECUTABLE);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006181 if (old_data_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006182 if (!old_data_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006183
6184 // Initialize the code space, set its maximum capacity to the old
kasper.lund7276f142008-07-30 08:49:36 +00006185 // generation size. It needs executable memory.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006186 // On 64-bit platform(s), we put all code objects in a 2 GB range of
6187 // virtual address space, so that they can call each other with near calls.
6188 if (code_range_size_ > 0) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006189 if (!isolate_->code_range()->SetUp(code_range_size_)) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006190 return false;
6191 }
6192 }
6193
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006194 code_space_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006195 new OldSpace(this, max_old_generation_size_, CODE_SPACE, EXECUTABLE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006196 if (code_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006197 if (!code_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006198
6199 // Initialize map space.
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00006200 map_space_ = new MapSpace(this, max_old_generation_size_, MAP_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006201 if (map_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006202 if (!map_space_->SetUp()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006203
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006204 // Initialize global property cell space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006205 cell_space_ = new CellSpace(this, max_old_generation_size_, CELL_SPACE);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006206 if (cell_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006207 if (!cell_space_->SetUp()) return false;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006208
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006209 // The large object code space may contain code or data. We set the memory
6210 // to be non-executable here for safety, but this means we need to enable it
6211 // explicitly when allocating large code objects.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006212 lo_space_ = new LargeObjectSpace(this, max_old_generation_size_, LO_SPACE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006213 if (lo_space_ == NULL) return false;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006214 if (!lo_space_->SetUp()) return false;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006215
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006216 // Set up the seed that is used to randomize the string hash function.
6217 ASSERT(hash_seed() == 0);
6218 if (FLAG_randomize_hashes) {
6219 if (FLAG_hash_seed == 0) {
6220 set_hash_seed(
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006221 Smi::FromInt(V8::RandomPrivate(isolate()) & 0x3fffffff));
6222 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006223 set_hash_seed(Smi::FromInt(FLAG_hash_seed));
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006224 }
6225 }
6226
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006227 if (create_heap_objects) {
6228 // Create initial maps.
6229 if (!CreateInitialMaps()) return false;
6230 if (!CreateApiObjects()) return false;
6231
6232 // Create initial objects
6233 if (!CreateInitialObjects()) return false;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00006234
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006235 native_contexts_list_ = undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006236 }
6237
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006238 LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity()));
6239 LOG(isolate_, IntPtrTEvent("heap-available", Available()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006240
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006241 store_buffer()->SetUp();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006242
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006243 if (FLAG_parallel_recompilation) relocation_mutex_ = OS::CreateMutex();
6244
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006245 return true;
6246}
6247
6248
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006249void Heap::SetStackLimits() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006250 ASSERT(isolate_ != NULL);
6251 ASSERT(isolate_ == isolate());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006252 // On 64 bit machines, pointers are generally out of range of Smis. We write
6253 // something that looks like an out of range Smi to the GC.
6254
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006255 // Set up the special root array entries containing the stack limits.
6256 // These are actually addresses, but the tag makes the GC ignore it.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006257 roots_[kStackLimitRootIndex] =
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006258 reinterpret_cast<Object*>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006259 (isolate_->stack_guard()->jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006260 roots_[kRealStackLimitRootIndex] =
6261 reinterpret_cast<Object*>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006262 (isolate_->stack_guard()->real_jslimit() & ~kSmiTagMask) | kSmiTag);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006263}
6264
6265
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006266void Heap::TearDown() {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006267#ifdef VERIFY_HEAP
danno@chromium.org1044a4d2012-04-30 12:34:39 +00006268 if (FLAG_verify_heap) {
6269 Verify();
6270 }
6271#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006272
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006273 if (FLAG_print_cumulative_gc_stat) {
6274 PrintF("\n\n");
6275 PrintF("gc_count=%d ", gc_count_);
6276 PrintF("mark_sweep_count=%d ", ms_count_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006277 PrintF("max_gc_pause=%d ", get_max_gc_pause());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006278 PrintF("total_gc_time=%d ", total_gc_time_ms_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006279 PrintF("min_in_mutator=%d ", get_min_in_mutator());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006280 PrintF("max_alive_after_gc=%" V8_PTR_PREFIX "d ",
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006281 get_max_alive_after_gc());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006282 PrintF("\n\n");
6283 }
6284
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006285 isolate_->global_handles()->TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006286
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006287 external_string_table_.TearDown();
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00006288
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006289 new_space_.TearDown();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006290
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006291 if (old_pointer_space_ != NULL) {
6292 old_pointer_space_->TearDown();
6293 delete old_pointer_space_;
6294 old_pointer_space_ = NULL;
6295 }
6296
6297 if (old_data_space_ != NULL) {
6298 old_data_space_->TearDown();
6299 delete old_data_space_;
6300 old_data_space_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006301 }
6302
6303 if (code_space_ != NULL) {
6304 code_space_->TearDown();
6305 delete code_space_;
6306 code_space_ = NULL;
6307 }
6308
6309 if (map_space_ != NULL) {
6310 map_space_->TearDown();
6311 delete map_space_;
6312 map_space_ = NULL;
6313 }
6314
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006315 if (cell_space_ != NULL) {
6316 cell_space_->TearDown();
6317 delete cell_space_;
6318 cell_space_ = NULL;
6319 }
6320
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006321 if (lo_space_ != NULL) {
6322 lo_space_->TearDown();
6323 delete lo_space_;
6324 lo_space_ = NULL;
6325 }
6326
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006327 store_buffer()->TearDown();
6328 incremental_marking()->TearDown();
6329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006330 isolate_->memory_allocator()->TearDown();
6331
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006332 delete relocation_mutex_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006333}
6334
6335
6336void Heap::Shrink() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006337 // Try to shrink all paged spaces.
6338 PagedSpaces spaces;
danno@chromium.org2c456792011-11-11 12:00:53 +00006339 for (PagedSpace* space = spaces.next();
6340 space != NULL;
6341 space = spaces.next()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006342 space->ReleaseAllUnusedPages();
danno@chromium.org2c456792011-11-11 12:00:53 +00006343 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006344}
6345
6346
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006347void Heap::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) {
6348 ASSERT(callback != NULL);
6349 GCPrologueCallbackPair pair(callback, gc_type);
6350 ASSERT(!gc_prologue_callbacks_.Contains(pair));
6351 return gc_prologue_callbacks_.Add(pair);
6352}
6353
6354
6355void Heap::RemoveGCPrologueCallback(GCPrologueCallback callback) {
6356 ASSERT(callback != NULL);
6357 for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
6358 if (gc_prologue_callbacks_[i].callback == callback) {
6359 gc_prologue_callbacks_.Remove(i);
6360 return;
6361 }
6362 }
6363 UNREACHABLE();
6364}
6365
6366
6367void Heap::AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type) {
6368 ASSERT(callback != NULL);
6369 GCEpilogueCallbackPair pair(callback, gc_type);
6370 ASSERT(!gc_epilogue_callbacks_.Contains(pair));
6371 return gc_epilogue_callbacks_.Add(pair);
6372}
6373
6374
6375void Heap::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
6376 ASSERT(callback != NULL);
6377 for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
6378 if (gc_epilogue_callbacks_[i].callback == callback) {
6379 gc_epilogue_callbacks_.Remove(i);
6380 return;
6381 }
6382 }
6383 UNREACHABLE();
6384}
6385
6386
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006387#ifdef DEBUG
6388
6389class PrintHandleVisitor: public ObjectVisitor {
6390 public:
6391 void VisitPointers(Object** start, Object** end) {
6392 for (Object** p = start; p < end; p++)
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006393 PrintF(" handle %p to %p\n",
6394 reinterpret_cast<void*>(p),
6395 reinterpret_cast<void*>(*p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006396 }
6397};
6398
6399void Heap::PrintHandles() {
6400 PrintF("Handles:\n");
6401 PrintHandleVisitor v;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006402 isolate_->handle_scope_implementer()->Iterate(&v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006403}
6404
6405#endif
6406
6407
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006408Space* AllSpaces::next() {
6409 switch (counter_++) {
6410 case NEW_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006411 return HEAP->new_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006412 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006413 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006414 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006415 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006416 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006417 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006418 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006419 return HEAP->map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006420 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006421 return HEAP->cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006422 case LO_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006423 return HEAP->lo_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006424 default:
6425 return NULL;
6426 }
6427}
6428
6429
6430PagedSpace* PagedSpaces::next() {
6431 switch (counter_++) {
6432 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006433 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006434 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006435 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006436 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006437 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006438 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006439 return HEAP->map_space();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006440 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006441 return HEAP->cell_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006442 default:
6443 return NULL;
6444 }
6445}
6446
6447
6448
6449OldSpace* OldSpaces::next() {
6450 switch (counter_++) {
6451 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006452 return HEAP->old_pointer_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006453 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006454 return HEAP->old_data_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006455 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006456 return HEAP->code_space();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006457 default:
6458 return NULL;
6459 }
6460}
6461
6462
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006463SpaceIterator::SpaceIterator()
6464 : current_space_(FIRST_SPACE),
6465 iterator_(NULL),
6466 size_func_(NULL) {
6467}
6468
6469
6470SpaceIterator::SpaceIterator(HeapObjectCallback size_func)
6471 : current_space_(FIRST_SPACE),
6472 iterator_(NULL),
6473 size_func_(size_func) {
kasper.lund7276f142008-07-30 08:49:36 +00006474}
6475
6476
6477SpaceIterator::~SpaceIterator() {
6478 // Delete active iterator if any.
6479 delete iterator_;
6480}
6481
6482
6483bool SpaceIterator::has_next() {
6484 // Iterate until no more spaces.
6485 return current_space_ != LAST_SPACE;
6486}
6487
6488
6489ObjectIterator* SpaceIterator::next() {
6490 if (iterator_ != NULL) {
6491 delete iterator_;
6492 iterator_ = NULL;
6493 // Move to the next space
6494 current_space_++;
6495 if (current_space_ > LAST_SPACE) {
6496 return NULL;
6497 }
6498 }
6499
6500 // Return iterator for the new current space.
6501 return CreateIterator();
6502}
6503
6504
6505// Create an iterator for the space to iterate.
6506ObjectIterator* SpaceIterator::CreateIterator() {
6507 ASSERT(iterator_ == NULL);
6508
6509 switch (current_space_) {
6510 case NEW_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006511 iterator_ = new SemiSpaceIterator(HEAP->new_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006512 break;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006513 case OLD_POINTER_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006514 iterator_ = new HeapObjectIterator(HEAP->old_pointer_space(), size_func_);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006515 break;
6516 case OLD_DATA_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006517 iterator_ = new HeapObjectIterator(HEAP->old_data_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006518 break;
6519 case CODE_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006520 iterator_ = new HeapObjectIterator(HEAP->code_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006521 break;
6522 case MAP_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006523 iterator_ = new HeapObjectIterator(HEAP->map_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006524 break;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006525 case CELL_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006526 iterator_ = new HeapObjectIterator(HEAP->cell_space(), size_func_);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006527 break;
kasper.lund7276f142008-07-30 08:49:36 +00006528 case LO_SPACE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006529 iterator_ = new LargeObjectIterator(HEAP->lo_space(), size_func_);
kasper.lund7276f142008-07-30 08:49:36 +00006530 break;
6531 }
6532
6533 // Return the newly allocated iterator;
6534 ASSERT(iterator_ != NULL);
6535 return iterator_;
6536}
6537
6538
whesse@chromium.org023421e2010-12-21 12:19:12 +00006539class HeapObjectsFilter {
6540 public:
6541 virtual ~HeapObjectsFilter() {}
6542 virtual bool SkipObject(HeapObject* object) = 0;
6543};
6544
6545
whesse@chromium.org023421e2010-12-21 12:19:12 +00006546class UnreachableObjectsFilter : public HeapObjectsFilter {
6547 public:
6548 UnreachableObjectsFilter() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006549 MarkReachableObjects();
6550 }
6551
6552 ~UnreachableObjectsFilter() {
6553 Isolate::Current()->heap()->mark_compact_collector()->ClearMarkbits();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006554 }
6555
6556 bool SkipObject(HeapObject* object) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006557 MarkBit mark_bit = Marking::MarkBitFrom(object);
6558 return !mark_bit.Get();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006559 }
6560
6561 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006562 class MarkingVisitor : public ObjectVisitor {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006563 public:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006564 MarkingVisitor() : marking_stack_(10) {}
whesse@chromium.org023421e2010-12-21 12:19:12 +00006565
6566 void VisitPointers(Object** start, Object** end) {
6567 for (Object** p = start; p < end; p++) {
6568 if (!(*p)->IsHeapObject()) continue;
6569 HeapObject* obj = HeapObject::cast(*p);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006570 MarkBit mark_bit = Marking::MarkBitFrom(obj);
6571 if (!mark_bit.Get()) {
6572 mark_bit.Set();
6573 marking_stack_.Add(obj);
whesse@chromium.org023421e2010-12-21 12:19:12 +00006574 }
6575 }
6576 }
6577
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006578 void TransitiveClosure() {
6579 while (!marking_stack_.is_empty()) {
6580 HeapObject* obj = marking_stack_.RemoveLast();
6581 obj->Iterate(this);
6582 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00006583 }
6584
6585 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006586 List<HeapObject*> marking_stack_;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006587 };
6588
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006589 void MarkReachableObjects() {
6590 Heap* heap = Isolate::Current()->heap();
6591 MarkingVisitor visitor;
6592 heap->IterateRoots(&visitor, VISIT_ALL);
6593 visitor.TransitiveClosure();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006594 }
6595
6596 AssertNoAllocation no_alloc;
6597};
6598
6599
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006600HeapIterator::HeapIterator()
6601 : filtering_(HeapIterator::kNoFiltering),
6602 filter_(NULL) {
6603 Init();
6604}
6605
6606
whesse@chromium.org023421e2010-12-21 12:19:12 +00006607HeapIterator::HeapIterator(HeapIterator::HeapObjectsFiltering filtering)
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006608 : filtering_(filtering),
6609 filter_(NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006610 Init();
6611}
6612
6613
6614HeapIterator::~HeapIterator() {
6615 Shutdown();
6616}
6617
6618
6619void HeapIterator::Init() {
6620 // Start the iteration.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006621 space_iterator_ = new SpaceIterator;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006622 switch (filtering_) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006623 case kFilterUnreachable:
6624 filter_ = new UnreachableObjectsFilter;
6625 break;
6626 default:
6627 break;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006628 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629 object_iterator_ = space_iterator_->next();
6630}
6631
6632
6633void HeapIterator::Shutdown() {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006634#ifdef DEBUG
whesse@chromium.org023421e2010-12-21 12:19:12 +00006635 // Assert that in filtering mode we have iterated through all
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006636 // objects. Otherwise, heap will be left in an inconsistent state.
whesse@chromium.org023421e2010-12-21 12:19:12 +00006637 if (filtering_ != kNoFiltering) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006638 ASSERT(object_iterator_ == NULL);
6639 }
6640#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006641 // Make sure the last iterator is deallocated.
6642 delete space_iterator_;
6643 space_iterator_ = NULL;
6644 object_iterator_ = NULL;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006645 delete filter_;
6646 filter_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006647}
6648
6649
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006650HeapObject* HeapIterator::next() {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006651 if (filter_ == NULL) return NextObject();
6652
6653 HeapObject* obj = NextObject();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006654 while (obj != NULL && filter_->SkipObject(obj)) obj = NextObject();
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00006655 return obj;
6656}
6657
6658
6659HeapObject* HeapIterator::NextObject() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006660 // No iterator means we are done.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006661 if (object_iterator_ == NULL) return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006662
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006663 if (HeapObject* obj = object_iterator_->next_object()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006664 // If the current iterator has more objects we are fine.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006665 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006666 } else {
6667 // Go though the spaces looking for one that has objects.
6668 while (space_iterator_->has_next()) {
6669 object_iterator_ = space_iterator_->next();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006670 if (HeapObject* obj = object_iterator_->next_object()) {
6671 return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006672 }
6673 }
6674 }
6675 // Done with the last space.
6676 object_iterator_ = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006677 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006678}
6679
6680
6681void HeapIterator::reset() {
6682 // Restart the iterator.
6683 Shutdown();
6684 Init();
6685}
6686
6687
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006688#if defined(DEBUG) || defined(LIVE_OBJECT_LIST)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006689
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006690Object* const PathTracer::kAnyGlobalObject = reinterpret_cast<Object*>(NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006691
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006692class PathTracer::MarkVisitor: public ObjectVisitor {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006693 public:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006694 explicit MarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006695 void VisitPointers(Object** start, Object** end) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006696 // Scan all HeapObject pointers in [start, end)
6697 for (Object** p = start; !tracer_->found() && (p < end); p++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006698 if ((*p)->IsHeapObject())
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006699 tracer_->MarkRecursively(p, this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006700 }
6701 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006702
6703 private:
6704 PathTracer* tracer_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006705};
6706
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006707
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006708class PathTracer::UnmarkVisitor: public ObjectVisitor {
6709 public:
6710 explicit UnmarkVisitor(PathTracer* tracer) : tracer_(tracer) {}
6711 void VisitPointers(Object** start, Object** end) {
6712 // Scan all HeapObject pointers in [start, end)
6713 for (Object** p = start; p < end; p++) {
6714 if ((*p)->IsHeapObject())
6715 tracer_->UnmarkRecursively(p, this);
6716 }
6717 }
6718
6719 private:
6720 PathTracer* tracer_;
6721};
6722
6723
6724void PathTracer::VisitPointers(Object** start, Object** end) {
6725 bool done = ((what_to_find_ == FIND_FIRST) && found_target_);
6726 // Visit all HeapObject pointers in [start, end)
6727 for (Object** p = start; !done && (p < end); p++) {
6728 if ((*p)->IsHeapObject()) {
6729 TracePathFrom(p);
6730 done = ((what_to_find_ == FIND_FIRST) && found_target_);
6731 }
6732 }
6733}
6734
6735
6736void PathTracer::Reset() {
6737 found_target_ = false;
6738 object_stack_.Clear();
6739}
6740
6741
6742void PathTracer::TracePathFrom(Object** root) {
6743 ASSERT((search_target_ == kAnyGlobalObject) ||
6744 search_target_->IsHeapObject());
6745 found_target_in_trace_ = false;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00006746 Reset();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006747
6748 MarkVisitor mark_visitor(this);
6749 MarkRecursively(root, &mark_visitor);
6750
6751 UnmarkVisitor unmark_visitor(this);
6752 UnmarkRecursively(root, &unmark_visitor);
6753
6754 ProcessResults();
6755}
6756
6757
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006758static bool SafeIsNativeContext(HeapObject* obj) {
6759 return obj->map() == obj->GetHeap()->raw_unchecked_native_context_map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006760}
6761
6762
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006763void PathTracer::MarkRecursively(Object** p, MarkVisitor* mark_visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006764 if (!(*p)->IsHeapObject()) return;
6765
6766 HeapObject* obj = HeapObject::cast(*p);
6767
6768 Object* map = obj->map();
6769
6770 if (!map->IsHeapObject()) return; // visited before
6771
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006772 if (found_target_in_trace_) return; // stop if target found
6773 object_stack_.Add(obj);
6774 if (((search_target_ == kAnyGlobalObject) && obj->IsJSGlobalObject()) ||
6775 (obj == search_target_)) {
6776 found_target_in_trace_ = true;
6777 found_target_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006778 return;
6779 }
6780
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006781 bool is_native_context = SafeIsNativeContext(obj);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006782
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006783 // not visited yet
6784 Map* map_p = reinterpret_cast<Map*>(HeapObject::cast(map));
6785
6786 Address map_addr = map_p->address();
6787
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006788 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_addr + kMarkTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006789
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006790 // Scan the object body.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006791 if (is_native_context && (visit_mode_ == VISIT_ONLY_STRONG)) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006792 // This is specialized to scan Context's properly.
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00006793 Object** start = reinterpret_cast<Object**>(obj->address() +
6794 Context::kHeaderSize);
6795 Object** end = reinterpret_cast<Object**>(obj->address() +
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006796 Context::kHeaderSize + Context::FIRST_WEAK_SLOT * kPointerSize);
danno@chromium.org2ab0c3b2012-10-05 08:50:56 +00006797 mark_visitor->VisitPointers(start, end);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006798 } else {
6799 obj->IterateBody(map_p->instance_type(),
6800 obj->SizeFromMap(map_p),
6801 mark_visitor);
6802 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006803
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006804 // Scan the map after the body because the body is a lot more interesting
6805 // when doing leak detection.
6806 MarkRecursively(&map, mark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006807
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006808 if (!found_target_in_trace_) // don't pop if found the target
6809 object_stack_.RemoveLast();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006810}
6811
6812
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006813void PathTracer::UnmarkRecursively(Object** p, UnmarkVisitor* unmark_visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006814 if (!(*p)->IsHeapObject()) return;
6815
6816 HeapObject* obj = HeapObject::cast(*p);
6817
6818 Object* map = obj->map();
6819
6820 if (map->IsHeapObject()) return; // unmarked already
6821
6822 Address map_addr = reinterpret_cast<Address>(map);
6823
6824 map_addr -= kMarkTag;
6825
6826 ASSERT_TAG_ALIGNED(map_addr);
6827
6828 HeapObject* map_p = HeapObject::FromAddress(map_addr);
6829
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006830 obj->set_map_no_write_barrier(reinterpret_cast<Map*>(map_p));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006831
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006832 UnmarkRecursively(reinterpret_cast<Object**>(&map_p), unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006833
6834 obj->IterateBody(Map::cast(map_p)->instance_type(),
6835 obj->SizeFromMap(Map::cast(map_p)),
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006836 unmark_visitor);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006837}
6838
6839
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006840void PathTracer::ProcessResults() {
6841 if (found_target_) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006842 PrintF("=====================================\n");
6843 PrintF("==== Path to object ====\n");
6844 PrintF("=====================================\n\n");
6845
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006846 ASSERT(!object_stack_.is_empty());
6847 for (int i = 0; i < object_stack_.length(); i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006848 if (i > 0) PrintF("\n |\n |\n V\n\n");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006849 Object* obj = object_stack_[i];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006850 obj->Print();
6851 }
6852 PrintF("=====================================\n");
6853 }
6854}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006855#endif // DEBUG || LIVE_OBJECT_LIST
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006856
6857
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006858#ifdef DEBUG
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00006859// Triggers a depth-first traversal of reachable objects from one
6860// given root object and finds a path to a specific heap object and
6861// prints it.
6862void Heap::TracePathToObjectFrom(Object* target, Object* root) {
6863 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
6864 tracer.VisitPointer(&root);
6865}
6866
6867
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006868// Triggers a depth-first traversal of reachable objects from roots
6869// and finds a path to a specific heap object and prints it.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00006870void Heap::TracePathToObject(Object* target) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006871 PathTracer tracer(target, PathTracer::FIND_ALL, VISIT_ALL);
6872 IterateRoots(&tracer, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006873}
6874
6875
6876// Triggers a depth-first traversal of reachable objects from roots
6877// and finds a path to any global object and prints it. Useful for
6878// determining the source for leaks of global objects.
6879void Heap::TracePathToGlobal() {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00006880 PathTracer tracer(PathTracer::kAnyGlobalObject,
6881 PathTracer::FIND_ALL,
6882 VISIT_ALL);
6883 IterateRoots(&tracer, VISIT_ONLY_STRONG);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006884}
6885#endif
6886
6887
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006888static intptr_t CountTotalHolesSize() {
6889 intptr_t holes_size = 0;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006890 OldSpaces spaces;
6891 for (OldSpace* space = spaces.next();
6892 space != NULL;
6893 space = spaces.next()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006894 holes_size += space->Waste() + space->Available();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006895 }
6896 return holes_size;
6897}
6898
6899
rossberg@chromium.org994edf62012-02-06 10:12:55 +00006900GCTracer::GCTracer(Heap* heap,
6901 const char* gc_reason,
6902 const char* collector_reason)
kasper.lund7276f142008-07-30 08:49:36 +00006903 : start_time_(0.0),
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00006904 start_object_size_(0),
6905 start_memory_size_(0),
kasper.lund7276f142008-07-30 08:49:36 +00006906 gc_count_(0),
6907 full_gc_count_(0),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006908 allocated_since_last_gc_(0),
6909 spent_in_mutator_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006910 promoted_objects_size_(0),
rossberg@chromium.org994edf62012-02-06 10:12:55 +00006911 heap_(heap),
6912 gc_reason_(gc_reason),
6913 collector_reason_(collector_reason) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006914 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
kasper.lund7276f142008-07-30 08:49:36 +00006915 start_time_ = OS::TimeCurrentMillis();
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00006916 start_object_size_ = heap_->SizeOfObjects();
6917 start_memory_size_ = heap_->isolate()->memory_allocator()->Size();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006918
6919 for (int i = 0; i < Scope::kNumberOfScopes; i++) {
6920 scopes_[i] = 0;
6921 }
6922
6923 in_free_list_or_wasted_before_gc_ = CountTotalHolesSize();
6924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006925 allocated_since_last_gc_ =
6926 heap_->SizeOfObjects() - heap_->alive_after_last_gc_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006927
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006928 if (heap_->last_gc_end_timestamp_ > 0) {
6929 spent_in_mutator_ = Max(start_time_ - heap_->last_gc_end_timestamp_, 0.0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006930 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006931
6932 steps_count_ = heap_->incremental_marking()->steps_count();
6933 steps_took_ = heap_->incremental_marking()->steps_took();
6934 longest_step_ = heap_->incremental_marking()->longest_step();
6935 steps_count_since_last_gc_ =
6936 heap_->incremental_marking()->steps_count_since_last_gc();
6937 steps_took_since_last_gc_ =
6938 heap_->incremental_marking()->steps_took_since_last_gc();
kasper.lund7276f142008-07-30 08:49:36 +00006939}
6940
6941
6942GCTracer::~GCTracer() {
kasper.lund7276f142008-07-30 08:49:36 +00006943 // Printf ONE line iff flag is set.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006944 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
6945
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006946 bool first_gc = (heap_->last_gc_end_timestamp_ == 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006947
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006948 heap_->alive_after_last_gc_ = heap_->SizeOfObjects();
6949 heap_->last_gc_end_timestamp_ = OS::TimeCurrentMillis();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006950
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006951 int time = static_cast<int>(heap_->last_gc_end_timestamp_ - start_time_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006952
6953 // Update cumulative GC statistics if required.
6954 if (FLAG_print_cumulative_gc_stat) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006955 heap_->total_gc_time_ms_ += time;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006956 heap_->max_gc_pause_ = Max(heap_->max_gc_pause_, time);
6957 heap_->max_alive_after_gc_ = Max(heap_->max_alive_after_gc_,
6958 heap_->alive_after_last_gc_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006959 if (!first_gc) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006960 heap_->min_in_mutator_ = Min(heap_->min_in_mutator_,
6961 static_cast<int>(spent_in_mutator_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006962 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006963 } else if (FLAG_trace_gc_verbose) {
6964 heap_->total_gc_time_ms_ += time;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006965 }
6966
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00006967 if (collector_ == SCAVENGER && FLAG_trace_gc_ignore_scavenger) return;
6968
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006969 PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init());
rossberg@chromium.org994edf62012-02-06 10:12:55 +00006970
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006971 if (!FLAG_trace_gc_nvp) {
6972 int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]);
6973
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00006974 double end_memory_size_mb =
6975 static_cast<double>(heap_->isolate()->memory_allocator()->Size()) / MB;
6976
6977 PrintF("%s %.1f (%.1f) -> %.1f (%.1f) MB, ",
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006978 CollectorString(),
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00006979 static_cast<double>(start_object_size_) / MB,
6980 static_cast<double>(start_memory_size_) / MB,
6981 SizeOfHeapObjects(),
6982 end_memory_size_mb);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006983
6984 if (external_time > 0) PrintF("%d / ", external_time);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006985 PrintF("%d ms", time);
6986 if (steps_count_ > 0) {
6987 if (collector_ == SCAVENGER) {
6988 PrintF(" (+ %d ms in %d steps since last GC)",
6989 static_cast<int>(steps_took_since_last_gc_),
6990 steps_count_since_last_gc_);
6991 } else {
6992 PrintF(" (+ %d ms in %d steps since start of marking, "
6993 "biggest step %f ms)",
6994 static_cast<int>(steps_took_),
6995 steps_count_,
6996 longest_step_);
6997 }
6998 }
rossberg@chromium.org994edf62012-02-06 10:12:55 +00006999
7000 if (gc_reason_ != NULL) {
7001 PrintF(" [%s]", gc_reason_);
7002 }
7003
7004 if (collector_reason_ != NULL) {
7005 PrintF(" [%s]", collector_reason_);
7006 }
7007
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007008 PrintF(".\n");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007009 } else {
7010 PrintF("pause=%d ", time);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00007011 PrintF("mutator=%d ", static_cast<int>(spent_in_mutator_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007012 PrintF("gc=");
7013 switch (collector_) {
7014 case SCAVENGER:
7015 PrintF("s");
7016 break;
7017 case MARK_COMPACTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007018 PrintF("ms");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007019 break;
7020 default:
7021 UNREACHABLE();
7022 }
7023 PrintF(" ");
7024
7025 PrintF("external=%d ", static_cast<int>(scopes_[Scope::EXTERNAL]));
7026 PrintF("mark=%d ", static_cast<int>(scopes_[Scope::MC_MARK]));
7027 PrintF("sweep=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP]));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007028 PrintF("sweepns=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP_NEWSPACE]));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00007029 PrintF("evacuate=%d ", static_cast<int>(scopes_[Scope::MC_EVACUATE_PAGES]));
7030 PrintF("new_new=%d ",
7031 static_cast<int>(scopes_[Scope::MC_UPDATE_NEW_TO_NEW_POINTERS]));
7032 PrintF("root_new=%d ",
7033 static_cast<int>(scopes_[Scope::MC_UPDATE_ROOT_TO_NEW_POINTERS]));
7034 PrintF("old_new=%d ",
7035 static_cast<int>(scopes_[Scope::MC_UPDATE_OLD_TO_NEW_POINTERS]));
7036 PrintF("compaction_ptrs=%d ",
7037 static_cast<int>(scopes_[Scope::MC_UPDATE_POINTERS_TO_EVACUATED]));
7038 PrintF("intracompaction_ptrs=%d ", static_cast<int>(scopes_[
7039 Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED]));
7040 PrintF("misc_compaction=%d ",
7041 static_cast<int>(scopes_[Scope::MC_UPDATE_MISC_POINTERS]));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007042
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00007043 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_object_size_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007044 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007045 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ",
7046 in_free_list_or_wasted_before_gc_);
7047 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", CountTotalHolesSize());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007048
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007049 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc_);
7050 PrintF("promoted=%" V8_PTR_PREFIX "d ", promoted_objects_size_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007051
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007052 if (collector_ == SCAVENGER) {
7053 PrintF("stepscount=%d ", steps_count_since_last_gc_);
7054 PrintF("stepstook=%d ", static_cast<int>(steps_took_since_last_gc_));
7055 } else {
7056 PrintF("stepscount=%d ", steps_count_);
7057 PrintF("stepstook=%d ", static_cast<int>(steps_took_));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007058 PrintF("longeststep=%.f ", longest_step_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007059 }
7060
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007061 PrintF("\n");
7062 }
kasperl@chromium.orge959c182009-07-27 08:59:04 +00007063
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007064 heap_->PrintShortHeapStatistics();
kasper.lund7276f142008-07-30 08:49:36 +00007065}
7066
7067
7068const char* GCTracer::CollectorString() {
7069 switch (collector_) {
7070 case SCAVENGER:
7071 return "Scavenge";
7072 case MARK_COMPACTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007073 return "Mark-sweep";
kasper.lund7276f142008-07-30 08:49:36 +00007074 }
7075 return "Unknown GC";
7076}
7077
7078
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007079int KeyedLookupCache::Hash(Map* map, String* name) {
7080 // Uses only lower 32 bits if pointers are larger.
7081 uintptr_t addr_hash =
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007082 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> kMapHashShift;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00007083 return static_cast<uint32_t>((addr_hash ^ name->Hash()) & kCapacityMask);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007084}
7085
7086
7087int KeyedLookupCache::Lookup(Map* map, String* name) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007088 int index = (Hash(map, name) & kHashMask);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007089 for (int i = 0; i < kEntriesPerBucket; i++) {
7090 Key& key = keys_[index + i];
7091 if ((key.map == map) && key.name->Equals(name)) {
7092 return field_offsets_[index + i];
7093 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007094 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007095 return kNotFound;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007096}
7097
7098
7099void KeyedLookupCache::Update(Map* map, String* name, int field_offset) {
7100 String* symbol;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007101 if (HEAP->LookupSymbolIfExists(name, &symbol)) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007102 int index = (Hash(map, symbol) & kHashMask);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007103 // After a GC there will be free slots, so we use them in order (this may
7104 // help to get the most frequently used one in position 0).
7105 for (int i = 0; i< kEntriesPerBucket; i++) {
7106 Key& key = keys_[index];
7107 Object* free_entry_indicator = NULL;
7108 if (key.map == free_entry_indicator) {
7109 key.map = map;
7110 key.name = symbol;
7111 field_offsets_[index + i] = field_offset;
7112 return;
7113 }
7114 }
7115 // No free entry found in this bucket, so we move them all down one and
7116 // put the new entry at position zero.
7117 for (int i = kEntriesPerBucket - 1; i > 0; i--) {
7118 Key& key = keys_[index + i];
7119 Key& key2 = keys_[index + i - 1];
7120 key = key2;
7121 field_offsets_[index + i] = field_offsets_[index + i - 1];
7122 }
7123
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007124 // Write the new first entry.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007125 Key& key = keys_[index];
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007126 key.map = map;
7127 key.name = symbol;
7128 field_offsets_[index] = field_offset;
7129 }
7130}
7131
7132
7133void KeyedLookupCache::Clear() {
7134 for (int index = 0; index < kLength; index++) keys_[index].map = NULL;
7135}
7136
7137
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007138void DescriptorLookupCache::Clear() {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007139 for (int index = 0; index < kLength; index++) keys_[index].source = NULL;
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007140}
7141
7142
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007143#ifdef DEBUG
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007144void Heap::GarbageCollectionGreedyCheck() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007145 ASSERT(FLAG_gc_greedy);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007146 if (isolate_->bootstrapper()->IsActive()) return;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007147 if (disallow_allocation_failure()) return;
7148 CollectGarbage(NEW_SPACE);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007149}
7150#endif
7151
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007152
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007153TranscendentalCache::SubCache::SubCache(Type t)
7154 : type_(t),
7155 isolate_(Isolate::Current()) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007156 uint32_t in0 = 0xffffffffu; // Bit-pattern for a NaN that isn't
7157 uint32_t in1 = 0xffffffffu; // generated by the FPU.
7158 for (int i = 0; i < kCacheSize; i++) {
7159 elements_[i].in[0] = in0;
7160 elements_[i].in[1] = in1;
7161 elements_[i].output = NULL;
7162 }
7163}
7164
7165
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007166void TranscendentalCache::Clear() {
7167 for (int i = 0; i < kNumberOfCaches; i++) {
7168 if (caches_[i] != NULL) {
7169 delete caches_[i];
7170 caches_[i] = NULL;
7171 }
7172 }
7173}
7174
7175
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007176void ExternalStringTable::CleanUp() {
7177 int last = 0;
7178 for (int i = 0; i < new_space_strings_.length(); ++i) {
danno@chromium.org72204d52012-10-31 10:02:10 +00007179 if (new_space_strings_[i] == heap_->the_hole_value()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007180 continue;
7181 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007182 if (heap_->InNewSpace(new_space_strings_[i])) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007183 new_space_strings_[last++] = new_space_strings_[i];
7184 } else {
7185 old_space_strings_.Add(new_space_strings_[i]);
7186 }
7187 }
7188 new_space_strings_.Rewind(last);
7189 last = 0;
7190 for (int i = 0; i < old_space_strings_.length(); ++i) {
danno@chromium.org72204d52012-10-31 10:02:10 +00007191 if (old_space_strings_[i] == heap_->the_hole_value()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007192 continue;
7193 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007194 ASSERT(!heap_->InNewSpace(old_space_strings_[i]));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007195 old_space_strings_[last++] = old_space_strings_[i];
7196 }
7197 old_space_strings_.Rewind(last);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007198#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007199 if (FLAG_verify_heap) {
7200 Verify();
7201 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007202#endif
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00007203}
7204
7205
7206void ExternalStringTable::TearDown() {
7207 new_space_strings_.Free();
7208 old_space_strings_.Free();
7209}
7210
7211
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007212void Heap::QueueMemoryChunkForFree(MemoryChunk* chunk) {
7213 chunk->set_next_chunk(chunks_queued_for_free_);
7214 chunks_queued_for_free_ = chunk;
7215}
7216
7217
7218void Heap::FreeQueuedChunks() {
7219 if (chunks_queued_for_free_ == NULL) return;
7220 MemoryChunk* next;
7221 MemoryChunk* chunk;
7222 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
7223 next = chunk->next_chunk();
7224 chunk->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
7225
7226 if (chunk->owner()->identity() == LO_SPACE) {
7227 // StoreBuffer::Filter relies on MemoryChunk::FromAnyPointerAddress.
7228 // If FromAnyPointerAddress encounters a slot that belongs to a large
7229 // chunk queued for deletion it will fail to find the chunk because
7230 // it try to perform a search in the list of pages owned by of the large
7231 // object space and queued chunks were detached from that list.
7232 // To work around this we split large chunk into normal kPageSize aligned
danno@chromium.org2c456792011-11-11 12:00:53 +00007233 // pieces and initialize size, owner and flags field of every piece.
7234 // If FromAnyPointerAddress encounters a slot that belongs to one of
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007235 // these smaller pieces it will treat it as a slot on a normal Page.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007236 Address chunk_end = chunk->address() + chunk->size();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007237 MemoryChunk* inner = MemoryChunk::FromAddress(
7238 chunk->address() + Page::kPageSize);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007239 MemoryChunk* inner_last = MemoryChunk::FromAddress(chunk_end - 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007240 while (inner <= inner_last) {
7241 // Size of a large chunk is always a multiple of
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00007242 // OS::AllocateAlignment() so there is always
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007243 // enough space for a fake MemoryChunk header.
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00007244 Address area_end = Min(inner->address() + Page::kPageSize, chunk_end);
7245 // Guard against overflow.
7246 if (area_end < inner->address()) area_end = chunk_end;
7247 inner->SetArea(inner->address(), area_end);
danno@chromium.org2c456792011-11-11 12:00:53 +00007248 inner->set_size(Page::kPageSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007249 inner->set_owner(lo_space());
7250 inner->SetFlag(MemoryChunk::ABOUT_TO_BE_FREED);
7251 inner = MemoryChunk::FromAddress(
7252 inner->address() + Page::kPageSize);
7253 }
7254 }
7255 }
7256 isolate_->heap()->store_buffer()->Compact();
7257 isolate_->heap()->store_buffer()->Filter(MemoryChunk::ABOUT_TO_BE_FREED);
7258 for (chunk = chunks_queued_for_free_; chunk != NULL; chunk = next) {
7259 next = chunk->next_chunk();
7260 isolate_->memory_allocator()->Free(chunk);
7261 }
7262 chunks_queued_for_free_ = NULL;
7263}
7264
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00007265
7266void Heap::RememberUnmappedPage(Address page, bool compacted) {
7267 uintptr_t p = reinterpret_cast<uintptr_t>(page);
7268 // Tag the page pointer to make it findable in the dump file.
7269 if (compacted) {
7270 p ^= 0xc1ead & (Page::kPageSize - 1); // Cleared.
7271 } else {
7272 p ^= 0x1d1ed & (Page::kPageSize - 1); // I died.
7273 }
7274 remembered_unmapped_pages_[remembered_unmapped_pages_index_] =
7275 reinterpret_cast<Address>(p);
7276 remembered_unmapped_pages_index_++;
7277 remembered_unmapped_pages_index_ %= kRememberedUnmappedPages;
7278}
7279
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00007280
7281void Heap::ClearObjectStats(bool clear_last_time_stats) {
7282 memset(object_counts_, 0, sizeof(object_counts_));
7283 memset(object_sizes_, 0, sizeof(object_sizes_));
7284 if (clear_last_time_stats) {
7285 memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_));
7286 memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_));
7287 }
7288}
7289
7290
7291static LazyMutex checkpoint_object_stats_mutex = LAZY_MUTEX_INITIALIZER;
7292
7293
7294void Heap::CheckpointObjectStats() {
7295 ScopedLock lock(checkpoint_object_stats_mutex.Pointer());
7296 Counters* counters = isolate()->counters();
7297#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7298 counters->count_of_##name()->Increment( \
7299 static_cast<int>(object_counts_[name])); \
7300 counters->count_of_##name()->Decrement( \
7301 static_cast<int>(object_counts_last_time_[name])); \
7302 counters->size_of_##name()->Increment( \
7303 static_cast<int>(object_sizes_[name])); \
7304 counters->size_of_##name()->Decrement( \
7305 static_cast<int>(object_sizes_last_time_[name]));
7306 INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7307#undef ADJUST_LAST_TIME_OBJECT_COUNT
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007308 int index;
7309#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7310 index = FIRST_CODE_KIND_SUB_TYPE + Code::name; \
7311 counters->count_of_CODE_TYPE_##name()->Increment( \
7312 static_cast<int>(object_counts_[index])); \
7313 counters->count_of_CODE_TYPE_##name()->Decrement( \
7314 static_cast<int>(object_counts_last_time_[index])); \
7315 counters->size_of_CODE_TYPE_##name()->Increment( \
7316 static_cast<int>(object_sizes_[index])); \
7317 counters->size_of_CODE_TYPE_##name()->Decrement( \
7318 static_cast<int>(object_sizes_last_time_[index]));
7319 CODE_KIND_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7320#undef ADJUST_LAST_TIME_OBJECT_COUNT
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007321#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
7322 index = FIRST_FIXED_ARRAY_SUB_TYPE + name; \
7323 counters->count_of_FIXED_ARRAY_##name()->Increment( \
7324 static_cast<int>(object_counts_[index])); \
7325 counters->count_of_FIXED_ARRAY_##name()->Decrement( \
7326 static_cast<int>(object_counts_last_time_[index])); \
7327 counters->size_of_FIXED_ARRAY_##name()->Increment( \
7328 static_cast<int>(object_sizes_[index])); \
7329 counters->size_of_FIXED_ARRAY_##name()->Decrement( \
7330 static_cast<int>(object_sizes_last_time_[index]));
7331 FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
7332#undef ADJUST_LAST_TIME_OBJECT_COUNT
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007333
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00007334 memcpy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
7335 memcpy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
7336 ClearObjectStats();
7337}
7338
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007339} } // namespace v8::internal