blob: 9aa839be6c38e131b32da90d3f6af1bfb6f21941 [file] [log] [blame]
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ulan@chromium.org750145a2013-03-07 15:14:13 +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.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000027
28#include <stdlib.h>
29
30#include "v8.h"
31
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000032#include "compilation-cache.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000033#include "execution.h"
34#include "factory.h"
35#include "macro-assembler.h"
36#include "global-handles.h"
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000037#include "stub-cache.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000038#include "cctest.h"
39
40using namespace v8::internal;
41
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000042
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000043// Go through all incremental marking steps in one swoop.
44static void SimulateIncrementalMarking() {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000045 MarkCompactCollector* collector = HEAP->mark_compact_collector();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000046 IncrementalMarking* marking = HEAP->incremental_marking();
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000047 if (collector->IsConcurrentSweepingInProgress()) {
48 collector->WaitUntilSweepingCompleted();
49 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000050 CHECK(marking->IsMarking() || marking->IsStopped());
51 if (marking->IsStopped()) {
52 marking->Start();
53 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000054 CHECK(marking->IsMarking());
55 while (!marking->IsComplete()) {
56 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
57 }
58 CHECK(marking->IsComplete());
59}
60
61
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000062static void CheckMap(Map* map, int type, int instance_size) {
63 CHECK(map->IsHeapObject());
64#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000065 CHECK(HEAP->Contains(map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000066#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 CHECK_EQ(HEAP->meta_map(), map->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000068 CHECK_EQ(type, map->instance_type());
69 CHECK_EQ(instance_size, map->instance_size());
70}
71
72
73TEST(HeapMaps) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000074 CcTest::InitializeVM();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000075 CheckMap(HEAP->meta_map(), MAP_TYPE, Map::kSize);
76 CheckMap(HEAP->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
77 CheckMap(HEAP->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
78 CheckMap(HEAP->string_map(), STRING_TYPE, kVariableSizeSentinel);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000079}
80
81
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000082static void CheckOddball(Isolate* isolate, Object* obj, const char* string) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000083 CHECK(obj->IsOddball());
84 bool exc;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000085 Object* print_string =
86 *Execution::ToString(Handle<Object>(obj, isolate), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000087 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000088}
89
90
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000091static void CheckSmi(Isolate* isolate, int value, const char* string) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000092 bool exc;
93 Object* print_string =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000094 *Execution::ToString(Handle<Object>(Smi::FromInt(value), isolate), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000095 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000096}
97
98
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000099static void CheckNumber(Isolate* isolate, double value, const char* string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000100 Object* obj = HEAP->NumberFromDouble(value)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000101 CHECK(obj->IsNumber());
102 bool exc;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000103 Object* print_string =
104 *Execution::ToString(Handle<Object>(obj, isolate), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000105 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000106}
107
108
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000109static void CheckFindCodeObject(Isolate* isolate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000110 // Test FindCodeObject
111#define __ assm.
112
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000113 Assembler assm(isolate, NULL, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000114
115 __ nop(); // supported on all architectures
116
117 CodeDesc desc;
118 assm.GetCode(&desc);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000119 Heap* heap = isolate->heap();
120 Object* code = heap->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000121 desc,
122 Code::ComputeFlags(Code::STUB),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000123 Handle<Code>())->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000124 CHECK(code->IsCode());
125
126 HeapObject* obj = HeapObject::cast(code);
127 Address obj_addr = obj->address();
128
129 for (int i = 0; i < obj->Size(); i += kPointerSize) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000130 Object* found = heap->FindCodeObject(obj_addr + i);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000131 CHECK_EQ(code, found);
132 }
133
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000134 Object* copy = heap->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000135 desc,
136 Code::ComputeFlags(Code::STUB),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000137 Handle<Code>())->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000138 CHECK(copy->IsCode());
139 HeapObject* obj_copy = HeapObject::cast(copy);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000140 Object* not_right = heap->FindCodeObject(obj_copy->address() +
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000141 obj_copy->Size() / 2);
142 CHECK(not_right != code);
143}
144
145
146TEST(HeapObjects) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000147 CcTest::InitializeVM();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000148 Isolate* isolate = Isolate::Current();
149 Heap* heap = isolate->heap();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000150
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000151 HandleScope sc(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000152 Object* value = heap->NumberFromDouble(1.000123)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000153 CHECK(value->IsHeapNumber());
154 CHECK(value->IsNumber());
155 CHECK_EQ(1.000123, value->Number());
156
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000157 value = heap->NumberFromDouble(1.0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000158 CHECK(value->IsSmi());
159 CHECK(value->IsNumber());
160 CHECK_EQ(1.0, value->Number());
161
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000162 value = heap->NumberFromInt32(1024)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000163 CHECK(value->IsSmi());
164 CHECK(value->IsNumber());
165 CHECK_EQ(1024.0, value->Number());
166
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000167 value = heap->NumberFromInt32(Smi::kMinValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000168 CHECK(value->IsSmi());
169 CHECK(value->IsNumber());
170 CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
171
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000172 value = heap->NumberFromInt32(Smi::kMaxValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000173 CHECK(value->IsSmi());
174 CHECK(value->IsNumber());
175 CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value());
176
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000177#ifndef V8_TARGET_ARCH_X64
178 // TODO(lrn): We need a NumberFromIntptr function in order to test this.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000179 value = heap->NumberFromInt32(Smi::kMinValue - 1)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000180 CHECK(value->IsHeapNumber());
181 CHECK(value->IsNumber());
182 CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000183#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000184
lrn@chromium.org303ada72010-10-27 09:33:13 +0000185 MaybeObject* maybe_value =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000186 heap->NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000187 value = maybe_value->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000188 CHECK(value->IsHeapNumber());
189 CHECK(value->IsNumber());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000190 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
191 value->Number());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000192
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000193 maybe_value = heap->NumberFromUint32(static_cast<uint32_t>(1) << 31);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000194 value = maybe_value->ToObjectChecked();
195 CHECK(value->IsHeapNumber());
196 CHECK(value->IsNumber());
197 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(1) << 31),
198 value->Number());
199
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000200 // nan oddball checks
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000201 CHECK(heap->nan_value()->IsNumber());
202 CHECK(isnan(heap->nan_value()->Number()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000204 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest "));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000205 CHECK(s->IsString());
206 CHECK_EQ(10, s->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000207
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000208 String* object_string = String::cast(heap->Object_string());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000209 CHECK(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000210 Isolate::Current()->context()->global_object()->HasLocalProperty(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000211 object_string));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000212
213 // Check ToString for oddballs
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000214 CheckOddball(isolate, heap->true_value(), "true");
215 CheckOddball(isolate, heap->false_value(), "false");
216 CheckOddball(isolate, heap->null_value(), "null");
217 CheckOddball(isolate, heap->undefined_value(), "undefined");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000218
219 // Check ToString for Smis
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000220 CheckSmi(isolate, 0, "0");
221 CheckSmi(isolate, 42, "42");
222 CheckSmi(isolate, -42, "-42");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000223
224 // Check ToString for Numbers
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000225 CheckNumber(isolate, 1.1, "1.1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000226
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000227 CheckFindCodeObject(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000228}
229
230
231TEST(Tagging) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000232 CcTest::InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000233 int request = 24;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000234 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000235 CHECK(Smi::FromInt(42)->IsSmi());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000236 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000237 CHECK_EQ(NEW_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000238 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000239 CHECK_EQ(OLD_POINTER_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000240 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000241 CHECK(Failure::Exception()->IsFailure());
242 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
243 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
244}
245
246
247TEST(GarbageCollection) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000248 CcTest::InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000249 Isolate* isolate = Isolate::Current();
250 Heap* heap = isolate->heap();
251 Factory* factory = isolate->factory();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000252
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000253 HandleScope sc(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000254 // Check GC.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000255 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000256
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000257 Handle<String> name = factory->InternalizeUtf8String("theFunction");
258 Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
259 Handle<String> prop_namex = factory->InternalizeUtf8String("theSlotx");
260 Handle<String> obj_name = factory->InternalizeUtf8String("theObject");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000261
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000262 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000263 HandleScope inner_scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000264 // Allocate a function and keep it in global object's property.
265 Handle<JSFunction> function =
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000266 factory->NewFunction(name, factory->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000267 Handle<Map> initial_map =
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000268 factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000269 function->set_initial_map(*initial_map);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000270 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000271 *name, *function, NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000272 // Allocate an object. Unrooted after leaving the scope.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000273 Handle<JSObject> obj = factory->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000274 obj->SetProperty(
275 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
276 obj->SetProperty(
277 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000278
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000279 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
280 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
281 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000282
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000283 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000284
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000285 // Function should be alive.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000286 CHECK(Isolate::Current()->context()->global_object()->
287 HasLocalProperty(*name));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000288 // Check function is retained.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000289 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000290 GetProperty(*name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000291 CHECK(func_value->IsJSFunction());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000292 Handle<JSFunction> function(JSFunction::cast(func_value));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000293
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000294 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000295 HandleScope inner_scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000296 // Allocate another object, make it reachable from global.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000297 Handle<JSObject> obj = factory->NewJSObject(function);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000298 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000299 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked();
300 obj->SetProperty(
301 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000302 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000303
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000304 // After gc, it should survive.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000305 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000306
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000307 CHECK(Isolate::Current()->context()->global_object()->
308 HasLocalProperty(*obj_name));
309 CHECK(Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000310 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000311 Object* obj = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000312 GetProperty(*obj_name)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000313 JSObject* js_obj = JSObject::cast(obj);
314 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000315}
316
317
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000318static void VerifyStringAllocation(Isolate* isolate, const char* string) {
319 HandleScope scope(isolate);
320 Handle<String> s = isolate->factory()->NewStringFromUtf8(CStrVector(string));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000321 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000322 for (int index = 0; index < s->length(); index++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000323 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
324 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000325}
326
327
328TEST(String) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000329 CcTest::InitializeVM();
330 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000331
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000332 VerifyStringAllocation(isolate, "a");
333 VerifyStringAllocation(isolate, "ab");
334 VerifyStringAllocation(isolate, "abc");
335 VerifyStringAllocation(isolate, "abcd");
336 VerifyStringAllocation(isolate, "fiskerdrengen er paa havet");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000337}
338
339
340TEST(LocalHandles) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000341 CcTest::InitializeVM();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000342
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000343 v8::HandleScope scope(CcTest::isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000344 const char* name = "Kasper the spunky";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000345 Handle<String> string = FACTORY->NewStringFromAscii(CStrVector(name));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000346 CHECK_EQ(StrLength(name), string->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000347}
348
349
350TEST(GlobalHandles) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000351 CcTest::InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000352 Isolate* isolate = Isolate::Current();
353 Heap* heap = isolate->heap();
354 Factory* factory = isolate->factory();
355 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000356
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000357 Handle<Object> h1;
358 Handle<Object> h2;
359 Handle<Object> h3;
360 Handle<Object> h4;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000361
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000362 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000363 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000364
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000365 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
366 Handle<Object> u = factory->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000368 h1 = global_handles->Create(*i);
369 h2 = global_handles->Create(*u);
370 h3 = global_handles->Create(*i);
371 h4 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000372 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000373
374 // after gc, it should survive
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000375 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000376
377 CHECK((*h1)->IsString());
378 CHECK((*h2)->IsHeapNumber());
379 CHECK((*h3)->IsString());
380 CHECK((*h4)->IsHeapNumber());
381
382 CHECK_EQ(*h3, *h1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000383 global_handles->Destroy(h1.location());
384 global_handles->Destroy(h3.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000385
386 CHECK_EQ(*h4, *h2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000387 global_handles->Destroy(h2.location());
388 global_handles->Destroy(h4.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000389}
390
391
392static bool WeakPointerCleared = false;
393
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000394static void TestWeakGlobalHandleCallback(v8::Isolate* isolate,
395 v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000396 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000397 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000398 handle.Dispose(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000399}
400
401
402TEST(WeakGlobalHandlesScavenge) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000403 CcTest::InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000404 Isolate* isolate = Isolate::Current();
405 Heap* heap = isolate->heap();
406 Factory* factory = isolate->factory();
407 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000408
409 WeakPointerCleared = false;
410
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000411 Handle<Object> h1;
412 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000413
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000414 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000415 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000416
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000417 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
418 Handle<Object> u = factory->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000419
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000420 h1 = global_handles->Create(*i);
421 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000422 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000423
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000424 global_handles->MakeWeak(h2.location(),
425 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000426 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000427 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000428
429 // Scavenge treats weak pointers as normal roots.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000430 heap->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000431
432 CHECK((*h1)->IsString());
433 CHECK((*h2)->IsHeapNumber());
434
435 CHECK(!WeakPointerCleared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000436 CHECK(!global_handles->IsNearDeath(h2.location()));
437 CHECK(!global_handles->IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000438
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000439 global_handles->Destroy(h1.location());
440 global_handles->Destroy(h2.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000441}
442
443
444TEST(WeakGlobalHandlesMark) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000445 CcTest::InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000446 Isolate* isolate = Isolate::Current();
447 Heap* heap = isolate->heap();
448 Factory* factory = isolate->factory();
449 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000450
451 WeakPointerCleared = false;
452
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000453 Handle<Object> h1;
454 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000455
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000456 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000457 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000458
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000459 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
460 Handle<Object> u = factory->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000461
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000462 h1 = global_handles->Create(*i);
463 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000464 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000465
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000466 // Make sure the objects are promoted.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000467 heap->CollectGarbage(OLD_POINTER_SPACE);
468 heap->CollectGarbage(NEW_SPACE);
469 CHECK(!heap->InNewSpace(*h1) && !heap->InNewSpace(*h2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000470
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000471 global_handles->MakeWeak(h2.location(),
472 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000473 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000474 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000475 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
476 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
477
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000478 // Incremental marking potentially marked handles before they turned weak.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000479 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000480
481 CHECK((*h1)->IsString());
482
483 CHECK(WeakPointerCleared);
484 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000485
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000486 global_handles->Destroy(h1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000487}
488
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000489
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000490TEST(DeleteWeakGlobalHandle) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000491 CcTest::InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000492 Isolate* isolate = Isolate::Current();
493 Heap* heap = isolate->heap();
494 Factory* factory = isolate->factory();
495 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000496
497 WeakPointerCleared = false;
498
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000499 Handle<Object> h;
500
501 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000502 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000503
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000504 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000505 h = global_handles->Create(*i);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000506 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000507
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000508 global_handles->MakeWeak(h.location(),
509 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000510 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000511 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000512
513 // Scanvenge does not recognize weak reference.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000514 heap->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000515
516 CHECK(!WeakPointerCleared);
517
518 // Mark-compact treats weak reference properly.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000519 heap->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000520
521 CHECK(WeakPointerCleared);
522}
523
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000524
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000525static const char* not_so_random_string_table[] = {
526 "abstract",
527 "boolean",
528 "break",
529 "byte",
530 "case",
531 "catch",
532 "char",
533 "class",
534 "const",
535 "continue",
536 "debugger",
537 "default",
538 "delete",
539 "do",
540 "double",
541 "else",
542 "enum",
543 "export",
544 "extends",
545 "false",
546 "final",
547 "finally",
548 "float",
549 "for",
550 "function",
551 "goto",
552 "if",
553 "implements",
554 "import",
555 "in",
556 "instanceof",
557 "int",
558 "interface",
559 "long",
560 "native",
561 "new",
562 "null",
563 "package",
564 "private",
565 "protected",
566 "public",
567 "return",
568 "short",
569 "static",
570 "super",
571 "switch",
572 "synchronized",
573 "this",
574 "throw",
575 "throws",
576 "transient",
577 "true",
578 "try",
579 "typeof",
580 "var",
581 "void",
582 "volatile",
583 "while",
584 "with",
585 0
586};
587
588
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000589static void CheckInternalizedStrings(const char** strings) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000590 for (const char* string = *strings; *strings != 0; string = *strings++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000591 Object* a;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000592 MaybeObject* maybe_a = HEAP->InternalizeUtf8String(string);
593 // InternalizeUtf8String may return a failure if a GC is needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000594 if (!maybe_a->ToObject(&a)) continue;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000595 CHECK(a->IsInternalizedString());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000596 Object* b;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000597 MaybeObject* maybe_b = HEAP->InternalizeUtf8String(string);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000598 if (!maybe_b->ToObject(&b)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000599 CHECK_EQ(b, a);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000600 CHECK(String::cast(b)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000601 }
602}
603
604
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000605TEST(StringTable) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000606 CcTest::InitializeVM();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000607
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000608 CheckInternalizedStrings(not_so_random_string_table);
609 CheckInternalizedStrings(not_so_random_string_table);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000610}
611
612
613TEST(FunctionAllocation) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000614 CcTest::InitializeVM();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000615
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000616 v8::HandleScope sc(CcTest::isolate());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000617 Handle<String> name = FACTORY->InternalizeUtf8String("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000618 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000620 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000621 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000622 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000623
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000624 Handle<String> prop_name = FACTORY->InternalizeUtf8String("theSlot");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000625 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000626 obj->SetProperty(
627 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000628 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000629 // Check that we can add properties to function objects.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000630 function->SetProperty(
631 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000632 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000633}
634
635
636TEST(ObjectProperties) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000637 CcTest::InitializeVM();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000638
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000639 v8::HandleScope sc(CcTest::isolate());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000640 String* object_string = String::cast(HEAP->Object_string());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000641 Object* raw_object = Isolate::Current()->context()->global_object()->
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000642 GetProperty(object_string)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000643 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000644 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000645 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000646 Handle<String> first = FACTORY->InternalizeUtf8String("first");
647 Handle<String> second = FACTORY->InternalizeUtf8String("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000648
649 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000650 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000651
652 // add first
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000653 obj->SetProperty(
654 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000655 CHECK(obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000656
657 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000658 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
659 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000660
661 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000662 obj->SetProperty(
663 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
664 obj->SetProperty(
665 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000666 CHECK(obj->HasLocalProperty(*first));
667 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000668
669 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000670 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
671 CHECK(obj->HasLocalProperty(*second));
672 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
673 CHECK(!obj->HasLocalProperty(*first));
674 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000675
676 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000677 obj->SetProperty(
678 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
679 obj->SetProperty(
680 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000681 CHECK(obj->HasLocalProperty(*first));
682 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000683
684 // delete second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000685 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
686 CHECK(obj->HasLocalProperty(*first));
687 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
688 CHECK(!obj->HasLocalProperty(*first));
689 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000690
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000691 // check string and internalized string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000692 const char* string1 = "fisk";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000693 Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000694 obj->SetProperty(
695 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000696 Handle<String> s1_string = FACTORY->InternalizeUtf8String(string1);
697 CHECK(obj->HasLocalProperty(*s1_string));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000698
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000699 // check internalized string and string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000700 const char* string2 = "fugl";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000701 Handle<String> s2_string = FACTORY->InternalizeUtf8String(string2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000702 obj->SetProperty(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000703 *s2_string, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000704 Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000705 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000706}
707
708
709TEST(JSObjectMaps) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000710 CcTest::InitializeVM();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000711
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000712 v8::HandleScope sc(CcTest::isolate());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000713 Handle<String> name = FACTORY->InternalizeUtf8String("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000714 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000715 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000716 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000717 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000718 function->set_initial_map(*initial_map);
719
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000720 Handle<String> prop_name = FACTORY->InternalizeUtf8String("theSlot");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000721 Handle<JSObject> obj = FACTORY->NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000722
723 // Set a propery
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000724 obj->SetProperty(
725 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000726 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000727
728 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000729 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000730}
731
732
733TEST(JSArray) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000734 CcTest::InitializeVM();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000735
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000736 v8::HandleScope sc(CcTest::isolate());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000737 Handle<String> name = FACTORY->InternalizeUtf8String("Array");
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000738 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000739 GetProperty(*name)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000740 Handle<JSFunction> function = Handle<JSFunction>(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000741 JSFunction::cast(raw_object));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000742
743 // Allocate the object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000744 Handle<JSObject> object = FACTORY->NewJSObject(function);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000745 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000746 // We just initialized the VM, no heap allocation failure yet.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000747 array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000748
749 // Set array length to 0.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000750 array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000751 CHECK_EQ(Smi::FromInt(0), array->length());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000752 // Must be in fast mode.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000753 CHECK(array->HasFastSmiOrObjectElements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000754
755 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000756 array->SetElement(0, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000757 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000758 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000759
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000760 // Set array length with larger than smi value.
761 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000762 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000763 array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000764
765 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000766 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000767 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000768 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000769
770 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000771 array->SetElement(int_length, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000772 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000773 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000774 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000775 CHECK_EQ(array->GetElement(int_length), *name);
776 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000777}
778
779
780TEST(JSObjectCopy) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000781 CcTest::InitializeVM();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000782
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000783 v8::HandleScope sc(CcTest::isolate());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000784 String* object_string = String::cast(HEAP->Object_string());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000785 Object* raw_object = Isolate::Current()->context()->global_object()->
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000786 GetProperty(object_string)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000787 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000788 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000789 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000790 Handle<String> first = FACTORY->InternalizeUtf8String("first");
791 Handle<String> second = FACTORY->InternalizeUtf8String("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000792
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000793 obj->SetProperty(
794 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
795 obj->SetProperty(
796 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000797
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000798 obj->SetElement(0, *first, NONE, kNonStrictMode)->ToObjectChecked();
799 obj->SetElement(1, *second, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000800
801 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000802 Handle<JSObject> clone = Copy(obj);
803 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000804
805 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
806 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
807
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000808 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
809 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000810
811 // Flip the values.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000812 clone->SetProperty(
813 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
814 clone->SetProperty(
815 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000816
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000817 clone->SetElement(0, *second, NONE, kNonStrictMode)->ToObjectChecked();
818 clone->SetElement(1, *first, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000819
820 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
821 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
822
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000823 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
824 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000825}
826
827
828TEST(StringAllocation) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000829 CcTest::InitializeVM();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000830
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000831 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
832 for (int length = 0; length < 100; length++) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000833 v8::HandleScope scope(CcTest::isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000834 char* non_ascii = NewArray<char>(3 * length + 1);
835 char* ascii = NewArray<char>(length + 1);
836 non_ascii[3 * length] = 0;
837 ascii[length] = 0;
838 for (int i = 0; i < length; i++) {
839 ascii[i] = 'a';
840 non_ascii[3 * i] = chars[0];
841 non_ascii[3 * i + 1] = chars[1];
842 non_ascii[3 * i + 2] = chars[2];
843 }
844 Handle<String> non_ascii_sym =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000845 FACTORY->InternalizeUtf8String(
846 Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000847 CHECK_EQ(length, non_ascii_sym->length());
848 Handle<String> ascii_sym =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000849 FACTORY->InternalizeOneByteString(OneByteVector(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000850 CHECK_EQ(length, ascii_sym->length());
851 Handle<String> non_ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000852 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000853 non_ascii_str->Hash();
854 CHECK_EQ(length, non_ascii_str->length());
855 Handle<String> ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000856 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000857 ascii_str->Hash();
858 CHECK_EQ(length, ascii_str->length());
859 DeleteArray(non_ascii);
860 DeleteArray(ascii);
861 }
862}
863
864
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000865static int ObjectsFoundInHeap(Heap* heap, Handle<Object> objs[], int size) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000866 // Count the number of objects found in the heap.
867 int found_count = 0;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000868 HeapIterator iterator(heap);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000869 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000870 for (int i = 0; i < size; i++) {
871 if (*objs[i] == obj) {
872 found_count++;
873 }
874 }
875 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000876 return found_count;
877}
878
879
880TEST(Iteration) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000881 CcTest::InitializeVM();
882 v8::HandleScope scope(CcTest::isolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000883
884 // Array of objects to scan haep for.
885 const int objs_count = 6;
886 Handle<Object> objs[objs_count];
887 int next_objs_index = 0;
888
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000889 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000890 objs[next_objs_index++] = FACTORY->NewJSArray(10);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000891 objs[next_objs_index++] = FACTORY->NewJSArray(10,
892 FAST_HOLEY_ELEMENTS,
893 TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000894
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000895 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000896 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000897 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000898 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000899 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000900
901 // Allocate a large string (for large object space).
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000902 int large_size = Page::kMaxNonCodeHeapObjectSize + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000903 char* str = new char[large_size];
904 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
905 str[large_size - 1] = '\0';
906 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000907 FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000908 delete[] str;
909
910 // Add a Map object to look for.
911 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
912
913 CHECK_EQ(objs_count, next_objs_index);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000914 CHECK_EQ(objs_count, ObjectsFoundInHeap(HEAP, objs, objs_count));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000915}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000916
917
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000918TEST(EmptyHandleEscapeFrom) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000919 CcTest::InitializeVM();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000920
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000921 v8::HandleScope scope(CcTest::isolate());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000922 Handle<JSObject> runaway;
923
924 {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000925 v8::HandleScope nested(CcTest::isolate());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000926 Handle<JSObject> empty;
927 runaway = empty.EscapeFrom(&nested);
928 }
929
930 CHECK(runaway.is_null());
931}
932
933
934static int LenFromSize(int size) {
935 return (size - FixedArray::kHeaderSize) / kPointerSize;
936}
937
938
939TEST(Regression39128) {
940 // Test case for crbug.com/39128.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000941 CcTest::InitializeVM();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000942
943 // Increase the chance of 'bump-the-pointer' allocation in old space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000944 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000945
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000946 v8::HandleScope scope(CcTest::isolate());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000947
948 // The plan: create JSObject which references objects in new space.
949 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000950 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000951
952 // Step 1: prepare a map for the object. We add 1 inobject property to it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000953 Handle<JSFunction> object_ctor(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000954 Isolate::Current()->native_context()->object_function());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000955 CHECK(object_ctor->has_initial_map());
956 Handle<Map> object_map(object_ctor->initial_map());
957 // Create a map with single inobject property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000958 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000959 int n_properties = my_map->inobject_properties();
960 CHECK_GT(n_properties, 0);
961
962 int object_size = my_map->instance_size();
963
964 // Step 2: allocate a lot of objects so to almost fill new space: we need
965 // just enough room to allocate JSObject and thus fill the newspace.
966
967 int allocation_amount = Min(FixedArray::kMaxSize,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000968 HEAP->MaxObjectSizeInNewSpace());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000969 int allocation_len = LenFromSize(allocation_amount);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000970 NewSpace* new_space = HEAP->new_space();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000971 Address* top_addr = new_space->allocation_top_address();
972 Address* limit_addr = new_space->allocation_limit_address();
973 while ((*limit_addr - *top_addr) > allocation_amount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000974 CHECK(!HEAP->always_allocate());
975 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
976 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000977 CHECK(new_space->Contains(array));
978 }
979
980 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000981 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000982 int fixed_array_len = LenFromSize(to_fill);
983 CHECK(fixed_array_len < FixedArray::kMaxLength);
984
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000985 CHECK(!HEAP->always_allocate());
986 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
987 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000988 CHECK(new_space->Contains(array));
989
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000990 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000991 CHECK(new_space->Contains(object));
992 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000993 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000994 CHECK_EQ(0, jsobject->properties()->length());
995 // Create a reference to object in new space in jsobject.
996 jsobject->FastPropertyAtPut(-1, array);
997
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000998 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000999
1000 // Step 4: clone jsobject, but force always allocate first to create a clone
1001 // in old pointer space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001002 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001003 AlwaysAllocateScope aa_scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001004 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001005 JSObject* clone = JSObject::cast(clone_obj);
1006 if (clone->address() != old_pointer_space_top) {
1007 // Alas, got allocated from free list, we cannot do checks.
1008 return;
1009 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001010 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001011}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001012
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001013
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001014TEST(TestCodeFlushing) {
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +00001015 // If we do not flush code this test is invalid.
1016 if (!FLAG_flush_code) return;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001017 i::FLAG_allow_natives_syntax = true;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001018 CcTest::InitializeVM();
1019 v8::HandleScope scope(CcTest::isolate());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001020 const char* source = "function foo() {"
1021 " var x = 42;"
1022 " var y = 42;"
1023 " var z = x + y;"
1024 "};"
1025 "foo()";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001026 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001027
1028 // This compile will add the code to the compilation cache.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001029 { v8::HandleScope scope(CcTest::isolate());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001030 CompileRun(source);
1031 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001032
1033 // Check function is compiled.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001034 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035 GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001036 CHECK(func_value->IsJSFunction());
1037 Handle<JSFunction> function(JSFunction::cast(func_value));
1038 CHECK(function->shared()->is_compiled());
1039
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001040 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001041 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1042 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001043 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001044
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001045 // Simulate several GCs that use full marking.
1046 const int kAgingThreshold = 6;
1047 for (int i = 0; i < kAgingThreshold; i++) {
1048 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1049 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001050
1051 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001052 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1053 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001054 // Call foo to get it recompiled.
1055 CompileRun("foo()");
1056 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001057 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001058}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001059
1060
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001061TEST(TestCodeFlushingIncremental) {
1062 // If we do not flush code this test is invalid.
1063 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1064 i::FLAG_allow_natives_syntax = true;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001065 CcTest::InitializeVM();
1066 v8::HandleScope scope(CcTest::isolate());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001067 const char* source = "function foo() {"
1068 " var x = 42;"
1069 " var y = 42;"
1070 " var z = x + y;"
1071 "};"
1072 "foo()";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001073 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001074
1075 // This compile will add the code to the compilation cache.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001076 { v8::HandleScope scope(CcTest::isolate());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001077 CompileRun(source);
1078 }
1079
1080 // Check function is compiled.
1081 Object* func_value = Isolate::Current()->context()->global_object()->
1082 GetProperty(*foo_name)->ToObjectChecked();
1083 CHECK(func_value->IsJSFunction());
1084 Handle<JSFunction> function(JSFunction::cast(func_value));
1085 CHECK(function->shared()->is_compiled());
1086
1087 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001088 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1089 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001090 CHECK(function->shared()->is_compiled());
1091
1092 // Simulate several GCs that use incremental marking.
1093 const int kAgingThreshold = 6;
1094 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001095 SimulateIncrementalMarking();
1096 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1097 }
1098 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1099 CHECK(!function->is_compiled() || function->IsOptimized());
1100
1101 // This compile will compile the function again.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001102 { v8::HandleScope scope(CcTest::isolate());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001103 CompileRun("foo();");
1104 }
1105
1106 // Simulate several GCs that use incremental marking but make sure
1107 // the loop breaks once the function is enqueued as a candidate.
1108 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001109 SimulateIncrementalMarking();
1110 if (!function->next_function_link()->IsUndefined()) break;
1111 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1112 }
1113
1114 // Force optimization while incremental marking is active and while
1115 // the function is enqueued as a candidate.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001116 { v8::HandleScope scope(CcTest::isolate());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001117 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1118 }
1119
1120 // Simulate one final GC to make sure the candidate queue is sane.
1121 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1122 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1123 CHECK(function->is_compiled() || !function->IsOptimized());
1124}
1125
1126
1127TEST(TestCodeFlushingIncrementalScavenge) {
1128 // If we do not flush code this test is invalid.
1129 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1130 i::FLAG_allow_natives_syntax = true;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001131 CcTest::InitializeVM();
1132 v8::HandleScope scope(CcTest::isolate());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001133 const char* source = "var foo = function() {"
1134 " var x = 42;"
1135 " var y = 42;"
1136 " var z = x + y;"
1137 "};"
1138 "foo();"
1139 "var bar = function() {"
1140 " var x = 23;"
1141 "};"
1142 "bar();";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001143 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
1144 Handle<String> bar_name = FACTORY->InternalizeUtf8String("bar");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001145
1146 // Perfrom one initial GC to enable code flushing.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001147 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001148
1149 // This compile will add the code to the compilation cache.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001150 { v8::HandleScope scope(CcTest::isolate());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001151 CompileRun(source);
1152 }
1153
1154 // Check functions are compiled.
1155 Object* func_value = Isolate::Current()->context()->global_object()->
1156 GetProperty(*foo_name)->ToObjectChecked();
1157 CHECK(func_value->IsJSFunction());
1158 Handle<JSFunction> function(JSFunction::cast(func_value));
1159 CHECK(function->shared()->is_compiled());
1160 Object* func_value2 = Isolate::Current()->context()->global_object()->
1161 GetProperty(*bar_name)->ToObjectChecked();
1162 CHECK(func_value2->IsJSFunction());
1163 Handle<JSFunction> function2(JSFunction::cast(func_value2));
1164 CHECK(function2->shared()->is_compiled());
1165
1166 // Clear references to functions so that one of them can die.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001167 { v8::HandleScope scope(CcTest::isolate());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001168 CompileRun("foo = 0; bar = 0;");
1169 }
1170
1171 // Bump the code age so that flushing is triggered while the function
1172 // object is still located in new-space.
1173 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001174 for (int i = 0; i < kAgingThreshold; i++) {
1175 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1176 function2->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1177 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001178
1179 // Simulate incremental marking so that the functions are enqueued as
1180 // code flushing candidates. Then kill one of the functions. Finally
1181 // perform a scavenge while incremental marking is still running.
1182 SimulateIncrementalMarking();
1183 *function2.location() = NULL;
1184 HEAP->CollectGarbage(NEW_SPACE, "test scavenge while marking");
1185
1186 // Simulate one final GC to make sure the candidate queue is sane.
1187 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1188 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1189 CHECK(!function->is_compiled() || function->IsOptimized());
1190}
1191
1192
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001193TEST(TestCodeFlushingIncrementalAbort) {
1194 // If we do not flush code this test is invalid.
1195 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1196 i::FLAG_allow_natives_syntax = true;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001197 CcTest::InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001198 Isolate* isolate = Isolate::Current();
1199 Heap* heap = isolate->heap();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001200 v8::HandleScope scope(CcTest::isolate());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001201 const char* source = "function foo() {"
1202 " var x = 42;"
1203 " var y = 42;"
1204 " var z = x + y;"
1205 "};"
1206 "foo()";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001207 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001208
1209 // This compile will add the code to the compilation cache.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001210 { v8::HandleScope scope(CcTest::isolate());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001211 CompileRun(source);
1212 }
1213
1214 // Check function is compiled.
1215 Object* func_value = Isolate::Current()->context()->global_object()->
1216 GetProperty(*foo_name)->ToObjectChecked();
1217 CHECK(func_value->IsJSFunction());
1218 Handle<JSFunction> function(JSFunction::cast(func_value));
1219 CHECK(function->shared()->is_compiled());
1220
1221 // The code will survive at least two GCs.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001222 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1223 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001224 CHECK(function->shared()->is_compiled());
1225
1226 // Bump the code age so that flushing is triggered.
1227 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001228 for (int i = 0; i < kAgingThreshold; i++) {
1229 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1230 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001231
1232 // Simulate incremental marking so that the function is enqueued as
1233 // code flushing candidate.
1234 SimulateIncrementalMarking();
1235
danno@chromium.orgc99cd482013-03-21 15:26:42 +00001236#ifdef ENABLE_DEBUGGER_SUPPORT
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001237 // Enable the debugger and add a breakpoint while incremental marking
1238 // is running so that incremental marking aborts and code flushing is
1239 // disabled.
1240 int position = 0;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001241 Handle<Object> breakpoint_object(Smi::FromInt(0), isolate);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001242 isolate->debug()->SetBreakPoint(function, breakpoint_object, &position);
1243 isolate->debug()->ClearAllBreakPoints();
danno@chromium.orgc99cd482013-03-21 15:26:42 +00001244#endif // ENABLE_DEBUGGER_SUPPORT
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001245
1246 // Force optimization now that code flushing is disabled.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001247 { v8::HandleScope scope(CcTest::isolate());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001248 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1249 }
1250
1251 // Simulate one final GC to make sure the candidate queue is sane.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001252 heap->CollectAllGarbage(Heap::kNoGCFlags);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001253 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1254 CHECK(function->is_compiled() || !function->IsOptimized());
1255}
1256
1257
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001258// Count the number of native contexts in the weak list of native contexts.
1259int CountNativeContexts() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001260 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001261 Object* object = HEAP->native_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001262 while (!object->IsUndefined()) {
1263 count++;
1264 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1265 }
1266 return count;
1267}
1268
1269
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001270// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001271// functions attached to a native context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001272static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1273 int count = 0;
1274 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1275 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1276 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1277 count++;
1278 object = JSFunction::cast(object)->next_function_link();
1279 }
1280 return count;
1281}
1282
1283
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001284TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001285 v8::V8::Initialize();
1286
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001287 // Some flags turn Scavenge collections into Mark-sweep collections
1288 // and hence are incompatible with this test case.
1289 if (FLAG_gc_global || FLAG_stress_compaction) return;
1290
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001291 static const int kNumTestContexts = 10;
1292
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001293 Isolate* isolate = Isolate::Current();
1294 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001295 HandleScope scope(isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001296 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1297
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001298 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001299
1300 // Create a number of global contests which gets linked together.
1301 for (int i = 0; i < kNumTestContexts; i++) {
1302 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001303
1304 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1305
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001306 CHECK_EQ(i + 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001307
1308 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001309
1310 // Create a handle scope so no function objects get stuch in the outer
1311 // handle scope
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001312 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001313 const char* source = "function f1() { };"
1314 "function f2() { };"
1315 "function f3() { };"
1316 "function f4() { };"
1317 "function f5() { };";
1318 CompileRun(source);
1319 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1320 CompileRun("f1()");
1321 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1322 CompileRun("f2()");
1323 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1324 CompileRun("f3()");
1325 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1326 CompileRun("f4()");
1327 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1328 CompileRun("f5()");
1329 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1330
1331 // Remove function f1, and
1332 CompileRun("f1=null");
1333
1334 // Scavenge treats these references as strong.
1335 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001336 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001337 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1338 }
1339
1340 // Mark compact handles the weak references.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001341 isolate->compilation_cache()->Clear();
1342 heap->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001343 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1344
1345 // Get rid of f3 and f5 in the same way.
1346 CompileRun("f3=null");
1347 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001348 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001349 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1350 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001351 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001352 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1353 CompileRun("f5=null");
1354 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001355 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001356 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1357 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001358 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001359 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1360
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001361 ctx[i]->Exit();
1362 }
1363
1364 // Force compilation cache cleanup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001365 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001366
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001367 // Dispose the native contexts one by one.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001368 for (int i = 0; i < kNumTestContexts; i++) {
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001369 ctx[i].Dispose(ctx[i]->GetIsolate());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001370 ctx[i].Clear();
1371
1372 // Scavenge treats these references as strong.
1373 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 HEAP->PerformScavenge();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001375 CHECK_EQ(kNumTestContexts - i, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001376 }
1377
1378 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001379 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001380 CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001381 }
1382
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001383 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001384}
1385
1386
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001387// Count the number of native contexts in the weak list of native contexts
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001388// causing a GC after the specified number of elements.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001389static int CountNativeContextsWithGC(Isolate* isolate, int n) {
1390 Heap* heap = isolate->heap();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001391 int count = 0;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001392 Handle<Object> object(heap->native_contexts_list(), isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001393 while (!object->IsUndefined()) {
1394 count++;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001395 if (count == n) heap->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001396 object =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001397 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK),
1398 isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001399 }
1400 return count;
1401}
1402
1403
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001404// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001405// functions attached to a native context causing a GC after the
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001406// specified number of elements.
1407static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1408 int n) {
1409 int count = 0;
1410 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001411 Isolate* isolate = icontext->GetIsolate();
1412 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST),
1413 isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001414 while (object->IsJSFunction() &&
1415 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1416 count++;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001417 if (count == n) isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001418 object = Handle<Object>(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001419 Object::cast(JSFunction::cast(*object)->next_function_link()),
1420 isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001421 }
1422 return count;
1423}
1424
1425
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001426TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001427 v8::V8::Initialize();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001428 Isolate* isolate = Isolate::Current();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001429
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001430 static const int kNumTestContexts = 10;
1431
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001432 HandleScope scope(isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001433 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1434
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001435 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001436
1437 // Create an number of contexts and check the length of the weak list both
1438 // with and without GCs while iterating the list.
1439 for (int i = 0; i < kNumTestContexts; i++) {
1440 ctx[i] = v8::Context::New();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001441 CHECK_EQ(i + 1, CountNativeContexts());
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001442 CHECK_EQ(i + 1, CountNativeContextsWithGC(isolate, i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001443 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001444
1445 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1446
1447 // Compile a number of functions the length of the weak list of optimized
1448 // functions both with and without GCs while iterating the list.
1449 ctx[0]->Enter();
1450 const char* source = "function f1() { };"
1451 "function f2() { };"
1452 "function f3() { };"
1453 "function f4() { };"
1454 "function f5() { };";
1455 CompileRun(source);
1456 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1457 CompileRun("f1()");
1458 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1459 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1460 CompileRun("f2()");
1461 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1462 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1463 CompileRun("f3()");
1464 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1465 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1466 CompileRun("f4()");
1467 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1468 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1469 CompileRun("f5()");
1470 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1471 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1472
1473 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001474}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001475
1476
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001477TEST(TestSizeOfObjects) {
1478 v8::V8::Initialize();
1479
1480 // Get initial heap size after several full GCs, which will stabilize
1481 // the heap size and return with sweeping finished completely.
1482 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1483 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1484 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1485 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001486 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001487 CHECK(HEAP->old_pointer_space()->IsLazySweepingComplete());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001488 int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1489
1490 {
1491 // Allocate objects on several different old-space pages so that
1492 // lazy sweeping kicks in for subsequent GC runs.
1493 AlwaysAllocateScope always_allocate;
1494 int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1495 for (int i = 1; i <= 100; i++) {
1496 HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1497 CHECK_EQ(initial_size + i * filler_size,
1498 static_cast<int>(HEAP->SizeOfObjects()));
1499 }
1500 }
1501
1502 // The heap size should go back to initial size after a full GC, even
1503 // though sweeping didn't finish yet.
1504 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001505
1506 // Normally sweeping would not be complete here, but no guarantees.
1507
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001508 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1509
1510 // Advancing the sweeper step-wise should not change the heap size.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001511 while (!HEAP->old_pointer_space()->IsLazySweepingComplete()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001512 HEAP->old_pointer_space()->AdvanceSweeper(KB);
1513 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1514 }
1515}
1516
1517
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001518TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001519 CcTest::InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001520 HEAP->EnsureHeapIsIterable();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001521 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001522 HeapIterator iterator(HEAP);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001523 intptr_t size_of_objects_2 = 0;
1524 for (HeapObject* obj = iterator.next();
1525 obj != NULL;
1526 obj = iterator.next()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001527 if (!obj->IsFreeSpace()) {
1528 size_of_objects_2 += obj->Size();
1529 }
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001530 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001531 // Delta must be within 5% of the larger result.
1532 // TODO(gc): Tighten this up by distinguishing between byte
1533 // arrays that are real and those that merely mark free space
1534 // on the heap.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001535 if (size_of_objects_1 > size_of_objects_2) {
1536 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1537 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1538 "Iterator: %" V8_PTR_PREFIX "d, "
1539 "delta: %" V8_PTR_PREFIX "d\n",
1540 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001541 CHECK_GT(size_of_objects_1 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001542 } else {
1543 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1544 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1545 "Iterator: %" V8_PTR_PREFIX "d, "
1546 "delta: %" V8_PTR_PREFIX "d\n",
1547 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001548 CHECK_GT(size_of_objects_2 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001549 }
1550}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001551
1552
danno@chromium.orgc612e022011-11-10 11:38:15 +00001553static void FillUpNewSpace(NewSpace* new_space) {
1554 // Fill up new space to the point that it is completely full. Make sure
1555 // that the scavenger does not undo the filling.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001556 Heap* heap = new_space->heap();
1557 Isolate* isolate = heap->isolate();
1558 Factory* factory = isolate->factory();
1559 HandleScope scope(isolate);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001560 AlwaysAllocateScope always_allocate;
1561 intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001562 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001563 for (intptr_t i = 0; i < number_of_fillers; i++) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001564 CHECK(heap->InNewSpace(*factory->NewFixedArray(32, NOT_TENURED)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001565 }
1566}
1567
1568
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001569TEST(GrowAndShrinkNewSpace) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001570 CcTest::InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001571 NewSpace* new_space = HEAP->new_space();
1572
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001573 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1574 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001575 // The max size cannot exceed the reserved size, since semispaces must be
1576 // always within the reserved space. We can't test new space growing and
1577 // shrinking if the reserved size is the same as the minimum (initial) size.
1578 return;
1579 }
1580
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001581 // Explicitly growing should double the space capacity.
1582 intptr_t old_capacity, new_capacity;
1583 old_capacity = new_space->Capacity();
1584 new_space->Grow();
1585 new_capacity = new_space->Capacity();
1586 CHECK(2 * old_capacity == new_capacity);
1587
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001588 old_capacity = new_space->Capacity();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001589 FillUpNewSpace(new_space);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001590 new_capacity = new_space->Capacity();
1591 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001592
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001593 // Explicitly shrinking should not affect space capacity.
1594 old_capacity = new_space->Capacity();
1595 new_space->Shrink();
1596 new_capacity = new_space->Capacity();
1597 CHECK(old_capacity == new_capacity);
1598
1599 // Let the scavenger empty the new space.
1600 HEAP->CollectGarbage(NEW_SPACE);
1601 CHECK_LE(new_space->Size(), old_capacity);
1602
1603 // Explicitly shrinking should halve the space capacity.
1604 old_capacity = new_space->Capacity();
1605 new_space->Shrink();
1606 new_capacity = new_space->Capacity();
1607 CHECK(old_capacity == 2 * new_capacity);
1608
1609 // Consecutive shrinking should not affect space capacity.
1610 old_capacity = new_space->Capacity();
1611 new_space->Shrink();
1612 new_space->Shrink();
1613 new_space->Shrink();
1614 new_capacity = new_space->Capacity();
1615 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001616}
danno@chromium.orgc612e022011-11-10 11:38:15 +00001617
1618
1619TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001620 CcTest::InitializeVM();
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001621
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001622 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1623 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001624 // The max size cannot exceed the reserved size, since semispaces must be
1625 // always within the reserved space. We can't test new space growing and
1626 // shrinking if the reserved size is the same as the minimum (initial) size.
1627 return;
1628 }
1629
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001630 v8::HandleScope scope(CcTest::isolate());
danno@chromium.orgc612e022011-11-10 11:38:15 +00001631 NewSpace* new_space = HEAP->new_space();
1632 intptr_t old_capacity, new_capacity;
1633 old_capacity = new_space->Capacity();
1634 new_space->Grow();
1635 new_capacity = new_space->Capacity();
1636 CHECK(2 * old_capacity == new_capacity);
1637 FillUpNewSpace(new_space);
1638 HEAP->CollectAllAvailableGarbage();
1639 new_capacity = new_space->Capacity();
1640 CHECK(old_capacity == new_capacity);
1641}
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001642
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001643
1644static int NumberOfGlobalObjects() {
1645 int count = 0;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001646 HeapIterator iterator(HEAP);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001647 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1648 if (obj->IsGlobalObject()) count++;
1649 }
1650 return count;
1651}
1652
1653
1654// Test that we don't embed maps from foreign contexts into
1655// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001656TEST(LeakNativeContextViaMap) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001657 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001658 v8::HandleScope outer_scope(v8::Isolate::GetCurrent());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001659 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1660 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1661 ctx1->Enter();
1662
1663 HEAP->CollectAllAvailableGarbage();
1664 CHECK_EQ(4, NumberOfGlobalObjects());
1665
1666 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001667 v8::HandleScope inner_scope(v8::Isolate::GetCurrent());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001668 CompileRun("var v = {x: 42}");
1669 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1670 ctx2->Enter();
1671 ctx2->Global()->Set(v8_str("o"), v);
1672 v8::Local<v8::Value> res = CompileRun(
1673 "function f() { return o.x; }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001674 "for (var i = 0; i < 10; ++i) f();"
1675 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001676 "f();");
1677 CHECK_EQ(42, res->Int32Value());
1678 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1679 ctx2->Exit();
1680 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001681 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001682 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001683 }
1684 HEAP->CollectAllAvailableGarbage();
1685 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001686 ctx2.Dispose(ctx2->GetIsolate());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001687 HEAP->CollectAllAvailableGarbage();
1688 CHECK_EQ(0, NumberOfGlobalObjects());
1689}
1690
1691
1692// Test that we don't embed functions from foreign contexts into
1693// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001694TEST(LeakNativeContextViaFunction) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001695 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001696 v8::HandleScope outer_scope(v8::Isolate::GetCurrent());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001697 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1698 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1699 ctx1->Enter();
1700
1701 HEAP->CollectAllAvailableGarbage();
1702 CHECK_EQ(4, NumberOfGlobalObjects());
1703
1704 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001705 v8::HandleScope inner_scope(v8::Isolate::GetCurrent());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001706 CompileRun("var v = function() { return 42; }");
1707 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1708 ctx2->Enter();
1709 ctx2->Global()->Set(v8_str("o"), v);
1710 v8::Local<v8::Value> res = CompileRun(
1711 "function f(x) { return x(); }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001712 "for (var i = 0; i < 10; ++i) f(o);"
1713 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001714 "f(o);");
1715 CHECK_EQ(42, res->Int32Value());
1716 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1717 ctx2->Exit();
1718 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001719 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001720 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001721 }
1722 HEAP->CollectAllAvailableGarbage();
1723 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001724 ctx2.Dispose(ctx2->GetIsolate());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001725 HEAP->CollectAllAvailableGarbage();
1726 CHECK_EQ(0, NumberOfGlobalObjects());
1727}
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001728
1729
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001730TEST(LeakNativeContextViaMapKeyed) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001731 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001732 v8::HandleScope outer_scope(v8::Isolate::GetCurrent());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001733 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1734 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1735 ctx1->Enter();
1736
1737 HEAP->CollectAllAvailableGarbage();
1738 CHECK_EQ(4, NumberOfGlobalObjects());
1739
1740 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001741 v8::HandleScope inner_scope(v8::Isolate::GetCurrent());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001742 CompileRun("var v = [42, 43]");
1743 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1744 ctx2->Enter();
1745 ctx2->Global()->Set(v8_str("o"), v);
1746 v8::Local<v8::Value> res = CompileRun(
1747 "function f() { return o[0]; }"
1748 "for (var i = 0; i < 10; ++i) f();"
1749 "%OptimizeFunctionOnNextCall(f);"
1750 "f();");
1751 CHECK_EQ(42, res->Int32Value());
1752 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1753 ctx2->Exit();
1754 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001755 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001756 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001757 }
1758 HEAP->CollectAllAvailableGarbage();
1759 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001760 ctx2.Dispose(ctx2->GetIsolate());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001761 HEAP->CollectAllAvailableGarbage();
1762 CHECK_EQ(0, NumberOfGlobalObjects());
1763}
1764
1765
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001766TEST(LeakNativeContextViaMapProto) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001767 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001768 v8::HandleScope outer_scope(v8::Isolate::GetCurrent());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001769 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1770 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1771 ctx1->Enter();
1772
1773 HEAP->CollectAllAvailableGarbage();
1774 CHECK_EQ(4, NumberOfGlobalObjects());
1775
1776 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001777 v8::HandleScope inner_scope(v8::Isolate::GetCurrent());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001778 CompileRun("var v = { y: 42}");
1779 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1780 ctx2->Enter();
1781 ctx2->Global()->Set(v8_str("o"), v);
1782 v8::Local<v8::Value> res = CompileRun(
1783 "function f() {"
1784 " var p = {x: 42};"
1785 " p.__proto__ = o;"
1786 " return p.x;"
1787 "}"
1788 "for (var i = 0; i < 10; ++i) f();"
1789 "%OptimizeFunctionOnNextCall(f);"
1790 "f();");
1791 CHECK_EQ(42, res->Int32Value());
1792 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1793 ctx2->Exit();
1794 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001795 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001796 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001797 }
1798 HEAP->CollectAllAvailableGarbage();
1799 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001800 ctx2.Dispose(ctx2->GetIsolate());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001801 HEAP->CollectAllAvailableGarbage();
1802 CHECK_EQ(0, NumberOfGlobalObjects());
1803}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001804
1805
1806TEST(InstanceOfStubWriteBarrier) {
1807 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001808#ifdef VERIFY_HEAP
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001809 i::FLAG_verify_heap = true;
1810#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001811
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001812 CcTest::InitializeVM();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001813 if (!i::V8::UseCrankshaft()) return;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001814 if (i::FLAG_force_marking_deque_overflows) return;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001815 v8::HandleScope outer_scope(v8::Isolate::GetCurrent());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001816
1817 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001818 v8::HandleScope scope(v8::Isolate::GetCurrent());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001819 CompileRun(
1820 "function foo () { }"
1821 "function mkbar () { return new (new Function(\"\")) (); }"
1822 "function f (x) { return (x instanceof foo); }"
1823 "function g () { f(mkbar()); }"
1824 "f(new foo()); f(new foo());"
1825 "%OptimizeFunctionOnNextCall(f);"
1826 "f(new foo()); g();");
1827 }
1828
1829 IncrementalMarking* marking = HEAP->incremental_marking();
1830 marking->Abort();
1831 marking->Start();
1832
1833 Handle<JSFunction> f =
1834 v8::Utils::OpenHandle(
1835 *v8::Handle<v8::Function>::Cast(
1836 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1837
1838 CHECK(f->IsOptimized());
1839
1840 while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1841 !marking->IsStopped()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001842 // Discard any pending GC requests otherwise we will get GC when we enter
1843 // code below.
1844 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001845 }
1846
1847 CHECK(marking->IsMarking());
1848
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001849 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001850 v8::HandleScope scope(v8::Isolate::GetCurrent());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001851 v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1852 v8::Handle<v8::Function> g =
1853 v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1854 g->Call(global, 0, NULL);
1855 }
1856
1857 HEAP->incremental_marking()->set_should_hurry(true);
1858 HEAP->CollectGarbage(OLD_POINTER_SPACE);
1859}
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001860
1861
1862TEST(PrototypeTransitionClearing) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001863 CcTest::InitializeVM();
1864 v8::HandleScope scope(CcTest::isolate());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001865
1866 CompileRun(
1867 "var base = {};"
1868 "var live = [];"
1869 "for (var i = 0; i < 10; i++) {"
1870 " var object = {};"
1871 " var prototype = {};"
1872 " object.__proto__ = prototype;"
1873 " if (i >= 3) live.push(object, prototype);"
1874 "}");
1875
1876 Handle<JSObject> baseObject =
1877 v8::Utils::OpenHandle(
1878 *v8::Handle<v8::Object>::Cast(
1879 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1880
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001881 // Verify that only dead prototype transitions are cleared.
1882 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001883 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001884 const int transitions = 10 - 3;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001885 CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001886
1887 // Verify that prototype transitions array was compacted.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001888 FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001889 for (int i = 0; i < transitions; i++) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001890 int j = Map::kProtoTransitionHeaderSize +
1891 i * Map::kProtoTransitionElementsPerEntry;
1892 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001893 Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
1894 CHECK(proto->IsTheHole() || proto->IsJSObject());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001895 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001896
1897 // Make sure next prototype is placed on an old-space evacuation candidate.
1898 Handle<JSObject> prototype;
1899 PagedSpace* space = HEAP->old_pointer_space();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001900 {
1901 AlwaysAllocateScope always_allocate;
1902 SimulateFullSpace(space);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001903 prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001904 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001905
1906 // Add a prototype on an evacuation candidate and verify that transition
1907 // clearing correctly records slots in prototype transition array.
1908 i::FLAG_always_compact = true;
1909 Handle<Map> map(baseObject->map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001910 CHECK(!space->LastPage()->Contains(
1911 map->GetPrototypeTransitions()->address()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001912 CHECK(space->LastPage()->Contains(prototype->address()));
1913 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1914 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1915 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1916 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001917}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001918
1919
1920TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1921 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001922#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001923 i::FLAG_verify_heap = true;
1924#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001925
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001926 CcTest::InitializeVM();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001927 if (!i::V8::UseCrankshaft()) return;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001928 v8::HandleScope outer_scope(v8::Isolate::GetCurrent());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001929
1930 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001931 v8::HandleScope scope(v8::Isolate::GetCurrent());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001932 CompileRun(
1933 "function f () {"
1934 " var s = 0;"
1935 " for (var i = 0; i < 100; i++) s += i;"
1936 " return s;"
1937 "}"
1938 "f(); f();"
1939 "%OptimizeFunctionOnNextCall(f);"
1940 "f();");
1941 }
1942 Handle<JSFunction> f =
1943 v8::Utils::OpenHandle(
1944 *v8::Handle<v8::Function>::Cast(
1945 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1946 CHECK(f->IsOptimized());
1947
1948 IncrementalMarking* marking = HEAP->incremental_marking();
1949 marking->Abort();
1950 marking->Start();
1951
1952 // The following two calls will increment HEAP->global_ic_age().
1953 const int kLongIdlePauseInMs = 1000;
1954 v8::V8::ContextDisposedNotification();
1955 v8::V8::IdleNotification(kLongIdlePauseInMs);
1956
1957 while (!marking->IsStopped() && !marking->IsComplete()) {
1958 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1959 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001960 if (!marking->IsStopped() || marking->should_hurry()) {
1961 // We don't normally finish a GC via Step(), we normally finish by
1962 // setting the stack guard and then do the final steps in the stack
1963 // guard interrupt. But here we didn't ask for that, and there is no
1964 // JS code running to trigger the interrupt, so we explicitly finalize
1965 // here.
1966 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1967 "Test finalizing incremental mark-sweep");
1968 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001969
1970 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1971 CHECK_EQ(0, f->shared()->opt_count());
1972 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1973}
1974
1975
1976TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1977 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001978#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001979 i::FLAG_verify_heap = true;
1980#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001981
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001982 CcTest::InitializeVM();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001983 if (!i::V8::UseCrankshaft()) return;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001984 v8::HandleScope outer_scope(CcTest::isolate());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001985
1986 {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001987 v8::HandleScope scope(CcTest::isolate());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001988 CompileRun(
1989 "function f () {"
1990 " var s = 0;"
1991 " for (var i = 0; i < 100; i++) s += i;"
1992 " return s;"
1993 "}"
1994 "f(); f();"
1995 "%OptimizeFunctionOnNextCall(f);"
1996 "f();");
1997 }
1998 Handle<JSFunction> f =
1999 v8::Utils::OpenHandle(
2000 *v8::Handle<v8::Function>::Cast(
2001 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2002 CHECK(f->IsOptimized());
2003
2004 HEAP->incremental_marking()->Abort();
2005
2006 // The following two calls will increment HEAP->global_ic_age().
2007 // Since incremental marking is off, IdleNotification will do full GC.
2008 const int kLongIdlePauseInMs = 1000;
2009 v8::V8::ContextDisposedNotification();
2010 v8::V8::IdleNotification(kLongIdlePauseInMs);
2011
2012 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
2013 CHECK_EQ(0, f->shared()->opt_count());
2014 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
2015}
2016
2017
2018// Test that HAllocateObject will always return an object in new-space.
2019TEST(OptimizedAllocationAlwaysInNewSpace) {
2020 i::FLAG_allow_natives_syntax = true;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002021 CcTest::InitializeVM();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002022 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00002023 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002024 v8::HandleScope scope(CcTest::isolate());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002025
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002026 SimulateFullSpace(HEAP->new_space());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002027 AlwaysAllocateScope always_allocate;
2028 v8::Local<v8::Value> res = CompileRun(
2029 "function c(x) {"
2030 " this.x = x;"
2031 " for (var i = 0; i < 32; i++) {"
2032 " this['x' + i] = x;"
2033 " }"
2034 "}"
2035 "function f(x) { return new c(x); };"
2036 "f(1); f(2); f(3);"
2037 "%OptimizeFunctionOnNextCall(f);"
2038 "f(4);");
2039 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
2040
2041 Handle<JSObject> o =
2042 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2043
2044 CHECK(HEAP->InNewSpace(*o));
2045}
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002046
2047
ulan@chromium.org750145a2013-03-07 15:14:13 +00002048// Test pretenuring of array literals allocated with HAllocate.
2049TEST(OptimizedPretenuringArrayLiterals) {
2050 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002051 i::FLAG_pretenure_literals = true;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002052 CcTest::InitializeVM();
ulan@chromium.org750145a2013-03-07 15:14:13 +00002053 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
2054 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002055 v8::HandleScope scope(CcTest::isolate());
ulan@chromium.org750145a2013-03-07 15:14:13 +00002056
2057 AlwaysAllocateScope always_allocate;
2058 v8::Local<v8::Value> res = CompileRun(
2059 "function f() {"
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002060 " var numbers = [1, 2, 3];"
2061 " numbers[0] = {};"
ulan@chromium.org750145a2013-03-07 15:14:13 +00002062 " return numbers;"
2063 "};"
2064 "f(); f(); f();"
2065 "%OptimizeFunctionOnNextCall(f);"
2066 "f();");
ulan@chromium.org750145a2013-03-07 15:14:13 +00002067
2068 Handle<JSObject> o =
2069 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2070
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002071 CHECK(HEAP->InOldPointerSpace(o->elements()));
ulan@chromium.org750145a2013-03-07 15:14:13 +00002072}
2073
2074
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002075TEST(OptimizedPretenuringSimpleArrayLiterals) {
2076 i::FLAG_allow_natives_syntax = true;
2077 i::FLAG_pretenure_literals = false;
2078 CcTest::InitializeVM();
2079 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
2080 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2081 v8::HandleScope scope(CcTest::isolate());
2082
2083 AlwaysAllocateScope always_allocate;
2084 v8::Local<v8::Value> res = CompileRun(
2085 "function f() {"
2086 " return [1, 2, 3];"
2087 "};"
2088 "f(); f(); f();"
2089 "%OptimizeFunctionOnNextCall(f);"
2090 "f();");
2091
2092 Handle<JSObject> o =
2093 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2094
2095 CHECK(HEAP->InNewSpace(*o));
2096}
2097
2098
ulan@chromium.org750145a2013-03-07 15:14:13 +00002099// Test regular array literals allocation.
2100TEST(OptimizedAllocationArrayLiterals) {
2101 i::FLAG_allow_natives_syntax = true;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002102 CcTest::InitializeVM();
ulan@chromium.org750145a2013-03-07 15:14:13 +00002103 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
2104 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002105 v8::HandleScope scope(CcTest::isolate());
ulan@chromium.org750145a2013-03-07 15:14:13 +00002106
2107 AlwaysAllocateScope always_allocate;
2108 v8::Local<v8::Value> res = CompileRun(
2109 "function f() {"
2110 " var numbers = new Array(1, 2, 3);"
2111 " numbers[0] = 3.14;"
2112 " return numbers;"
2113 "};"
2114 "f(); f(); f();"
2115 "%OptimizeFunctionOnNextCall(f);"
2116 "f();");
2117 CHECK_EQ(static_cast<int>(3.14),
2118 v8::Object::Cast(*res)->Get(v8_str("0"))->Int32Value());
2119
2120 Handle<JSObject> o =
2121 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2122
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002123 CHECK(HEAP->InNewSpace(o->elements()));
ulan@chromium.org750145a2013-03-07 15:14:13 +00002124}
2125
2126
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002127static int CountMapTransitions(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002128 return map->transitions()->number_of_transitions();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002129}
2130
2131
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002132// Test that map transitions are cleared and maps are collected with
2133// incremental marking as well.
2134TEST(Regress1465) {
2135 i::FLAG_allow_natives_syntax = true;
2136 i::FLAG_trace_incremental_marking = true;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002137 CcTest::InitializeVM();
2138 v8::HandleScope scope(CcTest::isolate());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002139 static const int transitions_count = 256;
2140
2141 {
2142 AlwaysAllocateScope always_allocate;
2143 for (int i = 0; i < transitions_count; i++) {
2144 EmbeddedVector<char, 64> buffer;
2145 OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
2146 CompileRun(buffer.start());
2147 }
2148 CompileRun("var root = new Object;");
2149 }
2150
2151 Handle<JSObject> root =
2152 v8::Utils::OpenHandle(
2153 *v8::Handle<v8::Object>::Cast(
2154 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2155
2156 // Count number of live transitions before marking.
2157 int transitions_before = CountMapTransitions(root->map());
2158 CompileRun("%DebugPrint(root);");
2159 CHECK_EQ(transitions_count, transitions_before);
2160
2161 SimulateIncrementalMarking();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002162 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002163
2164 // Count number of live transitions after marking. Note that one transition
2165 // is left, because 'o' still holds an instance of one transition target.
2166 int transitions_after = CountMapTransitions(root->map());
2167 CompileRun("%DebugPrint(root);");
2168 CHECK_EQ(1, transitions_after);
2169}
verwaest@chromium.org37141392012-05-31 13:27:02 +00002170
2171
2172TEST(Regress2143a) {
2173 i::FLAG_collect_maps = true;
2174 i::FLAG_incremental_marking = true;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002175 CcTest::InitializeVM();
2176 v8::HandleScope scope(CcTest::isolate());
verwaest@chromium.org37141392012-05-31 13:27:02 +00002177
2178 // Prepare a map transition from the root object together with a yet
2179 // untransitioned root object.
2180 CompileRun("var root = new Object;"
2181 "root.foo = 0;"
2182 "root = new Object;");
2183
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002184 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002185
2186 // Compile a StoreIC that performs the prepared map transition. This
2187 // will restart incremental marking and should make sure the root is
2188 // marked grey again.
2189 CompileRun("function f(o) {"
2190 " o.foo = 0;"
2191 "}"
2192 "f(new Object);"
2193 "f(root);");
2194
2195 // This bug only triggers with aggressive IC clearing.
2196 HEAP->AgeInlineCaches();
2197
2198 // Explicitly request GC to perform final marking step and sweeping.
2199 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002200
2201 Handle<JSObject> root =
2202 v8::Utils::OpenHandle(
2203 *v8::Handle<v8::Object>::Cast(
2204 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2205
2206 // The root object should be in a sane state.
2207 CHECK(root->IsJSObject());
2208 CHECK(root->map()->IsMap());
2209}
2210
2211
2212TEST(Regress2143b) {
2213 i::FLAG_collect_maps = true;
2214 i::FLAG_incremental_marking = true;
2215 i::FLAG_allow_natives_syntax = true;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002216 CcTest::InitializeVM();
2217 v8::HandleScope scope(CcTest::isolate());
verwaest@chromium.org37141392012-05-31 13:27:02 +00002218
2219 // Prepare a map transition from the root object together with a yet
2220 // untransitioned root object.
2221 CompileRun("var root = new Object;"
2222 "root.foo = 0;"
2223 "root = new Object;");
2224
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002225 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002226
2227 // Compile an optimized LStoreNamedField that performs the prepared
2228 // map transition. This will restart incremental marking and should
2229 // make sure the root is marked grey again.
2230 CompileRun("function f(o) {"
2231 " o.foo = 0;"
2232 "}"
2233 "f(new Object);"
2234 "f(new Object);"
2235 "%OptimizeFunctionOnNextCall(f);"
2236 "f(root);"
2237 "%DeoptimizeFunction(f);");
2238
2239 // This bug only triggers with aggressive IC clearing.
2240 HEAP->AgeInlineCaches();
2241
2242 // Explicitly request GC to perform final marking step and sweeping.
2243 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002244
2245 Handle<JSObject> root =
2246 v8::Utils::OpenHandle(
2247 *v8::Handle<v8::Object>::Cast(
2248 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2249
2250 // The root object should be in a sane state.
2251 CHECK(root->IsJSObject());
2252 CHECK(root->map()->IsMap());
2253}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002254
2255
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002256TEST(ReleaseOverReservedPages) {
2257 i::FLAG_trace_gc = true;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002258 // The optimizer can allocate stuff, messing up the test.
2259 i::FLAG_crankshaft = false;
2260 i::FLAG_always_opt = false;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002261 CcTest::InitializeVM();
2262 v8::HandleScope scope(CcTest::isolate());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002263 static const int number_of_test_pages = 20;
2264
2265 // Prepare many pages with low live-bytes count.
2266 PagedSpace* old_pointer_space = HEAP->old_pointer_space();
2267 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2268 for (int i = 0; i < number_of_test_pages; i++) {
2269 AlwaysAllocateScope always_allocate;
2270 SimulateFullSpace(old_pointer_space);
2271 FACTORY->NewFixedArray(1, TENURED);
2272 }
2273 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2274
2275 // Triggering one GC will cause a lot of garbage to be discovered but
2276 // even spread across all allocated pages.
2277 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00002278 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002279
2280 // Triggering subsequent GCs should cause at least half of the pages
2281 // to be released to the OS after at most two cycles.
2282 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
2283 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2284 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
2285 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
2286
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002287 // Triggering a last-resort GC should cause all pages to be released to the
2288 // OS so that other processes can seize the memory. If we get a failure here
2289 // where there are 2 pages left instead of 1, then we should increase the
2290 // size of the first page a little in SizeOfFirstPage in spaces.cc. The
2291 // first page should be small in order to reduce memory used when the VM
2292 // boots, but if the 20 small arrays don't fit on the first page then that's
2293 // an indication that it is too small.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002294 HEAP->CollectAllAvailableGarbage("triggered really hard");
2295 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2296}
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002297
2298
2299TEST(Regress2237) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002300 CcTest::InitializeVM();
2301 v8::HandleScope scope(CcTest::isolate());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002302 Handle<String> slice(HEAP->empty_string());
2303
2304 {
2305 // Generate a parent that lives in new-space.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002306 v8::HandleScope inner_scope(CcTest::isolate());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002307 const char* c = "This text is long enough to trigger sliced strings.";
2308 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002309 CHECK(s->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002310 CHECK(HEAP->InNewSpace(*s));
2311
2312 // Generate a sliced string that is based on the above parent and
2313 // lives in old-space.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002314 SimulateFullSpace(HEAP->new_space());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002315 AlwaysAllocateScope always_allocate;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002316 Handle<String> t = FACTORY->NewProperSubString(s, 5, 35);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002317 CHECK(t->IsSlicedString());
2318 CHECK(!HEAP->InNewSpace(*t));
2319 *slice.location() = *t.location();
2320 }
2321
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002322 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002323 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002324 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002325}
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00002326
2327
2328#ifdef OBJECT_PRINT
2329TEST(PrintSharedFunctionInfo) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002330 CcTest::InitializeVM();
2331 v8::HandleScope scope(CcTest::isolate());
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00002332 const char* source = "f = function() { return 987654321; }\n"
2333 "g = function() { return 123456789; }\n";
2334 CompileRun(source);
2335 Handle<JSFunction> g =
2336 v8::Utils::OpenHandle(
2337 *v8::Handle<v8::Function>::Cast(
2338 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2339
2340 AssertNoAllocation no_alloc;
2341 g->shared()->PrintLn();
2342}
2343#endif // OBJECT_PRINT
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002344
2345
2346TEST(Regress2211) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002347 CcTest::InitializeVM();
2348 v8::HandleScope scope(CcTest::isolate());
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002349
2350 v8::Handle<v8::String> value = v8_str("val string");
2351 Smi* hash = Smi::FromInt(321);
2352 Heap* heap = Isolate::Current()->heap();
2353
2354 for (int i = 0; i < 2; i++) {
2355 // Store identity hash first and common hidden property second.
2356 v8::Handle<v8::Object> obj = v8::Object::New();
2357 Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
2358 CHECK(internal_obj->HasFastProperties());
2359
2360 // In the first iteration, set hidden value first and identity hash second.
2361 // In the second iteration, reverse the order.
2362 if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
2363 MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
2364 ALLOW_CREATION);
2365 CHECK(!maybe_obj->IsFailure());
2366 if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
2367
2368 // Check values.
2369 CHECK_EQ(hash,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002370 internal_obj->GetHiddenProperty(heap->identity_hash_string()));
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002371 CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
2372
2373 // Check size.
2374 DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
2375 ObjectHashTable* hashtable = ObjectHashTable::cast(
2376 internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
2377 // HashTable header (5) and 4 initial entries (8).
2378 CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
2379 }
2380}
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002381
2382
2383TEST(IncrementalMarkingClearsTypeFeedbackCells) {
2384 if (i::FLAG_always_opt) return;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002385 CcTest::InitializeVM();
2386 v8::HandleScope scope(CcTest::isolate());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002387 v8::Local<v8::Value> fun1, fun2;
2388
2389 {
2390 LocalContext env;
2391 CompileRun("function fun() {};");
2392 fun1 = env->Global()->Get(v8_str("fun"));
2393 }
2394
2395 {
2396 LocalContext env;
2397 CompileRun("function fun() {};");
2398 fun2 = env->Global()->Get(v8_str("fun"));
2399 }
2400
2401 // Prepare function f that contains type feedback for closures
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002402 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002403 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1);
2404 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2);
2405 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
2406 Handle<JSFunction> f =
2407 v8::Utils::OpenHandle(
2408 *v8::Handle<v8::Function>::Cast(
2409 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2410 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast(
2411 f->shared()->code()->type_feedback_info())->type_feedback_cells());
2412
2413 CHECK_EQ(2, cells->CellCount());
2414 CHECK(cells->Cell(0)->value()->IsJSFunction());
2415 CHECK(cells->Cell(1)->value()->IsJSFunction());
2416
2417 SimulateIncrementalMarking();
2418 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2419
2420 CHECK_EQ(2, cells->CellCount());
2421 CHECK(cells->Cell(0)->value()->IsTheHole());
2422 CHECK(cells->Cell(1)->value()->IsTheHole());
2423}
2424
2425
2426static Code* FindFirstIC(Code* code, Code::Kind kind) {
2427 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
2428 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
2429 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
2430 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
2431 for (RelocIterator it(code, mask); !it.done(); it.next()) {
2432 RelocInfo* info = it.rinfo();
2433 Code* target = Code::GetCodeFromTargetAddress(info->target_address());
2434 if (target->is_inline_cache_stub() && target->kind() == kind) {
2435 return target;
2436 }
2437 }
2438 return NULL;
2439}
2440
2441
2442TEST(IncrementalMarkingPreservesMonomorhpicIC) {
2443 if (i::FLAG_always_opt) return;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002444 CcTest::InitializeVM();
2445 v8::HandleScope scope(CcTest::isolate());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002446
2447 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002448 // originating from the same native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002449 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
2450 "function f(o) { return o.x; } f(obj); f(obj);");
2451 Handle<JSFunction> f =
2452 v8::Utils::OpenHandle(
2453 *v8::Handle<v8::Function>::Cast(
2454 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2455
2456 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2457 CHECK(ic_before->ic_state() == MONOMORPHIC);
2458
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002459 SimulateIncrementalMarking();
2460 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2461
2462 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2463 CHECK(ic_after->ic_state() == MONOMORPHIC);
2464}
2465
2466
2467TEST(IncrementalMarkingClearsMonomorhpicIC) {
2468 if (i::FLAG_always_opt) return;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002469 CcTest::InitializeVM();
2470 v8::HandleScope scope(CcTest::isolate());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002471 v8::Local<v8::Value> obj1;
2472
2473 {
2474 LocalContext env;
2475 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2476 obj1 = env->Global()->Get(v8_str("obj"));
2477 }
2478
2479 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002480 // originating from a different native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002481 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2482 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
2483 Handle<JSFunction> f =
2484 v8::Utils::OpenHandle(
2485 *v8::Handle<v8::Function>::Cast(
2486 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2487
2488 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2489 CHECK(ic_before->ic_state() == MONOMORPHIC);
2490
2491 // Fire context dispose notification.
2492 v8::V8::ContextDisposedNotification();
2493 SimulateIncrementalMarking();
2494 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2495
2496 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2497 CHECK(ic_after->ic_state() == UNINITIALIZED);
2498}
2499
2500
2501TEST(IncrementalMarkingClearsPolymorhpicIC) {
2502 if (i::FLAG_always_opt) return;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002503 CcTest::InitializeVM();
2504 v8::HandleScope scope(CcTest::isolate());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002505 v8::Local<v8::Value> obj1, obj2;
2506
2507 {
2508 LocalContext env;
2509 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2510 obj1 = env->Global()->Get(v8_str("obj"));
2511 }
2512
2513 {
2514 LocalContext env;
2515 CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
2516 obj2 = env->Global()->Get(v8_str("obj"));
2517 }
2518
2519 // Prepare function f that contains a polymorphic IC for objects
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002520 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002521 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2522 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2);
2523 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
2524 Handle<JSFunction> f =
2525 v8::Utils::OpenHandle(
2526 *v8::Handle<v8::Function>::Cast(
2527 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2528
2529 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002530 CHECK(ic_before->ic_state() == POLYMORPHIC);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002531
2532 // Fire context dispose notification.
2533 v8::V8::ContextDisposedNotification();
2534 SimulateIncrementalMarking();
2535 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2536
2537 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2538 CHECK(ic_after->ic_state() == UNINITIALIZED);
2539}
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002540
2541
2542class SourceResource: public v8::String::ExternalAsciiStringResource {
2543 public:
2544 explicit SourceResource(const char* data)
2545 : data_(data), length_(strlen(data)) { }
2546
2547 virtual void Dispose() {
2548 i::DeleteArray(data_);
2549 data_ = NULL;
2550 }
2551
2552 const char* data() const { return data_; }
2553
2554 size_t length() const { return length_; }
2555
2556 bool IsDisposed() { return data_ == NULL; }
2557
2558 private:
2559 const char* data_;
2560 size_t length_;
2561};
2562
2563
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002564void ReleaseStackTraceDataTest(const char* source) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002565 // Test that the data retained by the Error.stack accessor is released
2566 // after the first time the accessor is fired. We use external string
2567 // to check whether the data is being released since the external string
2568 // resource's callback is fired when the external string is GC'ed.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002569 CcTest::InitializeVM();
2570 v8::HandleScope scope(CcTest::isolate());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002571 SourceResource* resource = new SourceResource(i::StrDup(source));
2572 {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002573 v8::HandleScope scope(CcTest::isolate());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002574 v8::Handle<v8::String> source_string = v8::String::NewExternal(resource);
2575 v8::Script::Compile(source_string)->Run();
2576 CHECK(!resource->IsDisposed());
2577 }
2578 HEAP->CollectAllAvailableGarbage();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002579
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002580 // External source has been released.
2581 CHECK(resource->IsDisposed());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002582 delete resource;
2583}
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002584
2585
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002586TEST(ReleaseStackTraceData) {
2587 static const char* source1 = "var error = null; "
2588 /* Normal Error */ "try { "
2589 " throw new Error(); "
2590 "} catch (e) { "
2591 " error = e; "
2592 "} ";
2593 static const char* source2 = "var error = null; "
2594 /* Stack overflow */ "try { "
2595 " (function f() { f(); })(); "
2596 "} catch (e) { "
2597 " error = e; "
2598 "} ";
2599 ReleaseStackTraceDataTest(source1);
2600 ReleaseStackTraceDataTest(source2);
2601}
2602
2603
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002604TEST(Regression144230) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002605 CcTest::InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002606 Isolate* isolate = Isolate::Current();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002607 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002608 HandleScope scope(isolate);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002609
2610 // First make sure that the uninitialized CallIC stub is on a single page
2611 // that will later be selected as an evacuation candidate.
2612 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002613 HandleScope inner_scope(isolate);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002614 AlwaysAllocateScope always_allocate;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002615 SimulateFullSpace(heap->code_space());
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002616 isolate->stub_cache()->ComputeCallInitialize(9, RelocInfo::CODE_TARGET);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002617 }
2618
2619 // Second compile a CallIC and execute it once so that it gets patched to
2620 // the pre-monomorphic stub. These code objects are on yet another page.
2621 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002622 HandleScope inner_scope(isolate);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002623 AlwaysAllocateScope always_allocate;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002624 SimulateFullSpace(heap->code_space());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002625 CompileRun("var o = { f:function(a,b,c,d,e,f,g,h,i) {}};"
2626 "function call() { o.f(1,2,3,4,5,6,7,8,9); };"
2627 "call();");
2628 }
2629
2630 // Third we fill up the last page of the code space so that it does not get
2631 // chosen as an evacuation candidate.
2632 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002633 HandleScope inner_scope(isolate);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002634 AlwaysAllocateScope always_allocate;
2635 CompileRun("for (var i = 0; i < 2000; i++) {"
2636 " eval('function f' + i + '() { return ' + i +'; };' +"
2637 " 'f' + i + '();');"
2638 "}");
2639 }
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002640 heap->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002641
2642 // Fourth is the tricky part. Make sure the code containing the CallIC is
2643 // visited first without clearing the IC. The shared function info is then
2644 // visited later, causing the CallIC to be cleared.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002645 Handle<String> name = isolate->factory()->InternalizeUtf8String("call");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002646 Handle<GlobalObject> global(isolate->context()->global_object());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002647 MaybeObject* maybe_call = global->GetProperty(*name);
2648 JSFunction* call = JSFunction::cast(maybe_call->ToObjectChecked());
2649 USE(global->SetProperty(*name, Smi::FromInt(0), NONE, kNonStrictMode));
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002650 isolate->compilation_cache()->Clear();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002651 call->shared()->set_ic_age(heap->global_ic_age() + 1);
2652 Handle<Object> call_code(call->code(), isolate);
2653 Handle<Object> call_function(call, isolate);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002654
2655 // Now we are ready to mess up the heap.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002656 heap->CollectAllGarbage(Heap::kReduceMemoryFootprintMask);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002657
2658 // Either heap verification caught the problem already or we go kaboom once
2659 // the CallIC is executed the next time.
2660 USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode));
2661 CompileRun("call();");
2662}
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002663
2664
2665TEST(Regress159140) {
2666 i::FLAG_allow_natives_syntax = true;
2667 i::FLAG_flush_code_incrementally = true;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002668 CcTest::InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002669 Isolate* isolate = Isolate::Current();
2670 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002671 HandleScope scope(isolate);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002672
2673 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002674 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002675
2676 // Prepare several closures that are all eligible for code flushing
2677 // because all reachable ones are not optimized. Make sure that the
2678 // optimized code object is directly reachable through a handle so
2679 // that it is marked black during incremental marking.
2680 Handle<Code> code;
2681 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002682 HandleScope inner_scope(isolate);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002683 CompileRun("function h(x) {}"
2684 "function mkClosure() {"
2685 " return function(x) { return x + 1; };"
2686 "}"
2687 "var f = mkClosure();"
2688 "var g = mkClosure();"
2689 "f(1); f(2);"
2690 "g(1); g(2);"
2691 "h(1); h(2);"
2692 "%OptimizeFunctionOnNextCall(f); f(3);"
2693 "%OptimizeFunctionOnNextCall(h); h(3);");
2694
2695 Handle<JSFunction> f =
2696 v8::Utils::OpenHandle(
2697 *v8::Handle<v8::Function>::Cast(
2698 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2699 CHECK(f->is_compiled());
2700 CompileRun("f = null;");
2701
2702 Handle<JSFunction> g =
2703 v8::Utils::OpenHandle(
2704 *v8::Handle<v8::Function>::Cast(
2705 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2706 CHECK(g->is_compiled());
2707 const int kAgingThreshold = 6;
2708 for (int i = 0; i < kAgingThreshold; i++) {
2709 g->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2710 }
2711
2712 code = inner_scope.CloseAndEscape(Handle<Code>(f->code()));
2713 }
2714
2715 // Simulate incremental marking so that the functions are enqueued as
2716 // code flushing candidates. Then optimize one function. Finally
2717 // finish the GC to complete code flushing.
2718 SimulateIncrementalMarking();
2719 CompileRun("%OptimizeFunctionOnNextCall(g); g(3);");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002720 heap->CollectAllGarbage(Heap::kNoGCFlags);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002721
2722 // Unoptimized code is missing and the deoptimizer will go ballistic.
2723 CompileRun("g('bozo');");
2724}
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002725
2726
2727TEST(Regress165495) {
2728 i::FLAG_allow_natives_syntax = true;
2729 i::FLAG_flush_code_incrementally = true;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002730 CcTest::InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002731 Isolate* isolate = Isolate::Current();
2732 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002733 HandleScope scope(isolate);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002734
2735 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002736 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002737
2738 // Prepare an optimized closure that the optimized code map will get
2739 // populated. Then age the unoptimized code to trigger code flushing
2740 // but make sure the optimized code is unreachable.
2741 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002742 HandleScope inner_scope(isolate);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002743 CompileRun("function mkClosure() {"
2744 " return function(x) { return x + 1; };"
2745 "}"
2746 "var f = mkClosure();"
2747 "f(1); f(2);"
2748 "%OptimizeFunctionOnNextCall(f); f(3);");
2749
2750 Handle<JSFunction> f =
2751 v8::Utils::OpenHandle(
2752 *v8::Handle<v8::Function>::Cast(
2753 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2754 CHECK(f->is_compiled());
2755 const int kAgingThreshold = 6;
2756 for (int i = 0; i < kAgingThreshold; i++) {
2757 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2758 }
2759
2760 CompileRun("f = null;");
2761 }
2762
2763 // Simulate incremental marking so that unoptimized code is flushed
2764 // even though it still is cached in the optimized code map.
2765 SimulateIncrementalMarking();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002766 heap->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002767
2768 // Make a new closure that will get code installed from the code map.
2769 // Unoptimized code is missing and the deoptimizer will go ballistic.
2770 CompileRun("var g = mkClosure(); g('bozo');");
2771}
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002772
2773
2774TEST(Regress169209) {
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002775 i::FLAG_stress_compaction = false;
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002776 i::FLAG_allow_natives_syntax = true;
2777 i::FLAG_flush_code_incrementally = true;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002778 CcTest::InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002779 Isolate* isolate = Isolate::Current();
2780 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002781 HandleScope scope(isolate);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002782
2783 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002784 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002785
2786 // Prepare a shared function info eligible for code flushing for which
2787 // the unoptimized code will be replaced during optimization.
2788 Handle<SharedFunctionInfo> shared1;
2789 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002790 HandleScope inner_scope(isolate);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002791 CompileRun("function f() { return 'foobar'; }"
2792 "function g(x) { if (x) f(); }"
2793 "f();"
2794 "g(false);"
2795 "g(false);");
2796
2797 Handle<JSFunction> f =
2798 v8::Utils::OpenHandle(
2799 *v8::Handle<v8::Function>::Cast(
2800 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2801 CHECK(f->is_compiled());
2802 const int kAgingThreshold = 6;
2803 for (int i = 0; i < kAgingThreshold; i++) {
2804 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2805 }
2806
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002807 shared1 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002808 }
2809
2810 // Prepare a shared function info eligible for code flushing that will
2811 // represent the dangling tail of the candidate list.
2812 Handle<SharedFunctionInfo> shared2;
2813 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002814 HandleScope inner_scope(isolate);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002815 CompileRun("function flushMe() { return 0; }"
2816 "flushMe(1);");
2817
2818 Handle<JSFunction> f =
2819 v8::Utils::OpenHandle(
2820 *v8::Handle<v8::Function>::Cast(
2821 v8::Context::GetCurrent()->Global()->Get(v8_str("flushMe"))));
2822 CHECK(f->is_compiled());
2823 const int kAgingThreshold = 6;
2824 for (int i = 0; i < kAgingThreshold; i++) {
2825 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2826 }
2827
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002828 shared2 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002829 }
2830
2831 // Simulate incremental marking and collect code flushing candidates.
2832 SimulateIncrementalMarking();
2833 CHECK(shared1->code()->gc_metadata() != NULL);
2834
2835 // Optimize function and make sure the unoptimized code is replaced.
2836#ifdef DEBUG
2837 FLAG_stop_at = "f";
2838#endif
2839 CompileRun("%OptimizeFunctionOnNextCall(g);"
2840 "g(false);");
2841
2842 // Finish garbage collection cycle.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002843 heap->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002844 CHECK(shared1->code()->gc_metadata() == NULL);
2845}
yangguo@chromium.org28381b42013-01-21 14:39:38 +00002846
2847
2848// Helper function that simulates a fill new-space in the heap.
2849static inline void AllocateAllButNBytes(v8::internal::NewSpace* space,
2850 int extra_bytes) {
2851 int space_remaining = static_cast<int>(
2852 *space->allocation_limit_address() - *space->allocation_top_address());
2853 CHECK(space_remaining >= extra_bytes);
2854 int new_linear_size = space_remaining - extra_bytes;
2855 v8::internal::MaybeObject* maybe = space->AllocateRaw(new_linear_size);
2856 v8::internal::FreeListNode* node = v8::internal::FreeListNode::cast(maybe);
2857 node->set_size(space->heap(), new_linear_size);
2858}
2859
2860
2861TEST(Regress169928) {
2862 i::FLAG_allow_natives_syntax = true;
2863 i::FLAG_crankshaft = false;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002864 CcTest::InitializeVM();
2865 v8::HandleScope scope(CcTest::isolate());
yangguo@chromium.org28381b42013-01-21 14:39:38 +00002866
2867 // Some flags turn Scavenge collections into Mark-sweep collections
2868 // and hence are incompatible with this test case.
2869 if (FLAG_gc_global || FLAG_stress_compaction) return;
2870
2871 // Prepare the environment
2872 CompileRun("function fastliteralcase(literal, value) {"
2873 " literal[0] = value;"
2874 " return literal;"
2875 "}"
2876 "function get_standard_literal() {"
2877 " var literal = [1, 2, 3];"
2878 " return literal;"
2879 "}"
2880 "obj = fastliteralcase(get_standard_literal(), 1);"
2881 "obj = fastliteralcase(get_standard_literal(), 1.5);"
2882 "obj = fastliteralcase(get_standard_literal(), 2);");
2883
2884 // prepare the heap
2885 v8::Local<v8::String> mote_code_string =
2886 v8_str("fastliteralcase(mote, 2.5);");
2887
2888 v8::Local<v8::String> array_name = v8_str("mote");
2889 v8::Context::GetCurrent()->Global()->Set(array_name, v8::Int32::New(0));
2890
2891 // First make sure we flip spaces
2892 HEAP->CollectGarbage(NEW_SPACE);
2893
2894 // Allocate the object.
2895 Handle<FixedArray> array_data = FACTORY->NewFixedArray(2, NOT_TENURED);
2896 array_data->set(0, Smi::FromInt(1));
2897 array_data->set(1, Smi::FromInt(2));
2898
2899 AllocateAllButNBytes(HEAP->new_space(),
2900 JSArray::kSize + AllocationSiteInfo::kSize +
2901 kPointerSize);
2902
2903 Handle<JSArray> array = FACTORY->NewJSArrayWithElements(array_data,
2904 FAST_SMI_ELEMENTS,
2905 NOT_TENURED);
2906
2907 CHECK_EQ(Smi::FromInt(2), array->length());
2908 CHECK(array->HasFastSmiOrObjectElements());
2909
2910 // We need filler the size of AllocationSiteInfo object, plus an extra
2911 // fill pointer value.
2912 MaybeObject* maybe_object = HEAP->AllocateRaw(
2913 AllocationSiteInfo::kSize + kPointerSize, NEW_SPACE, OLD_POINTER_SPACE);
2914 Object* obj = NULL;
2915 CHECK(maybe_object->ToObject(&obj));
2916 Address addr_obj = reinterpret_cast<Address>(
2917 reinterpret_cast<byte*>(obj - kHeapObjectTag));
2918 HEAP->CreateFillerObjectAt(addr_obj,
2919 AllocationSiteInfo::kSize + kPointerSize);
2920
2921 // Give the array a name, making sure not to allocate strings.
2922 v8::Handle<v8::Object> array_obj = v8::Utils::ToLocal(array);
2923 v8::Context::GetCurrent()->Global()->Set(array_name, array_obj);
2924
2925 // This should crash with a protection violation if we are running a build
2926 // with the bug.
2927 AlwaysAllocateScope aa_scope;
2928 v8::Script::Compile(mote_code_string)->Run();
2929}
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002930
2931
2932TEST(Regress168801) {
2933 i::FLAG_always_compact = true;
2934 i::FLAG_cache_optimized_code = false;
2935 i::FLAG_allow_natives_syntax = true;
2936 i::FLAG_flush_code_incrementally = true;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002937 CcTest::InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002938 Isolate* isolate = Isolate::Current();
2939 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002940 HandleScope scope(isolate);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002941
2942 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002943 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002944
2945 // Ensure the code ends up on an evacuation candidate.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002946 SimulateFullSpace(heap->code_space());
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002947
2948 // Prepare an unoptimized function that is eligible for code flushing.
2949 Handle<JSFunction> function;
2950 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002951 HandleScope inner_scope(isolate);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002952 CompileRun("function mkClosure() {"
2953 " return function(x) { return x + 1; };"
2954 "}"
2955 "var f = mkClosure();"
2956 "f(1); f(2);");
2957
2958 Handle<JSFunction> f =
2959 v8::Utils::OpenHandle(
2960 *v8::Handle<v8::Function>::Cast(
2961 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2962 CHECK(f->is_compiled());
2963 const int kAgingThreshold = 6;
2964 for (int i = 0; i < kAgingThreshold; i++) {
2965 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2966 }
2967
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002968 function = inner_scope.CloseAndEscape(handle(*f, isolate));
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002969 }
2970
2971 // Simulate incremental marking so that unoptimized function is enqueued as a
2972 // candidate for code flushing. The shared function info however will not be
2973 // explicitly enqueued.
2974 SimulateIncrementalMarking();
2975
2976 // Now optimize the function so that it is taken off the candidate list.
2977 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002978 HandleScope inner_scope(isolate);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002979 CompileRun("%OptimizeFunctionOnNextCall(f); f(3);");
2980 }
2981
2982 // This cycle will bust the heap and subsequent cycles will go ballistic.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002983 heap->CollectAllGarbage(Heap::kNoGCFlags);
2984 heap->CollectAllGarbage(Heap::kNoGCFlags);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002985}
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002986
2987
2988TEST(Regress173458) {
2989 i::FLAG_always_compact = true;
2990 i::FLAG_cache_optimized_code = false;
2991 i::FLAG_allow_natives_syntax = true;
2992 i::FLAG_flush_code_incrementally = true;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002993 CcTest::InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002994 Isolate* isolate = Isolate::Current();
2995 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002996 HandleScope scope(isolate);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002997
2998 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002999 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003000
3001 // Ensure the code ends up on an evacuation candidate.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00003002 SimulateFullSpace(heap->code_space());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003003
3004 // Prepare an unoptimized function that is eligible for code flushing.
3005 Handle<JSFunction> function;
3006 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00003007 HandleScope inner_scope(isolate);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003008 CompileRun("function mkClosure() {"
3009 " return function(x) { return x + 1; };"
3010 "}"
3011 "var f = mkClosure();"
3012 "f(1); f(2);");
3013
3014 Handle<JSFunction> f =
3015 v8::Utils::OpenHandle(
3016 *v8::Handle<v8::Function>::Cast(
3017 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
3018 CHECK(f->is_compiled());
3019 const int kAgingThreshold = 6;
3020 for (int i = 0; i < kAgingThreshold; i++) {
3021 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
3022 }
3023
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00003024 function = inner_scope.CloseAndEscape(handle(*f, isolate));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003025 }
3026
3027 // Simulate incremental marking so that unoptimized function is enqueued as a
3028 // candidate for code flushing. The shared function info however will not be
3029 // explicitly enqueued.
3030 SimulateIncrementalMarking();
3031
danno@chromium.orgc99cd482013-03-21 15:26:42 +00003032#ifdef ENABLE_DEBUGGER_SUPPORT
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003033 // Now enable the debugger which in turn will disable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00003034 CHECK(isolate->debug()->Load());
danno@chromium.orgc99cd482013-03-21 15:26:42 +00003035#endif // ENABLE_DEBUGGER_SUPPORT
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003036
3037 // This cycle will bust the heap and subsequent cycles will go ballistic.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00003038 heap->CollectAllGarbage(Heap::kNoGCFlags);
3039 heap->CollectAllGarbage(Heap::kNoGCFlags);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003040}
svenpanne@chromium.org876cca82013-03-18 14:43:20 +00003041
3042
3043class DummyVisitor : public ObjectVisitor {
3044 public:
3045 void VisitPointers(Object** start, Object** end) { }
3046};
3047
3048
3049TEST(DeferredHandles) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003050 CcTest::InitializeVM();
svenpanne@chromium.org876cca82013-03-18 14:43:20 +00003051 Isolate* isolate = Isolate::Current();
3052 Heap* heap = isolate->heap();
3053 v8::HandleScope scope;
3054 v8::ImplementationUtilities::HandleScopeData* data =
3055 isolate->handle_scope_data();
3056 Handle<Object> init(heap->empty_string(), isolate);
3057 while (data->next < data->limit) {
3058 Handle<Object> obj(heap->empty_string(), isolate);
3059 }
3060 // An entire block of handles has been filled.
3061 // Next handle would require a new block.
3062 ASSERT(data->next == data->limit);
3063
3064 DeferredHandleScope deferred(isolate);
3065 DummyVisitor visitor;
3066 isolate->handle_scope_implementer()->Iterate(&visitor);
3067 deferred.Detach();
3068}