blob: f94fe53ca6c5771a19182693e50a7a7fbef891c3 [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() {
53 IncrementalMarking* marking = HEAP->incremental_marking();
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000054 CHECK(marking->IsMarking() || marking->IsStopped());
55 if (marking->IsStopped()) {
56 marking->Start();
57 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000058 CHECK(marking->IsMarking());
59 while (!marking->IsComplete()) {
60 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
61 }
62 CHECK(marking->IsComplete());
63}
64
65
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000066static void CheckMap(Map* map, int type, int instance_size) {
67 CHECK(map->IsHeapObject());
68#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000069 CHECK(HEAP->Contains(map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000070#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000071 CHECK_EQ(HEAP->meta_map(), map->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000072 CHECK_EQ(type, map->instance_type());
73 CHECK_EQ(instance_size, map->instance_size());
74}
75
76
77TEST(HeapMaps) {
78 InitializeVM();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000079 CheckMap(HEAP->meta_map(), MAP_TYPE, Map::kSize);
80 CheckMap(HEAP->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
81 CheckMap(HEAP->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
82 CheckMap(HEAP->string_map(), STRING_TYPE, kVariableSizeSentinel);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000083}
84
85
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000086static void CheckOddball(Isolate* isolate, Object* obj, const char* string) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000087 CHECK(obj->IsOddball());
88 bool exc;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000089 Object* print_string =
90 *Execution::ToString(Handle<Object>(obj, isolate), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000091 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000092}
93
94
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000095static void CheckSmi(Isolate* isolate, int value, const char* string) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000096 bool exc;
97 Object* print_string =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000098 *Execution::ToString(Handle<Object>(Smi::FromInt(value), isolate), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000099 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000100}
101
102
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000103static void CheckNumber(Isolate* isolate, double value, const char* string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000104 Object* obj = HEAP->NumberFromDouble(value)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000105 CHECK(obj->IsNumber());
106 bool exc;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000107 Object* print_string =
108 *Execution::ToString(Handle<Object>(obj, isolate), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000109 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000110}
111
112
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000113static void CheckFindCodeObject(Isolate* isolate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000114 // Test FindCodeObject
115#define __ assm.
116
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000117 Assembler assm(isolate, NULL, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000118
119 __ nop(); // supported on all architectures
120
121 CodeDesc desc;
122 assm.GetCode(&desc);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000123 Heap* heap = isolate->heap();
124 Object* code = heap->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000125 desc,
126 Code::ComputeFlags(Code::STUB),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000127 Handle<Code>())->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000128 CHECK(code->IsCode());
129
130 HeapObject* obj = HeapObject::cast(code);
131 Address obj_addr = obj->address();
132
133 for (int i = 0; i < obj->Size(); i += kPointerSize) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000134 Object* found = heap->FindCodeObject(obj_addr + i);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000135 CHECK_EQ(code, found);
136 }
137
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000138 Object* copy = heap->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000139 desc,
140 Code::ComputeFlags(Code::STUB),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000141 Handle<Code>())->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000142 CHECK(copy->IsCode());
143 HeapObject* obj_copy = HeapObject::cast(copy);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000144 Object* not_right = heap->FindCodeObject(obj_copy->address() +
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000145 obj_copy->Size() / 2);
146 CHECK(not_right != code);
147}
148
149
150TEST(HeapObjects) {
151 InitializeVM();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000152 Isolate* isolate = Isolate::Current();
153 Heap* heap = isolate->heap();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000154
155 v8::HandleScope sc;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000156 Object* value = heap->NumberFromDouble(1.000123)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000157 CHECK(value->IsHeapNumber());
158 CHECK(value->IsNumber());
159 CHECK_EQ(1.000123, value->Number());
160
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000161 value = heap->NumberFromDouble(1.0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000162 CHECK(value->IsSmi());
163 CHECK(value->IsNumber());
164 CHECK_EQ(1.0, value->Number());
165
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000166 value = heap->NumberFromInt32(1024)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000167 CHECK(value->IsSmi());
168 CHECK(value->IsNumber());
169 CHECK_EQ(1024.0, value->Number());
170
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000171 value = heap->NumberFromInt32(Smi::kMinValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000172 CHECK(value->IsSmi());
173 CHECK(value->IsNumber());
174 CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
175
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000176 value = heap->NumberFromInt32(Smi::kMaxValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000177 CHECK(value->IsSmi());
178 CHECK(value->IsNumber());
179 CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value());
180
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000181#ifndef V8_TARGET_ARCH_X64
182 // TODO(lrn): We need a NumberFromIntptr function in order to test this.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000183 value = heap->NumberFromInt32(Smi::kMinValue - 1)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000184 CHECK(value->IsHeapNumber());
185 CHECK(value->IsNumber());
186 CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000187#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000188
lrn@chromium.org303ada72010-10-27 09:33:13 +0000189 MaybeObject* maybe_value =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000190 heap->NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000191 value = maybe_value->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000192 CHECK(value->IsHeapNumber());
193 CHECK(value->IsNumber());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000194 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
195 value->Number());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000196
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000197 maybe_value = heap->NumberFromUint32(static_cast<uint32_t>(1) << 31);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000198 value = maybe_value->ToObjectChecked();
199 CHECK(value->IsHeapNumber());
200 CHECK(value->IsNumber());
201 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(1) << 31),
202 value->Number());
203
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000204 // nan oddball checks
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000205 CHECK(heap->nan_value()->IsNumber());
206 CHECK(isnan(heap->nan_value()->Number()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000207
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000208 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest "));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000209 CHECK(s->IsString());
210 CHECK_EQ(10, s->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000211
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000212 String* object_string = String::cast(heap->Object_string());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000213 CHECK(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000214 Isolate::Current()->context()->global_object()->HasLocalProperty(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000215 object_string));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000216
217 // Check ToString for oddballs
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000218 CheckOddball(isolate, heap->true_value(), "true");
219 CheckOddball(isolate, heap->false_value(), "false");
220 CheckOddball(isolate, heap->null_value(), "null");
221 CheckOddball(isolate, heap->undefined_value(), "undefined");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000222
223 // Check ToString for Smis
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000224 CheckSmi(isolate, 0, "0");
225 CheckSmi(isolate, 42, "42");
226 CheckSmi(isolate, -42, "-42");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000227
228 // Check ToString for Numbers
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000229 CheckNumber(isolate, 1.1, "1.1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000230
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000231 CheckFindCodeObject(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000232}
233
234
235TEST(Tagging) {
236 InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000237 int request = 24;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000238 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000239 CHECK(Smi::FromInt(42)->IsSmi());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000240 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000241 CHECK_EQ(NEW_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000242 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000243 CHECK_EQ(OLD_POINTER_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000244 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000245 CHECK(Failure::Exception()->IsFailure());
246 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
247 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
248}
249
250
251TEST(GarbageCollection) {
252 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000253 Isolate* isolate = Isolate::Current();
254 Heap* heap = isolate->heap();
255 Factory* factory = isolate->factory();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000256
257 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000258 // Check GC.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000259 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000260
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000261 Handle<String> name = factory->InternalizeUtf8String("theFunction");
262 Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
263 Handle<String> prop_namex = factory->InternalizeUtf8String("theSlotx");
264 Handle<String> obj_name = factory->InternalizeUtf8String("theObject");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000265
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000266 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000267 HandleScope inner_scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000268 // Allocate a function and keep it in global object's property.
269 Handle<JSFunction> function =
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000270 factory->NewFunction(name, factory->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000271 Handle<Map> initial_map =
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000272 factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000273 function->set_initial_map(*initial_map);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000274 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000275 *name, *function, NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000276 // Allocate an object. Unrooted after leaving the scope.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000277 Handle<JSObject> obj = factory->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000278 obj->SetProperty(
279 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
280 obj->SetProperty(
281 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000282
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000283 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
284 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
285 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000286
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000287 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000288
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000289 // Function should be alive.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000290 CHECK(Isolate::Current()->context()->global_object()->
291 HasLocalProperty(*name));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000292 // Check function is retained.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000293 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000294 GetProperty(*name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000295 CHECK(func_value->IsJSFunction());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000296 Handle<JSFunction> function(JSFunction::cast(func_value));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000297
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000298 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000299 HandleScope inner_scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000300 // Allocate another object, make it reachable from global.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000301 Handle<JSObject> obj = factory->NewJSObject(function);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000302 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000303 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked();
304 obj->SetProperty(
305 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000306 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000307
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000308 // After gc, it should survive.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000309 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000310
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000311 CHECK(Isolate::Current()->context()->global_object()->
312 HasLocalProperty(*obj_name));
313 CHECK(Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000314 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000315 Object* obj = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000316 GetProperty(*obj_name)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000317 JSObject* js_obj = JSObject::cast(obj);
318 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000319}
320
321
322static void VerifyStringAllocation(const char* string) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000323 v8::HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 Handle<String> s = FACTORY->NewStringFromUtf8(CStrVector(string));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000325 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000326 for (int index = 0; index < s->length(); index++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000327 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
328 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000329}
330
331
332TEST(String) {
333 InitializeVM();
334
335 VerifyStringAllocation("a");
336 VerifyStringAllocation("ab");
337 VerifyStringAllocation("abc");
338 VerifyStringAllocation("abcd");
339 VerifyStringAllocation("fiskerdrengen er paa havet");
340}
341
342
343TEST(LocalHandles) {
344 InitializeVM();
345
346 v8::HandleScope scope;
347 const char* name = "Kasper the spunky";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000348 Handle<String> string = FACTORY->NewStringFromAscii(CStrVector(name));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000349 CHECK_EQ(StrLength(name), string->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000350}
351
352
353TEST(GlobalHandles) {
354 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000355 Isolate* isolate = Isolate::Current();
356 Heap* heap = isolate->heap();
357 Factory* factory = isolate->factory();
358 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000359
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000360 Handle<Object> h1;
361 Handle<Object> h2;
362 Handle<Object> h3;
363 Handle<Object> h4;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000364
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000365 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000366 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000367
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000368 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
369 Handle<Object> u = factory->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000370
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000371 h1 = global_handles->Create(*i);
372 h2 = global_handles->Create(*u);
373 h3 = global_handles->Create(*i);
374 h4 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000375 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000376
377 // after gc, it should survive
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000378 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000379
380 CHECK((*h1)->IsString());
381 CHECK((*h2)->IsHeapNumber());
382 CHECK((*h3)->IsString());
383 CHECK((*h4)->IsHeapNumber());
384
385 CHECK_EQ(*h3, *h1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000386 global_handles->Destroy(h1.location());
387 global_handles->Destroy(h3.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000388
389 CHECK_EQ(*h4, *h2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000390 global_handles->Destroy(h2.location());
391 global_handles->Destroy(h4.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000392}
393
394
395static bool WeakPointerCleared = false;
396
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000397static void TestWeakGlobalHandleCallback(v8::Isolate* isolate,
398 v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000399 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000400 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000401 handle.Dispose(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000402}
403
404
405TEST(WeakGlobalHandlesScavenge) {
406 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000407 Isolate* isolate = Isolate::Current();
408 Heap* heap = isolate->heap();
409 Factory* factory = isolate->factory();
410 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000411
412 WeakPointerCleared = false;
413
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000414 Handle<Object> h1;
415 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000416
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000417 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000418 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000419
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000420 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
421 Handle<Object> u = factory->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000422
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000423 h1 = global_handles->Create(*i);
424 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000425 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000427 global_handles->MakeWeak(h2.location(),
428 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000429 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000430 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000431
432 // Scavenge treats weak pointers as normal roots.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000433 heap->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000434
435 CHECK((*h1)->IsString());
436 CHECK((*h2)->IsHeapNumber());
437
438 CHECK(!WeakPointerCleared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000439 CHECK(!global_handles->IsNearDeath(h2.location()));
440 CHECK(!global_handles->IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000441
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000442 global_handles->Destroy(h1.location());
443 global_handles->Destroy(h2.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000444}
445
446
447TEST(WeakGlobalHandlesMark) {
448 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000449 Isolate* isolate = Isolate::Current();
450 Heap* heap = isolate->heap();
451 Factory* factory = isolate->factory();
452 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000453
454 WeakPointerCleared = false;
455
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000456 Handle<Object> h1;
457 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000458
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000459 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000460 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000461
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000462 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
463 Handle<Object> u = factory->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000464
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000465 h1 = global_handles->Create(*i);
466 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000467 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000468
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000469 // Make sure the objects are promoted.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000470 heap->CollectGarbage(OLD_POINTER_SPACE);
471 heap->CollectGarbage(NEW_SPACE);
472 CHECK(!heap->InNewSpace(*h1) && !heap->InNewSpace(*h2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000473
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000474 global_handles->MakeWeak(h2.location(),
475 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000476 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000477 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000478 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
479 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
480
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000481 // Incremental marking potentially marked handles before they turned weak.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000482 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000483
484 CHECK((*h1)->IsString());
485
486 CHECK(WeakPointerCleared);
487 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000489 global_handles->Destroy(h1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000490}
491
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000492
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000493TEST(DeleteWeakGlobalHandle) {
494 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000495 Isolate* isolate = Isolate::Current();
496 Heap* heap = isolate->heap();
497 Factory* factory = isolate->factory();
498 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000499
500 WeakPointerCleared = false;
501
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000502 Handle<Object> h;
503
504 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000505 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000506
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000507 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000508 h = global_handles->Create(*i);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000509 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000510
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000511 global_handles->MakeWeak(h.location(),
512 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000513 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000514 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000515
516 // Scanvenge does not recognize weak reference.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000517 heap->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000518
519 CHECK(!WeakPointerCleared);
520
521 // Mark-compact treats weak reference properly.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000522 heap->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000523
524 CHECK(WeakPointerCleared);
525}
526
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000527
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000528static const char* not_so_random_string_table[] = {
529 "abstract",
530 "boolean",
531 "break",
532 "byte",
533 "case",
534 "catch",
535 "char",
536 "class",
537 "const",
538 "continue",
539 "debugger",
540 "default",
541 "delete",
542 "do",
543 "double",
544 "else",
545 "enum",
546 "export",
547 "extends",
548 "false",
549 "final",
550 "finally",
551 "float",
552 "for",
553 "function",
554 "goto",
555 "if",
556 "implements",
557 "import",
558 "in",
559 "instanceof",
560 "int",
561 "interface",
562 "long",
563 "native",
564 "new",
565 "null",
566 "package",
567 "private",
568 "protected",
569 "public",
570 "return",
571 "short",
572 "static",
573 "super",
574 "switch",
575 "synchronized",
576 "this",
577 "throw",
578 "throws",
579 "transient",
580 "true",
581 "try",
582 "typeof",
583 "var",
584 "void",
585 "volatile",
586 "while",
587 "with",
588 0
589};
590
591
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000592static void CheckInternalizedStrings(const char** strings) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000593 for (const char* string = *strings; *strings != 0; string = *strings++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000594 Object* a;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000595 MaybeObject* maybe_a = HEAP->InternalizeUtf8String(string);
596 // InternalizeUtf8String may return a failure if a GC is needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000597 if (!maybe_a->ToObject(&a)) continue;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000598 CHECK(a->IsInternalizedString());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000599 Object* b;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000600 MaybeObject* maybe_b = HEAP->InternalizeUtf8String(string);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000601 if (!maybe_b->ToObject(&b)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000602 CHECK_EQ(b, a);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000603 CHECK(String::cast(b)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000604 }
605}
606
607
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000608TEST(StringTable) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000609 InitializeVM();
610
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000611 CheckInternalizedStrings(not_so_random_string_table);
612 CheckInternalizedStrings(not_so_random_string_table);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000613}
614
615
616TEST(FunctionAllocation) {
617 InitializeVM();
618
619 v8::HandleScope sc;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000620 Handle<String> name = FACTORY->InternalizeUtf8String("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000621 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000622 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000623 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000624 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000625 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000626
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000627 Handle<String> prop_name = FACTORY->InternalizeUtf8String("theSlot");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000628 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000629 obj->SetProperty(
630 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000631 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000632 // Check that we can add properties to function objects.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000633 function->SetProperty(
634 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000635 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000636}
637
638
639TEST(ObjectProperties) {
640 InitializeVM();
641
642 v8::HandleScope sc;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000643 String* object_string = String::cast(HEAP->Object_string());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000644 Object* raw_object = Isolate::Current()->context()->global_object()->
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000645 GetProperty(object_string)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000646 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000647 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000648 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000649 Handle<String> first = FACTORY->InternalizeUtf8String("first");
650 Handle<String> second = FACTORY->InternalizeUtf8String("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000651
652 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000653 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000654
655 // add first
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000656 obj->SetProperty(
657 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000658 CHECK(obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000659
660 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000661 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
662 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000663
664 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000665 obj->SetProperty(
666 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
667 obj->SetProperty(
668 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000669 CHECK(obj->HasLocalProperty(*first));
670 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000671
672 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000673 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
674 CHECK(obj->HasLocalProperty(*second));
675 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
676 CHECK(!obj->HasLocalProperty(*first));
677 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000678
679 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000680 obj->SetProperty(
681 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
682 obj->SetProperty(
683 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000684 CHECK(obj->HasLocalProperty(*first));
685 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000686
687 // delete second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000688 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
689 CHECK(obj->HasLocalProperty(*first));
690 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
691 CHECK(!obj->HasLocalProperty(*first));
692 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000693
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000694 // check string and internalized string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000695 const char* string1 = "fisk";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000696 Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000697 obj->SetProperty(
698 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000699 Handle<String> s1_string = FACTORY->InternalizeUtf8String(string1);
700 CHECK(obj->HasLocalProperty(*s1_string));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000701
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000702 // check internalized string and string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000703 const char* string2 = "fugl";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000704 Handle<String> s2_string = FACTORY->InternalizeUtf8String(string2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000705 obj->SetProperty(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000706 *s2_string, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000707 Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000708 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000709}
710
711
712TEST(JSObjectMaps) {
713 InitializeVM();
714
715 v8::HandleScope sc;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000716 Handle<String> name = FACTORY->InternalizeUtf8String("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000717 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000718 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000719 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000720 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000721 function->set_initial_map(*initial_map);
722
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000723 Handle<String> prop_name = FACTORY->InternalizeUtf8String("theSlot");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000724 Handle<JSObject> obj = FACTORY->NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000725
726 // Set a propery
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000727 obj->SetProperty(
728 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000729 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000730
731 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000732 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000733}
734
735
736TEST(JSArray) {
737 InitializeVM();
738
739 v8::HandleScope sc;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000740 Handle<String> name = FACTORY->InternalizeUtf8String("Array");
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000741 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000742 GetProperty(*name)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000743 Handle<JSFunction> function = Handle<JSFunction>(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000744 JSFunction::cast(raw_object));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000745
746 // Allocate the object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000747 Handle<JSObject> object = FACTORY->NewJSObject(function);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000748 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000749 // We just initialized the VM, no heap allocation failure yet.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000750 array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000751
752 // Set array length to 0.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000753 array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000754 CHECK_EQ(Smi::FromInt(0), array->length());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000755 // Must be in fast mode.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000756 CHECK(array->HasFastSmiOrObjectElements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000757
758 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000759 array->SetElement(0, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000760 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000761 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000762
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000763 // Set array length with larger than smi value.
764 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000765 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000766 array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000767
768 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000769 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000770 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000771 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000772
773 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000774 array->SetElement(int_length, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000775 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000776 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000777 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000778 CHECK_EQ(array->GetElement(int_length), *name);
779 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000780}
781
782
783TEST(JSObjectCopy) {
784 InitializeVM();
785
786 v8::HandleScope sc;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000787 String* object_string = String::cast(HEAP->Object_string());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000788 Object* raw_object = Isolate::Current()->context()->global_object()->
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000789 GetProperty(object_string)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000790 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000791 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000792 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000793 Handle<String> first = FACTORY->InternalizeUtf8String("first");
794 Handle<String> second = FACTORY->InternalizeUtf8String("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000795
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000796 obj->SetProperty(
797 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
798 obj->SetProperty(
799 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000800
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000801 obj->SetElement(0, *first, NONE, kNonStrictMode)->ToObjectChecked();
802 obj->SetElement(1, *second, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000803
804 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000805 Handle<JSObject> clone = Copy(obj);
806 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000807
808 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
809 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
810
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000811 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
812 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000813
814 // Flip the values.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000815 clone->SetProperty(
816 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
817 clone->SetProperty(
818 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000819
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000820 clone->SetElement(0, *second, NONE, kNonStrictMode)->ToObjectChecked();
821 clone->SetElement(1, *first, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000822
823 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
824 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
825
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000826 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
827 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000828}
829
830
831TEST(StringAllocation) {
832 InitializeVM();
833
834
835 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
836 for (int length = 0; length < 100; length++) {
837 v8::HandleScope scope;
838 char* non_ascii = NewArray<char>(3 * length + 1);
839 char* ascii = NewArray<char>(length + 1);
840 non_ascii[3 * length] = 0;
841 ascii[length] = 0;
842 for (int i = 0; i < length; i++) {
843 ascii[i] = 'a';
844 non_ascii[3 * i] = chars[0];
845 non_ascii[3 * i + 1] = chars[1];
846 non_ascii[3 * i + 2] = chars[2];
847 }
848 Handle<String> non_ascii_sym =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000849 FACTORY->InternalizeUtf8String(
850 Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000851 CHECK_EQ(length, non_ascii_sym->length());
852 Handle<String> ascii_sym =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000853 FACTORY->InternalizeOneByteString(OneByteVector(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000854 CHECK_EQ(length, ascii_sym->length());
855 Handle<String> non_ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000856 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000857 non_ascii_str->Hash();
858 CHECK_EQ(length, non_ascii_str->length());
859 Handle<String> ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000860 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000861 ascii_str->Hash();
862 CHECK_EQ(length, ascii_str->length());
863 DeleteArray(non_ascii);
864 DeleteArray(ascii);
865 }
866}
867
868
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000869static int ObjectsFoundInHeap(Heap* heap, Handle<Object> objs[], int size) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000870 // Count the number of objects found in the heap.
871 int found_count = 0;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000872 HeapIterator iterator(heap);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000873 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000874 for (int i = 0; i < size; i++) {
875 if (*objs[i] == obj) {
876 found_count++;
877 }
878 }
879 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000880 return found_count;
881}
882
883
884TEST(Iteration) {
885 InitializeVM();
886 v8::HandleScope scope;
887
888 // Array of objects to scan haep for.
889 const int objs_count = 6;
890 Handle<Object> objs[objs_count];
891 int next_objs_index = 0;
892
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000893 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 objs[next_objs_index++] = FACTORY->NewJSArray(10);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000895 objs[next_objs_index++] = FACTORY->NewJSArray(10,
896 FAST_HOLEY_ELEMENTS,
897 TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000898
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000899 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000900 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000901 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000902 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000903 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000904
905 // Allocate a large string (for large object space).
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000906 int large_size = Page::kMaxNonCodeHeapObjectSize + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000907 char* str = new char[large_size];
908 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
909 str[large_size - 1] = '\0';
910 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000911 FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000912 delete[] str;
913
914 // Add a Map object to look for.
915 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
916
917 CHECK_EQ(objs_count, next_objs_index);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000918 CHECK_EQ(objs_count, ObjectsFoundInHeap(HEAP, objs, objs_count));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000919}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000920
921
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000922TEST(EmptyHandleEscapeFrom) {
923 InitializeVM();
924
925 v8::HandleScope scope;
926 Handle<JSObject> runaway;
927
928 {
929 v8::HandleScope nested;
930 Handle<JSObject> empty;
931 runaway = empty.EscapeFrom(&nested);
932 }
933
934 CHECK(runaway.is_null());
935}
936
937
938static int LenFromSize(int size) {
939 return (size - FixedArray::kHeaderSize) / kPointerSize;
940}
941
942
943TEST(Regression39128) {
944 // Test case for crbug.com/39128.
945 InitializeVM();
946
947 // Increase the chance of 'bump-the-pointer' allocation in old space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000948 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000949
950 v8::HandleScope scope;
951
952 // The plan: create JSObject which references objects in new space.
953 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000954 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000955
956 // Step 1: prepare a map for the object. We add 1 inobject property to it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000957 Handle<JSFunction> object_ctor(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000958 Isolate::Current()->native_context()->object_function());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000959 CHECK(object_ctor->has_initial_map());
960 Handle<Map> object_map(object_ctor->initial_map());
961 // Create a map with single inobject property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000962 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000963 int n_properties = my_map->inobject_properties();
964 CHECK_GT(n_properties, 0);
965
966 int object_size = my_map->instance_size();
967
968 // Step 2: allocate a lot of objects so to almost fill new space: we need
969 // just enough room to allocate JSObject and thus fill the newspace.
970
971 int allocation_amount = Min(FixedArray::kMaxSize,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000972 HEAP->MaxObjectSizeInNewSpace());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000973 int allocation_len = LenFromSize(allocation_amount);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000974 NewSpace* new_space = HEAP->new_space();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000975 Address* top_addr = new_space->allocation_top_address();
976 Address* limit_addr = new_space->allocation_limit_address();
977 while ((*limit_addr - *top_addr) > allocation_amount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000978 CHECK(!HEAP->always_allocate());
979 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
980 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000981 CHECK(new_space->Contains(array));
982 }
983
984 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000985 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000986 int fixed_array_len = LenFromSize(to_fill);
987 CHECK(fixed_array_len < FixedArray::kMaxLength);
988
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000989 CHECK(!HEAP->always_allocate());
990 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
991 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000992 CHECK(new_space->Contains(array));
993
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000995 CHECK(new_space->Contains(object));
996 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000997 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000998 CHECK_EQ(0, jsobject->properties()->length());
999 // Create a reference to object in new space in jsobject.
1000 jsobject->FastPropertyAtPut(-1, array);
1001
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001002 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001003
1004 // Step 4: clone jsobject, but force always allocate first to create a clone
1005 // in old pointer space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001006 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001007 AlwaysAllocateScope aa_scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001008 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001009 JSObject* clone = JSObject::cast(clone_obj);
1010 if (clone->address() != old_pointer_space_top) {
1011 // Alas, got allocated from free list, we cannot do checks.
1012 return;
1013 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001014 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001015}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001016
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001017
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001018TEST(TestCodeFlushing) {
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +00001019 // If we do not flush code this test is invalid.
1020 if (!FLAG_flush_code) return;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001021 i::FLAG_allow_natives_syntax = true;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001022 InitializeVM();
1023 v8::HandleScope scope;
1024 const char* source = "function foo() {"
1025 " var x = 42;"
1026 " var y = 42;"
1027 " var z = x + y;"
1028 "};"
1029 "foo()";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001030 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001031
1032 // This compile will add the code to the compilation cache.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001033 { v8::HandleScope scope;
1034 CompileRun(source);
1035 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001036
1037 // Check function is compiled.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001038 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001039 GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001040 CHECK(func_value->IsJSFunction());
1041 Handle<JSFunction> function(JSFunction::cast(func_value));
1042 CHECK(function->shared()->is_compiled());
1043
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001044 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001045 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1046 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001047 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001048
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001049 // Simulate several GCs that use full marking.
1050 const int kAgingThreshold = 6;
1051 for (int i = 0; i < kAgingThreshold; i++) {
1052 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1053 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001054
1055 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001056 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1057 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001058 // Call foo to get it recompiled.
1059 CompileRun("foo()");
1060 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001061 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001062}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001063
1064
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001065TEST(TestCodeFlushingIncremental) {
1066 // If we do not flush code this test is invalid.
1067 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1068 i::FLAG_allow_natives_syntax = true;
1069 InitializeVM();
1070 v8::HandleScope scope;
1071 const char* source = "function foo() {"
1072 " var x = 42;"
1073 " var y = 42;"
1074 " var z = x + y;"
1075 "};"
1076 "foo()";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001077 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001078
1079 // This compile will add the code to the compilation cache.
1080 { v8::HandleScope scope;
1081 CompileRun(source);
1082 }
1083
1084 // Check function is compiled.
1085 Object* func_value = Isolate::Current()->context()->global_object()->
1086 GetProperty(*foo_name)->ToObjectChecked();
1087 CHECK(func_value->IsJSFunction());
1088 Handle<JSFunction> function(JSFunction::cast(func_value));
1089 CHECK(function->shared()->is_compiled());
1090
1091 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001092 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1093 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001094 CHECK(function->shared()->is_compiled());
1095
1096 // Simulate several GCs that use incremental marking.
1097 const int kAgingThreshold = 6;
1098 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001099 SimulateIncrementalMarking();
1100 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1101 }
1102 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1103 CHECK(!function->is_compiled() || function->IsOptimized());
1104
1105 // This compile will compile the function again.
1106 { v8::HandleScope scope;
1107 CompileRun("foo();");
1108 }
1109
1110 // Simulate several GCs that use incremental marking but make sure
1111 // the loop breaks once the function is enqueued as a candidate.
1112 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001113 SimulateIncrementalMarking();
1114 if (!function->next_function_link()->IsUndefined()) break;
1115 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1116 }
1117
1118 // Force optimization while incremental marking is active and while
1119 // the function is enqueued as a candidate.
1120 { v8::HandleScope scope;
1121 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1122 }
1123
1124 // Simulate one final GC to make sure the candidate queue is sane.
1125 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1126 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1127 CHECK(function->is_compiled() || !function->IsOptimized());
1128}
1129
1130
1131TEST(TestCodeFlushingIncrementalScavenge) {
1132 // If we do not flush code this test is invalid.
1133 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1134 i::FLAG_allow_natives_syntax = true;
1135 InitializeVM();
1136 v8::HandleScope scope;
1137 const char* source = "var foo = function() {"
1138 " var x = 42;"
1139 " var y = 42;"
1140 " var z = x + y;"
1141 "};"
1142 "foo();"
1143 "var bar = function() {"
1144 " var x = 23;"
1145 "};"
1146 "bar();";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001147 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
1148 Handle<String> bar_name = FACTORY->InternalizeUtf8String("bar");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001149
1150 // Perfrom one initial GC to enable code flushing.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001151 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001152
1153 // This compile will add the code to the compilation cache.
1154 { v8::HandleScope scope;
1155 CompileRun(source);
1156 }
1157
1158 // Check functions are compiled.
1159 Object* func_value = Isolate::Current()->context()->global_object()->
1160 GetProperty(*foo_name)->ToObjectChecked();
1161 CHECK(func_value->IsJSFunction());
1162 Handle<JSFunction> function(JSFunction::cast(func_value));
1163 CHECK(function->shared()->is_compiled());
1164 Object* func_value2 = Isolate::Current()->context()->global_object()->
1165 GetProperty(*bar_name)->ToObjectChecked();
1166 CHECK(func_value2->IsJSFunction());
1167 Handle<JSFunction> function2(JSFunction::cast(func_value2));
1168 CHECK(function2->shared()->is_compiled());
1169
1170 // Clear references to functions so that one of them can die.
1171 { v8::HandleScope scope;
1172 CompileRun("foo = 0; bar = 0;");
1173 }
1174
1175 // Bump the code age so that flushing is triggered while the function
1176 // object is still located in new-space.
1177 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001178 for (int i = 0; i < kAgingThreshold; i++) {
1179 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1180 function2->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1181 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001182
1183 // Simulate incremental marking so that the functions are enqueued as
1184 // code flushing candidates. Then kill one of the functions. Finally
1185 // perform a scavenge while incremental marking is still running.
1186 SimulateIncrementalMarking();
1187 *function2.location() = NULL;
1188 HEAP->CollectGarbage(NEW_SPACE, "test scavenge while marking");
1189
1190 // Simulate one final GC to make sure the candidate queue is sane.
1191 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1192 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1193 CHECK(!function->is_compiled() || function->IsOptimized());
1194}
1195
1196
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001197TEST(TestCodeFlushingIncrementalAbort) {
1198 // If we do not flush code this test is invalid.
1199 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1200 i::FLAG_allow_natives_syntax = true;
1201 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001202 Isolate* isolate = Isolate::Current();
1203 Heap* heap = isolate->heap();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001204 v8::HandleScope scope;
1205 const char* source = "function foo() {"
1206 " var x = 42;"
1207 " var y = 42;"
1208 " var z = x + y;"
1209 "};"
1210 "foo()";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001211 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001212
1213 // This compile will add the code to the compilation cache.
1214 { v8::HandleScope scope;
1215 CompileRun(source);
1216 }
1217
1218 // Check function is compiled.
1219 Object* func_value = Isolate::Current()->context()->global_object()->
1220 GetProperty(*foo_name)->ToObjectChecked();
1221 CHECK(func_value->IsJSFunction());
1222 Handle<JSFunction> function(JSFunction::cast(func_value));
1223 CHECK(function->shared()->is_compiled());
1224
1225 // The code will survive at least two GCs.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001226 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1227 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001228 CHECK(function->shared()->is_compiled());
1229
1230 // Bump the code age so that flushing is triggered.
1231 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001232 for (int i = 0; i < kAgingThreshold; i++) {
1233 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1234 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001235
1236 // Simulate incremental marking so that the function is enqueued as
1237 // code flushing candidate.
1238 SimulateIncrementalMarking();
1239
1240 // Enable the debugger and add a breakpoint while incremental marking
1241 // is running so that incremental marking aborts and code flushing is
1242 // disabled.
1243 int position = 0;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001244 Handle<Object> breakpoint_object(Smi::FromInt(0), isolate);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001245 isolate->debug()->SetBreakPoint(function, breakpoint_object, &position);
1246 isolate->debug()->ClearAllBreakPoints();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001247
1248 // Force optimization now that code flushing is disabled.
1249 { v8::HandleScope scope;
1250 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1251 }
1252
1253 // Simulate one final GC to make sure the candidate queue is sane.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001254 heap->CollectAllGarbage(Heap::kNoGCFlags);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001255 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1256 CHECK(function->is_compiled() || !function->IsOptimized());
1257}
1258
1259
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001260// Count the number of native contexts in the weak list of native contexts.
1261int CountNativeContexts() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001262 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001263 Object* object = HEAP->native_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001264 while (!object->IsUndefined()) {
1265 count++;
1266 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1267 }
1268 return count;
1269}
1270
1271
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001272// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001273// functions attached to a native context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001274static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1275 int count = 0;
1276 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1277 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1278 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1279 count++;
1280 object = JSFunction::cast(object)->next_function_link();
1281 }
1282 return count;
1283}
1284
1285
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001286TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001287 v8::V8::Initialize();
1288
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001289 // Some flags turn Scavenge collections into Mark-sweep collections
1290 // and hence are incompatible with this test case.
1291 if (FLAG_gc_global || FLAG_stress_compaction) return;
1292
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001293 static const int kNumTestContexts = 10;
1294
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001295 Isolate* isolate = Isolate::Current();
1296 Heap* heap = isolate->heap();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001297 v8::HandleScope scope;
1298 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1299
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001300 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001301
1302 // Create a number of global contests which gets linked together.
1303 for (int i = 0; i < kNumTestContexts; i++) {
1304 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001305
1306 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1307
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001308 CHECK_EQ(i + 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001309
1310 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001311
1312 // Create a handle scope so no function objects get stuch in the outer
1313 // handle scope
1314 v8::HandleScope scope;
1315 const char* source = "function f1() { };"
1316 "function f2() { };"
1317 "function f3() { };"
1318 "function f4() { };"
1319 "function f5() { };";
1320 CompileRun(source);
1321 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1322 CompileRun("f1()");
1323 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1324 CompileRun("f2()");
1325 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1326 CompileRun("f3()");
1327 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1328 CompileRun("f4()");
1329 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1330 CompileRun("f5()");
1331 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1332
1333 // Remove function f1, and
1334 CompileRun("f1=null");
1335
1336 // Scavenge treats these references as strong.
1337 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001338 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001339 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1340 }
1341
1342 // Mark compact handles the weak references.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001343 isolate->compilation_cache()->Clear();
1344 heap->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001345 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1346
1347 // Get rid of f3 and f5 in the same way.
1348 CompileRun("f3=null");
1349 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001350 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001351 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1352 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001353 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001354 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1355 CompileRun("f5=null");
1356 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001357 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001358 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1359 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001360 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001361 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1362
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001363 ctx[i]->Exit();
1364 }
1365
1366 // Force compilation cache cleanup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001367 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001368
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001369 // Dispose the native contexts one by one.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001370 for (int i = 0; i < kNumTestContexts; i++) {
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001371 ctx[i].Dispose(ctx[i]->GetIsolate());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001372 ctx[i].Clear();
1373
1374 // Scavenge treats these references as strong.
1375 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001376 HEAP->PerformScavenge();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001377 CHECK_EQ(kNumTestContexts - i, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001378 }
1379
1380 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001381 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001382 CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001383 }
1384
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001385 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001386}
1387
1388
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001389// Count the number of native contexts in the weak list of native contexts
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001390// causing a GC after the specified number of elements.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001391static int CountNativeContextsWithGC(Isolate* isolate, int n) {
1392 Heap* heap = isolate->heap();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001393 int count = 0;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001394 Handle<Object> object(heap->native_contexts_list(), isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001395 while (!object->IsUndefined()) {
1396 count++;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001397 if (count == n) heap->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001398 object =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001399 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK),
1400 isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001401 }
1402 return count;
1403}
1404
1405
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001406// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001407// functions attached to a native context causing a GC after the
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001408// specified number of elements.
1409static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1410 int n) {
1411 int count = 0;
1412 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001413 Isolate* isolate = icontext->GetIsolate();
1414 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST),
1415 isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001416 while (object->IsJSFunction() &&
1417 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1418 count++;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001419 if (count == n) isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001420 object = Handle<Object>(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001421 Object::cast(JSFunction::cast(*object)->next_function_link()),
1422 isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001423 }
1424 return count;
1425}
1426
1427
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001428TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001429 v8::V8::Initialize();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001430 Isolate* isolate = Isolate::Current();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001431
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001432 static const int kNumTestContexts = 10;
1433
1434 v8::HandleScope scope;
1435 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1436
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001437 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001438
1439 // Create an number of contexts and check the length of the weak list both
1440 // with and without GCs while iterating the list.
1441 for (int i = 0; i < kNumTestContexts; i++) {
1442 ctx[i] = v8::Context::New();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001443 CHECK_EQ(i + 1, CountNativeContexts());
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001444 CHECK_EQ(i + 1, CountNativeContextsWithGC(isolate, i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001445 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001446
1447 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1448
1449 // Compile a number of functions the length of the weak list of optimized
1450 // functions both with and without GCs while iterating the list.
1451 ctx[0]->Enter();
1452 const char* source = "function f1() { };"
1453 "function f2() { };"
1454 "function f3() { };"
1455 "function f4() { };"
1456 "function f5() { };";
1457 CompileRun(source);
1458 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1459 CompileRun("f1()");
1460 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1461 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1462 CompileRun("f2()");
1463 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1464 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1465 CompileRun("f3()");
1466 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1467 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1468 CompileRun("f4()");
1469 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1470 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1471 CompileRun("f5()");
1472 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1473 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1474
1475 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001476}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001477
1478
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001479TEST(TestSizeOfObjects) {
1480 v8::V8::Initialize();
1481
1482 // Get initial heap size after several full GCs, which will stabilize
1483 // the heap size and return with sweeping finished completely.
1484 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1485 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1486 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1487 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001488 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001489 CHECK(HEAP->old_pointer_space()->IsLazySweepingComplete());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001490 int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1491
1492 {
1493 // Allocate objects on several different old-space pages so that
1494 // lazy sweeping kicks in for subsequent GC runs.
1495 AlwaysAllocateScope always_allocate;
1496 int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1497 for (int i = 1; i <= 100; i++) {
1498 HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1499 CHECK_EQ(initial_size + i * filler_size,
1500 static_cast<int>(HEAP->SizeOfObjects()));
1501 }
1502 }
1503
1504 // The heap size should go back to initial size after a full GC, even
1505 // though sweeping didn't finish yet.
1506 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001507
1508 // Normally sweeping would not be complete here, but no guarantees.
1509
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001510 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1511
1512 // Advancing the sweeper step-wise should not change the heap size.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001513 while (!HEAP->old_pointer_space()->IsLazySweepingComplete()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001514 HEAP->old_pointer_space()->AdvanceSweeper(KB);
1515 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1516 }
1517}
1518
1519
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001520TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1521 InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001522 HEAP->EnsureHeapIsIterable();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001523 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001524 HeapIterator iterator(HEAP);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001525 intptr_t size_of_objects_2 = 0;
1526 for (HeapObject* obj = iterator.next();
1527 obj != NULL;
1528 obj = iterator.next()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001529 if (!obj->IsFreeSpace()) {
1530 size_of_objects_2 += obj->Size();
1531 }
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001532 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001533 // Delta must be within 5% of the larger result.
1534 // TODO(gc): Tighten this up by distinguishing between byte
1535 // arrays that are real and those that merely mark free space
1536 // on the heap.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001537 if (size_of_objects_1 > size_of_objects_2) {
1538 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1539 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1540 "Iterator: %" V8_PTR_PREFIX "d, "
1541 "delta: %" V8_PTR_PREFIX "d\n",
1542 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001543 CHECK_GT(size_of_objects_1 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001544 } else {
1545 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1546 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1547 "Iterator: %" V8_PTR_PREFIX "d, "
1548 "delta: %" V8_PTR_PREFIX "d\n",
1549 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001550 CHECK_GT(size_of_objects_2 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001551 }
1552}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001553
1554
danno@chromium.orgc612e022011-11-10 11:38:15 +00001555static void FillUpNewSpace(NewSpace* new_space) {
1556 // Fill up new space to the point that it is completely full. Make sure
1557 // that the scavenger does not undo the filling.
1558 v8::HandleScope scope;
1559 AlwaysAllocateScope always_allocate;
1560 intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001561 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001562 for (intptr_t i = 0; i < number_of_fillers; i++) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001563 CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001564 }
1565}
1566
1567
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001568TEST(GrowAndShrinkNewSpace) {
1569 InitializeVM();
1570 NewSpace* new_space = HEAP->new_space();
1571
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001572 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1573 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001574 // The max size cannot exceed the reserved size, since semispaces must be
1575 // always within the reserved space. We can't test new space growing and
1576 // shrinking if the reserved size is the same as the minimum (initial) size.
1577 return;
1578 }
1579
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001580 // Explicitly growing should double the space capacity.
1581 intptr_t old_capacity, new_capacity;
1582 old_capacity = new_space->Capacity();
1583 new_space->Grow();
1584 new_capacity = new_space->Capacity();
1585 CHECK(2 * old_capacity == new_capacity);
1586
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001587 old_capacity = new_space->Capacity();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001588 FillUpNewSpace(new_space);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001589 new_capacity = new_space->Capacity();
1590 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001591
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001592 // Explicitly shrinking should not affect space capacity.
1593 old_capacity = new_space->Capacity();
1594 new_space->Shrink();
1595 new_capacity = new_space->Capacity();
1596 CHECK(old_capacity == new_capacity);
1597
1598 // Let the scavenger empty the new space.
1599 HEAP->CollectGarbage(NEW_SPACE);
1600 CHECK_LE(new_space->Size(), old_capacity);
1601
1602 // Explicitly shrinking should halve the space capacity.
1603 old_capacity = new_space->Capacity();
1604 new_space->Shrink();
1605 new_capacity = new_space->Capacity();
1606 CHECK(old_capacity == 2 * new_capacity);
1607
1608 // Consecutive shrinking should not affect space capacity.
1609 old_capacity = new_space->Capacity();
1610 new_space->Shrink();
1611 new_space->Shrink();
1612 new_space->Shrink();
1613 new_capacity = new_space->Capacity();
1614 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001615}
danno@chromium.orgc612e022011-11-10 11:38:15 +00001616
1617
1618TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1619 InitializeVM();
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001620
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001621 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1622 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001623 // The max size cannot exceed the reserved size, since semispaces must be
1624 // always within the reserved space. We can't test new space growing and
1625 // shrinking if the reserved size is the same as the minimum (initial) size.
1626 return;
1627 }
1628
danno@chromium.orgc612e022011-11-10 11:38:15 +00001629 v8::HandleScope scope;
1630 NewSpace* new_space = HEAP->new_space();
1631 intptr_t old_capacity, new_capacity;
1632 old_capacity = new_space->Capacity();
1633 new_space->Grow();
1634 new_capacity = new_space->Capacity();
1635 CHECK(2 * old_capacity == new_capacity);
1636 FillUpNewSpace(new_space);
1637 HEAP->CollectAllAvailableGarbage();
1638 new_capacity = new_space->Capacity();
1639 CHECK(old_capacity == new_capacity);
1640}
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001641
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001642
1643static int NumberOfGlobalObjects() {
1644 int count = 0;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001645 HeapIterator iterator(HEAP);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001646 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1647 if (obj->IsGlobalObject()) count++;
1648 }
1649 return count;
1650}
1651
1652
1653// Test that we don't embed maps from foreign contexts into
1654// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001655TEST(LeakNativeContextViaMap) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001656 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001657 v8::HandleScope outer_scope;
1658 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1659 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1660 ctx1->Enter();
1661
1662 HEAP->CollectAllAvailableGarbage();
1663 CHECK_EQ(4, NumberOfGlobalObjects());
1664
1665 {
1666 v8::HandleScope inner_scope;
1667 CompileRun("var v = {x: 42}");
1668 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1669 ctx2->Enter();
1670 ctx2->Global()->Set(v8_str("o"), v);
1671 v8::Local<v8::Value> res = CompileRun(
1672 "function f() { return o.x; }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001673 "for (var i = 0; i < 10; ++i) f();"
1674 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001675 "f();");
1676 CHECK_EQ(42, res->Int32Value());
1677 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1678 ctx2->Exit();
1679 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001680 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001681 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001682 }
1683 HEAP->CollectAllAvailableGarbage();
1684 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001685 ctx2.Dispose(ctx2->GetIsolate());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001686 HEAP->CollectAllAvailableGarbage();
1687 CHECK_EQ(0, NumberOfGlobalObjects());
1688}
1689
1690
1691// Test that we don't embed functions from foreign contexts into
1692// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001693TEST(LeakNativeContextViaFunction) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001694 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001695 v8::HandleScope outer_scope;
1696 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1697 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1698 ctx1->Enter();
1699
1700 HEAP->CollectAllAvailableGarbage();
1701 CHECK_EQ(4, NumberOfGlobalObjects());
1702
1703 {
1704 v8::HandleScope inner_scope;
1705 CompileRun("var v = function() { return 42; }");
1706 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1707 ctx2->Enter();
1708 ctx2->Global()->Set(v8_str("o"), v);
1709 v8::Local<v8::Value> res = CompileRun(
1710 "function f(x) { return x(); }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001711 "for (var i = 0; i < 10; ++i) f(o);"
1712 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001713 "f(o);");
1714 CHECK_EQ(42, res->Int32Value());
1715 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1716 ctx2->Exit();
1717 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001718 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001719 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001720 }
1721 HEAP->CollectAllAvailableGarbage();
1722 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001723 ctx2.Dispose(ctx2->GetIsolate());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001724 HEAP->CollectAllAvailableGarbage();
1725 CHECK_EQ(0, NumberOfGlobalObjects());
1726}
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001727
1728
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001729TEST(LeakNativeContextViaMapKeyed) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001730 i::FLAG_allow_natives_syntax = true;
1731 v8::HandleScope outer_scope;
1732 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1733 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1734 ctx1->Enter();
1735
1736 HEAP->CollectAllAvailableGarbage();
1737 CHECK_EQ(4, NumberOfGlobalObjects());
1738
1739 {
1740 v8::HandleScope inner_scope;
1741 CompileRun("var v = [42, 43]");
1742 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1743 ctx2->Enter();
1744 ctx2->Global()->Set(v8_str("o"), v);
1745 v8::Local<v8::Value> res = CompileRun(
1746 "function f() { return o[0]; }"
1747 "for (var i = 0; i < 10; ++i) f();"
1748 "%OptimizeFunctionOnNextCall(f);"
1749 "f();");
1750 CHECK_EQ(42, res->Int32Value());
1751 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1752 ctx2->Exit();
1753 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001754 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001755 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001756 }
1757 HEAP->CollectAllAvailableGarbage();
1758 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001759 ctx2.Dispose(ctx2->GetIsolate());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001760 HEAP->CollectAllAvailableGarbage();
1761 CHECK_EQ(0, NumberOfGlobalObjects());
1762}
1763
1764
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001765TEST(LeakNativeContextViaMapProto) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001766 i::FLAG_allow_natives_syntax = true;
1767 v8::HandleScope outer_scope;
1768 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1769 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1770 ctx1->Enter();
1771
1772 HEAP->CollectAllAvailableGarbage();
1773 CHECK_EQ(4, NumberOfGlobalObjects());
1774
1775 {
1776 v8::HandleScope inner_scope;
1777 CompileRun("var v = { y: 42}");
1778 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1779 ctx2->Enter();
1780 ctx2->Global()->Set(v8_str("o"), v);
1781 v8::Local<v8::Value> res = CompileRun(
1782 "function f() {"
1783 " var p = {x: 42};"
1784 " p.__proto__ = o;"
1785 " return p.x;"
1786 "}"
1787 "for (var i = 0; i < 10; ++i) f();"
1788 "%OptimizeFunctionOnNextCall(f);"
1789 "f();");
1790 CHECK_EQ(42, res->Int32Value());
1791 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1792 ctx2->Exit();
1793 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001794 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001795 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001796 }
1797 HEAP->CollectAllAvailableGarbage();
1798 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001799 ctx2.Dispose(ctx2->GetIsolate());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001800 HEAP->CollectAllAvailableGarbage();
1801 CHECK_EQ(0, NumberOfGlobalObjects());
1802}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001803
1804
1805TEST(InstanceOfStubWriteBarrier) {
1806 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001807#ifdef VERIFY_HEAP
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001808 i::FLAG_verify_heap = true;
1809#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001810
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001811 InitializeVM();
1812 if (!i::V8::UseCrankshaft()) return;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001813 if (i::FLAG_force_marking_deque_overflows) return;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001814 v8::HandleScope outer_scope;
1815
1816 {
1817 v8::HandleScope scope;
1818 CompileRun(
1819 "function foo () { }"
1820 "function mkbar () { return new (new Function(\"\")) (); }"
1821 "function f (x) { return (x instanceof foo); }"
1822 "function g () { f(mkbar()); }"
1823 "f(new foo()); f(new foo());"
1824 "%OptimizeFunctionOnNextCall(f);"
1825 "f(new foo()); g();");
1826 }
1827
1828 IncrementalMarking* marking = HEAP->incremental_marking();
1829 marking->Abort();
1830 marking->Start();
1831
1832 Handle<JSFunction> f =
1833 v8::Utils::OpenHandle(
1834 *v8::Handle<v8::Function>::Cast(
1835 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1836
1837 CHECK(f->IsOptimized());
1838
1839 while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1840 !marking->IsStopped()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001841 // Discard any pending GC requests otherwise we will get GC when we enter
1842 // code below.
1843 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001844 }
1845
1846 CHECK(marking->IsMarking());
1847
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001848 {
1849 v8::HandleScope scope;
1850 v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1851 v8::Handle<v8::Function> g =
1852 v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1853 g->Call(global, 0, NULL);
1854 }
1855
1856 HEAP->incremental_marking()->set_should_hurry(true);
1857 HEAP->CollectGarbage(OLD_POINTER_SPACE);
1858}
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001859
1860
1861TEST(PrototypeTransitionClearing) {
1862 InitializeVM();
1863 v8::HandleScope scope;
1864
1865 CompileRun(
1866 "var base = {};"
1867 "var live = [];"
1868 "for (var i = 0; i < 10; i++) {"
1869 " var object = {};"
1870 " var prototype = {};"
1871 " object.__proto__ = prototype;"
1872 " if (i >= 3) live.push(object, prototype);"
1873 "}");
1874
1875 Handle<JSObject> baseObject =
1876 v8::Utils::OpenHandle(
1877 *v8::Handle<v8::Object>::Cast(
1878 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1879
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001880 // Verify that only dead prototype transitions are cleared.
1881 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001882 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001883 const int transitions = 10 - 3;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001884 CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001885
1886 // Verify that prototype transitions array was compacted.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001887 FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001888 for (int i = 0; i < transitions; i++) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001889 int j = Map::kProtoTransitionHeaderSize +
1890 i * Map::kProtoTransitionElementsPerEntry;
1891 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001892 Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
1893 CHECK(proto->IsTheHole() || proto->IsJSObject());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001894 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001895
1896 // Make sure next prototype is placed on an old-space evacuation candidate.
1897 Handle<JSObject> prototype;
1898 PagedSpace* space = HEAP->old_pointer_space();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001899 {
1900 AlwaysAllocateScope always_allocate;
1901 SimulateFullSpace(space);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001902 prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001903 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001904
1905 // Add a prototype on an evacuation candidate and verify that transition
1906 // clearing correctly records slots in prototype transition array.
1907 i::FLAG_always_compact = true;
1908 Handle<Map> map(baseObject->map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001909 CHECK(!space->LastPage()->Contains(
1910 map->GetPrototypeTransitions()->address()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001911 CHECK(space->LastPage()->Contains(prototype->address()));
1912 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1913 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1914 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1915 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001916}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001917
1918
1919TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1920 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001921#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001922 i::FLAG_verify_heap = true;
1923#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001924
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001925 InitializeVM();
1926 if (!i::V8::UseCrankshaft()) return;
1927 v8::HandleScope outer_scope;
1928
1929 {
1930 v8::HandleScope scope;
1931 CompileRun(
1932 "function f () {"
1933 " var s = 0;"
1934 " for (var i = 0; i < 100; i++) s += i;"
1935 " return s;"
1936 "}"
1937 "f(); f();"
1938 "%OptimizeFunctionOnNextCall(f);"
1939 "f();");
1940 }
1941 Handle<JSFunction> f =
1942 v8::Utils::OpenHandle(
1943 *v8::Handle<v8::Function>::Cast(
1944 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1945 CHECK(f->IsOptimized());
1946
1947 IncrementalMarking* marking = HEAP->incremental_marking();
1948 marking->Abort();
1949 marking->Start();
1950
1951 // The following two calls will increment HEAP->global_ic_age().
1952 const int kLongIdlePauseInMs = 1000;
1953 v8::V8::ContextDisposedNotification();
1954 v8::V8::IdleNotification(kLongIdlePauseInMs);
1955
1956 while (!marking->IsStopped() && !marking->IsComplete()) {
1957 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1958 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001959 if (!marking->IsStopped() || marking->should_hurry()) {
1960 // We don't normally finish a GC via Step(), we normally finish by
1961 // setting the stack guard and then do the final steps in the stack
1962 // guard interrupt. But here we didn't ask for that, and there is no
1963 // JS code running to trigger the interrupt, so we explicitly finalize
1964 // here.
1965 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1966 "Test finalizing incremental mark-sweep");
1967 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001968
1969 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1970 CHECK_EQ(0, f->shared()->opt_count());
1971 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1972}
1973
1974
1975TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1976 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001977#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001978 i::FLAG_verify_heap = true;
1979#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001980
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001981 InitializeVM();
1982 if (!i::V8::UseCrankshaft()) return;
1983 v8::HandleScope outer_scope;
1984
1985 {
1986 v8::HandleScope scope;
1987 CompileRun(
1988 "function f () {"
1989 " var s = 0;"
1990 " for (var i = 0; i < 100; i++) s += i;"
1991 " return s;"
1992 "}"
1993 "f(); f();"
1994 "%OptimizeFunctionOnNextCall(f);"
1995 "f();");
1996 }
1997 Handle<JSFunction> f =
1998 v8::Utils::OpenHandle(
1999 *v8::Handle<v8::Function>::Cast(
2000 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2001 CHECK(f->IsOptimized());
2002
2003 HEAP->incremental_marking()->Abort();
2004
2005 // The following two calls will increment HEAP->global_ic_age().
2006 // Since incremental marking is off, IdleNotification will do full GC.
2007 const int kLongIdlePauseInMs = 1000;
2008 v8::V8::ContextDisposedNotification();
2009 v8::V8::IdleNotification(kLongIdlePauseInMs);
2010
2011 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
2012 CHECK_EQ(0, f->shared()->opt_count());
2013 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
2014}
2015
2016
2017// Test that HAllocateObject will always return an object in new-space.
2018TEST(OptimizedAllocationAlwaysInNewSpace) {
2019 i::FLAG_allow_natives_syntax = true;
2020 InitializeVM();
2021 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00002022 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002023 v8::HandleScope scope;
2024
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002025 SimulateFullSpace(HEAP->new_space());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002026 AlwaysAllocateScope always_allocate;
2027 v8::Local<v8::Value> res = CompileRun(
2028 "function c(x) {"
2029 " this.x = x;"
2030 " for (var i = 0; i < 32; i++) {"
2031 " this['x' + i] = x;"
2032 " }"
2033 "}"
2034 "function f(x) { return new c(x); };"
2035 "f(1); f(2); f(3);"
2036 "%OptimizeFunctionOnNextCall(f);"
2037 "f(4);");
2038 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
2039
2040 Handle<JSObject> o =
2041 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2042
2043 CHECK(HEAP->InNewSpace(*o));
2044}
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002045
2046
ulan@chromium.org750145a2013-03-07 15:14:13 +00002047// Test pretenuring of array literals allocated with HAllocate.
2048TEST(OptimizedPretenuringArrayLiterals) {
2049 i::FLAG_allow_natives_syntax = true;
2050 InitializeVM();
2051 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
2052 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2053 v8::HandleScope scope;
2054
2055 AlwaysAllocateScope always_allocate;
2056 v8::Local<v8::Value> res = CompileRun(
2057 "function f() {"
2058 " var numbers = new Array(1, 2, 3);"
2059 " numbers[0] = 3.14;"
2060 " return numbers;"
2061 "};"
2062 "f(); f(); f();"
2063 "%OptimizeFunctionOnNextCall(f);"
2064 "f();");
2065 CHECK_EQ(static_cast<int>(3.14),
2066 v8::Object::Cast(*res)->Get(v8_str("0"))->Int32Value());
2067
2068 Handle<JSObject> o =
2069 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2070
2071 // TODO(hpayer): remove InNewSpace check and test if object was allocated
2072 // in old pointer space.
2073 CHECK(!HEAP->InOldPointerSpace(*o));
2074 CHECK(HEAP->InNewSpace(*o));
2075}
2076
2077
2078// Test regular array literals allocation.
2079TEST(OptimizedAllocationArrayLiterals) {
2080 i::FLAG_allow_natives_syntax = true;
2081 InitializeVM();
2082 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
2083 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2084 v8::HandleScope scope;
2085
2086 AlwaysAllocateScope always_allocate;
2087 v8::Local<v8::Value> res = CompileRun(
2088 "function f() {"
2089 " var numbers = new Array(1, 2, 3);"
2090 " numbers[0] = 3.14;"
2091 " return numbers;"
2092 "};"
2093 "f(); f(); f();"
2094 "%OptimizeFunctionOnNextCall(f);"
2095 "f();");
2096 CHECK_EQ(static_cast<int>(3.14),
2097 v8::Object::Cast(*res)->Get(v8_str("0"))->Int32Value());
2098
2099 Handle<JSObject> o =
2100 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2101
2102 CHECK(HEAP->InNewSpace(*o));
2103}
2104
2105
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002106static int CountMapTransitions(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002107 return map->transitions()->number_of_transitions();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002108}
2109
2110
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002111// Test that map transitions are cleared and maps are collected with
2112// incremental marking as well.
2113TEST(Regress1465) {
2114 i::FLAG_allow_natives_syntax = true;
2115 i::FLAG_trace_incremental_marking = true;
2116 InitializeVM();
2117 v8::HandleScope scope;
2118 static const int transitions_count = 256;
2119
2120 {
2121 AlwaysAllocateScope always_allocate;
2122 for (int i = 0; i < transitions_count; i++) {
2123 EmbeddedVector<char, 64> buffer;
2124 OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
2125 CompileRun(buffer.start());
2126 }
2127 CompileRun("var root = new Object;");
2128 }
2129
2130 Handle<JSObject> root =
2131 v8::Utils::OpenHandle(
2132 *v8::Handle<v8::Object>::Cast(
2133 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2134
2135 // Count number of live transitions before marking.
2136 int transitions_before = CountMapTransitions(root->map());
2137 CompileRun("%DebugPrint(root);");
2138 CHECK_EQ(transitions_count, transitions_before);
2139
2140 SimulateIncrementalMarking();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002141 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002142
2143 // Count number of live transitions after marking. Note that one transition
2144 // is left, because 'o' still holds an instance of one transition target.
2145 int transitions_after = CountMapTransitions(root->map());
2146 CompileRun("%DebugPrint(root);");
2147 CHECK_EQ(1, transitions_after);
2148}
verwaest@chromium.org37141392012-05-31 13:27:02 +00002149
2150
2151TEST(Regress2143a) {
2152 i::FLAG_collect_maps = true;
2153 i::FLAG_incremental_marking = true;
2154 InitializeVM();
2155 v8::HandleScope scope;
2156
2157 // Prepare a map transition from the root object together with a yet
2158 // untransitioned root object.
2159 CompileRun("var root = new Object;"
2160 "root.foo = 0;"
2161 "root = new Object;");
2162
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002163 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002164
2165 // Compile a StoreIC that performs the prepared map transition. This
2166 // will restart incremental marking and should make sure the root is
2167 // marked grey again.
2168 CompileRun("function f(o) {"
2169 " o.foo = 0;"
2170 "}"
2171 "f(new Object);"
2172 "f(root);");
2173
2174 // This bug only triggers with aggressive IC clearing.
2175 HEAP->AgeInlineCaches();
2176
2177 // Explicitly request GC to perform final marking step and sweeping.
2178 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002179
2180 Handle<JSObject> root =
2181 v8::Utils::OpenHandle(
2182 *v8::Handle<v8::Object>::Cast(
2183 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2184
2185 // The root object should be in a sane state.
2186 CHECK(root->IsJSObject());
2187 CHECK(root->map()->IsMap());
2188}
2189
2190
2191TEST(Regress2143b) {
2192 i::FLAG_collect_maps = true;
2193 i::FLAG_incremental_marking = true;
2194 i::FLAG_allow_natives_syntax = true;
2195 InitializeVM();
2196 v8::HandleScope scope;
2197
2198 // Prepare a map transition from the root object together with a yet
2199 // untransitioned root object.
2200 CompileRun("var root = new Object;"
2201 "root.foo = 0;"
2202 "root = new Object;");
2203
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002204 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002205
2206 // Compile an optimized LStoreNamedField that performs the prepared
2207 // map transition. This will restart incremental marking and should
2208 // make sure the root is marked grey again.
2209 CompileRun("function f(o) {"
2210 " o.foo = 0;"
2211 "}"
2212 "f(new Object);"
2213 "f(new Object);"
2214 "%OptimizeFunctionOnNextCall(f);"
2215 "f(root);"
2216 "%DeoptimizeFunction(f);");
2217
2218 // This bug only triggers with aggressive IC clearing.
2219 HEAP->AgeInlineCaches();
2220
2221 // Explicitly request GC to perform final marking step and sweeping.
2222 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002223
2224 Handle<JSObject> root =
2225 v8::Utils::OpenHandle(
2226 *v8::Handle<v8::Object>::Cast(
2227 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2228
2229 // The root object should be in a sane state.
2230 CHECK(root->IsJSObject());
2231 CHECK(root->map()->IsMap());
2232}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002233
2234
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002235TEST(ReleaseOverReservedPages) {
2236 i::FLAG_trace_gc = true;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002237 // The optimizer can allocate stuff, messing up the test.
2238 i::FLAG_crankshaft = false;
2239 i::FLAG_always_opt = false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002240 InitializeVM();
2241 v8::HandleScope scope;
2242 static const int number_of_test_pages = 20;
2243
2244 // Prepare many pages with low live-bytes count.
2245 PagedSpace* old_pointer_space = HEAP->old_pointer_space();
2246 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2247 for (int i = 0; i < number_of_test_pages; i++) {
2248 AlwaysAllocateScope always_allocate;
2249 SimulateFullSpace(old_pointer_space);
2250 FACTORY->NewFixedArray(1, TENURED);
2251 }
2252 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2253
2254 // Triggering one GC will cause a lot of garbage to be discovered but
2255 // even spread across all allocated pages.
2256 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00002257 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002258
2259 // Triggering subsequent GCs should cause at least half of the pages
2260 // to be released to the OS after at most two cycles.
2261 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
2262 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2263 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
2264 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
2265
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002266 // Triggering a last-resort GC should cause all pages to be released to the
2267 // OS so that other processes can seize the memory. If we get a failure here
2268 // where there are 2 pages left instead of 1, then we should increase the
2269 // size of the first page a little in SizeOfFirstPage in spaces.cc. The
2270 // first page should be small in order to reduce memory used when the VM
2271 // boots, but if the 20 small arrays don't fit on the first page then that's
2272 // an indication that it is too small.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002273 HEAP->CollectAllAvailableGarbage("triggered really hard");
2274 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2275}
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002276
2277
2278TEST(Regress2237) {
2279 InitializeVM();
2280 v8::HandleScope scope;
2281 Handle<String> slice(HEAP->empty_string());
2282
2283 {
2284 // Generate a parent that lives in new-space.
2285 v8::HandleScope inner_scope;
2286 const char* c = "This text is long enough to trigger sliced strings.";
2287 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002288 CHECK(s->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002289 CHECK(HEAP->InNewSpace(*s));
2290
2291 // Generate a sliced string that is based on the above parent and
2292 // lives in old-space.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002293 SimulateFullSpace(HEAP->new_space());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002294 AlwaysAllocateScope always_allocate;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002295 Handle<String> t = FACTORY->NewProperSubString(s, 5, 35);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002296 CHECK(t->IsSlicedString());
2297 CHECK(!HEAP->InNewSpace(*t));
2298 *slice.location() = *t.location();
2299 }
2300
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002301 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002302 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002303 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002304}
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00002305
2306
2307#ifdef OBJECT_PRINT
2308TEST(PrintSharedFunctionInfo) {
2309 InitializeVM();
2310 v8::HandleScope scope;
2311 const char* source = "f = function() { return 987654321; }\n"
2312 "g = function() { return 123456789; }\n";
2313 CompileRun(source);
2314 Handle<JSFunction> g =
2315 v8::Utils::OpenHandle(
2316 *v8::Handle<v8::Function>::Cast(
2317 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2318
2319 AssertNoAllocation no_alloc;
2320 g->shared()->PrintLn();
2321}
2322#endif // OBJECT_PRINT
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002323
2324
2325TEST(Regress2211) {
2326 InitializeVM();
2327 v8::HandleScope scope;
2328
2329 v8::Handle<v8::String> value = v8_str("val string");
2330 Smi* hash = Smi::FromInt(321);
2331 Heap* heap = Isolate::Current()->heap();
2332
2333 for (int i = 0; i < 2; i++) {
2334 // Store identity hash first and common hidden property second.
2335 v8::Handle<v8::Object> obj = v8::Object::New();
2336 Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
2337 CHECK(internal_obj->HasFastProperties());
2338
2339 // In the first iteration, set hidden value first and identity hash second.
2340 // In the second iteration, reverse the order.
2341 if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
2342 MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
2343 ALLOW_CREATION);
2344 CHECK(!maybe_obj->IsFailure());
2345 if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
2346
2347 // Check values.
2348 CHECK_EQ(hash,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002349 internal_obj->GetHiddenProperty(heap->identity_hash_string()));
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002350 CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
2351
2352 // Check size.
2353 DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
2354 ObjectHashTable* hashtable = ObjectHashTable::cast(
2355 internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
2356 // HashTable header (5) and 4 initial entries (8).
2357 CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
2358 }
2359}
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002360
2361
2362TEST(IncrementalMarkingClearsTypeFeedbackCells) {
2363 if (i::FLAG_always_opt) return;
2364 InitializeVM();
2365 v8::HandleScope scope;
2366 v8::Local<v8::Value> fun1, fun2;
2367
2368 {
2369 LocalContext env;
2370 CompileRun("function fun() {};");
2371 fun1 = env->Global()->Get(v8_str("fun"));
2372 }
2373
2374 {
2375 LocalContext env;
2376 CompileRun("function fun() {};");
2377 fun2 = env->Global()->Get(v8_str("fun"));
2378 }
2379
2380 // Prepare function f that contains type feedback for closures
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002381 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002382 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1);
2383 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2);
2384 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
2385 Handle<JSFunction> f =
2386 v8::Utils::OpenHandle(
2387 *v8::Handle<v8::Function>::Cast(
2388 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2389 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast(
2390 f->shared()->code()->type_feedback_info())->type_feedback_cells());
2391
2392 CHECK_EQ(2, cells->CellCount());
2393 CHECK(cells->Cell(0)->value()->IsJSFunction());
2394 CHECK(cells->Cell(1)->value()->IsJSFunction());
2395
2396 SimulateIncrementalMarking();
2397 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2398
2399 CHECK_EQ(2, cells->CellCount());
2400 CHECK(cells->Cell(0)->value()->IsTheHole());
2401 CHECK(cells->Cell(1)->value()->IsTheHole());
2402}
2403
2404
2405static Code* FindFirstIC(Code* code, Code::Kind kind) {
2406 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
2407 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
2408 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
2409 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
2410 for (RelocIterator it(code, mask); !it.done(); it.next()) {
2411 RelocInfo* info = it.rinfo();
2412 Code* target = Code::GetCodeFromTargetAddress(info->target_address());
2413 if (target->is_inline_cache_stub() && target->kind() == kind) {
2414 return target;
2415 }
2416 }
2417 return NULL;
2418}
2419
2420
2421TEST(IncrementalMarkingPreservesMonomorhpicIC) {
2422 if (i::FLAG_always_opt) return;
2423 InitializeVM();
2424 v8::HandleScope scope;
2425
2426 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002427 // originating from the same native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002428 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
2429 "function f(o) { return o.x; } f(obj); f(obj);");
2430 Handle<JSFunction> f =
2431 v8::Utils::OpenHandle(
2432 *v8::Handle<v8::Function>::Cast(
2433 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2434
2435 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2436 CHECK(ic_before->ic_state() == MONOMORPHIC);
2437
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002438 SimulateIncrementalMarking();
2439 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2440
2441 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2442 CHECK(ic_after->ic_state() == MONOMORPHIC);
2443}
2444
2445
2446TEST(IncrementalMarkingClearsMonomorhpicIC) {
2447 if (i::FLAG_always_opt) return;
2448 InitializeVM();
2449 v8::HandleScope scope;
2450 v8::Local<v8::Value> obj1;
2451
2452 {
2453 LocalContext env;
2454 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2455 obj1 = env->Global()->Get(v8_str("obj"));
2456 }
2457
2458 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002459 // originating from a different native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002460 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2461 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
2462 Handle<JSFunction> f =
2463 v8::Utils::OpenHandle(
2464 *v8::Handle<v8::Function>::Cast(
2465 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2466
2467 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2468 CHECK(ic_before->ic_state() == MONOMORPHIC);
2469
2470 // Fire context dispose notification.
2471 v8::V8::ContextDisposedNotification();
2472 SimulateIncrementalMarking();
2473 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2474
2475 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2476 CHECK(ic_after->ic_state() == UNINITIALIZED);
2477}
2478
2479
2480TEST(IncrementalMarkingClearsPolymorhpicIC) {
2481 if (i::FLAG_always_opt) return;
2482 InitializeVM();
2483 v8::HandleScope scope;
2484 v8::Local<v8::Value> obj1, obj2;
2485
2486 {
2487 LocalContext env;
2488 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2489 obj1 = env->Global()->Get(v8_str("obj"));
2490 }
2491
2492 {
2493 LocalContext env;
2494 CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
2495 obj2 = env->Global()->Get(v8_str("obj"));
2496 }
2497
2498 // Prepare function f that contains a polymorphic IC for objects
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002499 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002500 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2501 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2);
2502 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
2503 Handle<JSFunction> f =
2504 v8::Utils::OpenHandle(
2505 *v8::Handle<v8::Function>::Cast(
2506 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2507
2508 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002509 CHECK(ic_before->ic_state() == POLYMORPHIC);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002510
2511 // Fire context dispose notification.
2512 v8::V8::ContextDisposedNotification();
2513 SimulateIncrementalMarking();
2514 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2515
2516 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2517 CHECK(ic_after->ic_state() == UNINITIALIZED);
2518}
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002519
2520
2521class SourceResource: public v8::String::ExternalAsciiStringResource {
2522 public:
2523 explicit SourceResource(const char* data)
2524 : data_(data), length_(strlen(data)) { }
2525
2526 virtual void Dispose() {
2527 i::DeleteArray(data_);
2528 data_ = NULL;
2529 }
2530
2531 const char* data() const { return data_; }
2532
2533 size_t length() const { return length_; }
2534
2535 bool IsDisposed() { return data_ == NULL; }
2536
2537 private:
2538 const char* data_;
2539 size_t length_;
2540};
2541
2542
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002543void ReleaseStackTraceDataTest(const char* source) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002544 // Test that the data retained by the Error.stack accessor is released
2545 // after the first time the accessor is fired. We use external string
2546 // to check whether the data is being released since the external string
2547 // resource's callback is fired when the external string is GC'ed.
2548 InitializeVM();
2549 v8::HandleScope scope;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002550 SourceResource* resource = new SourceResource(i::StrDup(source));
2551 {
2552 v8::HandleScope scope;
2553 v8::Handle<v8::String> source_string = v8::String::NewExternal(resource);
2554 v8::Script::Compile(source_string)->Run();
2555 CHECK(!resource->IsDisposed());
2556 }
2557 HEAP->CollectAllAvailableGarbage();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002558
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002559 // External source has been released.
2560 CHECK(resource->IsDisposed());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002561 delete resource;
2562}
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002563
2564
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002565TEST(ReleaseStackTraceData) {
2566 static const char* source1 = "var error = null; "
2567 /* Normal Error */ "try { "
2568 " throw new Error(); "
2569 "} catch (e) { "
2570 " error = e; "
2571 "} ";
2572 static const char* source2 = "var error = null; "
2573 /* Stack overflow */ "try { "
2574 " (function f() { f(); })(); "
2575 "} catch (e) { "
2576 " error = e; "
2577 "} ";
2578 ReleaseStackTraceDataTest(source1);
2579 ReleaseStackTraceDataTest(source2);
2580}
2581
2582
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002583TEST(Regression144230) {
2584 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002585 Isolate* isolate = Isolate::Current();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002586 Heap* heap = isolate->heap();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002587 v8::HandleScope scope;
2588
2589 // First make sure that the uninitialized CallIC stub is on a single page
2590 // that will later be selected as an evacuation candidate.
2591 {
2592 v8::HandleScope inner_scope;
2593 AlwaysAllocateScope always_allocate;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002594 SimulateFullSpace(heap->code_space());
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002595 isolate->stub_cache()->ComputeCallInitialize(9, RelocInfo::CODE_TARGET);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002596 }
2597
2598 // Second compile a CallIC and execute it once so that it gets patched to
2599 // the pre-monomorphic stub. These code objects are on yet another page.
2600 {
2601 v8::HandleScope inner_scope;
2602 AlwaysAllocateScope always_allocate;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002603 SimulateFullSpace(heap->code_space());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002604 CompileRun("var o = { f:function(a,b,c,d,e,f,g,h,i) {}};"
2605 "function call() { o.f(1,2,3,4,5,6,7,8,9); };"
2606 "call();");
2607 }
2608
2609 // Third we fill up the last page of the code space so that it does not get
2610 // chosen as an evacuation candidate.
2611 {
2612 v8::HandleScope inner_scope;
2613 AlwaysAllocateScope always_allocate;
2614 CompileRun("for (var i = 0; i < 2000; i++) {"
2615 " eval('function f' + i + '() { return ' + i +'; };' +"
2616 " 'f' + i + '();');"
2617 "}");
2618 }
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002619 heap->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002620
2621 // Fourth is the tricky part. Make sure the code containing the CallIC is
2622 // visited first without clearing the IC. The shared function info is then
2623 // visited later, causing the CallIC to be cleared.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002624 Handle<String> name = isolate->factory()->InternalizeUtf8String("call");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002625 Handle<GlobalObject> global(isolate->context()->global_object());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002626 MaybeObject* maybe_call = global->GetProperty(*name);
2627 JSFunction* call = JSFunction::cast(maybe_call->ToObjectChecked());
2628 USE(global->SetProperty(*name, Smi::FromInt(0), NONE, kNonStrictMode));
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002629 isolate->compilation_cache()->Clear();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002630 call->shared()->set_ic_age(heap->global_ic_age() + 1);
2631 Handle<Object> call_code(call->code(), isolate);
2632 Handle<Object> call_function(call, isolate);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002633
2634 // Now we are ready to mess up the heap.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002635 heap->CollectAllGarbage(Heap::kReduceMemoryFootprintMask);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002636
2637 // Either heap verification caught the problem already or we go kaboom once
2638 // the CallIC is executed the next time.
2639 USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode));
2640 CompileRun("call();");
2641}
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002642
2643
2644TEST(Regress159140) {
2645 i::FLAG_allow_natives_syntax = true;
2646 i::FLAG_flush_code_incrementally = true;
2647 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002648 Isolate* isolate = Isolate::Current();
2649 Heap* heap = isolate->heap();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002650 v8::HandleScope scope;
2651
2652 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002653 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002654
2655 // Prepare several closures that are all eligible for code flushing
2656 // because all reachable ones are not optimized. Make sure that the
2657 // optimized code object is directly reachable through a handle so
2658 // that it is marked black during incremental marking.
2659 Handle<Code> code;
2660 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002661 HandleScope inner_scope(isolate);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002662 CompileRun("function h(x) {}"
2663 "function mkClosure() {"
2664 " return function(x) { return x + 1; };"
2665 "}"
2666 "var f = mkClosure();"
2667 "var g = mkClosure();"
2668 "f(1); f(2);"
2669 "g(1); g(2);"
2670 "h(1); h(2);"
2671 "%OptimizeFunctionOnNextCall(f); f(3);"
2672 "%OptimizeFunctionOnNextCall(h); h(3);");
2673
2674 Handle<JSFunction> f =
2675 v8::Utils::OpenHandle(
2676 *v8::Handle<v8::Function>::Cast(
2677 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2678 CHECK(f->is_compiled());
2679 CompileRun("f = null;");
2680
2681 Handle<JSFunction> g =
2682 v8::Utils::OpenHandle(
2683 *v8::Handle<v8::Function>::Cast(
2684 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2685 CHECK(g->is_compiled());
2686 const int kAgingThreshold = 6;
2687 for (int i = 0; i < kAgingThreshold; i++) {
2688 g->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2689 }
2690
2691 code = inner_scope.CloseAndEscape(Handle<Code>(f->code()));
2692 }
2693
2694 // Simulate incremental marking so that the functions are enqueued as
2695 // code flushing candidates. Then optimize one function. Finally
2696 // finish the GC to complete code flushing.
2697 SimulateIncrementalMarking();
2698 CompileRun("%OptimizeFunctionOnNextCall(g); g(3);");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002699 heap->CollectAllGarbage(Heap::kNoGCFlags);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002700
2701 // Unoptimized code is missing and the deoptimizer will go ballistic.
2702 CompileRun("g('bozo');");
2703}
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002704
2705
2706TEST(Regress165495) {
2707 i::FLAG_allow_natives_syntax = true;
2708 i::FLAG_flush_code_incrementally = true;
2709 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002710 Isolate* isolate = Isolate::Current();
2711 Heap* heap = isolate->heap();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002712 v8::HandleScope scope;
2713
2714 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002715 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002716
2717 // Prepare an optimized closure that the optimized code map will get
2718 // populated. Then age the unoptimized code to trigger code flushing
2719 // but make sure the optimized code is unreachable.
2720 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002721 HandleScope inner_scope(isolate);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002722 CompileRun("function mkClosure() {"
2723 " return function(x) { return x + 1; };"
2724 "}"
2725 "var f = mkClosure();"
2726 "f(1); f(2);"
2727 "%OptimizeFunctionOnNextCall(f); f(3);");
2728
2729 Handle<JSFunction> f =
2730 v8::Utils::OpenHandle(
2731 *v8::Handle<v8::Function>::Cast(
2732 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2733 CHECK(f->is_compiled());
2734 const int kAgingThreshold = 6;
2735 for (int i = 0; i < kAgingThreshold; i++) {
2736 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2737 }
2738
2739 CompileRun("f = null;");
2740 }
2741
2742 // Simulate incremental marking so that unoptimized code is flushed
2743 // even though it still is cached in the optimized code map.
2744 SimulateIncrementalMarking();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002745 heap->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002746
2747 // Make a new closure that will get code installed from the code map.
2748 // Unoptimized code is missing and the deoptimizer will go ballistic.
2749 CompileRun("var g = mkClosure(); g('bozo');");
2750}
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002751
2752
2753TEST(Regress169209) {
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002754 i::FLAG_stress_compaction = false;
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002755 i::FLAG_allow_natives_syntax = true;
2756 i::FLAG_flush_code_incrementally = true;
2757 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002758 Isolate* isolate = Isolate::Current();
2759 Heap* heap = isolate->heap();
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002760 v8::HandleScope scope;
2761
2762 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002763 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002764
2765 // Prepare a shared function info eligible for code flushing for which
2766 // the unoptimized code will be replaced during optimization.
2767 Handle<SharedFunctionInfo> shared1;
2768 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002769 HandleScope inner_scope(isolate);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002770 CompileRun("function f() { return 'foobar'; }"
2771 "function g(x) { if (x) f(); }"
2772 "f();"
2773 "g(false);"
2774 "g(false);");
2775
2776 Handle<JSFunction> f =
2777 v8::Utils::OpenHandle(
2778 *v8::Handle<v8::Function>::Cast(
2779 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2780 CHECK(f->is_compiled());
2781 const int kAgingThreshold = 6;
2782 for (int i = 0; i < kAgingThreshold; i++) {
2783 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2784 }
2785
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002786 shared1 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002787 }
2788
2789 // Prepare a shared function info eligible for code flushing that will
2790 // represent the dangling tail of the candidate list.
2791 Handle<SharedFunctionInfo> shared2;
2792 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002793 HandleScope inner_scope(isolate);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002794 CompileRun("function flushMe() { return 0; }"
2795 "flushMe(1);");
2796
2797 Handle<JSFunction> f =
2798 v8::Utils::OpenHandle(
2799 *v8::Handle<v8::Function>::Cast(
2800 v8::Context::GetCurrent()->Global()->Get(v8_str("flushMe"))));
2801 CHECK(f->is_compiled());
2802 const int kAgingThreshold = 6;
2803 for (int i = 0; i < kAgingThreshold; i++) {
2804 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2805 }
2806
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002807 shared2 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002808 }
2809
2810 // Simulate incremental marking and collect code flushing candidates.
2811 SimulateIncrementalMarking();
2812 CHECK(shared1->code()->gc_metadata() != NULL);
2813
2814 // Optimize function and make sure the unoptimized code is replaced.
2815#ifdef DEBUG
2816 FLAG_stop_at = "f";
2817#endif
2818 CompileRun("%OptimizeFunctionOnNextCall(g);"
2819 "g(false);");
2820
2821 // Finish garbage collection cycle.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002822 heap->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002823 CHECK(shared1->code()->gc_metadata() == NULL);
2824}
yangguo@chromium.org28381b42013-01-21 14:39:38 +00002825
2826
2827// Helper function that simulates a fill new-space in the heap.
2828static inline void AllocateAllButNBytes(v8::internal::NewSpace* space,
2829 int extra_bytes) {
2830 int space_remaining = static_cast<int>(
2831 *space->allocation_limit_address() - *space->allocation_top_address());
2832 CHECK(space_remaining >= extra_bytes);
2833 int new_linear_size = space_remaining - extra_bytes;
2834 v8::internal::MaybeObject* maybe = space->AllocateRaw(new_linear_size);
2835 v8::internal::FreeListNode* node = v8::internal::FreeListNode::cast(maybe);
2836 node->set_size(space->heap(), new_linear_size);
2837}
2838
2839
2840TEST(Regress169928) {
2841 i::FLAG_allow_natives_syntax = true;
2842 i::FLAG_crankshaft = false;
2843 InitializeVM();
2844 v8::HandleScope scope;
2845
2846 // Some flags turn Scavenge collections into Mark-sweep collections
2847 // and hence are incompatible with this test case.
2848 if (FLAG_gc_global || FLAG_stress_compaction) return;
2849
2850 // Prepare the environment
2851 CompileRun("function fastliteralcase(literal, value) {"
2852 " literal[0] = value;"
2853 " return literal;"
2854 "}"
2855 "function get_standard_literal() {"
2856 " var literal = [1, 2, 3];"
2857 " return literal;"
2858 "}"
2859 "obj = fastliteralcase(get_standard_literal(), 1);"
2860 "obj = fastliteralcase(get_standard_literal(), 1.5);"
2861 "obj = fastliteralcase(get_standard_literal(), 2);");
2862
2863 // prepare the heap
2864 v8::Local<v8::String> mote_code_string =
2865 v8_str("fastliteralcase(mote, 2.5);");
2866
2867 v8::Local<v8::String> array_name = v8_str("mote");
2868 v8::Context::GetCurrent()->Global()->Set(array_name, v8::Int32::New(0));
2869
2870 // First make sure we flip spaces
2871 HEAP->CollectGarbage(NEW_SPACE);
2872
2873 // Allocate the object.
2874 Handle<FixedArray> array_data = FACTORY->NewFixedArray(2, NOT_TENURED);
2875 array_data->set(0, Smi::FromInt(1));
2876 array_data->set(1, Smi::FromInt(2));
2877
2878 AllocateAllButNBytes(HEAP->new_space(),
2879 JSArray::kSize + AllocationSiteInfo::kSize +
2880 kPointerSize);
2881
2882 Handle<JSArray> array = FACTORY->NewJSArrayWithElements(array_data,
2883 FAST_SMI_ELEMENTS,
2884 NOT_TENURED);
2885
2886 CHECK_EQ(Smi::FromInt(2), array->length());
2887 CHECK(array->HasFastSmiOrObjectElements());
2888
2889 // We need filler the size of AllocationSiteInfo object, plus an extra
2890 // fill pointer value.
2891 MaybeObject* maybe_object = HEAP->AllocateRaw(
2892 AllocationSiteInfo::kSize + kPointerSize, NEW_SPACE, OLD_POINTER_SPACE);
2893 Object* obj = NULL;
2894 CHECK(maybe_object->ToObject(&obj));
2895 Address addr_obj = reinterpret_cast<Address>(
2896 reinterpret_cast<byte*>(obj - kHeapObjectTag));
2897 HEAP->CreateFillerObjectAt(addr_obj,
2898 AllocationSiteInfo::kSize + kPointerSize);
2899
2900 // Give the array a name, making sure not to allocate strings.
2901 v8::Handle<v8::Object> array_obj = v8::Utils::ToLocal(array);
2902 v8::Context::GetCurrent()->Global()->Set(array_name, array_obj);
2903
2904 // This should crash with a protection violation if we are running a build
2905 // with the bug.
2906 AlwaysAllocateScope aa_scope;
2907 v8::Script::Compile(mote_code_string)->Run();
2908}
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002909
2910
2911TEST(Regress168801) {
2912 i::FLAG_always_compact = true;
2913 i::FLAG_cache_optimized_code = false;
2914 i::FLAG_allow_natives_syntax = true;
2915 i::FLAG_flush_code_incrementally = true;
2916 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002917 Isolate* isolate = Isolate::Current();
2918 Heap* heap = isolate->heap();
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002919 v8::HandleScope scope;
2920
2921 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002922 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002923
2924 // Ensure the code ends up on an evacuation candidate.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002925 SimulateFullSpace(heap->code_space());
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002926
2927 // Prepare an unoptimized function that is eligible for code flushing.
2928 Handle<JSFunction> function;
2929 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002930 HandleScope inner_scope(isolate);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002931 CompileRun("function mkClosure() {"
2932 " return function(x) { return x + 1; };"
2933 "}"
2934 "var f = mkClosure();"
2935 "f(1); f(2);");
2936
2937 Handle<JSFunction> f =
2938 v8::Utils::OpenHandle(
2939 *v8::Handle<v8::Function>::Cast(
2940 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2941 CHECK(f->is_compiled());
2942 const int kAgingThreshold = 6;
2943 for (int i = 0; i < kAgingThreshold; i++) {
2944 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2945 }
2946
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002947 function = inner_scope.CloseAndEscape(handle(*f, isolate));
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002948 }
2949
2950 // Simulate incremental marking so that unoptimized function is enqueued as a
2951 // candidate for code flushing. The shared function info however will not be
2952 // explicitly enqueued.
2953 SimulateIncrementalMarking();
2954
2955 // Now optimize the function so that it is taken off the candidate list.
2956 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002957 HandleScope inner_scope(isolate);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002958 CompileRun("%OptimizeFunctionOnNextCall(f); f(3);");
2959 }
2960
2961 // This cycle will bust the heap and subsequent cycles will go ballistic.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002962 heap->CollectAllGarbage(Heap::kNoGCFlags);
2963 heap->CollectAllGarbage(Heap::kNoGCFlags);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002964}
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002965
2966
2967TEST(Regress173458) {
2968 i::FLAG_always_compact = true;
2969 i::FLAG_cache_optimized_code = false;
2970 i::FLAG_allow_natives_syntax = true;
2971 i::FLAG_flush_code_incrementally = true;
2972 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002973 Isolate* isolate = Isolate::Current();
2974 Heap* heap = isolate->heap();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002975 v8::HandleScope scope;
2976
2977 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002978 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002979
2980 // Ensure the code ends up on an evacuation candidate.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002981 SimulateFullSpace(heap->code_space());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002982
2983 // Prepare an unoptimized function that is eligible for code flushing.
2984 Handle<JSFunction> function;
2985 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002986 HandleScope inner_scope(isolate);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002987 CompileRun("function mkClosure() {"
2988 " return function(x) { return x + 1; };"
2989 "}"
2990 "var f = mkClosure();"
2991 "f(1); f(2);");
2992
2993 Handle<JSFunction> f =
2994 v8::Utils::OpenHandle(
2995 *v8::Handle<v8::Function>::Cast(
2996 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2997 CHECK(f->is_compiled());
2998 const int kAgingThreshold = 6;
2999 for (int i = 0; i < kAgingThreshold; i++) {
3000 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
3001 }
3002
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00003003 function = inner_scope.CloseAndEscape(handle(*f, isolate));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003004 }
3005
3006 // Simulate incremental marking so that unoptimized function is enqueued as a
3007 // candidate for code flushing. The shared function info however will not be
3008 // explicitly enqueued.
3009 SimulateIncrementalMarking();
3010
3011 // Now enable the debugger which in turn will disable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00003012 CHECK(isolate->debug()->Load());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003013
3014 // This cycle will bust the heap and subsequent cycles will go ballistic.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00003015 heap->CollectAllGarbage(Heap::kNoGCFlags);
3016 heap->CollectAllGarbage(Heap::kNoGCFlags);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003017}