blob: a710385bfa73851e3c6f7d74bbe56bf0987e6c48 [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
42static v8::Persistent<v8::Context> env;
43
44static void InitializeVM() {
45 if (env.IsEmpty()) env = v8::Context::New();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000046 env->Enter();
47}
48
49
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000050// Go through all incremental marking steps in one swoop.
51static void SimulateIncrementalMarking() {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000052 MarkCompactCollector* collector = HEAP->mark_compact_collector();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000053 IncrementalMarking* marking = HEAP->incremental_marking();
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000054 if (collector->IsConcurrentSweepingInProgress()) {
55 collector->WaitUntilSweepingCompleted();
56 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000057 CHECK(marking->IsMarking() || marking->IsStopped());
58 if (marking->IsStopped()) {
59 marking->Start();
60 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000061 CHECK(marking->IsMarking());
62 while (!marking->IsComplete()) {
63 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
64 }
65 CHECK(marking->IsComplete());
66}
67
68
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000069static void CheckMap(Map* map, int type, int instance_size) {
70 CHECK(map->IsHeapObject());
71#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000072 CHECK(HEAP->Contains(map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000073#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000074 CHECK_EQ(HEAP->meta_map(), map->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000075 CHECK_EQ(type, map->instance_type());
76 CHECK_EQ(instance_size, map->instance_size());
77}
78
79
80TEST(HeapMaps) {
81 InitializeVM();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000082 CheckMap(HEAP->meta_map(), MAP_TYPE, Map::kSize);
83 CheckMap(HEAP->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
84 CheckMap(HEAP->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
85 CheckMap(HEAP->string_map(), STRING_TYPE, kVariableSizeSentinel);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000086}
87
88
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000089static void CheckOddball(Isolate* isolate, Object* obj, const char* string) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000090 CHECK(obj->IsOddball());
91 bool exc;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000092 Object* print_string =
93 *Execution::ToString(Handle<Object>(obj, isolate), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000094 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000095}
96
97
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000098static void CheckSmi(Isolate* isolate, int value, const char* string) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000099 bool exc;
100 Object* print_string =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000101 *Execution::ToString(Handle<Object>(Smi::FromInt(value), isolate), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000102 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000103}
104
105
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000106static void CheckNumber(Isolate* isolate, double value, const char* string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000107 Object* obj = HEAP->NumberFromDouble(value)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000108 CHECK(obj->IsNumber());
109 bool exc;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000110 Object* print_string =
111 *Execution::ToString(Handle<Object>(obj, isolate), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000112 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000113}
114
115
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000116static void CheckFindCodeObject(Isolate* isolate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000117 // Test FindCodeObject
118#define __ assm.
119
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000120 Assembler assm(isolate, NULL, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000121
122 __ nop(); // supported on all architectures
123
124 CodeDesc desc;
125 assm.GetCode(&desc);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000126 Heap* heap = isolate->heap();
127 Object* code = heap->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000128 desc,
129 Code::ComputeFlags(Code::STUB),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000130 Handle<Code>())->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000131 CHECK(code->IsCode());
132
133 HeapObject* obj = HeapObject::cast(code);
134 Address obj_addr = obj->address();
135
136 for (int i = 0; i < obj->Size(); i += kPointerSize) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000137 Object* found = heap->FindCodeObject(obj_addr + i);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000138 CHECK_EQ(code, found);
139 }
140
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000141 Object* copy = heap->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000142 desc,
143 Code::ComputeFlags(Code::STUB),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000144 Handle<Code>())->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000145 CHECK(copy->IsCode());
146 HeapObject* obj_copy = HeapObject::cast(copy);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000147 Object* not_right = heap->FindCodeObject(obj_copy->address() +
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000148 obj_copy->Size() / 2);
149 CHECK(not_right != code);
150}
151
152
153TEST(HeapObjects) {
154 InitializeVM();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000155 Isolate* isolate = Isolate::Current();
156 Heap* heap = isolate->heap();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000157
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000158 HandleScope sc(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000159 Object* value = heap->NumberFromDouble(1.000123)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000160 CHECK(value->IsHeapNumber());
161 CHECK(value->IsNumber());
162 CHECK_EQ(1.000123, value->Number());
163
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000164 value = heap->NumberFromDouble(1.0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000165 CHECK(value->IsSmi());
166 CHECK(value->IsNumber());
167 CHECK_EQ(1.0, value->Number());
168
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000169 value = heap->NumberFromInt32(1024)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000170 CHECK(value->IsSmi());
171 CHECK(value->IsNumber());
172 CHECK_EQ(1024.0, value->Number());
173
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000174 value = heap->NumberFromInt32(Smi::kMinValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000175 CHECK(value->IsSmi());
176 CHECK(value->IsNumber());
177 CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
178
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000179 value = heap->NumberFromInt32(Smi::kMaxValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000180 CHECK(value->IsSmi());
181 CHECK(value->IsNumber());
182 CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value());
183
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000184#ifndef V8_TARGET_ARCH_X64
185 // TODO(lrn): We need a NumberFromIntptr function in order to test this.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000186 value = heap->NumberFromInt32(Smi::kMinValue - 1)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000187 CHECK(value->IsHeapNumber());
188 CHECK(value->IsNumber());
189 CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000190#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000191
lrn@chromium.org303ada72010-10-27 09:33:13 +0000192 MaybeObject* maybe_value =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000193 heap->NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000194 value = maybe_value->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000195 CHECK(value->IsHeapNumber());
196 CHECK(value->IsNumber());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000197 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
198 value->Number());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000199
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000200 maybe_value = heap->NumberFromUint32(static_cast<uint32_t>(1) << 31);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000201 value = maybe_value->ToObjectChecked();
202 CHECK(value->IsHeapNumber());
203 CHECK(value->IsNumber());
204 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(1) << 31),
205 value->Number());
206
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000207 // nan oddball checks
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000208 CHECK(heap->nan_value()->IsNumber());
209 CHECK(isnan(heap->nan_value()->Number()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000210
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000211 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest "));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000212 CHECK(s->IsString());
213 CHECK_EQ(10, s->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000214
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000215 String* object_string = String::cast(heap->Object_string());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000216 CHECK(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000217 Isolate::Current()->context()->global_object()->HasLocalProperty(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000218 object_string));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000219
220 // Check ToString for oddballs
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000221 CheckOddball(isolate, heap->true_value(), "true");
222 CheckOddball(isolate, heap->false_value(), "false");
223 CheckOddball(isolate, heap->null_value(), "null");
224 CheckOddball(isolate, heap->undefined_value(), "undefined");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000225
226 // Check ToString for Smis
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000227 CheckSmi(isolate, 0, "0");
228 CheckSmi(isolate, 42, "42");
229 CheckSmi(isolate, -42, "-42");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000230
231 // Check ToString for Numbers
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000232 CheckNumber(isolate, 1.1, "1.1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000233
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000234 CheckFindCodeObject(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000235}
236
237
238TEST(Tagging) {
239 InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000240 int request = 24;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000241 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000242 CHECK(Smi::FromInt(42)->IsSmi());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000243 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000244 CHECK_EQ(NEW_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000245 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000246 CHECK_EQ(OLD_POINTER_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000247 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000248 CHECK(Failure::Exception()->IsFailure());
249 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
250 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
251}
252
253
254TEST(GarbageCollection) {
255 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000256 Isolate* isolate = Isolate::Current();
257 Heap* heap = isolate->heap();
258 Factory* factory = isolate->factory();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000259
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000260 HandleScope sc(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000261 // Check GC.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000262 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000263
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000264 Handle<String> name = factory->InternalizeUtf8String("theFunction");
265 Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
266 Handle<String> prop_namex = factory->InternalizeUtf8String("theSlotx");
267 Handle<String> obj_name = factory->InternalizeUtf8String("theObject");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000268
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000269 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000270 HandleScope inner_scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000271 // Allocate a function and keep it in global object's property.
272 Handle<JSFunction> function =
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000273 factory->NewFunction(name, factory->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000274 Handle<Map> initial_map =
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000275 factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000276 function->set_initial_map(*initial_map);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000277 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000278 *name, *function, NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000279 // Allocate an object. Unrooted after leaving the scope.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000280 Handle<JSObject> obj = factory->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000281 obj->SetProperty(
282 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
283 obj->SetProperty(
284 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000285
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000286 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
287 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
288 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000289
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000290 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000291
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000292 // Function should be alive.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000293 CHECK(Isolate::Current()->context()->global_object()->
294 HasLocalProperty(*name));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000295 // Check function is retained.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000296 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000297 GetProperty(*name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000298 CHECK(func_value->IsJSFunction());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000299 Handle<JSFunction> function(JSFunction::cast(func_value));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000300
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000301 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000302 HandleScope inner_scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000303 // Allocate another object, make it reachable from global.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000304 Handle<JSObject> obj = factory->NewJSObject(function);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000305 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000306 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked();
307 obj->SetProperty(
308 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000309 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000310
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000311 // After gc, it should survive.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000312 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000313
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000314 CHECK(Isolate::Current()->context()->global_object()->
315 HasLocalProperty(*obj_name));
316 CHECK(Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000317 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000318 Object* obj = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000319 GetProperty(*obj_name)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000320 JSObject* js_obj = JSObject::cast(obj);
321 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000322}
323
324
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000325static void VerifyStringAllocation(Isolate* isolate, const char* string) {
326 HandleScope scope(isolate);
327 Handle<String> s = isolate->factory()->NewStringFromUtf8(CStrVector(string));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000328 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000329 for (int index = 0; index < s->length(); index++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000330 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
331 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000332}
333
334
335TEST(String) {
336 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000337 Isolate* isolate = reinterpret_cast<Isolate*>(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000338
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000339 VerifyStringAllocation(isolate, "a");
340 VerifyStringAllocation(isolate, "ab");
341 VerifyStringAllocation(isolate, "abc");
342 VerifyStringAllocation(isolate, "abcd");
343 VerifyStringAllocation(isolate, "fiskerdrengen er paa havet");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000344}
345
346
347TEST(LocalHandles) {
348 InitializeVM();
349
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000350 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000351 const char* name = "Kasper the spunky";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000352 Handle<String> string = FACTORY->NewStringFromAscii(CStrVector(name));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000353 CHECK_EQ(StrLength(name), string->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000354}
355
356
357TEST(GlobalHandles) {
358 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000359 Isolate* isolate = Isolate::Current();
360 Heap* heap = isolate->heap();
361 Factory* factory = isolate->factory();
362 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000363
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000364 Handle<Object> h1;
365 Handle<Object> h2;
366 Handle<Object> h3;
367 Handle<Object> h4;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000368
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000369 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000370 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000371
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000372 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
373 Handle<Object> u = factory->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000374
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000375 h1 = global_handles->Create(*i);
376 h2 = global_handles->Create(*u);
377 h3 = global_handles->Create(*i);
378 h4 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000379 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000380
381 // after gc, it should survive
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000382 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000383
384 CHECK((*h1)->IsString());
385 CHECK((*h2)->IsHeapNumber());
386 CHECK((*h3)->IsString());
387 CHECK((*h4)->IsHeapNumber());
388
389 CHECK_EQ(*h3, *h1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000390 global_handles->Destroy(h1.location());
391 global_handles->Destroy(h3.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000392
393 CHECK_EQ(*h4, *h2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000394 global_handles->Destroy(h2.location());
395 global_handles->Destroy(h4.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000396}
397
398
399static bool WeakPointerCleared = false;
400
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000401static void TestWeakGlobalHandleCallback(v8::Isolate* isolate,
402 v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000403 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000404 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000405 handle.Dispose(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000406}
407
408
409TEST(WeakGlobalHandlesScavenge) {
410 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000411 Isolate* isolate = Isolate::Current();
412 Heap* heap = isolate->heap();
413 Factory* factory = isolate->factory();
414 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000415
416 WeakPointerCleared = false;
417
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000418 Handle<Object> h1;
419 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000420
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000421 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000422 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000423
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000424 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
425 Handle<Object> u = factory->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000427 h1 = global_handles->Create(*i);
428 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000429 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000430
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000431 global_handles->MakeWeak(h2.location(),
432 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000433 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000434 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000435
436 // Scavenge treats weak pointers as normal roots.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000437 heap->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000438
439 CHECK((*h1)->IsString());
440 CHECK((*h2)->IsHeapNumber());
441
442 CHECK(!WeakPointerCleared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000443 CHECK(!global_handles->IsNearDeath(h2.location()));
444 CHECK(!global_handles->IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000445
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000446 global_handles->Destroy(h1.location());
447 global_handles->Destroy(h2.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000448}
449
450
451TEST(WeakGlobalHandlesMark) {
452 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000453 Isolate* isolate = Isolate::Current();
454 Heap* heap = isolate->heap();
455 Factory* factory = isolate->factory();
456 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000457
458 WeakPointerCleared = false;
459
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000460 Handle<Object> h1;
461 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000462
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000463 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000464 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000465
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000466 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
467 Handle<Object> u = factory->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000468
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000469 h1 = global_handles->Create(*i);
470 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000471 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000472
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000473 // Make sure the objects are promoted.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000474 heap->CollectGarbage(OLD_POINTER_SPACE);
475 heap->CollectGarbage(NEW_SPACE);
476 CHECK(!heap->InNewSpace(*h1) && !heap->InNewSpace(*h2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000478 global_handles->MakeWeak(h2.location(),
479 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000480 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000481 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000482 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
483 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
484
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000485 // Incremental marking potentially marked handles before they turned weak.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000486 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000487
488 CHECK((*h1)->IsString());
489
490 CHECK(WeakPointerCleared);
491 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000492
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000493 global_handles->Destroy(h1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000494}
495
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000496
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000497TEST(DeleteWeakGlobalHandle) {
498 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000499 Isolate* isolate = Isolate::Current();
500 Heap* heap = isolate->heap();
501 Factory* factory = isolate->factory();
502 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000503
504 WeakPointerCleared = false;
505
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000506 Handle<Object> h;
507
508 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000509 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000510
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000511 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000512 h = global_handles->Create(*i);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000513 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000514
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000515 global_handles->MakeWeak(h.location(),
516 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000517 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000518 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000519
520 // Scanvenge does not recognize weak reference.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000521 heap->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000522
523 CHECK(!WeakPointerCleared);
524
525 // Mark-compact treats weak reference properly.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000526 heap->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000527
528 CHECK(WeakPointerCleared);
529}
530
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000531
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000532static const char* not_so_random_string_table[] = {
533 "abstract",
534 "boolean",
535 "break",
536 "byte",
537 "case",
538 "catch",
539 "char",
540 "class",
541 "const",
542 "continue",
543 "debugger",
544 "default",
545 "delete",
546 "do",
547 "double",
548 "else",
549 "enum",
550 "export",
551 "extends",
552 "false",
553 "final",
554 "finally",
555 "float",
556 "for",
557 "function",
558 "goto",
559 "if",
560 "implements",
561 "import",
562 "in",
563 "instanceof",
564 "int",
565 "interface",
566 "long",
567 "native",
568 "new",
569 "null",
570 "package",
571 "private",
572 "protected",
573 "public",
574 "return",
575 "short",
576 "static",
577 "super",
578 "switch",
579 "synchronized",
580 "this",
581 "throw",
582 "throws",
583 "transient",
584 "true",
585 "try",
586 "typeof",
587 "var",
588 "void",
589 "volatile",
590 "while",
591 "with",
592 0
593};
594
595
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000596static void CheckInternalizedStrings(const char** strings) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000597 for (const char* string = *strings; *strings != 0; string = *strings++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000598 Object* a;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000599 MaybeObject* maybe_a = HEAP->InternalizeUtf8String(string);
600 // InternalizeUtf8String may return a failure if a GC is needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000601 if (!maybe_a->ToObject(&a)) continue;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000602 CHECK(a->IsInternalizedString());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000603 Object* b;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000604 MaybeObject* maybe_b = HEAP->InternalizeUtf8String(string);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000605 if (!maybe_b->ToObject(&b)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000606 CHECK_EQ(b, a);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000607 CHECK(String::cast(b)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000608 }
609}
610
611
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000612TEST(StringTable) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000613 InitializeVM();
614
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000615 CheckInternalizedStrings(not_so_random_string_table);
616 CheckInternalizedStrings(not_so_random_string_table);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000617}
618
619
620TEST(FunctionAllocation) {
621 InitializeVM();
622
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000623 v8::HandleScope sc(env->GetIsolate());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000624 Handle<String> name = FACTORY->InternalizeUtf8String("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000625 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000626 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000627 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000628 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000629 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000630
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000631 Handle<String> prop_name = FACTORY->InternalizeUtf8String("theSlot");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000632 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000633 obj->SetProperty(
634 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000635 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000636 // Check that we can add properties to function objects.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000637 function->SetProperty(
638 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000639 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000640}
641
642
643TEST(ObjectProperties) {
644 InitializeVM();
645
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000646 v8::HandleScope sc(env->GetIsolate());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000647 String* object_string = String::cast(HEAP->Object_string());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000648 Object* raw_object = Isolate::Current()->context()->global_object()->
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000649 GetProperty(object_string)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000650 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000651 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000652 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000653 Handle<String> first = FACTORY->InternalizeUtf8String("first");
654 Handle<String> second = FACTORY->InternalizeUtf8String("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000655
656 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000657 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000658
659 // add first
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000660 obj->SetProperty(
661 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000662 CHECK(obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000663
664 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000665 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
666 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000667
668 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000669 obj->SetProperty(
670 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
671 obj->SetProperty(
672 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000673 CHECK(obj->HasLocalProperty(*first));
674 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000675
676 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000677 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
678 CHECK(obj->HasLocalProperty(*second));
679 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
680 CHECK(!obj->HasLocalProperty(*first));
681 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000682
683 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000684 obj->SetProperty(
685 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
686 obj->SetProperty(
687 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000688 CHECK(obj->HasLocalProperty(*first));
689 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000690
691 // delete second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000692 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
693 CHECK(obj->HasLocalProperty(*first));
694 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
695 CHECK(!obj->HasLocalProperty(*first));
696 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000697
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000698 // check string and internalized string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000699 const char* string1 = "fisk";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000700 Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000701 obj->SetProperty(
702 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000703 Handle<String> s1_string = FACTORY->InternalizeUtf8String(string1);
704 CHECK(obj->HasLocalProperty(*s1_string));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000705
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000706 // check internalized string and string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000707 const char* string2 = "fugl";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000708 Handle<String> s2_string = FACTORY->InternalizeUtf8String(string2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000709 obj->SetProperty(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000710 *s2_string, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000711 Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000712 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000713}
714
715
716TEST(JSObjectMaps) {
717 InitializeVM();
718
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000719 v8::HandleScope sc(env->GetIsolate());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000720 Handle<String> name = FACTORY->InternalizeUtf8String("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000721 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000722 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000723 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000724 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000725 function->set_initial_map(*initial_map);
726
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000727 Handle<String> prop_name = FACTORY->InternalizeUtf8String("theSlot");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000728 Handle<JSObject> obj = FACTORY->NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000729
730 // Set a propery
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000731 obj->SetProperty(
732 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000733 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000734
735 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000736 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000737}
738
739
740TEST(JSArray) {
741 InitializeVM();
742
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000743 v8::HandleScope sc(env->GetIsolate());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000744 Handle<String> name = FACTORY->InternalizeUtf8String("Array");
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000745 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000746 GetProperty(*name)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000747 Handle<JSFunction> function = Handle<JSFunction>(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000748 JSFunction::cast(raw_object));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000749
750 // Allocate the object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000751 Handle<JSObject> object = FACTORY->NewJSObject(function);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000752 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000753 // We just initialized the VM, no heap allocation failure yet.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000754 array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000755
756 // Set array length to 0.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000757 array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000758 CHECK_EQ(Smi::FromInt(0), array->length());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000759 // Must be in fast mode.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000760 CHECK(array->HasFastSmiOrObjectElements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000761
762 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000763 array->SetElement(0, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000764 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000765 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000766
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000767 // Set array length with larger than smi value.
768 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000769 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000770 array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000771
772 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000773 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000774 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000775 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000776
777 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000778 array->SetElement(int_length, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000779 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000780 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000781 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000782 CHECK_EQ(array->GetElement(int_length), *name);
783 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000784}
785
786
787TEST(JSObjectCopy) {
788 InitializeVM();
789
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000790 v8::HandleScope sc(env->GetIsolate());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000791 String* object_string = String::cast(HEAP->Object_string());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000792 Object* raw_object = Isolate::Current()->context()->global_object()->
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000793 GetProperty(object_string)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000794 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000795 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000796 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000797 Handle<String> first = FACTORY->InternalizeUtf8String("first");
798 Handle<String> second = FACTORY->InternalizeUtf8String("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000799
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000800 obj->SetProperty(
801 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
802 obj->SetProperty(
803 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000804
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000805 obj->SetElement(0, *first, NONE, kNonStrictMode)->ToObjectChecked();
806 obj->SetElement(1, *second, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000807
808 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000809 Handle<JSObject> clone = Copy(obj);
810 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000811
812 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
813 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
814
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000815 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
816 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000817
818 // Flip the values.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000819 clone->SetProperty(
820 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
821 clone->SetProperty(
822 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000823
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000824 clone->SetElement(0, *second, NONE, kNonStrictMode)->ToObjectChecked();
825 clone->SetElement(1, *first, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000826
827 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
828 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
829
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000830 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
831 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000832}
833
834
835TEST(StringAllocation) {
836 InitializeVM();
837
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000838 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
839 for (int length = 0; length < 100; length++) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000840 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000841 char* non_ascii = NewArray<char>(3 * length + 1);
842 char* ascii = NewArray<char>(length + 1);
843 non_ascii[3 * length] = 0;
844 ascii[length] = 0;
845 for (int i = 0; i < length; i++) {
846 ascii[i] = 'a';
847 non_ascii[3 * i] = chars[0];
848 non_ascii[3 * i + 1] = chars[1];
849 non_ascii[3 * i + 2] = chars[2];
850 }
851 Handle<String> non_ascii_sym =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000852 FACTORY->InternalizeUtf8String(
853 Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000854 CHECK_EQ(length, non_ascii_sym->length());
855 Handle<String> ascii_sym =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000856 FACTORY->InternalizeOneByteString(OneByteVector(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000857 CHECK_EQ(length, ascii_sym->length());
858 Handle<String> non_ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000859 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000860 non_ascii_str->Hash();
861 CHECK_EQ(length, non_ascii_str->length());
862 Handle<String> ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000863 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000864 ascii_str->Hash();
865 CHECK_EQ(length, ascii_str->length());
866 DeleteArray(non_ascii);
867 DeleteArray(ascii);
868 }
869}
870
871
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000872static int ObjectsFoundInHeap(Heap* heap, Handle<Object> objs[], int size) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000873 // Count the number of objects found in the heap.
874 int found_count = 0;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000875 HeapIterator iterator(heap);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000876 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000877 for (int i = 0; i < size; i++) {
878 if (*objs[i] == obj) {
879 found_count++;
880 }
881 }
882 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000883 return found_count;
884}
885
886
887TEST(Iteration) {
888 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000889 v8::HandleScope scope(env->GetIsolate());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000890
891 // Array of objects to scan haep for.
892 const int objs_count = 6;
893 Handle<Object> objs[objs_count];
894 int next_objs_index = 0;
895
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000896 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000897 objs[next_objs_index++] = FACTORY->NewJSArray(10);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000898 objs[next_objs_index++] = FACTORY->NewJSArray(10,
899 FAST_HOLEY_ELEMENTS,
900 TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000901
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000902 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000903 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000904 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000905 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000906 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000907
908 // Allocate a large string (for large object space).
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000909 int large_size = Page::kMaxNonCodeHeapObjectSize + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000910 char* str = new char[large_size];
911 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
912 str[large_size - 1] = '\0';
913 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000914 FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000915 delete[] str;
916
917 // Add a Map object to look for.
918 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
919
920 CHECK_EQ(objs_count, next_objs_index);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000921 CHECK_EQ(objs_count, ObjectsFoundInHeap(HEAP, objs, objs_count));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000922}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000923
924
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000925TEST(EmptyHandleEscapeFrom) {
926 InitializeVM();
927
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000928 v8::HandleScope scope(env->GetIsolate());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000929 Handle<JSObject> runaway;
930
931 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000932 v8::HandleScope nested(env->GetIsolate());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000933 Handle<JSObject> empty;
934 runaway = empty.EscapeFrom(&nested);
935 }
936
937 CHECK(runaway.is_null());
938}
939
940
941static int LenFromSize(int size) {
942 return (size - FixedArray::kHeaderSize) / kPointerSize;
943}
944
945
946TEST(Regression39128) {
947 // Test case for crbug.com/39128.
948 InitializeVM();
949
950 // Increase the chance of 'bump-the-pointer' allocation in old space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000951 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000952
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000953 v8::HandleScope scope(env->GetIsolate());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000954
955 // The plan: create JSObject which references objects in new space.
956 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000957 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000958
959 // Step 1: prepare a map for the object. We add 1 inobject property to it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000960 Handle<JSFunction> object_ctor(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000961 Isolate::Current()->native_context()->object_function());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000962 CHECK(object_ctor->has_initial_map());
963 Handle<Map> object_map(object_ctor->initial_map());
964 // Create a map with single inobject property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000965 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000966 int n_properties = my_map->inobject_properties();
967 CHECK_GT(n_properties, 0);
968
969 int object_size = my_map->instance_size();
970
971 // Step 2: allocate a lot of objects so to almost fill new space: we need
972 // just enough room to allocate JSObject and thus fill the newspace.
973
974 int allocation_amount = Min(FixedArray::kMaxSize,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000975 HEAP->MaxObjectSizeInNewSpace());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000976 int allocation_len = LenFromSize(allocation_amount);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000977 NewSpace* new_space = HEAP->new_space();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000978 Address* top_addr = new_space->allocation_top_address();
979 Address* limit_addr = new_space->allocation_limit_address();
980 while ((*limit_addr - *top_addr) > allocation_amount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000981 CHECK(!HEAP->always_allocate());
982 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
983 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000984 CHECK(new_space->Contains(array));
985 }
986
987 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000988 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000989 int fixed_array_len = LenFromSize(to_fill);
990 CHECK(fixed_array_len < FixedArray::kMaxLength);
991
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000992 CHECK(!HEAP->always_allocate());
993 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
994 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000995 CHECK(new_space->Contains(array));
996
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000997 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000998 CHECK(new_space->Contains(object));
999 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001000 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001001 CHECK_EQ(0, jsobject->properties()->length());
1002 // Create a reference to object in new space in jsobject.
1003 jsobject->FastPropertyAtPut(-1, array);
1004
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001005 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001006
1007 // Step 4: clone jsobject, but force always allocate first to create a clone
1008 // in old pointer space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001009 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001010 AlwaysAllocateScope aa_scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001011 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001012 JSObject* clone = JSObject::cast(clone_obj);
1013 if (clone->address() != old_pointer_space_top) {
1014 // Alas, got allocated from free list, we cannot do checks.
1015 return;
1016 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001017 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001018}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001019
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001020
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001021TEST(TestCodeFlushing) {
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +00001022 // If we do not flush code this test is invalid.
1023 if (!FLAG_flush_code) return;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001024 i::FLAG_allow_natives_syntax = true;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001025 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001026 v8::HandleScope scope(env->GetIsolate());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001027 const char* source = "function foo() {"
1028 " var x = 42;"
1029 " var y = 42;"
1030 " var z = x + y;"
1031 "};"
1032 "foo()";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001033 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001034
1035 // This compile will add the code to the compilation cache.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001036 { v8::HandleScope scope(env->GetIsolate());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001037 CompileRun(source);
1038 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001039
1040 // Check function is compiled.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001041 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001042 GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001043 CHECK(func_value->IsJSFunction());
1044 Handle<JSFunction> function(JSFunction::cast(func_value));
1045 CHECK(function->shared()->is_compiled());
1046
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001047 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001048 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1049 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001050 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001051
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001052 // Simulate several GCs that use full marking.
1053 const int kAgingThreshold = 6;
1054 for (int i = 0; i < kAgingThreshold; i++) {
1055 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1056 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001057
1058 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001059 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1060 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001061 // Call foo to get it recompiled.
1062 CompileRun("foo()");
1063 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001064 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001065}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001066
1067
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001068TEST(TestCodeFlushingIncremental) {
1069 // If we do not flush code this test is invalid.
1070 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1071 i::FLAG_allow_natives_syntax = true;
1072 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001073 v8::HandleScope scope(env->GetIsolate());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001074 const char* source = "function foo() {"
1075 " var x = 42;"
1076 " var y = 42;"
1077 " var z = x + y;"
1078 "};"
1079 "foo()";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001080 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001081
1082 // This compile will add the code to the compilation cache.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001083 { v8::HandleScope scope(env->GetIsolate());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001084 CompileRun(source);
1085 }
1086
1087 // Check function is compiled.
1088 Object* func_value = Isolate::Current()->context()->global_object()->
1089 GetProperty(*foo_name)->ToObjectChecked();
1090 CHECK(func_value->IsJSFunction());
1091 Handle<JSFunction> function(JSFunction::cast(func_value));
1092 CHECK(function->shared()->is_compiled());
1093
1094 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001095 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1096 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001097 CHECK(function->shared()->is_compiled());
1098
1099 // Simulate several GCs that use incremental marking.
1100 const int kAgingThreshold = 6;
1101 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001102 SimulateIncrementalMarking();
1103 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1104 }
1105 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1106 CHECK(!function->is_compiled() || function->IsOptimized());
1107
1108 // This compile will compile the function again.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001109 { v8::HandleScope scope(env->GetIsolate());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001110 CompileRun("foo();");
1111 }
1112
1113 // Simulate several GCs that use incremental marking but make sure
1114 // the loop breaks once the function is enqueued as a candidate.
1115 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001116 SimulateIncrementalMarking();
1117 if (!function->next_function_link()->IsUndefined()) break;
1118 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1119 }
1120
1121 // Force optimization while incremental marking is active and while
1122 // the function is enqueued as a candidate.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001123 { v8::HandleScope scope(env->GetIsolate());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001124 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1125 }
1126
1127 // Simulate one final GC to make sure the candidate queue is sane.
1128 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1129 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1130 CHECK(function->is_compiled() || !function->IsOptimized());
1131}
1132
1133
1134TEST(TestCodeFlushingIncrementalScavenge) {
1135 // If we do not flush code this test is invalid.
1136 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1137 i::FLAG_allow_natives_syntax = true;
1138 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001139 v8::HandleScope scope(env->GetIsolate());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001140 const char* source = "var foo = function() {"
1141 " var x = 42;"
1142 " var y = 42;"
1143 " var z = x + y;"
1144 "};"
1145 "foo();"
1146 "var bar = function() {"
1147 " var x = 23;"
1148 "};"
1149 "bar();";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001150 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
1151 Handle<String> bar_name = FACTORY->InternalizeUtf8String("bar");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001152
1153 // Perfrom one initial GC to enable code flushing.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001154 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001155
1156 // This compile will add the code to the compilation cache.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001157 { v8::HandleScope scope(env->GetIsolate());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001158 CompileRun(source);
1159 }
1160
1161 // Check functions are compiled.
1162 Object* func_value = Isolate::Current()->context()->global_object()->
1163 GetProperty(*foo_name)->ToObjectChecked();
1164 CHECK(func_value->IsJSFunction());
1165 Handle<JSFunction> function(JSFunction::cast(func_value));
1166 CHECK(function->shared()->is_compiled());
1167 Object* func_value2 = Isolate::Current()->context()->global_object()->
1168 GetProperty(*bar_name)->ToObjectChecked();
1169 CHECK(func_value2->IsJSFunction());
1170 Handle<JSFunction> function2(JSFunction::cast(func_value2));
1171 CHECK(function2->shared()->is_compiled());
1172
1173 // Clear references to functions so that one of them can die.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001174 { v8::HandleScope scope(env->GetIsolate());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001175 CompileRun("foo = 0; bar = 0;");
1176 }
1177
1178 // Bump the code age so that flushing is triggered while the function
1179 // object is still located in new-space.
1180 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001181 for (int i = 0; i < kAgingThreshold; i++) {
1182 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1183 function2->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1184 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001185
1186 // Simulate incremental marking so that the functions are enqueued as
1187 // code flushing candidates. Then kill one of the functions. Finally
1188 // perform a scavenge while incremental marking is still running.
1189 SimulateIncrementalMarking();
1190 *function2.location() = NULL;
1191 HEAP->CollectGarbage(NEW_SPACE, "test scavenge while marking");
1192
1193 // Simulate one final GC to make sure the candidate queue is sane.
1194 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1195 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1196 CHECK(!function->is_compiled() || function->IsOptimized());
1197}
1198
1199
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001200TEST(TestCodeFlushingIncrementalAbort) {
1201 // If we do not flush code this test is invalid.
1202 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1203 i::FLAG_allow_natives_syntax = true;
1204 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001205 Isolate* isolate = Isolate::Current();
1206 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001207 v8::HandleScope scope(env->GetIsolate());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001208 const char* source = "function foo() {"
1209 " var x = 42;"
1210 " var y = 42;"
1211 " var z = x + y;"
1212 "};"
1213 "foo()";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001214 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001215
1216 // This compile will add the code to the compilation cache.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001217 { v8::HandleScope scope(env->GetIsolate());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001218 CompileRun(source);
1219 }
1220
1221 // Check function is compiled.
1222 Object* func_value = Isolate::Current()->context()->global_object()->
1223 GetProperty(*foo_name)->ToObjectChecked();
1224 CHECK(func_value->IsJSFunction());
1225 Handle<JSFunction> function(JSFunction::cast(func_value));
1226 CHECK(function->shared()->is_compiled());
1227
1228 // The code will survive at least two GCs.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001229 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1230 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001231 CHECK(function->shared()->is_compiled());
1232
1233 // Bump the code age so that flushing is triggered.
1234 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001235 for (int i = 0; i < kAgingThreshold; i++) {
1236 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1237 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001238
1239 // Simulate incremental marking so that the function is enqueued as
1240 // code flushing candidate.
1241 SimulateIncrementalMarking();
1242
1243 // Enable the debugger and add a breakpoint while incremental marking
1244 // is running so that incremental marking aborts and code flushing is
1245 // disabled.
1246 int position = 0;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001247 Handle<Object> breakpoint_object(Smi::FromInt(0), isolate);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001248 isolate->debug()->SetBreakPoint(function, breakpoint_object, &position);
1249 isolate->debug()->ClearAllBreakPoints();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001250
1251 // Force optimization now that code flushing is disabled.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001252 { v8::HandleScope scope(env->GetIsolate());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001253 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1254 }
1255
1256 // Simulate one final GC to make sure the candidate queue is sane.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001257 heap->CollectAllGarbage(Heap::kNoGCFlags);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001258 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1259 CHECK(function->is_compiled() || !function->IsOptimized());
1260}
1261
1262
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001263// Count the number of native contexts in the weak list of native contexts.
1264int CountNativeContexts() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001265 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001266 Object* object = HEAP->native_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001267 while (!object->IsUndefined()) {
1268 count++;
1269 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1270 }
1271 return count;
1272}
1273
1274
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001275// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001276// functions attached to a native context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001277static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1278 int count = 0;
1279 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1280 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1281 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1282 count++;
1283 object = JSFunction::cast(object)->next_function_link();
1284 }
1285 return count;
1286}
1287
1288
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001289TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001290 v8::V8::Initialize();
1291
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001292 // Some flags turn Scavenge collections into Mark-sweep collections
1293 // and hence are incompatible with this test case.
1294 if (FLAG_gc_global || FLAG_stress_compaction) return;
1295
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001296 static const int kNumTestContexts = 10;
1297
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001298 Isolate* isolate = Isolate::Current();
1299 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001300 HandleScope scope(isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001301 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1302
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001303 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001304
1305 // Create a number of global contests which gets linked together.
1306 for (int i = 0; i < kNumTestContexts; i++) {
1307 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001308
1309 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1310
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001311 CHECK_EQ(i + 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001312
1313 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001314
1315 // Create a handle scope so no function objects get stuch in the outer
1316 // handle scope
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001317 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001318 const char* source = "function f1() { };"
1319 "function f2() { };"
1320 "function f3() { };"
1321 "function f4() { };"
1322 "function f5() { };";
1323 CompileRun(source);
1324 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1325 CompileRun("f1()");
1326 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1327 CompileRun("f2()");
1328 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1329 CompileRun("f3()");
1330 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1331 CompileRun("f4()");
1332 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1333 CompileRun("f5()");
1334 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1335
1336 // Remove function f1, and
1337 CompileRun("f1=null");
1338
1339 // Scavenge treats these references as strong.
1340 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001341 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001342 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1343 }
1344
1345 // Mark compact handles the weak references.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001346 isolate->compilation_cache()->Clear();
1347 heap->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001348 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1349
1350 // Get rid of f3 and f5 in the same way.
1351 CompileRun("f3=null");
1352 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001353 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001354 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1355 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001356 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001357 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1358 CompileRun("f5=null");
1359 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001360 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001361 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1362 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001363 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001364 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1365
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001366 ctx[i]->Exit();
1367 }
1368
1369 // Force compilation cache cleanup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001370 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001371
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001372 // Dispose the native contexts one by one.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001373 for (int i = 0; i < kNumTestContexts; i++) {
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001374 ctx[i].Dispose(ctx[i]->GetIsolate());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001375 ctx[i].Clear();
1376
1377 // Scavenge treats these references as strong.
1378 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001379 HEAP->PerformScavenge();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001380 CHECK_EQ(kNumTestContexts - i, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001381 }
1382
1383 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001384 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001385 CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001386 }
1387
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001388 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001389}
1390
1391
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001392// Count the number of native contexts in the weak list of native contexts
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001393// causing a GC after the specified number of elements.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001394static int CountNativeContextsWithGC(Isolate* isolate, int n) {
1395 Heap* heap = isolate->heap();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001396 int count = 0;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001397 Handle<Object> object(heap->native_contexts_list(), isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001398 while (!object->IsUndefined()) {
1399 count++;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001400 if (count == n) heap->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001401 object =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001402 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK),
1403 isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001404 }
1405 return count;
1406}
1407
1408
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001409// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001410// functions attached to a native context causing a GC after the
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001411// specified number of elements.
1412static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1413 int n) {
1414 int count = 0;
1415 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001416 Isolate* isolate = icontext->GetIsolate();
1417 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST),
1418 isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001419 while (object->IsJSFunction() &&
1420 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1421 count++;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001422 if (count == n) isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001423 object = Handle<Object>(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001424 Object::cast(JSFunction::cast(*object)->next_function_link()),
1425 isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001426 }
1427 return count;
1428}
1429
1430
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001431TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001432 v8::V8::Initialize();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001433 Isolate* isolate = Isolate::Current();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001434
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001435 static const int kNumTestContexts = 10;
1436
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001437 HandleScope scope(isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001438 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1439
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001440 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001441
1442 // Create an number of contexts and check the length of the weak list both
1443 // with and without GCs while iterating the list.
1444 for (int i = 0; i < kNumTestContexts; i++) {
1445 ctx[i] = v8::Context::New();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001446 CHECK_EQ(i + 1, CountNativeContexts());
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001447 CHECK_EQ(i + 1, CountNativeContextsWithGC(isolate, i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001448 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001449
1450 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1451
1452 // Compile a number of functions the length of the weak list of optimized
1453 // functions both with and without GCs while iterating the list.
1454 ctx[0]->Enter();
1455 const char* source = "function f1() { };"
1456 "function f2() { };"
1457 "function f3() { };"
1458 "function f4() { };"
1459 "function f5() { };";
1460 CompileRun(source);
1461 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1462 CompileRun("f1()");
1463 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1464 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1465 CompileRun("f2()");
1466 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1467 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1468 CompileRun("f3()");
1469 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1470 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1471 CompileRun("f4()");
1472 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1473 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1474 CompileRun("f5()");
1475 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1476 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1477
1478 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001479}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001480
1481
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001482TEST(TestSizeOfObjects) {
1483 v8::V8::Initialize();
1484
1485 // Get initial heap size after several full GCs, which will stabilize
1486 // the heap size and return with sweeping finished completely.
1487 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1488 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1489 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1490 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001491 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001492 CHECK(HEAP->old_pointer_space()->IsLazySweepingComplete());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001493 int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1494
1495 {
1496 // Allocate objects on several different old-space pages so that
1497 // lazy sweeping kicks in for subsequent GC runs.
1498 AlwaysAllocateScope always_allocate;
1499 int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1500 for (int i = 1; i <= 100; i++) {
1501 HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1502 CHECK_EQ(initial_size + i * filler_size,
1503 static_cast<int>(HEAP->SizeOfObjects()));
1504 }
1505 }
1506
1507 // The heap size should go back to initial size after a full GC, even
1508 // though sweeping didn't finish yet.
1509 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001510
1511 // Normally sweeping would not be complete here, but no guarantees.
1512
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001513 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1514
1515 // Advancing the sweeper step-wise should not change the heap size.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001516 while (!HEAP->old_pointer_space()->IsLazySweepingComplete()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001517 HEAP->old_pointer_space()->AdvanceSweeper(KB);
1518 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1519 }
1520}
1521
1522
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001523TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1524 InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001525 HEAP->EnsureHeapIsIterable();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001526 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001527 HeapIterator iterator(HEAP);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001528 intptr_t size_of_objects_2 = 0;
1529 for (HeapObject* obj = iterator.next();
1530 obj != NULL;
1531 obj = iterator.next()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001532 if (!obj->IsFreeSpace()) {
1533 size_of_objects_2 += obj->Size();
1534 }
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001535 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001536 // Delta must be within 5% of the larger result.
1537 // TODO(gc): Tighten this up by distinguishing between byte
1538 // arrays that are real and those that merely mark free space
1539 // on the heap.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001540 if (size_of_objects_1 > size_of_objects_2) {
1541 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1542 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1543 "Iterator: %" V8_PTR_PREFIX "d, "
1544 "delta: %" V8_PTR_PREFIX "d\n",
1545 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001546 CHECK_GT(size_of_objects_1 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001547 } else {
1548 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1549 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1550 "Iterator: %" V8_PTR_PREFIX "d, "
1551 "delta: %" V8_PTR_PREFIX "d\n",
1552 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001553 CHECK_GT(size_of_objects_2 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001554 }
1555}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001556
1557
danno@chromium.orgc612e022011-11-10 11:38:15 +00001558static void FillUpNewSpace(NewSpace* new_space) {
1559 // Fill up new space to the point that it is completely full. Make sure
1560 // that the scavenger does not undo the filling.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001561 Heap* heap = new_space->heap();
1562 Isolate* isolate = heap->isolate();
1563 Factory* factory = isolate->factory();
1564 HandleScope scope(isolate);
danno@chromium.orgc612e022011-11-10 11:38:15 +00001565 AlwaysAllocateScope always_allocate;
1566 intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001567 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001568 for (intptr_t i = 0; i < number_of_fillers; i++) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001569 CHECK(heap->InNewSpace(*factory->NewFixedArray(32, NOT_TENURED)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001570 }
1571}
1572
1573
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001574TEST(GrowAndShrinkNewSpace) {
1575 InitializeVM();
1576 NewSpace* new_space = HEAP->new_space();
1577
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001578 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1579 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001580 // The max size cannot exceed the reserved size, since semispaces must be
1581 // always within the reserved space. We can't test new space growing and
1582 // shrinking if the reserved size is the same as the minimum (initial) size.
1583 return;
1584 }
1585
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001586 // Explicitly growing should double the space capacity.
1587 intptr_t old_capacity, new_capacity;
1588 old_capacity = new_space->Capacity();
1589 new_space->Grow();
1590 new_capacity = new_space->Capacity();
1591 CHECK(2 * old_capacity == new_capacity);
1592
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001593 old_capacity = new_space->Capacity();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001594 FillUpNewSpace(new_space);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001595 new_capacity = new_space->Capacity();
1596 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001597
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001598 // Explicitly shrinking should not affect space capacity.
1599 old_capacity = new_space->Capacity();
1600 new_space->Shrink();
1601 new_capacity = new_space->Capacity();
1602 CHECK(old_capacity == new_capacity);
1603
1604 // Let the scavenger empty the new space.
1605 HEAP->CollectGarbage(NEW_SPACE);
1606 CHECK_LE(new_space->Size(), old_capacity);
1607
1608 // Explicitly shrinking should halve the space capacity.
1609 old_capacity = new_space->Capacity();
1610 new_space->Shrink();
1611 new_capacity = new_space->Capacity();
1612 CHECK(old_capacity == 2 * new_capacity);
1613
1614 // Consecutive shrinking should not affect space capacity.
1615 old_capacity = new_space->Capacity();
1616 new_space->Shrink();
1617 new_space->Shrink();
1618 new_space->Shrink();
1619 new_capacity = new_space->Capacity();
1620 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001621}
danno@chromium.orgc612e022011-11-10 11:38:15 +00001622
1623
1624TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1625 InitializeVM();
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001626
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001627 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1628 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001629 // The max size cannot exceed the reserved size, since semispaces must be
1630 // always within the reserved space. We can't test new space growing and
1631 // shrinking if the reserved size is the same as the minimum (initial) size.
1632 return;
1633 }
1634
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001635 v8::HandleScope scope(env->GetIsolate());
danno@chromium.orgc612e022011-11-10 11:38:15 +00001636 NewSpace* new_space = HEAP->new_space();
1637 intptr_t old_capacity, new_capacity;
1638 old_capacity = new_space->Capacity();
1639 new_space->Grow();
1640 new_capacity = new_space->Capacity();
1641 CHECK(2 * old_capacity == new_capacity);
1642 FillUpNewSpace(new_space);
1643 HEAP->CollectAllAvailableGarbage();
1644 new_capacity = new_space->Capacity();
1645 CHECK(old_capacity == new_capacity);
1646}
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001647
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001648
1649static int NumberOfGlobalObjects() {
1650 int count = 0;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001651 HeapIterator iterator(HEAP);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001652 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1653 if (obj->IsGlobalObject()) count++;
1654 }
1655 return count;
1656}
1657
1658
1659// Test that we don't embed maps from foreign contexts into
1660// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001661TEST(LeakNativeContextViaMap) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001662 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001663 v8::HandleScope outer_scope(v8::Isolate::GetCurrent());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001664 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1665 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1666 ctx1->Enter();
1667
1668 HEAP->CollectAllAvailableGarbage();
1669 CHECK_EQ(4, NumberOfGlobalObjects());
1670
1671 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001672 v8::HandleScope inner_scope(v8::Isolate::GetCurrent());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001673 CompileRun("var v = {x: 42}");
1674 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1675 ctx2->Enter();
1676 ctx2->Global()->Set(v8_str("o"), v);
1677 v8::Local<v8::Value> res = CompileRun(
1678 "function f() { return o.x; }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001679 "for (var i = 0; i < 10; ++i) f();"
1680 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001681 "f();");
1682 CHECK_EQ(42, res->Int32Value());
1683 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1684 ctx2->Exit();
1685 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001686 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001687 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001688 }
1689 HEAP->CollectAllAvailableGarbage();
1690 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001691 ctx2.Dispose(ctx2->GetIsolate());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001692 HEAP->CollectAllAvailableGarbage();
1693 CHECK_EQ(0, NumberOfGlobalObjects());
1694}
1695
1696
1697// Test that we don't embed functions from foreign contexts into
1698// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001699TEST(LeakNativeContextViaFunction) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001700 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001701 v8::HandleScope outer_scope(v8::Isolate::GetCurrent());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001702 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1703 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1704 ctx1->Enter();
1705
1706 HEAP->CollectAllAvailableGarbage();
1707 CHECK_EQ(4, NumberOfGlobalObjects());
1708
1709 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001710 v8::HandleScope inner_scope(v8::Isolate::GetCurrent());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001711 CompileRun("var v = function() { return 42; }");
1712 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1713 ctx2->Enter();
1714 ctx2->Global()->Set(v8_str("o"), v);
1715 v8::Local<v8::Value> res = CompileRun(
1716 "function f(x) { return x(); }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001717 "for (var i = 0; i < 10; ++i) f(o);"
1718 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001719 "f(o);");
1720 CHECK_EQ(42, res->Int32Value());
1721 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1722 ctx2->Exit();
1723 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001724 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001725 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001726 }
1727 HEAP->CollectAllAvailableGarbage();
1728 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001729 ctx2.Dispose(ctx2->GetIsolate());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001730 HEAP->CollectAllAvailableGarbage();
1731 CHECK_EQ(0, NumberOfGlobalObjects());
1732}
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001733
1734
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001735TEST(LeakNativeContextViaMapKeyed) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001736 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001737 v8::HandleScope outer_scope(v8::Isolate::GetCurrent());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001738 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1739 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1740 ctx1->Enter();
1741
1742 HEAP->CollectAllAvailableGarbage();
1743 CHECK_EQ(4, NumberOfGlobalObjects());
1744
1745 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001746 v8::HandleScope inner_scope(v8::Isolate::GetCurrent());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001747 CompileRun("var v = [42, 43]");
1748 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1749 ctx2->Enter();
1750 ctx2->Global()->Set(v8_str("o"), v);
1751 v8::Local<v8::Value> res = CompileRun(
1752 "function f() { return o[0]; }"
1753 "for (var i = 0; i < 10; ++i) f();"
1754 "%OptimizeFunctionOnNextCall(f);"
1755 "f();");
1756 CHECK_EQ(42, res->Int32Value());
1757 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1758 ctx2->Exit();
1759 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001760 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001761 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001762 }
1763 HEAP->CollectAllAvailableGarbage();
1764 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001765 ctx2.Dispose(ctx2->GetIsolate());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001766 HEAP->CollectAllAvailableGarbage();
1767 CHECK_EQ(0, NumberOfGlobalObjects());
1768}
1769
1770
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001771TEST(LeakNativeContextViaMapProto) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001772 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001773 v8::HandleScope outer_scope(v8::Isolate::GetCurrent());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001774 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1775 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1776 ctx1->Enter();
1777
1778 HEAP->CollectAllAvailableGarbage();
1779 CHECK_EQ(4, NumberOfGlobalObjects());
1780
1781 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001782 v8::HandleScope inner_scope(v8::Isolate::GetCurrent());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001783 CompileRun("var v = { y: 42}");
1784 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1785 ctx2->Enter();
1786 ctx2->Global()->Set(v8_str("o"), v);
1787 v8::Local<v8::Value> res = CompileRun(
1788 "function f() {"
1789 " var p = {x: 42};"
1790 " p.__proto__ = o;"
1791 " return p.x;"
1792 "}"
1793 "for (var i = 0; i < 10; ++i) f();"
1794 "%OptimizeFunctionOnNextCall(f);"
1795 "f();");
1796 CHECK_EQ(42, res->Int32Value());
1797 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1798 ctx2->Exit();
1799 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001800 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001801 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001802 }
1803 HEAP->CollectAllAvailableGarbage();
1804 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001805 ctx2.Dispose(ctx2->GetIsolate());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001806 HEAP->CollectAllAvailableGarbage();
1807 CHECK_EQ(0, NumberOfGlobalObjects());
1808}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001809
1810
1811TEST(InstanceOfStubWriteBarrier) {
1812 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001813#ifdef VERIFY_HEAP
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001814 i::FLAG_verify_heap = true;
1815#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001816
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001817 InitializeVM();
1818 if (!i::V8::UseCrankshaft()) return;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001819 if (i::FLAG_force_marking_deque_overflows) return;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001820 v8::HandleScope outer_scope(v8::Isolate::GetCurrent());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001821
1822 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001823 v8::HandleScope scope(v8::Isolate::GetCurrent());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001824 CompileRun(
1825 "function foo () { }"
1826 "function mkbar () { return new (new Function(\"\")) (); }"
1827 "function f (x) { return (x instanceof foo); }"
1828 "function g () { f(mkbar()); }"
1829 "f(new foo()); f(new foo());"
1830 "%OptimizeFunctionOnNextCall(f);"
1831 "f(new foo()); g();");
1832 }
1833
1834 IncrementalMarking* marking = HEAP->incremental_marking();
1835 marking->Abort();
1836 marking->Start();
1837
1838 Handle<JSFunction> f =
1839 v8::Utils::OpenHandle(
1840 *v8::Handle<v8::Function>::Cast(
1841 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1842
1843 CHECK(f->IsOptimized());
1844
1845 while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1846 !marking->IsStopped()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001847 // Discard any pending GC requests otherwise we will get GC when we enter
1848 // code below.
1849 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001850 }
1851
1852 CHECK(marking->IsMarking());
1853
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001854 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001855 v8::HandleScope scope(v8::Isolate::GetCurrent());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001856 v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1857 v8::Handle<v8::Function> g =
1858 v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1859 g->Call(global, 0, NULL);
1860 }
1861
1862 HEAP->incremental_marking()->set_should_hurry(true);
1863 HEAP->CollectGarbage(OLD_POINTER_SPACE);
1864}
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001865
1866
1867TEST(PrototypeTransitionClearing) {
1868 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001869 v8::HandleScope scope(env->GetIsolate());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001870
1871 CompileRun(
1872 "var base = {};"
1873 "var live = [];"
1874 "for (var i = 0; i < 10; i++) {"
1875 " var object = {};"
1876 " var prototype = {};"
1877 " object.__proto__ = prototype;"
1878 " if (i >= 3) live.push(object, prototype);"
1879 "}");
1880
1881 Handle<JSObject> baseObject =
1882 v8::Utils::OpenHandle(
1883 *v8::Handle<v8::Object>::Cast(
1884 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1885
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001886 // Verify that only dead prototype transitions are cleared.
1887 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001888 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001889 const int transitions = 10 - 3;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001890 CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001891
1892 // Verify that prototype transitions array was compacted.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001893 FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001894 for (int i = 0; i < transitions; i++) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001895 int j = Map::kProtoTransitionHeaderSize +
1896 i * Map::kProtoTransitionElementsPerEntry;
1897 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001898 Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
1899 CHECK(proto->IsTheHole() || proto->IsJSObject());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001900 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001901
1902 // Make sure next prototype is placed on an old-space evacuation candidate.
1903 Handle<JSObject> prototype;
1904 PagedSpace* space = HEAP->old_pointer_space();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001905 {
1906 AlwaysAllocateScope always_allocate;
1907 SimulateFullSpace(space);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001908 prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001909 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001910
1911 // Add a prototype on an evacuation candidate and verify that transition
1912 // clearing correctly records slots in prototype transition array.
1913 i::FLAG_always_compact = true;
1914 Handle<Map> map(baseObject->map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001915 CHECK(!space->LastPage()->Contains(
1916 map->GetPrototypeTransitions()->address()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001917 CHECK(space->LastPage()->Contains(prototype->address()));
1918 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1919 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1920 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1921 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001922}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001923
1924
1925TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1926 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001927#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001928 i::FLAG_verify_heap = true;
1929#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001930
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001931 InitializeVM();
1932 if (!i::V8::UseCrankshaft()) return;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001933 v8::HandleScope outer_scope(v8::Isolate::GetCurrent());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001934
1935 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001936 v8::HandleScope scope(v8::Isolate::GetCurrent());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001937 CompileRun(
1938 "function f () {"
1939 " var s = 0;"
1940 " for (var i = 0; i < 100; i++) s += i;"
1941 " return s;"
1942 "}"
1943 "f(); f();"
1944 "%OptimizeFunctionOnNextCall(f);"
1945 "f();");
1946 }
1947 Handle<JSFunction> f =
1948 v8::Utils::OpenHandle(
1949 *v8::Handle<v8::Function>::Cast(
1950 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1951 CHECK(f->IsOptimized());
1952
1953 IncrementalMarking* marking = HEAP->incremental_marking();
1954 marking->Abort();
1955 marking->Start();
1956
1957 // The following two calls will increment HEAP->global_ic_age().
1958 const int kLongIdlePauseInMs = 1000;
1959 v8::V8::ContextDisposedNotification();
1960 v8::V8::IdleNotification(kLongIdlePauseInMs);
1961
1962 while (!marking->IsStopped() && !marking->IsComplete()) {
1963 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1964 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001965 if (!marking->IsStopped() || marking->should_hurry()) {
1966 // We don't normally finish a GC via Step(), we normally finish by
1967 // setting the stack guard and then do the final steps in the stack
1968 // guard interrupt. But here we didn't ask for that, and there is no
1969 // JS code running to trigger the interrupt, so we explicitly finalize
1970 // here.
1971 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1972 "Test finalizing incremental mark-sweep");
1973 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001974
1975 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1976 CHECK_EQ(0, f->shared()->opt_count());
1977 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1978}
1979
1980
1981TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1982 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001983#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001984 i::FLAG_verify_heap = true;
1985#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001986
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001987 InitializeVM();
1988 if (!i::V8::UseCrankshaft()) return;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001989 v8::HandleScope outer_scope(env->GetIsolate());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001990
1991 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001992 v8::HandleScope scope(env->GetIsolate());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001993 CompileRun(
1994 "function f () {"
1995 " var s = 0;"
1996 " for (var i = 0; i < 100; i++) s += i;"
1997 " return s;"
1998 "}"
1999 "f(); f();"
2000 "%OptimizeFunctionOnNextCall(f);"
2001 "f();");
2002 }
2003 Handle<JSFunction> f =
2004 v8::Utils::OpenHandle(
2005 *v8::Handle<v8::Function>::Cast(
2006 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2007 CHECK(f->IsOptimized());
2008
2009 HEAP->incremental_marking()->Abort();
2010
2011 // The following two calls will increment HEAP->global_ic_age().
2012 // Since incremental marking is off, IdleNotification will do full GC.
2013 const int kLongIdlePauseInMs = 1000;
2014 v8::V8::ContextDisposedNotification();
2015 v8::V8::IdleNotification(kLongIdlePauseInMs);
2016
2017 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
2018 CHECK_EQ(0, f->shared()->opt_count());
2019 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
2020}
2021
2022
2023// Test that HAllocateObject will always return an object in new-space.
2024TEST(OptimizedAllocationAlwaysInNewSpace) {
2025 i::FLAG_allow_natives_syntax = true;
2026 InitializeVM();
2027 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00002028 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002029 v8::HandleScope scope(env->GetIsolate());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002030
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002031 SimulateFullSpace(HEAP->new_space());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002032 AlwaysAllocateScope always_allocate;
2033 v8::Local<v8::Value> res = CompileRun(
2034 "function c(x) {"
2035 " this.x = x;"
2036 " for (var i = 0; i < 32; i++) {"
2037 " this['x' + i] = x;"
2038 " }"
2039 "}"
2040 "function f(x) { return new c(x); };"
2041 "f(1); f(2); f(3);"
2042 "%OptimizeFunctionOnNextCall(f);"
2043 "f(4);");
2044 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
2045
2046 Handle<JSObject> o =
2047 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2048
2049 CHECK(HEAP->InNewSpace(*o));
2050}
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002051
2052
ulan@chromium.org750145a2013-03-07 15:14:13 +00002053// Test pretenuring of array literals allocated with HAllocate.
2054TEST(OptimizedPretenuringArrayLiterals) {
2055 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002056 i::FLAG_pretenure_literals = true;
ulan@chromium.org750145a2013-03-07 15:14:13 +00002057 InitializeVM();
2058 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
2059 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002060 v8::HandleScope scope(env->GetIsolate());
ulan@chromium.org750145a2013-03-07 15:14:13 +00002061
2062 AlwaysAllocateScope always_allocate;
2063 v8::Local<v8::Value> res = CompileRun(
2064 "function f() {"
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002065 " var numbers = [1, 2, 3];"
2066 " numbers[0] = {};"
ulan@chromium.org750145a2013-03-07 15:14:13 +00002067 " return numbers;"
2068 "};"
2069 "f(); f(); f();"
2070 "%OptimizeFunctionOnNextCall(f);"
2071 "f();");
ulan@chromium.org750145a2013-03-07 15:14:13 +00002072
2073 Handle<JSObject> o =
2074 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2075
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002076 CHECK(HEAP->InOldPointerSpace(o->elements()));
ulan@chromium.org750145a2013-03-07 15:14:13 +00002077}
2078
2079
2080// Test regular array literals allocation.
2081TEST(OptimizedAllocationArrayLiterals) {
2082 i::FLAG_allow_natives_syntax = true;
2083 InitializeVM();
2084 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
2085 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002086 v8::HandleScope scope(env->GetIsolate());
ulan@chromium.org750145a2013-03-07 15:14:13 +00002087
2088 AlwaysAllocateScope always_allocate;
2089 v8::Local<v8::Value> res = CompileRun(
2090 "function f() {"
2091 " var numbers = new Array(1, 2, 3);"
2092 " numbers[0] = 3.14;"
2093 " return numbers;"
2094 "};"
2095 "f(); f(); f();"
2096 "%OptimizeFunctionOnNextCall(f);"
2097 "f();");
2098 CHECK_EQ(static_cast<int>(3.14),
2099 v8::Object::Cast(*res)->Get(v8_str("0"))->Int32Value());
2100
2101 Handle<JSObject> o =
2102 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2103
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002104 CHECK(HEAP->InNewSpace(o->elements()));
ulan@chromium.org750145a2013-03-07 15:14:13 +00002105}
2106
2107
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002108static int CountMapTransitions(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002109 return map->transitions()->number_of_transitions();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002110}
2111
2112
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002113// Test that map transitions are cleared and maps are collected with
2114// incremental marking as well.
2115TEST(Regress1465) {
2116 i::FLAG_allow_natives_syntax = true;
2117 i::FLAG_trace_incremental_marking = true;
2118 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002119 v8::HandleScope scope(env->GetIsolate());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002120 static const int transitions_count = 256;
2121
2122 {
2123 AlwaysAllocateScope always_allocate;
2124 for (int i = 0; i < transitions_count; i++) {
2125 EmbeddedVector<char, 64> buffer;
2126 OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
2127 CompileRun(buffer.start());
2128 }
2129 CompileRun("var root = new Object;");
2130 }
2131
2132 Handle<JSObject> root =
2133 v8::Utils::OpenHandle(
2134 *v8::Handle<v8::Object>::Cast(
2135 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2136
2137 // Count number of live transitions before marking.
2138 int transitions_before = CountMapTransitions(root->map());
2139 CompileRun("%DebugPrint(root);");
2140 CHECK_EQ(transitions_count, transitions_before);
2141
2142 SimulateIncrementalMarking();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002143 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002144
2145 // Count number of live transitions after marking. Note that one transition
2146 // is left, because 'o' still holds an instance of one transition target.
2147 int transitions_after = CountMapTransitions(root->map());
2148 CompileRun("%DebugPrint(root);");
2149 CHECK_EQ(1, transitions_after);
2150}
verwaest@chromium.org37141392012-05-31 13:27:02 +00002151
2152
2153TEST(Regress2143a) {
2154 i::FLAG_collect_maps = true;
2155 i::FLAG_incremental_marking = true;
2156 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002157 v8::HandleScope scope(env->GetIsolate());
verwaest@chromium.org37141392012-05-31 13:27:02 +00002158
2159 // Prepare a map transition from the root object together with a yet
2160 // untransitioned root object.
2161 CompileRun("var root = new Object;"
2162 "root.foo = 0;"
2163 "root = new Object;");
2164
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002165 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002166
2167 // Compile a StoreIC that performs the prepared map transition. This
2168 // will restart incremental marking and should make sure the root is
2169 // marked grey again.
2170 CompileRun("function f(o) {"
2171 " o.foo = 0;"
2172 "}"
2173 "f(new Object);"
2174 "f(root);");
2175
2176 // This bug only triggers with aggressive IC clearing.
2177 HEAP->AgeInlineCaches();
2178
2179 // Explicitly request GC to perform final marking step and sweeping.
2180 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002181
2182 Handle<JSObject> root =
2183 v8::Utils::OpenHandle(
2184 *v8::Handle<v8::Object>::Cast(
2185 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2186
2187 // The root object should be in a sane state.
2188 CHECK(root->IsJSObject());
2189 CHECK(root->map()->IsMap());
2190}
2191
2192
2193TEST(Regress2143b) {
2194 i::FLAG_collect_maps = true;
2195 i::FLAG_incremental_marking = true;
2196 i::FLAG_allow_natives_syntax = true;
2197 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002198 v8::HandleScope scope(env->GetIsolate());
verwaest@chromium.org37141392012-05-31 13:27:02 +00002199
2200 // Prepare a map transition from the root object together with a yet
2201 // untransitioned root object.
2202 CompileRun("var root = new Object;"
2203 "root.foo = 0;"
2204 "root = new Object;");
2205
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002206 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002207
2208 // Compile an optimized LStoreNamedField that performs the prepared
2209 // map transition. This will restart incremental marking and should
2210 // make sure the root is marked grey again.
2211 CompileRun("function f(o) {"
2212 " o.foo = 0;"
2213 "}"
2214 "f(new Object);"
2215 "f(new Object);"
2216 "%OptimizeFunctionOnNextCall(f);"
2217 "f(root);"
2218 "%DeoptimizeFunction(f);");
2219
2220 // This bug only triggers with aggressive IC clearing.
2221 HEAP->AgeInlineCaches();
2222
2223 // Explicitly request GC to perform final marking step and sweeping.
2224 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002225
2226 Handle<JSObject> root =
2227 v8::Utils::OpenHandle(
2228 *v8::Handle<v8::Object>::Cast(
2229 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2230
2231 // The root object should be in a sane state.
2232 CHECK(root->IsJSObject());
2233 CHECK(root->map()->IsMap());
2234}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002235
2236
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002237TEST(ReleaseOverReservedPages) {
2238 i::FLAG_trace_gc = true;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002239 // The optimizer can allocate stuff, messing up the test.
2240 i::FLAG_crankshaft = false;
2241 i::FLAG_always_opt = false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002242 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002243 v8::HandleScope scope(env->GetIsolate());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002244 static const int number_of_test_pages = 20;
2245
2246 // Prepare many pages with low live-bytes count.
2247 PagedSpace* old_pointer_space = HEAP->old_pointer_space();
2248 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2249 for (int i = 0; i < number_of_test_pages; i++) {
2250 AlwaysAllocateScope always_allocate;
2251 SimulateFullSpace(old_pointer_space);
2252 FACTORY->NewFixedArray(1, TENURED);
2253 }
2254 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2255
2256 // Triggering one GC will cause a lot of garbage to be discovered but
2257 // even spread across all allocated pages.
2258 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00002259 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002260
2261 // Triggering subsequent GCs should cause at least half of the pages
2262 // to be released to the OS after at most two cycles.
2263 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
2264 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2265 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
2266 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
2267
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002268 // Triggering a last-resort GC should cause all pages to be released to the
2269 // OS so that other processes can seize the memory. If we get a failure here
2270 // where there are 2 pages left instead of 1, then we should increase the
2271 // size of the first page a little in SizeOfFirstPage in spaces.cc. The
2272 // first page should be small in order to reduce memory used when the VM
2273 // boots, but if the 20 small arrays don't fit on the first page then that's
2274 // an indication that it is too small.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002275 HEAP->CollectAllAvailableGarbage("triggered really hard");
2276 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2277}
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002278
2279
2280TEST(Regress2237) {
2281 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002282 v8::HandleScope scope(env->GetIsolate());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002283 Handle<String> slice(HEAP->empty_string());
2284
2285 {
2286 // Generate a parent that lives in new-space.
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002287 v8::HandleScope inner_scope(env->GetIsolate());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002288 const char* c = "This text is long enough to trigger sliced strings.";
2289 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002290 CHECK(s->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002291 CHECK(HEAP->InNewSpace(*s));
2292
2293 // Generate a sliced string that is based on the above parent and
2294 // lives in old-space.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002295 SimulateFullSpace(HEAP->new_space());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002296 AlwaysAllocateScope always_allocate;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002297 Handle<String> t = FACTORY->NewProperSubString(s, 5, 35);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002298 CHECK(t->IsSlicedString());
2299 CHECK(!HEAP->InNewSpace(*t));
2300 *slice.location() = *t.location();
2301 }
2302
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002303 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002304 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002305 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002306}
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00002307
2308
2309#ifdef OBJECT_PRINT
2310TEST(PrintSharedFunctionInfo) {
2311 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002312 v8::HandleScope scope(env->GetIsolate());
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00002313 const char* source = "f = function() { return 987654321; }\n"
2314 "g = function() { return 123456789; }\n";
2315 CompileRun(source);
2316 Handle<JSFunction> g =
2317 v8::Utils::OpenHandle(
2318 *v8::Handle<v8::Function>::Cast(
2319 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2320
2321 AssertNoAllocation no_alloc;
2322 g->shared()->PrintLn();
2323}
2324#endif // OBJECT_PRINT
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002325
2326
2327TEST(Regress2211) {
2328 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002329 v8::HandleScope scope(env->GetIsolate());
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002330
2331 v8::Handle<v8::String> value = v8_str("val string");
2332 Smi* hash = Smi::FromInt(321);
2333 Heap* heap = Isolate::Current()->heap();
2334
2335 for (int i = 0; i < 2; i++) {
2336 // Store identity hash first and common hidden property second.
2337 v8::Handle<v8::Object> obj = v8::Object::New();
2338 Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
2339 CHECK(internal_obj->HasFastProperties());
2340
2341 // In the first iteration, set hidden value first and identity hash second.
2342 // In the second iteration, reverse the order.
2343 if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
2344 MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
2345 ALLOW_CREATION);
2346 CHECK(!maybe_obj->IsFailure());
2347 if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
2348
2349 // Check values.
2350 CHECK_EQ(hash,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002351 internal_obj->GetHiddenProperty(heap->identity_hash_string()));
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002352 CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
2353
2354 // Check size.
2355 DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
2356 ObjectHashTable* hashtable = ObjectHashTable::cast(
2357 internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
2358 // HashTable header (5) and 4 initial entries (8).
2359 CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
2360 }
2361}
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002362
2363
2364TEST(IncrementalMarkingClearsTypeFeedbackCells) {
2365 if (i::FLAG_always_opt) return;
2366 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002367 v8::HandleScope scope(env->GetIsolate());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002368 v8::Local<v8::Value> fun1, fun2;
2369
2370 {
2371 LocalContext env;
2372 CompileRun("function fun() {};");
2373 fun1 = env->Global()->Get(v8_str("fun"));
2374 }
2375
2376 {
2377 LocalContext env;
2378 CompileRun("function fun() {};");
2379 fun2 = env->Global()->Get(v8_str("fun"));
2380 }
2381
2382 // Prepare function f that contains type feedback for closures
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002383 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002384 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1);
2385 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2);
2386 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
2387 Handle<JSFunction> f =
2388 v8::Utils::OpenHandle(
2389 *v8::Handle<v8::Function>::Cast(
2390 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2391 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast(
2392 f->shared()->code()->type_feedback_info())->type_feedback_cells());
2393
2394 CHECK_EQ(2, cells->CellCount());
2395 CHECK(cells->Cell(0)->value()->IsJSFunction());
2396 CHECK(cells->Cell(1)->value()->IsJSFunction());
2397
2398 SimulateIncrementalMarking();
2399 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2400
2401 CHECK_EQ(2, cells->CellCount());
2402 CHECK(cells->Cell(0)->value()->IsTheHole());
2403 CHECK(cells->Cell(1)->value()->IsTheHole());
2404}
2405
2406
2407static Code* FindFirstIC(Code* code, Code::Kind kind) {
2408 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
2409 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
2410 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
2411 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
2412 for (RelocIterator it(code, mask); !it.done(); it.next()) {
2413 RelocInfo* info = it.rinfo();
2414 Code* target = Code::GetCodeFromTargetAddress(info->target_address());
2415 if (target->is_inline_cache_stub() && target->kind() == kind) {
2416 return target;
2417 }
2418 }
2419 return NULL;
2420}
2421
2422
2423TEST(IncrementalMarkingPreservesMonomorhpicIC) {
2424 if (i::FLAG_always_opt) return;
2425 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002426 v8::HandleScope scope(env->GetIsolate());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002427
2428 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002429 // originating from the same native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002430 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
2431 "function f(o) { return o.x; } f(obj); f(obj);");
2432 Handle<JSFunction> f =
2433 v8::Utils::OpenHandle(
2434 *v8::Handle<v8::Function>::Cast(
2435 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2436
2437 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2438 CHECK(ic_before->ic_state() == MONOMORPHIC);
2439
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002440 SimulateIncrementalMarking();
2441 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2442
2443 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2444 CHECK(ic_after->ic_state() == MONOMORPHIC);
2445}
2446
2447
2448TEST(IncrementalMarkingClearsMonomorhpicIC) {
2449 if (i::FLAG_always_opt) return;
2450 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002451 v8::HandleScope scope(env->GetIsolate());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002452 v8::Local<v8::Value> obj1;
2453
2454 {
2455 LocalContext env;
2456 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2457 obj1 = env->Global()->Get(v8_str("obj"));
2458 }
2459
2460 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002461 // originating from a different native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002462 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2463 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
2464 Handle<JSFunction> f =
2465 v8::Utils::OpenHandle(
2466 *v8::Handle<v8::Function>::Cast(
2467 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2468
2469 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2470 CHECK(ic_before->ic_state() == MONOMORPHIC);
2471
2472 // Fire context dispose notification.
2473 v8::V8::ContextDisposedNotification();
2474 SimulateIncrementalMarking();
2475 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2476
2477 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2478 CHECK(ic_after->ic_state() == UNINITIALIZED);
2479}
2480
2481
2482TEST(IncrementalMarkingClearsPolymorhpicIC) {
2483 if (i::FLAG_always_opt) return;
2484 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002485 v8::HandleScope scope(env->GetIsolate());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002486 v8::Local<v8::Value> obj1, obj2;
2487
2488 {
2489 LocalContext env;
2490 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2491 obj1 = env->Global()->Get(v8_str("obj"));
2492 }
2493
2494 {
2495 LocalContext env;
2496 CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
2497 obj2 = env->Global()->Get(v8_str("obj"));
2498 }
2499
2500 // Prepare function f that contains a polymorphic IC for objects
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002501 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002502 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2503 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2);
2504 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
2505 Handle<JSFunction> f =
2506 v8::Utils::OpenHandle(
2507 *v8::Handle<v8::Function>::Cast(
2508 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2509
2510 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002511 CHECK(ic_before->ic_state() == POLYMORPHIC);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002512
2513 // Fire context dispose notification.
2514 v8::V8::ContextDisposedNotification();
2515 SimulateIncrementalMarking();
2516 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2517
2518 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2519 CHECK(ic_after->ic_state() == UNINITIALIZED);
2520}
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002521
2522
2523class SourceResource: public v8::String::ExternalAsciiStringResource {
2524 public:
2525 explicit SourceResource(const char* data)
2526 : data_(data), length_(strlen(data)) { }
2527
2528 virtual void Dispose() {
2529 i::DeleteArray(data_);
2530 data_ = NULL;
2531 }
2532
2533 const char* data() const { return data_; }
2534
2535 size_t length() const { return length_; }
2536
2537 bool IsDisposed() { return data_ == NULL; }
2538
2539 private:
2540 const char* data_;
2541 size_t length_;
2542};
2543
2544
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002545void ReleaseStackTraceDataTest(const char* source) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002546 // Test that the data retained by the Error.stack accessor is released
2547 // after the first time the accessor is fired. We use external string
2548 // to check whether the data is being released since the external string
2549 // resource's callback is fired when the external string is GC'ed.
2550 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002551 v8::HandleScope scope(env->GetIsolate());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002552 SourceResource* resource = new SourceResource(i::StrDup(source));
2553 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002554 v8::HandleScope scope(env->GetIsolate());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002555 v8::Handle<v8::String> source_string = v8::String::NewExternal(resource);
2556 v8::Script::Compile(source_string)->Run();
2557 CHECK(!resource->IsDisposed());
2558 }
2559 HEAP->CollectAllAvailableGarbage();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002560
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002561 // External source has been released.
2562 CHECK(resource->IsDisposed());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002563 delete resource;
2564}
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002565
2566
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002567TEST(ReleaseStackTraceData) {
2568 static const char* source1 = "var error = null; "
2569 /* Normal Error */ "try { "
2570 " throw new Error(); "
2571 "} catch (e) { "
2572 " error = e; "
2573 "} ";
2574 static const char* source2 = "var error = null; "
2575 /* Stack overflow */ "try { "
2576 " (function f() { f(); })(); "
2577 "} catch (e) { "
2578 " error = e; "
2579 "} ";
2580 ReleaseStackTraceDataTest(source1);
2581 ReleaseStackTraceDataTest(source2);
2582}
2583
2584
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002585TEST(Regression144230) {
2586 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002587 Isolate* isolate = Isolate::Current();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002588 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002589 HandleScope scope(isolate);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002590
2591 // First make sure that the uninitialized CallIC stub is on a single page
2592 // that will later be selected as an evacuation candidate.
2593 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002594 HandleScope inner_scope(isolate);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002595 AlwaysAllocateScope always_allocate;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002596 SimulateFullSpace(heap->code_space());
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002597 isolate->stub_cache()->ComputeCallInitialize(9, RelocInfo::CODE_TARGET);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002598 }
2599
2600 // Second compile a CallIC and execute it once so that it gets patched to
2601 // the pre-monomorphic stub. These code objects are on yet another page.
2602 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002603 HandleScope inner_scope(isolate);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002604 AlwaysAllocateScope always_allocate;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002605 SimulateFullSpace(heap->code_space());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002606 CompileRun("var o = { f:function(a,b,c,d,e,f,g,h,i) {}};"
2607 "function call() { o.f(1,2,3,4,5,6,7,8,9); };"
2608 "call();");
2609 }
2610
2611 // Third we fill up the last page of the code space so that it does not get
2612 // chosen as an evacuation candidate.
2613 {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002614 HandleScope inner_scope(isolate);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002615 AlwaysAllocateScope always_allocate;
2616 CompileRun("for (var i = 0; i < 2000; i++) {"
2617 " eval('function f' + i + '() { return ' + i +'; };' +"
2618 " 'f' + i + '();');"
2619 "}");
2620 }
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002621 heap->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002622
2623 // Fourth is the tricky part. Make sure the code containing the CallIC is
2624 // visited first without clearing the IC. The shared function info is then
2625 // visited later, causing the CallIC to be cleared.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002626 Handle<String> name = isolate->factory()->InternalizeUtf8String("call");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002627 Handle<GlobalObject> global(isolate->context()->global_object());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002628 MaybeObject* maybe_call = global->GetProperty(*name);
2629 JSFunction* call = JSFunction::cast(maybe_call->ToObjectChecked());
2630 USE(global->SetProperty(*name, Smi::FromInt(0), NONE, kNonStrictMode));
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002631 isolate->compilation_cache()->Clear();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002632 call->shared()->set_ic_age(heap->global_ic_age() + 1);
2633 Handle<Object> call_code(call->code(), isolate);
2634 Handle<Object> call_function(call, isolate);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002635
2636 // Now we are ready to mess up the heap.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002637 heap->CollectAllGarbage(Heap::kReduceMemoryFootprintMask);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002638
2639 // Either heap verification caught the problem already or we go kaboom once
2640 // the CallIC is executed the next time.
2641 USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode));
2642 CompileRun("call();");
2643}
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002644
2645
2646TEST(Regress159140) {
2647 i::FLAG_allow_natives_syntax = true;
2648 i::FLAG_flush_code_incrementally = true;
2649 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002650 Isolate* isolate = Isolate::Current();
2651 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002652 HandleScope scope(isolate);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002653
2654 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002655 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002656
2657 // Prepare several closures that are all eligible for code flushing
2658 // because all reachable ones are not optimized. Make sure that the
2659 // optimized code object is directly reachable through a handle so
2660 // that it is marked black during incremental marking.
2661 Handle<Code> code;
2662 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002663 HandleScope inner_scope(isolate);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002664 CompileRun("function h(x) {}"
2665 "function mkClosure() {"
2666 " return function(x) { return x + 1; };"
2667 "}"
2668 "var f = mkClosure();"
2669 "var g = mkClosure();"
2670 "f(1); f(2);"
2671 "g(1); g(2);"
2672 "h(1); h(2);"
2673 "%OptimizeFunctionOnNextCall(f); f(3);"
2674 "%OptimizeFunctionOnNextCall(h); h(3);");
2675
2676 Handle<JSFunction> f =
2677 v8::Utils::OpenHandle(
2678 *v8::Handle<v8::Function>::Cast(
2679 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2680 CHECK(f->is_compiled());
2681 CompileRun("f = null;");
2682
2683 Handle<JSFunction> g =
2684 v8::Utils::OpenHandle(
2685 *v8::Handle<v8::Function>::Cast(
2686 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2687 CHECK(g->is_compiled());
2688 const int kAgingThreshold = 6;
2689 for (int i = 0; i < kAgingThreshold; i++) {
2690 g->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2691 }
2692
2693 code = inner_scope.CloseAndEscape(Handle<Code>(f->code()));
2694 }
2695
2696 // Simulate incremental marking so that the functions are enqueued as
2697 // code flushing candidates. Then optimize one function. Finally
2698 // finish the GC to complete code flushing.
2699 SimulateIncrementalMarking();
2700 CompileRun("%OptimizeFunctionOnNextCall(g); g(3);");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002701 heap->CollectAllGarbage(Heap::kNoGCFlags);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002702
2703 // Unoptimized code is missing and the deoptimizer will go ballistic.
2704 CompileRun("g('bozo');");
2705}
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002706
2707
2708TEST(Regress165495) {
2709 i::FLAG_allow_natives_syntax = true;
2710 i::FLAG_flush_code_incrementally = true;
2711 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002712 Isolate* isolate = Isolate::Current();
2713 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002714 HandleScope scope(isolate);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002715
2716 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002717 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002718
2719 // Prepare an optimized closure that the optimized code map will get
2720 // populated. Then age the unoptimized code to trigger code flushing
2721 // but make sure the optimized code is unreachable.
2722 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002723 HandleScope inner_scope(isolate);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002724 CompileRun("function mkClosure() {"
2725 " return function(x) { return x + 1; };"
2726 "}"
2727 "var f = mkClosure();"
2728 "f(1); f(2);"
2729 "%OptimizeFunctionOnNextCall(f); f(3);");
2730
2731 Handle<JSFunction> f =
2732 v8::Utils::OpenHandle(
2733 *v8::Handle<v8::Function>::Cast(
2734 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2735 CHECK(f->is_compiled());
2736 const int kAgingThreshold = 6;
2737 for (int i = 0; i < kAgingThreshold; i++) {
2738 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2739 }
2740
2741 CompileRun("f = null;");
2742 }
2743
2744 // Simulate incremental marking so that unoptimized code is flushed
2745 // even though it still is cached in the optimized code map.
2746 SimulateIncrementalMarking();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002747 heap->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002748
2749 // Make a new closure that will get code installed from the code map.
2750 // Unoptimized code is missing and the deoptimizer will go ballistic.
2751 CompileRun("var g = mkClosure(); g('bozo');");
2752}
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002753
2754
2755TEST(Regress169209) {
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002756 i::FLAG_stress_compaction = false;
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002757 i::FLAG_allow_natives_syntax = true;
2758 i::FLAG_flush_code_incrementally = true;
2759 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002760 Isolate* isolate = Isolate::Current();
2761 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002762 HandleScope scope(isolate);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002763
2764 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002765 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002766
2767 // Prepare a shared function info eligible for code flushing for which
2768 // the unoptimized code will be replaced during optimization.
2769 Handle<SharedFunctionInfo> shared1;
2770 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002771 HandleScope inner_scope(isolate);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002772 CompileRun("function f() { return 'foobar'; }"
2773 "function g(x) { if (x) f(); }"
2774 "f();"
2775 "g(false);"
2776 "g(false);");
2777
2778 Handle<JSFunction> f =
2779 v8::Utils::OpenHandle(
2780 *v8::Handle<v8::Function>::Cast(
2781 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2782 CHECK(f->is_compiled());
2783 const int kAgingThreshold = 6;
2784 for (int i = 0; i < kAgingThreshold; i++) {
2785 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2786 }
2787
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002788 shared1 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002789 }
2790
2791 // Prepare a shared function info eligible for code flushing that will
2792 // represent the dangling tail of the candidate list.
2793 Handle<SharedFunctionInfo> shared2;
2794 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002795 HandleScope inner_scope(isolate);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002796 CompileRun("function flushMe() { return 0; }"
2797 "flushMe(1);");
2798
2799 Handle<JSFunction> f =
2800 v8::Utils::OpenHandle(
2801 *v8::Handle<v8::Function>::Cast(
2802 v8::Context::GetCurrent()->Global()->Get(v8_str("flushMe"))));
2803 CHECK(f->is_compiled());
2804 const int kAgingThreshold = 6;
2805 for (int i = 0; i < kAgingThreshold; i++) {
2806 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2807 }
2808
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002809 shared2 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002810 }
2811
2812 // Simulate incremental marking and collect code flushing candidates.
2813 SimulateIncrementalMarking();
2814 CHECK(shared1->code()->gc_metadata() != NULL);
2815
2816 // Optimize function and make sure the unoptimized code is replaced.
2817#ifdef DEBUG
2818 FLAG_stop_at = "f";
2819#endif
2820 CompileRun("%OptimizeFunctionOnNextCall(g);"
2821 "g(false);");
2822
2823 // Finish garbage collection cycle.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002824 heap->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002825 CHECK(shared1->code()->gc_metadata() == NULL);
2826}
yangguo@chromium.org28381b42013-01-21 14:39:38 +00002827
2828
2829// Helper function that simulates a fill new-space in the heap.
2830static inline void AllocateAllButNBytes(v8::internal::NewSpace* space,
2831 int extra_bytes) {
2832 int space_remaining = static_cast<int>(
2833 *space->allocation_limit_address() - *space->allocation_top_address());
2834 CHECK(space_remaining >= extra_bytes);
2835 int new_linear_size = space_remaining - extra_bytes;
2836 v8::internal::MaybeObject* maybe = space->AllocateRaw(new_linear_size);
2837 v8::internal::FreeListNode* node = v8::internal::FreeListNode::cast(maybe);
2838 node->set_size(space->heap(), new_linear_size);
2839}
2840
2841
2842TEST(Regress169928) {
2843 i::FLAG_allow_natives_syntax = true;
2844 i::FLAG_crankshaft = false;
2845 InitializeVM();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002846 v8::HandleScope scope(env->GetIsolate());
yangguo@chromium.org28381b42013-01-21 14:39:38 +00002847
2848 // Some flags turn Scavenge collections into Mark-sweep collections
2849 // and hence are incompatible with this test case.
2850 if (FLAG_gc_global || FLAG_stress_compaction) return;
2851
2852 // Prepare the environment
2853 CompileRun("function fastliteralcase(literal, value) {"
2854 " literal[0] = value;"
2855 " return literal;"
2856 "}"
2857 "function get_standard_literal() {"
2858 " var literal = [1, 2, 3];"
2859 " return literal;"
2860 "}"
2861 "obj = fastliteralcase(get_standard_literal(), 1);"
2862 "obj = fastliteralcase(get_standard_literal(), 1.5);"
2863 "obj = fastliteralcase(get_standard_literal(), 2);");
2864
2865 // prepare the heap
2866 v8::Local<v8::String> mote_code_string =
2867 v8_str("fastliteralcase(mote, 2.5);");
2868
2869 v8::Local<v8::String> array_name = v8_str("mote");
2870 v8::Context::GetCurrent()->Global()->Set(array_name, v8::Int32::New(0));
2871
2872 // First make sure we flip spaces
2873 HEAP->CollectGarbage(NEW_SPACE);
2874
2875 // Allocate the object.
2876 Handle<FixedArray> array_data = FACTORY->NewFixedArray(2, NOT_TENURED);
2877 array_data->set(0, Smi::FromInt(1));
2878 array_data->set(1, Smi::FromInt(2));
2879
2880 AllocateAllButNBytes(HEAP->new_space(),
2881 JSArray::kSize + AllocationSiteInfo::kSize +
2882 kPointerSize);
2883
2884 Handle<JSArray> array = FACTORY->NewJSArrayWithElements(array_data,
2885 FAST_SMI_ELEMENTS,
2886 NOT_TENURED);
2887
2888 CHECK_EQ(Smi::FromInt(2), array->length());
2889 CHECK(array->HasFastSmiOrObjectElements());
2890
2891 // We need filler the size of AllocationSiteInfo object, plus an extra
2892 // fill pointer value.
2893 MaybeObject* maybe_object = HEAP->AllocateRaw(
2894 AllocationSiteInfo::kSize + kPointerSize, NEW_SPACE, OLD_POINTER_SPACE);
2895 Object* obj = NULL;
2896 CHECK(maybe_object->ToObject(&obj));
2897 Address addr_obj = reinterpret_cast<Address>(
2898 reinterpret_cast<byte*>(obj - kHeapObjectTag));
2899 HEAP->CreateFillerObjectAt(addr_obj,
2900 AllocationSiteInfo::kSize + kPointerSize);
2901
2902 // Give the array a name, making sure not to allocate strings.
2903 v8::Handle<v8::Object> array_obj = v8::Utils::ToLocal(array);
2904 v8::Context::GetCurrent()->Global()->Set(array_name, array_obj);
2905
2906 // This should crash with a protection violation if we are running a build
2907 // with the bug.
2908 AlwaysAllocateScope aa_scope;
2909 v8::Script::Compile(mote_code_string)->Run();
2910}
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002911
2912
2913TEST(Regress168801) {
2914 i::FLAG_always_compact = true;
2915 i::FLAG_cache_optimized_code = false;
2916 i::FLAG_allow_natives_syntax = true;
2917 i::FLAG_flush_code_incrementally = true;
2918 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002919 Isolate* isolate = Isolate::Current();
2920 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002921 HandleScope scope(isolate);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002922
2923 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002924 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002925
2926 // Ensure the code ends up on an evacuation candidate.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002927 SimulateFullSpace(heap->code_space());
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002928
2929 // Prepare an unoptimized function that is eligible for code flushing.
2930 Handle<JSFunction> function;
2931 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002932 HandleScope inner_scope(isolate);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002933 CompileRun("function mkClosure() {"
2934 " return function(x) { return x + 1; };"
2935 "}"
2936 "var f = mkClosure();"
2937 "f(1); f(2);");
2938
2939 Handle<JSFunction> f =
2940 v8::Utils::OpenHandle(
2941 *v8::Handle<v8::Function>::Cast(
2942 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2943 CHECK(f->is_compiled());
2944 const int kAgingThreshold = 6;
2945 for (int i = 0; i < kAgingThreshold; i++) {
2946 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2947 }
2948
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002949 function = inner_scope.CloseAndEscape(handle(*f, isolate));
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002950 }
2951
2952 // Simulate incremental marking so that unoptimized function is enqueued as a
2953 // candidate for code flushing. The shared function info however will not be
2954 // explicitly enqueued.
2955 SimulateIncrementalMarking();
2956
2957 // Now optimize the function so that it is taken off the candidate list.
2958 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002959 HandleScope inner_scope(isolate);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002960 CompileRun("%OptimizeFunctionOnNextCall(f); f(3);");
2961 }
2962
2963 // This cycle will bust the heap and subsequent cycles will go ballistic.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002964 heap->CollectAllGarbage(Heap::kNoGCFlags);
2965 heap->CollectAllGarbage(Heap::kNoGCFlags);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002966}
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002967
2968
2969TEST(Regress173458) {
2970 i::FLAG_always_compact = true;
2971 i::FLAG_cache_optimized_code = false;
2972 i::FLAG_allow_natives_syntax = true;
2973 i::FLAG_flush_code_incrementally = true;
2974 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002975 Isolate* isolate = Isolate::Current();
2976 Heap* heap = isolate->heap();
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00002977 HandleScope scope(isolate);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002978
2979 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002980 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002981
2982 // Ensure the code ends up on an evacuation candidate.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002983 SimulateFullSpace(heap->code_space());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002984
2985 // Prepare an unoptimized function that is eligible for code flushing.
2986 Handle<JSFunction> function;
2987 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002988 HandleScope inner_scope(isolate);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002989 CompileRun("function mkClosure() {"
2990 " return function(x) { return x + 1; };"
2991 "}"
2992 "var f = mkClosure();"
2993 "f(1); f(2);");
2994
2995 Handle<JSFunction> f =
2996 v8::Utils::OpenHandle(
2997 *v8::Handle<v8::Function>::Cast(
2998 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2999 CHECK(f->is_compiled());
3000 const int kAgingThreshold = 6;
3001 for (int i = 0; i < kAgingThreshold; i++) {
3002 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
3003 }
3004
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00003005 function = inner_scope.CloseAndEscape(handle(*f, isolate));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003006 }
3007
3008 // Simulate incremental marking so that unoptimized function is enqueued as a
3009 // candidate for code flushing. The shared function info however will not be
3010 // explicitly enqueued.
3011 SimulateIncrementalMarking();
3012
3013 // Now enable the debugger which in turn will disable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00003014 CHECK(isolate->debug()->Load());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003015
3016 // This cycle will bust the heap and subsequent cycles will go ballistic.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00003017 heap->CollectAllGarbage(Heap::kNoGCFlags);
3018 heap->CollectAllGarbage(Heap::kNoGCFlags);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003019}
svenpanne@chromium.org876cca82013-03-18 14:43:20 +00003020
3021
3022class DummyVisitor : public ObjectVisitor {
3023 public:
3024 void VisitPointers(Object** start, Object** end) { }
3025};
3026
3027
3028TEST(DeferredHandles) {
3029 InitializeVM();
3030 Isolate* isolate = Isolate::Current();
3031 Heap* heap = isolate->heap();
3032 v8::HandleScope scope;
3033 v8::ImplementationUtilities::HandleScopeData* data =
3034 isolate->handle_scope_data();
3035 Handle<Object> init(heap->empty_string(), isolate);
3036 while (data->next < data->limit) {
3037 Handle<Object> obj(heap->empty_string(), isolate);
3038 }
3039 // An entire block of handles has been filled.
3040 // Next handle would require a new block.
3041 ASSERT(data->next == data->limit);
3042
3043 DeferredHandleScope deferred(isolate);
3044 DummyVisitor visitor;
3045 isolate->handle_scope_implementer()->Iterate(&visitor);
3046 deferred.Detach();
3047}