blob: 7cdae6b36c3a7e99d7ce6797179cb3c067675a00 [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();
46 v8::HandleScope scope;
47 env->Enter();
48}
49
50
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000051// Go through all incremental marking steps in one swoop.
52static void SimulateIncrementalMarking() {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000053 MarkCompactCollector* collector = HEAP->mark_compact_collector();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000054 IncrementalMarking* marking = HEAP->incremental_marking();
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000055 if (collector->IsConcurrentSweepingInProgress()) {
56 collector->WaitUntilSweepingCompleted();
57 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000058 CHECK(marking->IsMarking() || marking->IsStopped());
59 if (marking->IsStopped()) {
60 marking->Start();
61 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000062 CHECK(marking->IsMarking());
63 while (!marking->IsComplete()) {
64 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
65 }
66 CHECK(marking->IsComplete());
67}
68
69
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000070static void CheckMap(Map* map, int type, int instance_size) {
71 CHECK(map->IsHeapObject());
72#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000073 CHECK(HEAP->Contains(map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000074#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000075 CHECK_EQ(HEAP->meta_map(), map->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000076 CHECK_EQ(type, map->instance_type());
77 CHECK_EQ(instance_size, map->instance_size());
78}
79
80
81TEST(HeapMaps) {
82 InitializeVM();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000083 CheckMap(HEAP->meta_map(), MAP_TYPE, Map::kSize);
84 CheckMap(HEAP->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
85 CheckMap(HEAP->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
86 CheckMap(HEAP->string_map(), STRING_TYPE, kVariableSizeSentinel);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000087}
88
89
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000090static void CheckOddball(Isolate* isolate, Object* obj, const char* string) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000091 CHECK(obj->IsOddball());
92 bool exc;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000093 Object* print_string =
94 *Execution::ToString(Handle<Object>(obj, isolate), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000095 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000096}
97
98
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000099static void CheckSmi(Isolate* isolate, int value, const char* string) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000100 bool exc;
101 Object* print_string =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000102 *Execution::ToString(Handle<Object>(Smi::FromInt(value), isolate), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000103 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000104}
105
106
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000107static void CheckNumber(Isolate* isolate, double value, const char* string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000108 Object* obj = HEAP->NumberFromDouble(value)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000109 CHECK(obj->IsNumber());
110 bool exc;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000111 Object* print_string =
112 *Execution::ToString(Handle<Object>(obj, isolate), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000113 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000114}
115
116
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000117static void CheckFindCodeObject(Isolate* isolate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000118 // Test FindCodeObject
119#define __ assm.
120
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000121 Assembler assm(isolate, NULL, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000122
123 __ nop(); // supported on all architectures
124
125 CodeDesc desc;
126 assm.GetCode(&desc);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000127 Heap* heap = isolate->heap();
128 Object* code = heap->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000129 desc,
130 Code::ComputeFlags(Code::STUB),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000131 Handle<Code>())->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000132 CHECK(code->IsCode());
133
134 HeapObject* obj = HeapObject::cast(code);
135 Address obj_addr = obj->address();
136
137 for (int i = 0; i < obj->Size(); i += kPointerSize) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000138 Object* found = heap->FindCodeObject(obj_addr + i);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000139 CHECK_EQ(code, found);
140 }
141
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000142 Object* copy = heap->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000143 desc,
144 Code::ComputeFlags(Code::STUB),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000145 Handle<Code>())->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000146 CHECK(copy->IsCode());
147 HeapObject* obj_copy = HeapObject::cast(copy);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000148 Object* not_right = heap->FindCodeObject(obj_copy->address() +
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000149 obj_copy->Size() / 2);
150 CHECK(not_right != code);
151}
152
153
154TEST(HeapObjects) {
155 InitializeVM();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000156 Isolate* isolate = Isolate::Current();
157 Heap* heap = isolate->heap();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000158
159 v8::HandleScope sc;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000160 Object* value = heap->NumberFromDouble(1.000123)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000161 CHECK(value->IsHeapNumber());
162 CHECK(value->IsNumber());
163 CHECK_EQ(1.000123, value->Number());
164
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000165 value = heap->NumberFromDouble(1.0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000166 CHECK(value->IsSmi());
167 CHECK(value->IsNumber());
168 CHECK_EQ(1.0, value->Number());
169
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000170 value = heap->NumberFromInt32(1024)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000171 CHECK(value->IsSmi());
172 CHECK(value->IsNumber());
173 CHECK_EQ(1024.0, value->Number());
174
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000175 value = heap->NumberFromInt32(Smi::kMinValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000176 CHECK(value->IsSmi());
177 CHECK(value->IsNumber());
178 CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
179
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000180 value = heap->NumberFromInt32(Smi::kMaxValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000181 CHECK(value->IsSmi());
182 CHECK(value->IsNumber());
183 CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value());
184
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000185#ifndef V8_TARGET_ARCH_X64
186 // TODO(lrn): We need a NumberFromIntptr function in order to test this.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000187 value = heap->NumberFromInt32(Smi::kMinValue - 1)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000188 CHECK(value->IsHeapNumber());
189 CHECK(value->IsNumber());
190 CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000191#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000192
lrn@chromium.org303ada72010-10-27 09:33:13 +0000193 MaybeObject* maybe_value =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000194 heap->NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000195 value = maybe_value->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000196 CHECK(value->IsHeapNumber());
197 CHECK(value->IsNumber());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000198 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
199 value->Number());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000200
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000201 maybe_value = heap->NumberFromUint32(static_cast<uint32_t>(1) << 31);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000202 value = maybe_value->ToObjectChecked();
203 CHECK(value->IsHeapNumber());
204 CHECK(value->IsNumber());
205 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(1) << 31),
206 value->Number());
207
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000208 // nan oddball checks
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000209 CHECK(heap->nan_value()->IsNumber());
210 CHECK(isnan(heap->nan_value()->Number()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000211
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000212 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest "));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000213 CHECK(s->IsString());
214 CHECK_EQ(10, s->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000215
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000216 String* object_string = String::cast(heap->Object_string());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000217 CHECK(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000218 Isolate::Current()->context()->global_object()->HasLocalProperty(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000219 object_string));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000220
221 // Check ToString for oddballs
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000222 CheckOddball(isolate, heap->true_value(), "true");
223 CheckOddball(isolate, heap->false_value(), "false");
224 CheckOddball(isolate, heap->null_value(), "null");
225 CheckOddball(isolate, heap->undefined_value(), "undefined");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000226
227 // Check ToString for Smis
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000228 CheckSmi(isolate, 0, "0");
229 CheckSmi(isolate, 42, "42");
230 CheckSmi(isolate, -42, "-42");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000231
232 // Check ToString for Numbers
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000233 CheckNumber(isolate, 1.1, "1.1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000234
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000235 CheckFindCodeObject(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000236}
237
238
239TEST(Tagging) {
240 InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000241 int request = 24;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000242 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000243 CHECK(Smi::FromInt(42)->IsSmi());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000244 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000245 CHECK_EQ(NEW_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000246 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000247 CHECK_EQ(OLD_POINTER_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000248 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000249 CHECK(Failure::Exception()->IsFailure());
250 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
251 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
252}
253
254
255TEST(GarbageCollection) {
256 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000257 Isolate* isolate = Isolate::Current();
258 Heap* heap = isolate->heap();
259 Factory* factory = isolate->factory();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000260
261 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000262 // Check GC.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000263 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000264
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000265 Handle<String> name = factory->InternalizeUtf8String("theFunction");
266 Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
267 Handle<String> prop_namex = factory->InternalizeUtf8String("theSlotx");
268 Handle<String> obj_name = factory->InternalizeUtf8String("theObject");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000269
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000270 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000271 HandleScope inner_scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000272 // Allocate a function and keep it in global object's property.
273 Handle<JSFunction> function =
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000274 factory->NewFunction(name, factory->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000275 Handle<Map> initial_map =
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000276 factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000277 function->set_initial_map(*initial_map);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000278 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000279 *name, *function, NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000280 // Allocate an object. Unrooted after leaving the scope.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000281 Handle<JSObject> obj = factory->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000282 obj->SetProperty(
283 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
284 obj->SetProperty(
285 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000286
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000287 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
288 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
289 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000290
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000291 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000292
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000293 // Function should be alive.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000294 CHECK(Isolate::Current()->context()->global_object()->
295 HasLocalProperty(*name));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000296 // Check function is retained.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000297 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000298 GetProperty(*name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000299 CHECK(func_value->IsJSFunction());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000300 Handle<JSFunction> function(JSFunction::cast(func_value));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000301
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000302 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000303 HandleScope inner_scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000304 // Allocate another object, make it reachable from global.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000305 Handle<JSObject> obj = factory->NewJSObject(function);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000306 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000307 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked();
308 obj->SetProperty(
309 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000310 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000311
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000312 // After gc, it should survive.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000313 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000314
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000315 CHECK(Isolate::Current()->context()->global_object()->
316 HasLocalProperty(*obj_name));
317 CHECK(Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000318 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000319 Object* obj = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000320 GetProperty(*obj_name)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000321 JSObject* js_obj = JSObject::cast(obj);
322 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000323}
324
325
326static void VerifyStringAllocation(const char* string) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000327 v8::HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000328 Handle<String> s = FACTORY->NewStringFromUtf8(CStrVector(string));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000329 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000330 for (int index = 0; index < s->length(); index++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000331 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
332 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000333}
334
335
336TEST(String) {
337 InitializeVM();
338
339 VerifyStringAllocation("a");
340 VerifyStringAllocation("ab");
341 VerifyStringAllocation("abc");
342 VerifyStringAllocation("abcd");
343 VerifyStringAllocation("fiskerdrengen er paa havet");
344}
345
346
347TEST(LocalHandles) {
348 InitializeVM();
349
350 v8::HandleScope scope;
351 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
623 v8::HandleScope sc;
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
646 v8::HandleScope sc;
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
719 v8::HandleScope sc;
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
743 v8::HandleScope sc;
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
790 v8::HandleScope sc;
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
838
839 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
840 for (int length = 0; length < 100; length++) {
841 v8::HandleScope scope;
842 char* non_ascii = NewArray<char>(3 * length + 1);
843 char* ascii = NewArray<char>(length + 1);
844 non_ascii[3 * length] = 0;
845 ascii[length] = 0;
846 for (int i = 0; i < length; i++) {
847 ascii[i] = 'a';
848 non_ascii[3 * i] = chars[0];
849 non_ascii[3 * i + 1] = chars[1];
850 non_ascii[3 * i + 2] = chars[2];
851 }
852 Handle<String> non_ascii_sym =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000853 FACTORY->InternalizeUtf8String(
854 Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000855 CHECK_EQ(length, non_ascii_sym->length());
856 Handle<String> ascii_sym =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000857 FACTORY->InternalizeOneByteString(OneByteVector(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000858 CHECK_EQ(length, ascii_sym->length());
859 Handle<String> non_ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000860 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000861 non_ascii_str->Hash();
862 CHECK_EQ(length, non_ascii_str->length());
863 Handle<String> ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000864 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000865 ascii_str->Hash();
866 CHECK_EQ(length, ascii_str->length());
867 DeleteArray(non_ascii);
868 DeleteArray(ascii);
869 }
870}
871
872
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000873static int ObjectsFoundInHeap(Heap* heap, Handle<Object> objs[], int size) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000874 // Count the number of objects found in the heap.
875 int found_count = 0;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000876 HeapIterator iterator(heap);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000877 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000878 for (int i = 0; i < size; i++) {
879 if (*objs[i] == obj) {
880 found_count++;
881 }
882 }
883 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000884 return found_count;
885}
886
887
888TEST(Iteration) {
889 InitializeVM();
890 v8::HandleScope scope;
891
892 // Array of objects to scan haep for.
893 const int objs_count = 6;
894 Handle<Object> objs[objs_count];
895 int next_objs_index = 0;
896
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000897 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000898 objs[next_objs_index++] = FACTORY->NewJSArray(10);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000899 objs[next_objs_index++] = FACTORY->NewJSArray(10,
900 FAST_HOLEY_ELEMENTS,
901 TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000902
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000903 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000904 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000905 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000906 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000907 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000908
909 // Allocate a large string (for large object space).
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000910 int large_size = Page::kMaxNonCodeHeapObjectSize + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000911 char* str = new char[large_size];
912 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
913 str[large_size - 1] = '\0';
914 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000915 FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000916 delete[] str;
917
918 // Add a Map object to look for.
919 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
920
921 CHECK_EQ(objs_count, next_objs_index);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000922 CHECK_EQ(objs_count, ObjectsFoundInHeap(HEAP, objs, objs_count));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000923}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000924
925
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000926TEST(EmptyHandleEscapeFrom) {
927 InitializeVM();
928
929 v8::HandleScope scope;
930 Handle<JSObject> runaway;
931
932 {
933 v8::HandleScope nested;
934 Handle<JSObject> empty;
935 runaway = empty.EscapeFrom(&nested);
936 }
937
938 CHECK(runaway.is_null());
939}
940
941
942static int LenFromSize(int size) {
943 return (size - FixedArray::kHeaderSize) / kPointerSize;
944}
945
946
947TEST(Regression39128) {
948 // Test case for crbug.com/39128.
949 InitializeVM();
950
951 // Increase the chance of 'bump-the-pointer' allocation in old space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000952 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000953
954 v8::HandleScope scope;
955
956 // The plan: create JSObject which references objects in new space.
957 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000958 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000959
960 // Step 1: prepare a map for the object. We add 1 inobject property to it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000961 Handle<JSFunction> object_ctor(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000962 Isolate::Current()->native_context()->object_function());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000963 CHECK(object_ctor->has_initial_map());
964 Handle<Map> object_map(object_ctor->initial_map());
965 // Create a map with single inobject property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000966 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000967 int n_properties = my_map->inobject_properties();
968 CHECK_GT(n_properties, 0);
969
970 int object_size = my_map->instance_size();
971
972 // Step 2: allocate a lot of objects so to almost fill new space: we need
973 // just enough room to allocate JSObject and thus fill the newspace.
974
975 int allocation_amount = Min(FixedArray::kMaxSize,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000976 HEAP->MaxObjectSizeInNewSpace());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000977 int allocation_len = LenFromSize(allocation_amount);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000978 NewSpace* new_space = HEAP->new_space();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000979 Address* top_addr = new_space->allocation_top_address();
980 Address* limit_addr = new_space->allocation_limit_address();
981 while ((*limit_addr - *top_addr) > allocation_amount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000982 CHECK(!HEAP->always_allocate());
983 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
984 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000985 CHECK(new_space->Contains(array));
986 }
987
988 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000989 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000990 int fixed_array_len = LenFromSize(to_fill);
991 CHECK(fixed_array_len < FixedArray::kMaxLength);
992
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000993 CHECK(!HEAP->always_allocate());
994 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
995 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000996 CHECK(new_space->Contains(array));
997
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000998 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000999 CHECK(new_space->Contains(object));
1000 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001001 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001002 CHECK_EQ(0, jsobject->properties()->length());
1003 // Create a reference to object in new space in jsobject.
1004 jsobject->FastPropertyAtPut(-1, array);
1005
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001006 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001007
1008 // Step 4: clone jsobject, but force always allocate first to create a clone
1009 // in old pointer space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001010 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001011 AlwaysAllocateScope aa_scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001012 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001013 JSObject* clone = JSObject::cast(clone_obj);
1014 if (clone->address() != old_pointer_space_top) {
1015 // Alas, got allocated from free list, we cannot do checks.
1016 return;
1017 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001018 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001019}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001020
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001021
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001022TEST(TestCodeFlushing) {
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +00001023 // If we do not flush code this test is invalid.
1024 if (!FLAG_flush_code) return;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001025 i::FLAG_allow_natives_syntax = true;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001026 InitializeVM();
1027 v8::HandleScope scope;
1028 const char* source = "function foo() {"
1029 " var x = 42;"
1030 " var y = 42;"
1031 " var z = x + y;"
1032 "};"
1033 "foo()";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001034 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001035
1036 // This compile will add the code to the compilation cache.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001037 { v8::HandleScope scope;
1038 CompileRun(source);
1039 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001040
1041 // Check function is compiled.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001042 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001043 GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001044 CHECK(func_value->IsJSFunction());
1045 Handle<JSFunction> function(JSFunction::cast(func_value));
1046 CHECK(function->shared()->is_compiled());
1047
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001048 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001049 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1050 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001051 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001052
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001053 // Simulate several GCs that use full marking.
1054 const int kAgingThreshold = 6;
1055 for (int i = 0; i < kAgingThreshold; i++) {
1056 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1057 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001058
1059 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001060 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1061 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001062 // Call foo to get it recompiled.
1063 CompileRun("foo()");
1064 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001065 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001066}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001067
1068
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001069TEST(TestCodeFlushingIncremental) {
1070 // If we do not flush code this test is invalid.
1071 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1072 i::FLAG_allow_natives_syntax = true;
1073 InitializeVM();
1074 v8::HandleScope scope;
1075 const char* source = "function foo() {"
1076 " var x = 42;"
1077 " var y = 42;"
1078 " var z = x + y;"
1079 "};"
1080 "foo()";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001081 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001082
1083 // This compile will add the code to the compilation cache.
1084 { v8::HandleScope scope;
1085 CompileRun(source);
1086 }
1087
1088 // Check function is compiled.
1089 Object* func_value = Isolate::Current()->context()->global_object()->
1090 GetProperty(*foo_name)->ToObjectChecked();
1091 CHECK(func_value->IsJSFunction());
1092 Handle<JSFunction> function(JSFunction::cast(func_value));
1093 CHECK(function->shared()->is_compiled());
1094
1095 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001096 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1097 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001098 CHECK(function->shared()->is_compiled());
1099
1100 // Simulate several GCs that use incremental marking.
1101 const int kAgingThreshold = 6;
1102 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001103 SimulateIncrementalMarking();
1104 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1105 }
1106 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1107 CHECK(!function->is_compiled() || function->IsOptimized());
1108
1109 // This compile will compile the function again.
1110 { v8::HandleScope scope;
1111 CompileRun("foo();");
1112 }
1113
1114 // Simulate several GCs that use incremental marking but make sure
1115 // the loop breaks once the function is enqueued as a candidate.
1116 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001117 SimulateIncrementalMarking();
1118 if (!function->next_function_link()->IsUndefined()) break;
1119 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1120 }
1121
1122 // Force optimization while incremental marking is active and while
1123 // the function is enqueued as a candidate.
1124 { v8::HandleScope scope;
1125 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1126 }
1127
1128 // Simulate one final GC to make sure the candidate queue is sane.
1129 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1130 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1131 CHECK(function->is_compiled() || !function->IsOptimized());
1132}
1133
1134
1135TEST(TestCodeFlushingIncrementalScavenge) {
1136 // If we do not flush code this test is invalid.
1137 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1138 i::FLAG_allow_natives_syntax = true;
1139 InitializeVM();
1140 v8::HandleScope scope;
1141 const char* source = "var foo = function() {"
1142 " var x = 42;"
1143 " var y = 42;"
1144 " var z = x + y;"
1145 "};"
1146 "foo();"
1147 "var bar = function() {"
1148 " var x = 23;"
1149 "};"
1150 "bar();";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001151 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
1152 Handle<String> bar_name = FACTORY->InternalizeUtf8String("bar");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001153
1154 // Perfrom one initial GC to enable code flushing.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001155 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001156
1157 // This compile will add the code to the compilation cache.
1158 { v8::HandleScope scope;
1159 CompileRun(source);
1160 }
1161
1162 // Check functions are compiled.
1163 Object* func_value = Isolate::Current()->context()->global_object()->
1164 GetProperty(*foo_name)->ToObjectChecked();
1165 CHECK(func_value->IsJSFunction());
1166 Handle<JSFunction> function(JSFunction::cast(func_value));
1167 CHECK(function->shared()->is_compiled());
1168 Object* func_value2 = Isolate::Current()->context()->global_object()->
1169 GetProperty(*bar_name)->ToObjectChecked();
1170 CHECK(func_value2->IsJSFunction());
1171 Handle<JSFunction> function2(JSFunction::cast(func_value2));
1172 CHECK(function2->shared()->is_compiled());
1173
1174 // Clear references to functions so that one of them can die.
1175 { v8::HandleScope scope;
1176 CompileRun("foo = 0; bar = 0;");
1177 }
1178
1179 // Bump the code age so that flushing is triggered while the function
1180 // object is still located in new-space.
1181 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001182 for (int i = 0; i < kAgingThreshold; i++) {
1183 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1184 function2->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1185 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001186
1187 // Simulate incremental marking so that the functions are enqueued as
1188 // code flushing candidates. Then kill one of the functions. Finally
1189 // perform a scavenge while incremental marking is still running.
1190 SimulateIncrementalMarking();
1191 *function2.location() = NULL;
1192 HEAP->CollectGarbage(NEW_SPACE, "test scavenge while marking");
1193
1194 // Simulate one final GC to make sure the candidate queue is sane.
1195 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1196 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1197 CHECK(!function->is_compiled() || function->IsOptimized());
1198}
1199
1200
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001201TEST(TestCodeFlushingIncrementalAbort) {
1202 // If we do not flush code this test is invalid.
1203 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1204 i::FLAG_allow_natives_syntax = true;
1205 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001206 Isolate* isolate = Isolate::Current();
1207 Heap* heap = isolate->heap();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001208 v8::HandleScope scope;
1209 const char* source = "function foo() {"
1210 " var x = 42;"
1211 " var y = 42;"
1212 " var z = x + y;"
1213 "};"
1214 "foo()";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001215 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001216
1217 // This compile will add the code to the compilation cache.
1218 { v8::HandleScope scope;
1219 CompileRun(source);
1220 }
1221
1222 // Check function is compiled.
1223 Object* func_value = Isolate::Current()->context()->global_object()->
1224 GetProperty(*foo_name)->ToObjectChecked();
1225 CHECK(func_value->IsJSFunction());
1226 Handle<JSFunction> function(JSFunction::cast(func_value));
1227 CHECK(function->shared()->is_compiled());
1228
1229 // The code will survive at least two GCs.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001230 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1231 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001232 CHECK(function->shared()->is_compiled());
1233
1234 // Bump the code age so that flushing is triggered.
1235 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001236 for (int i = 0; i < kAgingThreshold; i++) {
1237 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1238 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001239
1240 // Simulate incremental marking so that the function is enqueued as
1241 // code flushing candidate.
1242 SimulateIncrementalMarking();
1243
1244 // Enable the debugger and add a breakpoint while incremental marking
1245 // is running so that incremental marking aborts and code flushing is
1246 // disabled.
1247 int position = 0;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001248 Handle<Object> breakpoint_object(Smi::FromInt(0), isolate);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001249 isolate->debug()->SetBreakPoint(function, breakpoint_object, &position);
1250 isolate->debug()->ClearAllBreakPoints();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001251
1252 // Force optimization now that code flushing is disabled.
1253 { v8::HandleScope scope;
1254 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1255 }
1256
1257 // Simulate one final GC to make sure the candidate queue is sane.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001258 heap->CollectAllGarbage(Heap::kNoGCFlags);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001259 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1260 CHECK(function->is_compiled() || !function->IsOptimized());
1261}
1262
1263
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001264// Count the number of native contexts in the weak list of native contexts.
1265int CountNativeContexts() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001266 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001267 Object* object = HEAP->native_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001268 while (!object->IsUndefined()) {
1269 count++;
1270 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1271 }
1272 return count;
1273}
1274
1275
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001276// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001277// functions attached to a native context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001278static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1279 int count = 0;
1280 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1281 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1282 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1283 count++;
1284 object = JSFunction::cast(object)->next_function_link();
1285 }
1286 return count;
1287}
1288
1289
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001290TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001291 v8::V8::Initialize();
1292
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001293 // Some flags turn Scavenge collections into Mark-sweep collections
1294 // and hence are incompatible with this test case.
1295 if (FLAG_gc_global || FLAG_stress_compaction) return;
1296
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001297 static const int kNumTestContexts = 10;
1298
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001299 Isolate* isolate = Isolate::Current();
1300 Heap* heap = isolate->heap();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001301 v8::HandleScope scope;
1302 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1303
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001304 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001305
1306 // Create a number of global contests which gets linked together.
1307 for (int i = 0; i < kNumTestContexts; i++) {
1308 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001309
1310 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1311
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001312 CHECK_EQ(i + 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001313
1314 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001315
1316 // Create a handle scope so no function objects get stuch in the outer
1317 // handle scope
1318 v8::HandleScope scope;
1319 const char* source = "function f1() { };"
1320 "function f2() { };"
1321 "function f3() { };"
1322 "function f4() { };"
1323 "function f5() { };";
1324 CompileRun(source);
1325 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1326 CompileRun("f1()");
1327 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1328 CompileRun("f2()");
1329 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1330 CompileRun("f3()");
1331 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1332 CompileRun("f4()");
1333 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1334 CompileRun("f5()");
1335 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1336
1337 // Remove function f1, and
1338 CompileRun("f1=null");
1339
1340 // Scavenge treats these references as strong.
1341 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001342 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001343 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1344 }
1345
1346 // Mark compact handles the weak references.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001347 isolate->compilation_cache()->Clear();
1348 heap->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001349 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1350
1351 // Get rid of f3 and f5 in the same way.
1352 CompileRun("f3=null");
1353 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001354 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001355 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1356 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001357 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001358 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1359 CompileRun("f5=null");
1360 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001361 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001362 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1363 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001364 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001365 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1366
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001367 ctx[i]->Exit();
1368 }
1369
1370 // Force compilation cache cleanup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001371 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001372
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001373 // Dispose the native contexts one by one.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001374 for (int i = 0; i < kNumTestContexts; i++) {
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001375 ctx[i].Dispose(ctx[i]->GetIsolate());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001376 ctx[i].Clear();
1377
1378 // Scavenge treats these references as strong.
1379 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001380 HEAP->PerformScavenge();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001381 CHECK_EQ(kNumTestContexts - i, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001382 }
1383
1384 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001385 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001386 CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001387 }
1388
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001389 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001390}
1391
1392
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001393// Count the number of native contexts in the weak list of native contexts
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001394// causing a GC after the specified number of elements.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001395static int CountNativeContextsWithGC(Isolate* isolate, int n) {
1396 Heap* heap = isolate->heap();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001397 int count = 0;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001398 Handle<Object> object(heap->native_contexts_list(), isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001399 while (!object->IsUndefined()) {
1400 count++;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001401 if (count == n) heap->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001402 object =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001403 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK),
1404 isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001405 }
1406 return count;
1407}
1408
1409
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001410// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001411// functions attached to a native context causing a GC after the
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001412// specified number of elements.
1413static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1414 int n) {
1415 int count = 0;
1416 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001417 Isolate* isolate = icontext->GetIsolate();
1418 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST),
1419 isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001420 while (object->IsJSFunction() &&
1421 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1422 count++;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001423 if (count == n) isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001424 object = Handle<Object>(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001425 Object::cast(JSFunction::cast(*object)->next_function_link()),
1426 isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001427 }
1428 return count;
1429}
1430
1431
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001432TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001433 v8::V8::Initialize();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001434 Isolate* isolate = Isolate::Current();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001435
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001436 static const int kNumTestContexts = 10;
1437
1438 v8::HandleScope scope;
1439 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1440
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001441 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001442
1443 // Create an number of contexts and check the length of the weak list both
1444 // with and without GCs while iterating the list.
1445 for (int i = 0; i < kNumTestContexts; i++) {
1446 ctx[i] = v8::Context::New();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001447 CHECK_EQ(i + 1, CountNativeContexts());
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001448 CHECK_EQ(i + 1, CountNativeContextsWithGC(isolate, i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001449 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001450
1451 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1452
1453 // Compile a number of functions the length of the weak list of optimized
1454 // functions both with and without GCs while iterating the list.
1455 ctx[0]->Enter();
1456 const char* source = "function f1() { };"
1457 "function f2() { };"
1458 "function f3() { };"
1459 "function f4() { };"
1460 "function f5() { };";
1461 CompileRun(source);
1462 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1463 CompileRun("f1()");
1464 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1465 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1466 CompileRun("f2()");
1467 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1468 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1469 CompileRun("f3()");
1470 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1471 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1472 CompileRun("f4()");
1473 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1474 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1475 CompileRun("f5()");
1476 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1477 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1478
1479 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001480}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001481
1482
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001483TEST(TestSizeOfObjects) {
1484 v8::V8::Initialize();
1485
1486 // Get initial heap size after several full GCs, which will stabilize
1487 // the heap size and return with sweeping finished completely.
1488 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1489 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1490 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1491 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001492 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001493 CHECK(HEAP->old_pointer_space()->IsLazySweepingComplete());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001494 int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1495
1496 {
1497 // Allocate objects on several different old-space pages so that
1498 // lazy sweeping kicks in for subsequent GC runs.
1499 AlwaysAllocateScope always_allocate;
1500 int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1501 for (int i = 1; i <= 100; i++) {
1502 HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1503 CHECK_EQ(initial_size + i * filler_size,
1504 static_cast<int>(HEAP->SizeOfObjects()));
1505 }
1506 }
1507
1508 // The heap size should go back to initial size after a full GC, even
1509 // though sweeping didn't finish yet.
1510 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001511
1512 // Normally sweeping would not be complete here, but no guarantees.
1513
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001514 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1515
1516 // Advancing the sweeper step-wise should not change the heap size.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001517 while (!HEAP->old_pointer_space()->IsLazySweepingComplete()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001518 HEAP->old_pointer_space()->AdvanceSweeper(KB);
1519 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1520 }
1521}
1522
1523
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001524TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1525 InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001526 HEAP->EnsureHeapIsIterable();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001527 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001528 HeapIterator iterator(HEAP);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001529 intptr_t size_of_objects_2 = 0;
1530 for (HeapObject* obj = iterator.next();
1531 obj != NULL;
1532 obj = iterator.next()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001533 if (!obj->IsFreeSpace()) {
1534 size_of_objects_2 += obj->Size();
1535 }
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001536 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001537 // Delta must be within 5% of the larger result.
1538 // TODO(gc): Tighten this up by distinguishing between byte
1539 // arrays that are real and those that merely mark free space
1540 // on the heap.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001541 if (size_of_objects_1 > size_of_objects_2) {
1542 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1543 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1544 "Iterator: %" V8_PTR_PREFIX "d, "
1545 "delta: %" V8_PTR_PREFIX "d\n",
1546 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001547 CHECK_GT(size_of_objects_1 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001548 } else {
1549 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1550 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1551 "Iterator: %" V8_PTR_PREFIX "d, "
1552 "delta: %" V8_PTR_PREFIX "d\n",
1553 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001554 CHECK_GT(size_of_objects_2 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001555 }
1556}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001557
1558
danno@chromium.orgc612e022011-11-10 11:38:15 +00001559static void FillUpNewSpace(NewSpace* new_space) {
1560 // Fill up new space to the point that it is completely full. Make sure
1561 // that the scavenger does not undo the filling.
1562 v8::HandleScope scope;
1563 AlwaysAllocateScope always_allocate;
1564 intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001565 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001566 for (intptr_t i = 0; i < number_of_fillers; i++) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001567 CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001568 }
1569}
1570
1571
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001572TEST(GrowAndShrinkNewSpace) {
1573 InitializeVM();
1574 NewSpace* new_space = HEAP->new_space();
1575
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001576 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1577 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001578 // The max size cannot exceed the reserved size, since semispaces must be
1579 // always within the reserved space. We can't test new space growing and
1580 // shrinking if the reserved size is the same as the minimum (initial) size.
1581 return;
1582 }
1583
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001584 // Explicitly growing should double the space capacity.
1585 intptr_t old_capacity, new_capacity;
1586 old_capacity = new_space->Capacity();
1587 new_space->Grow();
1588 new_capacity = new_space->Capacity();
1589 CHECK(2 * old_capacity == new_capacity);
1590
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001591 old_capacity = new_space->Capacity();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001592 FillUpNewSpace(new_space);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001593 new_capacity = new_space->Capacity();
1594 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001595
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001596 // Explicitly shrinking should not affect space capacity.
1597 old_capacity = new_space->Capacity();
1598 new_space->Shrink();
1599 new_capacity = new_space->Capacity();
1600 CHECK(old_capacity == new_capacity);
1601
1602 // Let the scavenger empty the new space.
1603 HEAP->CollectGarbage(NEW_SPACE);
1604 CHECK_LE(new_space->Size(), old_capacity);
1605
1606 // Explicitly shrinking should halve the space capacity.
1607 old_capacity = new_space->Capacity();
1608 new_space->Shrink();
1609 new_capacity = new_space->Capacity();
1610 CHECK(old_capacity == 2 * new_capacity);
1611
1612 // Consecutive shrinking should not affect space capacity.
1613 old_capacity = new_space->Capacity();
1614 new_space->Shrink();
1615 new_space->Shrink();
1616 new_space->Shrink();
1617 new_capacity = new_space->Capacity();
1618 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001619}
danno@chromium.orgc612e022011-11-10 11:38:15 +00001620
1621
1622TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1623 InitializeVM();
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001624
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001625 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1626 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001627 // The max size cannot exceed the reserved size, since semispaces must be
1628 // always within the reserved space. We can't test new space growing and
1629 // shrinking if the reserved size is the same as the minimum (initial) size.
1630 return;
1631 }
1632
danno@chromium.orgc612e022011-11-10 11:38:15 +00001633 v8::HandleScope scope;
1634 NewSpace* new_space = HEAP->new_space();
1635 intptr_t old_capacity, new_capacity;
1636 old_capacity = new_space->Capacity();
1637 new_space->Grow();
1638 new_capacity = new_space->Capacity();
1639 CHECK(2 * old_capacity == new_capacity);
1640 FillUpNewSpace(new_space);
1641 HEAP->CollectAllAvailableGarbage();
1642 new_capacity = new_space->Capacity();
1643 CHECK(old_capacity == new_capacity);
1644}
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001645
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001646
1647static int NumberOfGlobalObjects() {
1648 int count = 0;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001649 HeapIterator iterator(HEAP);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001650 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1651 if (obj->IsGlobalObject()) count++;
1652 }
1653 return count;
1654}
1655
1656
1657// Test that we don't embed maps from foreign contexts into
1658// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001659TEST(LeakNativeContextViaMap) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001660 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001661 v8::HandleScope outer_scope;
1662 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1663 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1664 ctx1->Enter();
1665
1666 HEAP->CollectAllAvailableGarbage();
1667 CHECK_EQ(4, NumberOfGlobalObjects());
1668
1669 {
1670 v8::HandleScope inner_scope;
1671 CompileRun("var v = {x: 42}");
1672 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1673 ctx2->Enter();
1674 ctx2->Global()->Set(v8_str("o"), v);
1675 v8::Local<v8::Value> res = CompileRun(
1676 "function f() { return o.x; }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001677 "for (var i = 0; i < 10; ++i) f();"
1678 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001679 "f();");
1680 CHECK_EQ(42, res->Int32Value());
1681 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1682 ctx2->Exit();
1683 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001684 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001685 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001686 }
1687 HEAP->CollectAllAvailableGarbage();
1688 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001689 ctx2.Dispose(ctx2->GetIsolate());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001690 HEAP->CollectAllAvailableGarbage();
1691 CHECK_EQ(0, NumberOfGlobalObjects());
1692}
1693
1694
1695// Test that we don't embed functions from foreign contexts into
1696// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001697TEST(LeakNativeContextViaFunction) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001698 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001699 v8::HandleScope outer_scope;
1700 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1701 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1702 ctx1->Enter();
1703
1704 HEAP->CollectAllAvailableGarbage();
1705 CHECK_EQ(4, NumberOfGlobalObjects());
1706
1707 {
1708 v8::HandleScope inner_scope;
1709 CompileRun("var v = function() { return 42; }");
1710 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1711 ctx2->Enter();
1712 ctx2->Global()->Set(v8_str("o"), v);
1713 v8::Local<v8::Value> res = CompileRun(
1714 "function f(x) { return x(); }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001715 "for (var i = 0; i < 10; ++i) f(o);"
1716 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001717 "f(o);");
1718 CHECK_EQ(42, res->Int32Value());
1719 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1720 ctx2->Exit();
1721 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001722 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001723 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001724 }
1725 HEAP->CollectAllAvailableGarbage();
1726 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001727 ctx2.Dispose(ctx2->GetIsolate());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001728 HEAP->CollectAllAvailableGarbage();
1729 CHECK_EQ(0, NumberOfGlobalObjects());
1730}
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001731
1732
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001733TEST(LeakNativeContextViaMapKeyed) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001734 i::FLAG_allow_natives_syntax = true;
1735 v8::HandleScope outer_scope;
1736 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1737 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1738 ctx1->Enter();
1739
1740 HEAP->CollectAllAvailableGarbage();
1741 CHECK_EQ(4, NumberOfGlobalObjects());
1742
1743 {
1744 v8::HandleScope inner_scope;
1745 CompileRun("var v = [42, 43]");
1746 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1747 ctx2->Enter();
1748 ctx2->Global()->Set(v8_str("o"), v);
1749 v8::Local<v8::Value> res = CompileRun(
1750 "function f() { return o[0]; }"
1751 "for (var i = 0; i < 10; ++i) f();"
1752 "%OptimizeFunctionOnNextCall(f);"
1753 "f();");
1754 CHECK_EQ(42, res->Int32Value());
1755 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1756 ctx2->Exit();
1757 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001758 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001759 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001760 }
1761 HEAP->CollectAllAvailableGarbage();
1762 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001763 ctx2.Dispose(ctx2->GetIsolate());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001764 HEAP->CollectAllAvailableGarbage();
1765 CHECK_EQ(0, NumberOfGlobalObjects());
1766}
1767
1768
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001769TEST(LeakNativeContextViaMapProto) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001770 i::FLAG_allow_natives_syntax = true;
1771 v8::HandleScope outer_scope;
1772 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1773 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1774 ctx1->Enter();
1775
1776 HEAP->CollectAllAvailableGarbage();
1777 CHECK_EQ(4, NumberOfGlobalObjects());
1778
1779 {
1780 v8::HandleScope inner_scope;
1781 CompileRun("var v = { y: 42}");
1782 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1783 ctx2->Enter();
1784 ctx2->Global()->Set(v8_str("o"), v);
1785 v8::Local<v8::Value> res = CompileRun(
1786 "function f() {"
1787 " var p = {x: 42};"
1788 " p.__proto__ = o;"
1789 " return p.x;"
1790 "}"
1791 "for (var i = 0; i < 10; ++i) f();"
1792 "%OptimizeFunctionOnNextCall(f);"
1793 "f();");
1794 CHECK_EQ(42, res->Int32Value());
1795 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1796 ctx2->Exit();
1797 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001798 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001799 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001800 }
1801 HEAP->CollectAllAvailableGarbage();
1802 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001803 ctx2.Dispose(ctx2->GetIsolate());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001804 HEAP->CollectAllAvailableGarbage();
1805 CHECK_EQ(0, NumberOfGlobalObjects());
1806}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001807
1808
1809TEST(InstanceOfStubWriteBarrier) {
1810 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001811#ifdef VERIFY_HEAP
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001812 i::FLAG_verify_heap = true;
1813#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001814
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001815 InitializeVM();
1816 if (!i::V8::UseCrankshaft()) return;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001817 if (i::FLAG_force_marking_deque_overflows) return;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001818 v8::HandleScope outer_scope;
1819
1820 {
1821 v8::HandleScope scope;
1822 CompileRun(
1823 "function foo () { }"
1824 "function mkbar () { return new (new Function(\"\")) (); }"
1825 "function f (x) { return (x instanceof foo); }"
1826 "function g () { f(mkbar()); }"
1827 "f(new foo()); f(new foo());"
1828 "%OptimizeFunctionOnNextCall(f);"
1829 "f(new foo()); g();");
1830 }
1831
1832 IncrementalMarking* marking = HEAP->incremental_marking();
1833 marking->Abort();
1834 marking->Start();
1835
1836 Handle<JSFunction> f =
1837 v8::Utils::OpenHandle(
1838 *v8::Handle<v8::Function>::Cast(
1839 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1840
1841 CHECK(f->IsOptimized());
1842
1843 while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1844 !marking->IsStopped()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001845 // Discard any pending GC requests otherwise we will get GC when we enter
1846 // code below.
1847 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001848 }
1849
1850 CHECK(marking->IsMarking());
1851
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001852 {
1853 v8::HandleScope scope;
1854 v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1855 v8::Handle<v8::Function> g =
1856 v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1857 g->Call(global, 0, NULL);
1858 }
1859
1860 HEAP->incremental_marking()->set_should_hurry(true);
1861 HEAP->CollectGarbage(OLD_POINTER_SPACE);
1862}
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001863
1864
1865TEST(PrototypeTransitionClearing) {
1866 InitializeVM();
1867 v8::HandleScope scope;
1868
1869 CompileRun(
1870 "var base = {};"
1871 "var live = [];"
1872 "for (var i = 0; i < 10; i++) {"
1873 " var object = {};"
1874 " var prototype = {};"
1875 " object.__proto__ = prototype;"
1876 " if (i >= 3) live.push(object, prototype);"
1877 "}");
1878
1879 Handle<JSObject> baseObject =
1880 v8::Utils::OpenHandle(
1881 *v8::Handle<v8::Object>::Cast(
1882 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1883
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001884 // Verify that only dead prototype transitions are cleared.
1885 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001886 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001887 const int transitions = 10 - 3;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001888 CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001889
1890 // Verify that prototype transitions array was compacted.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001891 FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001892 for (int i = 0; i < transitions; i++) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001893 int j = Map::kProtoTransitionHeaderSize +
1894 i * Map::kProtoTransitionElementsPerEntry;
1895 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001896 Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
1897 CHECK(proto->IsTheHole() || proto->IsJSObject());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001898 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001899
1900 // Make sure next prototype is placed on an old-space evacuation candidate.
1901 Handle<JSObject> prototype;
1902 PagedSpace* space = HEAP->old_pointer_space();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001903 {
1904 AlwaysAllocateScope always_allocate;
1905 SimulateFullSpace(space);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001906 prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001907 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001908
1909 // Add a prototype on an evacuation candidate and verify that transition
1910 // clearing correctly records slots in prototype transition array.
1911 i::FLAG_always_compact = true;
1912 Handle<Map> map(baseObject->map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001913 CHECK(!space->LastPage()->Contains(
1914 map->GetPrototypeTransitions()->address()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001915 CHECK(space->LastPage()->Contains(prototype->address()));
1916 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1917 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1918 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1919 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001920}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001921
1922
1923TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1924 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001925#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001926 i::FLAG_verify_heap = true;
1927#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001928
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001929 InitializeVM();
1930 if (!i::V8::UseCrankshaft()) return;
1931 v8::HandleScope outer_scope;
1932
1933 {
1934 v8::HandleScope scope;
1935 CompileRun(
1936 "function f () {"
1937 " var s = 0;"
1938 " for (var i = 0; i < 100; i++) s += i;"
1939 " return s;"
1940 "}"
1941 "f(); f();"
1942 "%OptimizeFunctionOnNextCall(f);"
1943 "f();");
1944 }
1945 Handle<JSFunction> f =
1946 v8::Utils::OpenHandle(
1947 *v8::Handle<v8::Function>::Cast(
1948 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1949 CHECK(f->IsOptimized());
1950
1951 IncrementalMarking* marking = HEAP->incremental_marking();
1952 marking->Abort();
1953 marking->Start();
1954
1955 // The following two calls will increment HEAP->global_ic_age().
1956 const int kLongIdlePauseInMs = 1000;
1957 v8::V8::ContextDisposedNotification();
1958 v8::V8::IdleNotification(kLongIdlePauseInMs);
1959
1960 while (!marking->IsStopped() && !marking->IsComplete()) {
1961 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1962 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001963 if (!marking->IsStopped() || marking->should_hurry()) {
1964 // We don't normally finish a GC via Step(), we normally finish by
1965 // setting the stack guard and then do the final steps in the stack
1966 // guard interrupt. But here we didn't ask for that, and there is no
1967 // JS code running to trigger the interrupt, so we explicitly finalize
1968 // here.
1969 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1970 "Test finalizing incremental mark-sweep");
1971 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001972
1973 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1974 CHECK_EQ(0, f->shared()->opt_count());
1975 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1976}
1977
1978
1979TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1980 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001981#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001982 i::FLAG_verify_heap = true;
1983#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001984
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001985 InitializeVM();
1986 if (!i::V8::UseCrankshaft()) return;
1987 v8::HandleScope outer_scope;
1988
1989 {
1990 v8::HandleScope scope;
1991 CompileRun(
1992 "function f () {"
1993 " var s = 0;"
1994 " for (var i = 0; i < 100; i++) s += i;"
1995 " return s;"
1996 "}"
1997 "f(); f();"
1998 "%OptimizeFunctionOnNextCall(f);"
1999 "f();");
2000 }
2001 Handle<JSFunction> f =
2002 v8::Utils::OpenHandle(
2003 *v8::Handle<v8::Function>::Cast(
2004 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2005 CHECK(f->IsOptimized());
2006
2007 HEAP->incremental_marking()->Abort();
2008
2009 // The following two calls will increment HEAP->global_ic_age().
2010 // Since incremental marking is off, IdleNotification will do full GC.
2011 const int kLongIdlePauseInMs = 1000;
2012 v8::V8::ContextDisposedNotification();
2013 v8::V8::IdleNotification(kLongIdlePauseInMs);
2014
2015 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
2016 CHECK_EQ(0, f->shared()->opt_count());
2017 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
2018}
2019
2020
2021// Test that HAllocateObject will always return an object in new-space.
2022TEST(OptimizedAllocationAlwaysInNewSpace) {
2023 i::FLAG_allow_natives_syntax = true;
2024 InitializeVM();
2025 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00002026 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002027 v8::HandleScope scope;
2028
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002029 SimulateFullSpace(HEAP->new_space());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002030 AlwaysAllocateScope always_allocate;
2031 v8::Local<v8::Value> res = CompileRun(
2032 "function c(x) {"
2033 " this.x = x;"
2034 " for (var i = 0; i < 32; i++) {"
2035 " this['x' + i] = x;"
2036 " }"
2037 "}"
2038 "function f(x) { return new c(x); };"
2039 "f(1); f(2); f(3);"
2040 "%OptimizeFunctionOnNextCall(f);"
2041 "f(4);");
2042 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
2043
2044 Handle<JSObject> o =
2045 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2046
2047 CHECK(HEAP->InNewSpace(*o));
2048}
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002049
2050
ulan@chromium.org750145a2013-03-07 15:14:13 +00002051// Test pretenuring of array literals allocated with HAllocate.
2052TEST(OptimizedPretenuringArrayLiterals) {
2053 i::FLAG_allow_natives_syntax = true;
2054 InitializeVM();
2055 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
2056 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2057 v8::HandleScope scope;
2058
2059 AlwaysAllocateScope always_allocate;
2060 v8::Local<v8::Value> res = CompileRun(
2061 "function f() {"
2062 " var numbers = new Array(1, 2, 3);"
2063 " numbers[0] = 3.14;"
2064 " return numbers;"
2065 "};"
2066 "f(); f(); f();"
2067 "%OptimizeFunctionOnNextCall(f);"
2068 "f();");
2069 CHECK_EQ(static_cast<int>(3.14),
2070 v8::Object::Cast(*res)->Get(v8_str("0"))->Int32Value());
2071
2072 Handle<JSObject> o =
2073 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2074
2075 // TODO(hpayer): remove InNewSpace check and test if object was allocated
2076 // in old pointer space.
2077 CHECK(!HEAP->InOldPointerSpace(*o));
2078 CHECK(HEAP->InNewSpace(*o));
2079}
2080
2081
2082// Test regular array literals allocation.
2083TEST(OptimizedAllocationArrayLiterals) {
2084 i::FLAG_allow_natives_syntax = true;
2085 InitializeVM();
2086 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
2087 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2088 v8::HandleScope scope;
2089
2090 AlwaysAllocateScope always_allocate;
2091 v8::Local<v8::Value> res = CompileRun(
2092 "function f() {"
2093 " var numbers = new Array(1, 2, 3);"
2094 " numbers[0] = 3.14;"
2095 " return numbers;"
2096 "};"
2097 "f(); f(); f();"
2098 "%OptimizeFunctionOnNextCall(f);"
2099 "f();");
2100 CHECK_EQ(static_cast<int>(3.14),
2101 v8::Object::Cast(*res)->Get(v8_str("0"))->Int32Value());
2102
2103 Handle<JSObject> o =
2104 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2105
2106 CHECK(HEAP->InNewSpace(*o));
2107}
2108
2109
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002110static int CountMapTransitions(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002111 return map->transitions()->number_of_transitions();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002112}
2113
2114
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002115// Test that map transitions are cleared and maps are collected with
2116// incremental marking as well.
2117TEST(Regress1465) {
2118 i::FLAG_allow_natives_syntax = true;
2119 i::FLAG_trace_incremental_marking = true;
2120 InitializeVM();
2121 v8::HandleScope scope;
2122 static const int transitions_count = 256;
2123
2124 {
2125 AlwaysAllocateScope always_allocate;
2126 for (int i = 0; i < transitions_count; i++) {
2127 EmbeddedVector<char, 64> buffer;
2128 OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
2129 CompileRun(buffer.start());
2130 }
2131 CompileRun("var root = new Object;");
2132 }
2133
2134 Handle<JSObject> root =
2135 v8::Utils::OpenHandle(
2136 *v8::Handle<v8::Object>::Cast(
2137 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2138
2139 // Count number of live transitions before marking.
2140 int transitions_before = CountMapTransitions(root->map());
2141 CompileRun("%DebugPrint(root);");
2142 CHECK_EQ(transitions_count, transitions_before);
2143
2144 SimulateIncrementalMarking();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002145 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002146
2147 // Count number of live transitions after marking. Note that one transition
2148 // is left, because 'o' still holds an instance of one transition target.
2149 int transitions_after = CountMapTransitions(root->map());
2150 CompileRun("%DebugPrint(root);");
2151 CHECK_EQ(1, transitions_after);
2152}
verwaest@chromium.org37141392012-05-31 13:27:02 +00002153
2154
2155TEST(Regress2143a) {
2156 i::FLAG_collect_maps = true;
2157 i::FLAG_incremental_marking = true;
2158 InitializeVM();
2159 v8::HandleScope scope;
2160
2161 // Prepare a map transition from the root object together with a yet
2162 // untransitioned root object.
2163 CompileRun("var root = new Object;"
2164 "root.foo = 0;"
2165 "root = new Object;");
2166
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002167 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002168
2169 // Compile a StoreIC that performs the prepared map transition. This
2170 // will restart incremental marking and should make sure the root is
2171 // marked grey again.
2172 CompileRun("function f(o) {"
2173 " o.foo = 0;"
2174 "}"
2175 "f(new Object);"
2176 "f(root);");
2177
2178 // This bug only triggers with aggressive IC clearing.
2179 HEAP->AgeInlineCaches();
2180
2181 // Explicitly request GC to perform final marking step and sweeping.
2182 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002183
2184 Handle<JSObject> root =
2185 v8::Utils::OpenHandle(
2186 *v8::Handle<v8::Object>::Cast(
2187 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2188
2189 // The root object should be in a sane state.
2190 CHECK(root->IsJSObject());
2191 CHECK(root->map()->IsMap());
2192}
2193
2194
2195TEST(Regress2143b) {
2196 i::FLAG_collect_maps = true;
2197 i::FLAG_incremental_marking = true;
2198 i::FLAG_allow_natives_syntax = true;
2199 InitializeVM();
2200 v8::HandleScope scope;
2201
2202 // Prepare a map transition from the root object together with a yet
2203 // untransitioned root object.
2204 CompileRun("var root = new Object;"
2205 "root.foo = 0;"
2206 "root = new Object;");
2207
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002208 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002209
2210 // Compile an optimized LStoreNamedField that performs the prepared
2211 // map transition. This will restart incremental marking and should
2212 // make sure the root is marked grey again.
2213 CompileRun("function f(o) {"
2214 " o.foo = 0;"
2215 "}"
2216 "f(new Object);"
2217 "f(new Object);"
2218 "%OptimizeFunctionOnNextCall(f);"
2219 "f(root);"
2220 "%DeoptimizeFunction(f);");
2221
2222 // This bug only triggers with aggressive IC clearing.
2223 HEAP->AgeInlineCaches();
2224
2225 // Explicitly request GC to perform final marking step and sweeping.
2226 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002227
2228 Handle<JSObject> root =
2229 v8::Utils::OpenHandle(
2230 *v8::Handle<v8::Object>::Cast(
2231 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2232
2233 // The root object should be in a sane state.
2234 CHECK(root->IsJSObject());
2235 CHECK(root->map()->IsMap());
2236}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002237
2238
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002239TEST(ReleaseOverReservedPages) {
2240 i::FLAG_trace_gc = true;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002241 // The optimizer can allocate stuff, messing up the test.
2242 i::FLAG_crankshaft = false;
2243 i::FLAG_always_opt = false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002244 InitializeVM();
2245 v8::HandleScope scope;
2246 static const int number_of_test_pages = 20;
2247
2248 // Prepare many pages with low live-bytes count.
2249 PagedSpace* old_pointer_space = HEAP->old_pointer_space();
2250 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2251 for (int i = 0; i < number_of_test_pages; i++) {
2252 AlwaysAllocateScope always_allocate;
2253 SimulateFullSpace(old_pointer_space);
2254 FACTORY->NewFixedArray(1, TENURED);
2255 }
2256 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2257
2258 // Triggering one GC will cause a lot of garbage to be discovered but
2259 // even spread across all allocated pages.
2260 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00002261 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002262
2263 // Triggering subsequent GCs should cause at least half of the pages
2264 // to be released to the OS after at most two cycles.
2265 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
2266 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2267 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
2268 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
2269
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002270 // Triggering a last-resort GC should cause all pages to be released to the
2271 // OS so that other processes can seize the memory. If we get a failure here
2272 // where there are 2 pages left instead of 1, then we should increase the
2273 // size of the first page a little in SizeOfFirstPage in spaces.cc. The
2274 // first page should be small in order to reduce memory used when the VM
2275 // boots, but if the 20 small arrays don't fit on the first page then that's
2276 // an indication that it is too small.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002277 HEAP->CollectAllAvailableGarbage("triggered really hard");
2278 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2279}
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002280
2281
2282TEST(Regress2237) {
2283 InitializeVM();
2284 v8::HandleScope scope;
2285 Handle<String> slice(HEAP->empty_string());
2286
2287 {
2288 // Generate a parent that lives in new-space.
2289 v8::HandleScope inner_scope;
2290 const char* c = "This text is long enough to trigger sliced strings.";
2291 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002292 CHECK(s->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002293 CHECK(HEAP->InNewSpace(*s));
2294
2295 // Generate a sliced string that is based on the above parent and
2296 // lives in old-space.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002297 SimulateFullSpace(HEAP->new_space());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002298 AlwaysAllocateScope always_allocate;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002299 Handle<String> t = FACTORY->NewProperSubString(s, 5, 35);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002300 CHECK(t->IsSlicedString());
2301 CHECK(!HEAP->InNewSpace(*t));
2302 *slice.location() = *t.location();
2303 }
2304
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002305 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002306 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002307 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002308}
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00002309
2310
2311#ifdef OBJECT_PRINT
2312TEST(PrintSharedFunctionInfo) {
2313 InitializeVM();
2314 v8::HandleScope scope;
2315 const char* source = "f = function() { return 987654321; }\n"
2316 "g = function() { return 123456789; }\n";
2317 CompileRun(source);
2318 Handle<JSFunction> g =
2319 v8::Utils::OpenHandle(
2320 *v8::Handle<v8::Function>::Cast(
2321 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2322
2323 AssertNoAllocation no_alloc;
2324 g->shared()->PrintLn();
2325}
2326#endif // OBJECT_PRINT
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002327
2328
2329TEST(Regress2211) {
2330 InitializeVM();
2331 v8::HandleScope scope;
2332
2333 v8::Handle<v8::String> value = v8_str("val string");
2334 Smi* hash = Smi::FromInt(321);
2335 Heap* heap = Isolate::Current()->heap();
2336
2337 for (int i = 0; i < 2; i++) {
2338 // Store identity hash first and common hidden property second.
2339 v8::Handle<v8::Object> obj = v8::Object::New();
2340 Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
2341 CHECK(internal_obj->HasFastProperties());
2342
2343 // In the first iteration, set hidden value first and identity hash second.
2344 // In the second iteration, reverse the order.
2345 if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
2346 MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
2347 ALLOW_CREATION);
2348 CHECK(!maybe_obj->IsFailure());
2349 if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
2350
2351 // Check values.
2352 CHECK_EQ(hash,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002353 internal_obj->GetHiddenProperty(heap->identity_hash_string()));
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002354 CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
2355
2356 // Check size.
2357 DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
2358 ObjectHashTable* hashtable = ObjectHashTable::cast(
2359 internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
2360 // HashTable header (5) and 4 initial entries (8).
2361 CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
2362 }
2363}
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002364
2365
2366TEST(IncrementalMarkingClearsTypeFeedbackCells) {
2367 if (i::FLAG_always_opt) return;
2368 InitializeVM();
2369 v8::HandleScope scope;
2370 v8::Local<v8::Value> fun1, fun2;
2371
2372 {
2373 LocalContext env;
2374 CompileRun("function fun() {};");
2375 fun1 = env->Global()->Get(v8_str("fun"));
2376 }
2377
2378 {
2379 LocalContext env;
2380 CompileRun("function fun() {};");
2381 fun2 = env->Global()->Get(v8_str("fun"));
2382 }
2383
2384 // Prepare function f that contains type feedback for closures
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002385 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002386 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1);
2387 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2);
2388 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
2389 Handle<JSFunction> f =
2390 v8::Utils::OpenHandle(
2391 *v8::Handle<v8::Function>::Cast(
2392 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2393 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast(
2394 f->shared()->code()->type_feedback_info())->type_feedback_cells());
2395
2396 CHECK_EQ(2, cells->CellCount());
2397 CHECK(cells->Cell(0)->value()->IsJSFunction());
2398 CHECK(cells->Cell(1)->value()->IsJSFunction());
2399
2400 SimulateIncrementalMarking();
2401 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2402
2403 CHECK_EQ(2, cells->CellCount());
2404 CHECK(cells->Cell(0)->value()->IsTheHole());
2405 CHECK(cells->Cell(1)->value()->IsTheHole());
2406}
2407
2408
2409static Code* FindFirstIC(Code* code, Code::Kind kind) {
2410 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
2411 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
2412 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
2413 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
2414 for (RelocIterator it(code, mask); !it.done(); it.next()) {
2415 RelocInfo* info = it.rinfo();
2416 Code* target = Code::GetCodeFromTargetAddress(info->target_address());
2417 if (target->is_inline_cache_stub() && target->kind() == kind) {
2418 return target;
2419 }
2420 }
2421 return NULL;
2422}
2423
2424
2425TEST(IncrementalMarkingPreservesMonomorhpicIC) {
2426 if (i::FLAG_always_opt) return;
2427 InitializeVM();
2428 v8::HandleScope scope;
2429
2430 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002431 // originating from the same native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002432 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
2433 "function f(o) { return o.x; } f(obj); f(obj);");
2434 Handle<JSFunction> f =
2435 v8::Utils::OpenHandle(
2436 *v8::Handle<v8::Function>::Cast(
2437 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2438
2439 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2440 CHECK(ic_before->ic_state() == MONOMORPHIC);
2441
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002442 SimulateIncrementalMarking();
2443 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2444
2445 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2446 CHECK(ic_after->ic_state() == MONOMORPHIC);
2447}
2448
2449
2450TEST(IncrementalMarkingClearsMonomorhpicIC) {
2451 if (i::FLAG_always_opt) return;
2452 InitializeVM();
2453 v8::HandleScope scope;
2454 v8::Local<v8::Value> obj1;
2455
2456 {
2457 LocalContext env;
2458 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2459 obj1 = env->Global()->Get(v8_str("obj"));
2460 }
2461
2462 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002463 // originating from a different native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002464 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2465 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
2466 Handle<JSFunction> f =
2467 v8::Utils::OpenHandle(
2468 *v8::Handle<v8::Function>::Cast(
2469 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2470
2471 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2472 CHECK(ic_before->ic_state() == MONOMORPHIC);
2473
2474 // Fire context dispose notification.
2475 v8::V8::ContextDisposedNotification();
2476 SimulateIncrementalMarking();
2477 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2478
2479 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2480 CHECK(ic_after->ic_state() == UNINITIALIZED);
2481}
2482
2483
2484TEST(IncrementalMarkingClearsPolymorhpicIC) {
2485 if (i::FLAG_always_opt) return;
2486 InitializeVM();
2487 v8::HandleScope scope;
2488 v8::Local<v8::Value> obj1, obj2;
2489
2490 {
2491 LocalContext env;
2492 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2493 obj1 = env->Global()->Get(v8_str("obj"));
2494 }
2495
2496 {
2497 LocalContext env;
2498 CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
2499 obj2 = env->Global()->Get(v8_str("obj"));
2500 }
2501
2502 // Prepare function f that contains a polymorphic IC for objects
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002503 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002504 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2505 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2);
2506 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
2507 Handle<JSFunction> f =
2508 v8::Utils::OpenHandle(
2509 *v8::Handle<v8::Function>::Cast(
2510 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2511
2512 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002513 CHECK(ic_before->ic_state() == POLYMORPHIC);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002514
2515 // Fire context dispose notification.
2516 v8::V8::ContextDisposedNotification();
2517 SimulateIncrementalMarking();
2518 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2519
2520 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2521 CHECK(ic_after->ic_state() == UNINITIALIZED);
2522}
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002523
2524
2525class SourceResource: public v8::String::ExternalAsciiStringResource {
2526 public:
2527 explicit SourceResource(const char* data)
2528 : data_(data), length_(strlen(data)) { }
2529
2530 virtual void Dispose() {
2531 i::DeleteArray(data_);
2532 data_ = NULL;
2533 }
2534
2535 const char* data() const { return data_; }
2536
2537 size_t length() const { return length_; }
2538
2539 bool IsDisposed() { return data_ == NULL; }
2540
2541 private:
2542 const char* data_;
2543 size_t length_;
2544};
2545
2546
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002547void ReleaseStackTraceDataTest(const char* source) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002548 // Test that the data retained by the Error.stack accessor is released
2549 // after the first time the accessor is fired. We use external string
2550 // to check whether the data is being released since the external string
2551 // resource's callback is fired when the external string is GC'ed.
2552 InitializeVM();
2553 v8::HandleScope scope;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002554 SourceResource* resource = new SourceResource(i::StrDup(source));
2555 {
2556 v8::HandleScope scope;
2557 v8::Handle<v8::String> source_string = v8::String::NewExternal(resource);
2558 v8::Script::Compile(source_string)->Run();
2559 CHECK(!resource->IsDisposed());
2560 }
2561 HEAP->CollectAllAvailableGarbage();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002562
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002563 // External source has been released.
2564 CHECK(resource->IsDisposed());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002565 delete resource;
2566}
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002567
2568
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002569TEST(ReleaseStackTraceData) {
2570 static const char* source1 = "var error = null; "
2571 /* Normal Error */ "try { "
2572 " throw new Error(); "
2573 "} catch (e) { "
2574 " error = e; "
2575 "} ";
2576 static const char* source2 = "var error = null; "
2577 /* Stack overflow */ "try { "
2578 " (function f() { f(); })(); "
2579 "} catch (e) { "
2580 " error = e; "
2581 "} ";
2582 ReleaseStackTraceDataTest(source1);
2583 ReleaseStackTraceDataTest(source2);
2584}
2585
2586
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002587TEST(Regression144230) {
2588 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002589 Isolate* isolate = Isolate::Current();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002590 Heap* heap = isolate->heap();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002591 v8::HandleScope scope;
2592
2593 // First make sure that the uninitialized CallIC stub is on a single page
2594 // that will later be selected as an evacuation candidate.
2595 {
2596 v8::HandleScope inner_scope;
2597 AlwaysAllocateScope always_allocate;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002598 SimulateFullSpace(heap->code_space());
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002599 isolate->stub_cache()->ComputeCallInitialize(9, RelocInfo::CODE_TARGET);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002600 }
2601
2602 // Second compile a CallIC and execute it once so that it gets patched to
2603 // the pre-monomorphic stub. These code objects are on yet another page.
2604 {
2605 v8::HandleScope inner_scope;
2606 AlwaysAllocateScope always_allocate;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002607 SimulateFullSpace(heap->code_space());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002608 CompileRun("var o = { f:function(a,b,c,d,e,f,g,h,i) {}};"
2609 "function call() { o.f(1,2,3,4,5,6,7,8,9); };"
2610 "call();");
2611 }
2612
2613 // Third we fill up the last page of the code space so that it does not get
2614 // chosen as an evacuation candidate.
2615 {
2616 v8::HandleScope inner_scope;
2617 AlwaysAllocateScope always_allocate;
2618 CompileRun("for (var i = 0; i < 2000; i++) {"
2619 " eval('function f' + i + '() { return ' + i +'; };' +"
2620 " 'f' + i + '();');"
2621 "}");
2622 }
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002623 heap->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002624
2625 // Fourth is the tricky part. Make sure the code containing the CallIC is
2626 // visited first without clearing the IC. The shared function info is then
2627 // visited later, causing the CallIC to be cleared.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002628 Handle<String> name = isolate->factory()->InternalizeUtf8String("call");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002629 Handle<GlobalObject> global(isolate->context()->global_object());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002630 MaybeObject* maybe_call = global->GetProperty(*name);
2631 JSFunction* call = JSFunction::cast(maybe_call->ToObjectChecked());
2632 USE(global->SetProperty(*name, Smi::FromInt(0), NONE, kNonStrictMode));
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002633 isolate->compilation_cache()->Clear();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002634 call->shared()->set_ic_age(heap->global_ic_age() + 1);
2635 Handle<Object> call_code(call->code(), isolate);
2636 Handle<Object> call_function(call, isolate);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002637
2638 // Now we are ready to mess up the heap.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002639 heap->CollectAllGarbage(Heap::kReduceMemoryFootprintMask);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002640
2641 // Either heap verification caught the problem already or we go kaboom once
2642 // the CallIC is executed the next time.
2643 USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode));
2644 CompileRun("call();");
2645}
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002646
2647
2648TEST(Regress159140) {
2649 i::FLAG_allow_natives_syntax = true;
2650 i::FLAG_flush_code_incrementally = true;
2651 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002652 Isolate* isolate = Isolate::Current();
2653 Heap* heap = isolate->heap();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002654 v8::HandleScope scope;
2655
2656 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002657 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002658
2659 // Prepare several closures that are all eligible for code flushing
2660 // because all reachable ones are not optimized. Make sure that the
2661 // optimized code object is directly reachable through a handle so
2662 // that it is marked black during incremental marking.
2663 Handle<Code> code;
2664 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002665 HandleScope inner_scope(isolate);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002666 CompileRun("function h(x) {}"
2667 "function mkClosure() {"
2668 " return function(x) { return x + 1; };"
2669 "}"
2670 "var f = mkClosure();"
2671 "var g = mkClosure();"
2672 "f(1); f(2);"
2673 "g(1); g(2);"
2674 "h(1); h(2);"
2675 "%OptimizeFunctionOnNextCall(f); f(3);"
2676 "%OptimizeFunctionOnNextCall(h); h(3);");
2677
2678 Handle<JSFunction> f =
2679 v8::Utils::OpenHandle(
2680 *v8::Handle<v8::Function>::Cast(
2681 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2682 CHECK(f->is_compiled());
2683 CompileRun("f = null;");
2684
2685 Handle<JSFunction> g =
2686 v8::Utils::OpenHandle(
2687 *v8::Handle<v8::Function>::Cast(
2688 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2689 CHECK(g->is_compiled());
2690 const int kAgingThreshold = 6;
2691 for (int i = 0; i < kAgingThreshold; i++) {
2692 g->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2693 }
2694
2695 code = inner_scope.CloseAndEscape(Handle<Code>(f->code()));
2696 }
2697
2698 // Simulate incremental marking so that the functions are enqueued as
2699 // code flushing candidates. Then optimize one function. Finally
2700 // finish the GC to complete code flushing.
2701 SimulateIncrementalMarking();
2702 CompileRun("%OptimizeFunctionOnNextCall(g); g(3);");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002703 heap->CollectAllGarbage(Heap::kNoGCFlags);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002704
2705 // Unoptimized code is missing and the deoptimizer will go ballistic.
2706 CompileRun("g('bozo');");
2707}
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002708
2709
2710TEST(Regress165495) {
2711 i::FLAG_allow_natives_syntax = true;
2712 i::FLAG_flush_code_incrementally = true;
2713 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002714 Isolate* isolate = Isolate::Current();
2715 Heap* heap = isolate->heap();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002716 v8::HandleScope scope;
2717
2718 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002719 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002720
2721 // Prepare an optimized closure that the optimized code map will get
2722 // populated. Then age the unoptimized code to trigger code flushing
2723 // but make sure the optimized code is unreachable.
2724 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002725 HandleScope inner_scope(isolate);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002726 CompileRun("function mkClosure() {"
2727 " return function(x) { return x + 1; };"
2728 "}"
2729 "var f = mkClosure();"
2730 "f(1); f(2);"
2731 "%OptimizeFunctionOnNextCall(f); f(3);");
2732
2733 Handle<JSFunction> f =
2734 v8::Utils::OpenHandle(
2735 *v8::Handle<v8::Function>::Cast(
2736 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2737 CHECK(f->is_compiled());
2738 const int kAgingThreshold = 6;
2739 for (int i = 0; i < kAgingThreshold; i++) {
2740 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2741 }
2742
2743 CompileRun("f = null;");
2744 }
2745
2746 // Simulate incremental marking so that unoptimized code is flushed
2747 // even though it still is cached in the optimized code map.
2748 SimulateIncrementalMarking();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002749 heap->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002750
2751 // Make a new closure that will get code installed from the code map.
2752 // Unoptimized code is missing and the deoptimizer will go ballistic.
2753 CompileRun("var g = mkClosure(); g('bozo');");
2754}
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002755
2756
2757TEST(Regress169209) {
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002758 i::FLAG_stress_compaction = false;
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002759 i::FLAG_allow_natives_syntax = true;
2760 i::FLAG_flush_code_incrementally = true;
2761 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002762 Isolate* isolate = Isolate::Current();
2763 Heap* heap = isolate->heap();
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002764 v8::HandleScope scope;
2765
2766 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002767 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002768
2769 // Prepare a shared function info eligible for code flushing for which
2770 // the unoptimized code will be replaced during optimization.
2771 Handle<SharedFunctionInfo> shared1;
2772 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002773 HandleScope inner_scope(isolate);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002774 CompileRun("function f() { return 'foobar'; }"
2775 "function g(x) { if (x) f(); }"
2776 "f();"
2777 "g(false);"
2778 "g(false);");
2779
2780 Handle<JSFunction> f =
2781 v8::Utils::OpenHandle(
2782 *v8::Handle<v8::Function>::Cast(
2783 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2784 CHECK(f->is_compiled());
2785 const int kAgingThreshold = 6;
2786 for (int i = 0; i < kAgingThreshold; i++) {
2787 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2788 }
2789
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002790 shared1 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002791 }
2792
2793 // Prepare a shared function info eligible for code flushing that will
2794 // represent the dangling tail of the candidate list.
2795 Handle<SharedFunctionInfo> shared2;
2796 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002797 HandleScope inner_scope(isolate);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002798 CompileRun("function flushMe() { return 0; }"
2799 "flushMe(1);");
2800
2801 Handle<JSFunction> f =
2802 v8::Utils::OpenHandle(
2803 *v8::Handle<v8::Function>::Cast(
2804 v8::Context::GetCurrent()->Global()->Get(v8_str("flushMe"))));
2805 CHECK(f->is_compiled());
2806 const int kAgingThreshold = 6;
2807 for (int i = 0; i < kAgingThreshold; i++) {
2808 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2809 }
2810
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002811 shared2 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002812 }
2813
2814 // Simulate incremental marking and collect code flushing candidates.
2815 SimulateIncrementalMarking();
2816 CHECK(shared1->code()->gc_metadata() != NULL);
2817
2818 // Optimize function and make sure the unoptimized code is replaced.
2819#ifdef DEBUG
2820 FLAG_stop_at = "f";
2821#endif
2822 CompileRun("%OptimizeFunctionOnNextCall(g);"
2823 "g(false);");
2824
2825 // Finish garbage collection cycle.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002826 heap->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002827 CHECK(shared1->code()->gc_metadata() == NULL);
2828}
yangguo@chromium.org28381b42013-01-21 14:39:38 +00002829
2830
2831// Helper function that simulates a fill new-space in the heap.
2832static inline void AllocateAllButNBytes(v8::internal::NewSpace* space,
2833 int extra_bytes) {
2834 int space_remaining = static_cast<int>(
2835 *space->allocation_limit_address() - *space->allocation_top_address());
2836 CHECK(space_remaining >= extra_bytes);
2837 int new_linear_size = space_remaining - extra_bytes;
2838 v8::internal::MaybeObject* maybe = space->AllocateRaw(new_linear_size);
2839 v8::internal::FreeListNode* node = v8::internal::FreeListNode::cast(maybe);
2840 node->set_size(space->heap(), new_linear_size);
2841}
2842
2843
2844TEST(Regress169928) {
2845 i::FLAG_allow_natives_syntax = true;
2846 i::FLAG_crankshaft = false;
2847 InitializeVM();
2848 v8::HandleScope scope;
2849
2850 // Some flags turn Scavenge collections into Mark-sweep collections
2851 // and hence are incompatible with this test case.
2852 if (FLAG_gc_global || FLAG_stress_compaction) return;
2853
2854 // Prepare the environment
2855 CompileRun("function fastliteralcase(literal, value) {"
2856 " literal[0] = value;"
2857 " return literal;"
2858 "}"
2859 "function get_standard_literal() {"
2860 " var literal = [1, 2, 3];"
2861 " return literal;"
2862 "}"
2863 "obj = fastliteralcase(get_standard_literal(), 1);"
2864 "obj = fastliteralcase(get_standard_literal(), 1.5);"
2865 "obj = fastliteralcase(get_standard_literal(), 2);");
2866
2867 // prepare the heap
2868 v8::Local<v8::String> mote_code_string =
2869 v8_str("fastliteralcase(mote, 2.5);");
2870
2871 v8::Local<v8::String> array_name = v8_str("mote");
2872 v8::Context::GetCurrent()->Global()->Set(array_name, v8::Int32::New(0));
2873
2874 // First make sure we flip spaces
2875 HEAP->CollectGarbage(NEW_SPACE);
2876
2877 // Allocate the object.
2878 Handle<FixedArray> array_data = FACTORY->NewFixedArray(2, NOT_TENURED);
2879 array_data->set(0, Smi::FromInt(1));
2880 array_data->set(1, Smi::FromInt(2));
2881
2882 AllocateAllButNBytes(HEAP->new_space(),
2883 JSArray::kSize + AllocationSiteInfo::kSize +
2884 kPointerSize);
2885
2886 Handle<JSArray> array = FACTORY->NewJSArrayWithElements(array_data,
2887 FAST_SMI_ELEMENTS,
2888 NOT_TENURED);
2889
2890 CHECK_EQ(Smi::FromInt(2), array->length());
2891 CHECK(array->HasFastSmiOrObjectElements());
2892
2893 // We need filler the size of AllocationSiteInfo object, plus an extra
2894 // fill pointer value.
2895 MaybeObject* maybe_object = HEAP->AllocateRaw(
2896 AllocationSiteInfo::kSize + kPointerSize, NEW_SPACE, OLD_POINTER_SPACE);
2897 Object* obj = NULL;
2898 CHECK(maybe_object->ToObject(&obj));
2899 Address addr_obj = reinterpret_cast<Address>(
2900 reinterpret_cast<byte*>(obj - kHeapObjectTag));
2901 HEAP->CreateFillerObjectAt(addr_obj,
2902 AllocationSiteInfo::kSize + kPointerSize);
2903
2904 // Give the array a name, making sure not to allocate strings.
2905 v8::Handle<v8::Object> array_obj = v8::Utils::ToLocal(array);
2906 v8::Context::GetCurrent()->Global()->Set(array_name, array_obj);
2907
2908 // This should crash with a protection violation if we are running a build
2909 // with the bug.
2910 AlwaysAllocateScope aa_scope;
2911 v8::Script::Compile(mote_code_string)->Run();
2912}
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002913
2914
2915TEST(Regress168801) {
2916 i::FLAG_always_compact = true;
2917 i::FLAG_cache_optimized_code = false;
2918 i::FLAG_allow_natives_syntax = true;
2919 i::FLAG_flush_code_incrementally = true;
2920 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002921 Isolate* isolate = Isolate::Current();
2922 Heap* heap = isolate->heap();
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002923 v8::HandleScope scope;
2924
2925 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002926 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002927
2928 // Ensure the code ends up on an evacuation candidate.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002929 SimulateFullSpace(heap->code_space());
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002930
2931 // Prepare an unoptimized function that is eligible for code flushing.
2932 Handle<JSFunction> function;
2933 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002934 HandleScope inner_scope(isolate);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002935 CompileRun("function mkClosure() {"
2936 " return function(x) { return x + 1; };"
2937 "}"
2938 "var f = mkClosure();"
2939 "f(1); f(2);");
2940
2941 Handle<JSFunction> f =
2942 v8::Utils::OpenHandle(
2943 *v8::Handle<v8::Function>::Cast(
2944 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2945 CHECK(f->is_compiled());
2946 const int kAgingThreshold = 6;
2947 for (int i = 0; i < kAgingThreshold; i++) {
2948 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2949 }
2950
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002951 function = inner_scope.CloseAndEscape(handle(*f, isolate));
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002952 }
2953
2954 // Simulate incremental marking so that unoptimized function is enqueued as a
2955 // candidate for code flushing. The shared function info however will not be
2956 // explicitly enqueued.
2957 SimulateIncrementalMarking();
2958
2959 // Now optimize the function so that it is taken off the candidate list.
2960 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002961 HandleScope inner_scope(isolate);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002962 CompileRun("%OptimizeFunctionOnNextCall(f); f(3);");
2963 }
2964
2965 // This cycle will bust the heap and subsequent cycles will go ballistic.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002966 heap->CollectAllGarbage(Heap::kNoGCFlags);
2967 heap->CollectAllGarbage(Heap::kNoGCFlags);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002968}
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002969
2970
2971TEST(Regress173458) {
2972 i::FLAG_always_compact = true;
2973 i::FLAG_cache_optimized_code = false;
2974 i::FLAG_allow_natives_syntax = true;
2975 i::FLAG_flush_code_incrementally = true;
2976 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002977 Isolate* isolate = Isolate::Current();
2978 Heap* heap = isolate->heap();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002979 v8::HandleScope scope;
2980
2981 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002982 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002983
2984 // Ensure the code ends up on an evacuation candidate.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002985 SimulateFullSpace(heap->code_space());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002986
2987 // Prepare an unoptimized function that is eligible for code flushing.
2988 Handle<JSFunction> function;
2989 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002990 HandleScope inner_scope(isolate);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002991 CompileRun("function mkClosure() {"
2992 " return function(x) { return x + 1; };"
2993 "}"
2994 "var f = mkClosure();"
2995 "f(1); f(2);");
2996
2997 Handle<JSFunction> f =
2998 v8::Utils::OpenHandle(
2999 *v8::Handle<v8::Function>::Cast(
3000 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
3001 CHECK(f->is_compiled());
3002 const int kAgingThreshold = 6;
3003 for (int i = 0; i < kAgingThreshold; i++) {
3004 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
3005 }
3006
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00003007 function = inner_scope.CloseAndEscape(handle(*f, isolate));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003008 }
3009
3010 // Simulate incremental marking so that unoptimized function is enqueued as a
3011 // candidate for code flushing. The shared function info however will not be
3012 // explicitly enqueued.
3013 SimulateIncrementalMarking();
3014
3015 // Now enable the debugger which in turn will disable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00003016 CHECK(isolate->debug()->Load());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003017
3018 // This cycle will bust the heap and subsequent cycles will go ballistic.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00003019 heap->CollectAllGarbage(Heap::kNoGCFlags);
3020 heap->CollectAllGarbage(Heap::kNoGCFlags);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003021}