blob: c45c7b61f25b1ca372802931098f80349377ac5e [file] [log] [blame]
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001// Copyright 2012 the V8 project authors. All rights reserved.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002
3#include <stdlib.h>
4
5#include "v8.h"
6
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007#include "compilation-cache.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008#include "execution.h"
9#include "factory.h"
10#include "macro-assembler.h"
11#include "global-handles.h"
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000012#include "stub-cache.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000013#include "cctest.h"
14
15using namespace v8::internal;
16
17static v8::Persistent<v8::Context> env;
18
19static void InitializeVM() {
20 if (env.IsEmpty()) env = v8::Context::New();
21 v8::HandleScope scope;
22 env->Enter();
23}
24
25
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000026// Go through all incremental marking steps in one swoop.
27static void SimulateIncrementalMarking() {
28 IncrementalMarking* marking = HEAP->incremental_marking();
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000029 CHECK(marking->IsMarking() || marking->IsStopped());
30 if (marking->IsStopped()) {
31 marking->Start();
32 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000033 CHECK(marking->IsMarking());
34 while (!marking->IsComplete()) {
35 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
36 }
37 CHECK(marking->IsComplete());
38}
39
40
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000041static void CheckMap(Map* map, int type, int instance_size) {
42 CHECK(map->IsHeapObject());
43#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000044 CHECK(HEAP->Contains(map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000045#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000046 CHECK_EQ(HEAP->meta_map(), map->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000047 CHECK_EQ(type, map->instance_type());
48 CHECK_EQ(instance_size, map->instance_size());
49}
50
51
52TEST(HeapMaps) {
53 InitializeVM();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000054 CheckMap(HEAP->meta_map(), MAP_TYPE, Map::kSize);
55 CheckMap(HEAP->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
56 CheckMap(HEAP->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
57 CheckMap(HEAP->string_map(), STRING_TYPE, kVariableSizeSentinel);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000058}
59
60
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000061static void CheckOddball(Isolate* isolate, Object* obj, const char* string) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000062 CHECK(obj->IsOddball());
63 bool exc;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000064 Object* print_string =
65 *Execution::ToString(Handle<Object>(obj, isolate), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000066 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000067}
68
69
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000070static void CheckSmi(Isolate* isolate, int value, const char* string) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000071 bool exc;
72 Object* print_string =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000073 *Execution::ToString(Handle<Object>(Smi::FromInt(value), isolate), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000074 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000075}
76
77
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000078static void CheckNumber(Isolate* isolate, double value, const char* string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000079 Object* obj = HEAP->NumberFromDouble(value)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000080 CHECK(obj->IsNumber());
81 bool exc;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000082 Object* print_string =
83 *Execution::ToString(Handle<Object>(obj, isolate), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000084 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000085}
86
87
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000088static void CheckFindCodeObject(Isolate* isolate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000089 // Test FindCodeObject
90#define __ assm.
91
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000092 Assembler assm(isolate, NULL, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000093
94 __ nop(); // supported on all architectures
95
96 CodeDesc desc;
97 assm.GetCode(&desc);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000098 Heap* heap = isolate->heap();
99 Object* code = heap->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000100 desc,
101 Code::ComputeFlags(Code::STUB),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000102 Handle<Code>())->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000103 CHECK(code->IsCode());
104
105 HeapObject* obj = HeapObject::cast(code);
106 Address obj_addr = obj->address();
107
108 for (int i = 0; i < obj->Size(); i += kPointerSize) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000109 Object* found = heap->FindCodeObject(obj_addr + i);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000110 CHECK_EQ(code, found);
111 }
112
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000113 Object* copy = heap->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000114 desc,
115 Code::ComputeFlags(Code::STUB),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000116 Handle<Code>())->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000117 CHECK(copy->IsCode());
118 HeapObject* obj_copy = HeapObject::cast(copy);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000119 Object* not_right = heap->FindCodeObject(obj_copy->address() +
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000120 obj_copy->Size() / 2);
121 CHECK(not_right != code);
122}
123
124
125TEST(HeapObjects) {
126 InitializeVM();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000127 Isolate* isolate = Isolate::Current();
128 Heap* heap = isolate->heap();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000129
130 v8::HandleScope sc;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000131 Object* value = heap->NumberFromDouble(1.000123)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000132 CHECK(value->IsHeapNumber());
133 CHECK(value->IsNumber());
134 CHECK_EQ(1.000123, value->Number());
135
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000136 value = heap->NumberFromDouble(1.0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000137 CHECK(value->IsSmi());
138 CHECK(value->IsNumber());
139 CHECK_EQ(1.0, value->Number());
140
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000141 value = heap->NumberFromInt32(1024)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000142 CHECK(value->IsSmi());
143 CHECK(value->IsNumber());
144 CHECK_EQ(1024.0, value->Number());
145
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000146 value = heap->NumberFromInt32(Smi::kMinValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000147 CHECK(value->IsSmi());
148 CHECK(value->IsNumber());
149 CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
150
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000151 value = heap->NumberFromInt32(Smi::kMaxValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000152 CHECK(value->IsSmi());
153 CHECK(value->IsNumber());
154 CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value());
155
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000156#ifndef V8_TARGET_ARCH_X64
157 // TODO(lrn): We need a NumberFromIntptr function in order to test this.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000158 value = heap->NumberFromInt32(Smi::kMinValue - 1)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000159 CHECK(value->IsHeapNumber());
160 CHECK(value->IsNumber());
161 CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000162#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000163
lrn@chromium.org303ada72010-10-27 09:33:13 +0000164 MaybeObject* maybe_value =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000165 heap->NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000166 value = maybe_value->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000167 CHECK(value->IsHeapNumber());
168 CHECK(value->IsNumber());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000169 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
170 value->Number());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000171
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000172 maybe_value = heap->NumberFromUint32(static_cast<uint32_t>(1) << 31);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000173 value = maybe_value->ToObjectChecked();
174 CHECK(value->IsHeapNumber());
175 CHECK(value->IsNumber());
176 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(1) << 31),
177 value->Number());
178
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000179 // nan oddball checks
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000180 CHECK(heap->nan_value()->IsNumber());
181 CHECK(isnan(heap->nan_value()->Number()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000182
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000183 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest "));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000184 CHECK(s->IsString());
185 CHECK_EQ(10, s->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000186
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000187 String* object_string = String::cast(heap->Object_string());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000188 CHECK(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000189 Isolate::Current()->context()->global_object()->HasLocalProperty(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000190 object_string));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000191
192 // Check ToString for oddballs
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000193 CheckOddball(isolate, heap->true_value(), "true");
194 CheckOddball(isolate, heap->false_value(), "false");
195 CheckOddball(isolate, heap->null_value(), "null");
196 CheckOddball(isolate, heap->undefined_value(), "undefined");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000197
198 // Check ToString for Smis
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000199 CheckSmi(isolate, 0, "0");
200 CheckSmi(isolate, 42, "42");
201 CheckSmi(isolate, -42, "-42");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000202
203 // Check ToString for Numbers
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000204 CheckNumber(isolate, 1.1, "1.1");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000205
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000206 CheckFindCodeObject(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000207}
208
209
210TEST(Tagging) {
211 InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000212 int request = 24;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000213 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000214 CHECK(Smi::FromInt(42)->IsSmi());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000215 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000216 CHECK_EQ(NEW_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000217 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000218 CHECK_EQ(OLD_POINTER_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000219 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000220 CHECK(Failure::Exception()->IsFailure());
221 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
222 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
223}
224
225
226TEST(GarbageCollection) {
227 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000228 Isolate* isolate = Isolate::Current();
229 Heap* heap = isolate->heap();
230 Factory* factory = isolate->factory();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000231
232 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000233 // Check GC.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000234 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000235
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000236 Handle<String> name = factory->InternalizeUtf8String("theFunction");
237 Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
238 Handle<String> prop_namex = factory->InternalizeUtf8String("theSlotx");
239 Handle<String> obj_name = factory->InternalizeUtf8String("theObject");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000240
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000241 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000242 HandleScope inner_scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000243 // Allocate a function and keep it in global object's property.
244 Handle<JSFunction> function =
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000245 factory->NewFunction(name, factory->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000246 Handle<Map> initial_map =
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000247 factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000248 function->set_initial_map(*initial_map);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000249 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000250 *name, *function, NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000251 // Allocate an object. Unrooted after leaving the scope.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000252 Handle<JSObject> obj = factory->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000253 obj->SetProperty(
254 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
255 obj->SetProperty(
256 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000257
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000258 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
259 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
260 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000261
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000262 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000263
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000264 // Function should be alive.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000265 CHECK(Isolate::Current()->context()->global_object()->
266 HasLocalProperty(*name));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000267 // Check function is retained.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000268 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000269 GetProperty(*name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000270 CHECK(func_value->IsJSFunction());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000271 Handle<JSFunction> function(JSFunction::cast(func_value));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000272
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000273 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000274 HandleScope inner_scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000275 // Allocate another object, make it reachable from global.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000276 Handle<JSObject> obj = factory->NewJSObject(function);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000277 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000278 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked();
279 obj->SetProperty(
280 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000281 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000282
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000283 // After gc, it should survive.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000284 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000285
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000286 CHECK(Isolate::Current()->context()->global_object()->
287 HasLocalProperty(*obj_name));
288 CHECK(Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000289 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000290 Object* obj = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000291 GetProperty(*obj_name)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000292 JSObject* js_obj = JSObject::cast(obj);
293 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000294}
295
296
297static void VerifyStringAllocation(const char* string) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000298 v8::HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000299 Handle<String> s = FACTORY->NewStringFromUtf8(CStrVector(string));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000300 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000301 for (int index = 0; index < s->length(); index++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000302 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
303 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000304}
305
306
307TEST(String) {
308 InitializeVM();
309
310 VerifyStringAllocation("a");
311 VerifyStringAllocation("ab");
312 VerifyStringAllocation("abc");
313 VerifyStringAllocation("abcd");
314 VerifyStringAllocation("fiskerdrengen er paa havet");
315}
316
317
318TEST(LocalHandles) {
319 InitializeVM();
320
321 v8::HandleScope scope;
322 const char* name = "Kasper the spunky";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000323 Handle<String> string = FACTORY->NewStringFromAscii(CStrVector(name));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000324 CHECK_EQ(StrLength(name), string->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000325}
326
327
328TEST(GlobalHandles) {
329 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000330 Isolate* isolate = Isolate::Current();
331 Heap* heap = isolate->heap();
332 Factory* factory = isolate->factory();
333 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000334
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000335 Handle<Object> h1;
336 Handle<Object> h2;
337 Handle<Object> h3;
338 Handle<Object> h4;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000339
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000340 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000341 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000342
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000343 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
344 Handle<Object> u = factory->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000346 h1 = global_handles->Create(*i);
347 h2 = global_handles->Create(*u);
348 h3 = global_handles->Create(*i);
349 h4 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000350 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000351
352 // after gc, it should survive
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000353 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000354
355 CHECK((*h1)->IsString());
356 CHECK((*h2)->IsHeapNumber());
357 CHECK((*h3)->IsString());
358 CHECK((*h4)->IsHeapNumber());
359
360 CHECK_EQ(*h3, *h1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 global_handles->Destroy(h1.location());
362 global_handles->Destroy(h3.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000363
364 CHECK_EQ(*h4, *h2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000365 global_handles->Destroy(h2.location());
366 global_handles->Destroy(h4.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000367}
368
369
370static bool WeakPointerCleared = false;
371
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000372static void TestWeakGlobalHandleCallback(v8::Isolate* isolate,
373 v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000374 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000375 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000376 handle.Dispose(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000377}
378
379
380TEST(WeakGlobalHandlesScavenge) {
381 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000382 Isolate* isolate = Isolate::Current();
383 Heap* heap = isolate->heap();
384 Factory* factory = isolate->factory();
385 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000386
387 WeakPointerCleared = false;
388
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000389 Handle<Object> h1;
390 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000391
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000392 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000393 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000394
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000395 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
396 Handle<Object> u = factory->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000397
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000398 h1 = global_handles->Create(*i);
399 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000400 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000401
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000402 global_handles->MakeWeak(h2.location(),
403 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000404 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000406
407 // Scavenge treats weak pointers as normal roots.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000408 heap->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000409
410 CHECK((*h1)->IsString());
411 CHECK((*h2)->IsHeapNumber());
412
413 CHECK(!WeakPointerCleared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000414 CHECK(!global_handles->IsNearDeath(h2.location()));
415 CHECK(!global_handles->IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000416
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000417 global_handles->Destroy(h1.location());
418 global_handles->Destroy(h2.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000419}
420
421
422TEST(WeakGlobalHandlesMark) {
423 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000424 Isolate* isolate = Isolate::Current();
425 Heap* heap = isolate->heap();
426 Factory* factory = isolate->factory();
427 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000428
429 WeakPointerCleared = false;
430
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000431 Handle<Object> h1;
432 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000433
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000434 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000435 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000436
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000437 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
438 Handle<Object> u = factory->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000439
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000440 h1 = global_handles->Create(*i);
441 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000442 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000443
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000444 // Make sure the objects are promoted.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000445 heap->CollectGarbage(OLD_POINTER_SPACE);
446 heap->CollectGarbage(NEW_SPACE);
447 CHECK(!heap->InNewSpace(*h1) && !heap->InNewSpace(*h2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000448
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000449 global_handles->MakeWeak(h2.location(),
450 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000451 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000452 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000453 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
454 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
455
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000456 // Incremental marking potentially marked handles before they turned weak.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000457 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000458
459 CHECK((*h1)->IsString());
460
461 CHECK(WeakPointerCleared);
462 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000463
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000464 global_handles->Destroy(h1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000465}
466
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000467
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000468TEST(DeleteWeakGlobalHandle) {
469 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000470 Isolate* isolate = Isolate::Current();
471 Heap* heap = isolate->heap();
472 Factory* factory = isolate->factory();
473 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000474
475 WeakPointerCleared = false;
476
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000477 Handle<Object> h;
478
479 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000480 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000481
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000482 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000483 h = global_handles->Create(*i);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000484 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000485
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000486 global_handles->MakeWeak(h.location(),
487 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000488 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000489 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000490
491 // Scanvenge does not recognize weak reference.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000492 heap->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000493
494 CHECK(!WeakPointerCleared);
495
496 // Mark-compact treats weak reference properly.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000497 heap->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000498
499 CHECK(WeakPointerCleared);
500}
501
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000502
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000503static const char* not_so_random_string_table[] = {
504 "abstract",
505 "boolean",
506 "break",
507 "byte",
508 "case",
509 "catch",
510 "char",
511 "class",
512 "const",
513 "continue",
514 "debugger",
515 "default",
516 "delete",
517 "do",
518 "double",
519 "else",
520 "enum",
521 "export",
522 "extends",
523 "false",
524 "final",
525 "finally",
526 "float",
527 "for",
528 "function",
529 "goto",
530 "if",
531 "implements",
532 "import",
533 "in",
534 "instanceof",
535 "int",
536 "interface",
537 "long",
538 "native",
539 "new",
540 "null",
541 "package",
542 "private",
543 "protected",
544 "public",
545 "return",
546 "short",
547 "static",
548 "super",
549 "switch",
550 "synchronized",
551 "this",
552 "throw",
553 "throws",
554 "transient",
555 "true",
556 "try",
557 "typeof",
558 "var",
559 "void",
560 "volatile",
561 "while",
562 "with",
563 0
564};
565
566
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000567static void CheckInternalizedStrings(const char** strings) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000568 for (const char* string = *strings; *strings != 0; string = *strings++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000569 Object* a;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000570 MaybeObject* maybe_a = HEAP->InternalizeUtf8String(string);
571 // InternalizeUtf8String may return a failure if a GC is needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000572 if (!maybe_a->ToObject(&a)) continue;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000573 CHECK(a->IsInternalizedString());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000574 Object* b;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000575 MaybeObject* maybe_b = HEAP->InternalizeUtf8String(string);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000576 if (!maybe_b->ToObject(&b)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000577 CHECK_EQ(b, a);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000578 CHECK(String::cast(b)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000579 }
580}
581
582
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000583TEST(StringTable) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000584 InitializeVM();
585
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000586 CheckInternalizedStrings(not_so_random_string_table);
587 CheckInternalizedStrings(not_so_random_string_table);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000588}
589
590
591TEST(FunctionAllocation) {
592 InitializeVM();
593
594 v8::HandleScope sc;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000595 Handle<String> name = FACTORY->InternalizeUtf8String("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000596 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000598 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000600 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000601
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000602 Handle<String> prop_name = FACTORY->InternalizeUtf8String("theSlot");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000603 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000604 obj->SetProperty(
605 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000606 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000607 // Check that we can add properties to function objects.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000608 function->SetProperty(
609 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000610 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000611}
612
613
614TEST(ObjectProperties) {
615 InitializeVM();
616
617 v8::HandleScope sc;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000618 String* object_string = String::cast(HEAP->Object_string());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000619 Object* raw_object = Isolate::Current()->context()->global_object()->
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000620 GetProperty(object_string)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000621 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000622 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000623 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000624 Handle<String> first = FACTORY->InternalizeUtf8String("first");
625 Handle<String> second = FACTORY->InternalizeUtf8String("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000626
627 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000628 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000629
630 // add first
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000631 obj->SetProperty(
632 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000633 CHECK(obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000634
635 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000636 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
637 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000638
639 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000640 obj->SetProperty(
641 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
642 obj->SetProperty(
643 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000644 CHECK(obj->HasLocalProperty(*first));
645 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000646
647 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000648 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
649 CHECK(obj->HasLocalProperty(*second));
650 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
651 CHECK(!obj->HasLocalProperty(*first));
652 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000653
654 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000655 obj->SetProperty(
656 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
657 obj->SetProperty(
658 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000659 CHECK(obj->HasLocalProperty(*first));
660 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000661
662 // delete second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000663 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
664 CHECK(obj->HasLocalProperty(*first));
665 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
666 CHECK(!obj->HasLocalProperty(*first));
667 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000668
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000669 // check string and internalized string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000670 const char* string1 = "fisk";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000671 Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000672 obj->SetProperty(
673 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000674 Handle<String> s1_string = FACTORY->InternalizeUtf8String(string1);
675 CHECK(obj->HasLocalProperty(*s1_string));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000676
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000677 // check internalized string and string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000678 const char* string2 = "fugl";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000679 Handle<String> s2_string = FACTORY->InternalizeUtf8String(string2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000680 obj->SetProperty(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000681 *s2_string, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000682 Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000683 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000684}
685
686
687TEST(JSObjectMaps) {
688 InitializeVM();
689
690 v8::HandleScope sc;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000691 Handle<String> name = FACTORY->InternalizeUtf8String("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000692 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000693 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000694 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000695 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000696 function->set_initial_map(*initial_map);
697
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000698 Handle<String> prop_name = FACTORY->InternalizeUtf8String("theSlot");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000699 Handle<JSObject> obj = FACTORY->NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000700
701 // Set a propery
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000702 obj->SetProperty(
703 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000704 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000705
706 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000707 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000708}
709
710
711TEST(JSArray) {
712 InitializeVM();
713
714 v8::HandleScope sc;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000715 Handle<String> name = FACTORY->InternalizeUtf8String("Array");
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000716 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000717 GetProperty(*name)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000718 Handle<JSFunction> function = Handle<JSFunction>(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000719 JSFunction::cast(raw_object));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000720
721 // Allocate the object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000722 Handle<JSObject> object = FACTORY->NewJSObject(function);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000723 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000724 // We just initialized the VM, no heap allocation failure yet.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000725 array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000726
727 // Set array length to 0.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000728 array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000729 CHECK_EQ(Smi::FromInt(0), array->length());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000730 // Must be in fast mode.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000731 CHECK(array->HasFastSmiOrObjectElements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000732
733 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000734 array->SetElement(0, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000735 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000736 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000737
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000738 // Set array length with larger than smi value.
739 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000740 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000741 array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000742
743 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000744 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000745 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000746 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000747
748 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000749 array->SetElement(int_length, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000750 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000751 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000752 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000753 CHECK_EQ(array->GetElement(int_length), *name);
754 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000755}
756
757
758TEST(JSObjectCopy) {
759 InitializeVM();
760
761 v8::HandleScope sc;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000762 String* object_string = String::cast(HEAP->Object_string());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000763 Object* raw_object = Isolate::Current()->context()->global_object()->
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000764 GetProperty(object_string)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000765 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000766 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000767 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000768 Handle<String> first = FACTORY->InternalizeUtf8String("first");
769 Handle<String> second = FACTORY->InternalizeUtf8String("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000770
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000771 obj->SetProperty(
772 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
773 obj->SetProperty(
774 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000775
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000776 obj->SetElement(0, *first, NONE, kNonStrictMode)->ToObjectChecked();
777 obj->SetElement(1, *second, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000778
779 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000780 Handle<JSObject> clone = Copy(obj);
781 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000782
783 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
784 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
785
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000786 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
787 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000788
789 // Flip the values.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000790 clone->SetProperty(
791 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
792 clone->SetProperty(
793 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000794
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000795 clone->SetElement(0, *second, NONE, kNonStrictMode)->ToObjectChecked();
796 clone->SetElement(1, *first, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000797
798 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
799 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
800
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000801 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
802 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000803}
804
805
806TEST(StringAllocation) {
807 InitializeVM();
808
809
810 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
811 for (int length = 0; length < 100; length++) {
812 v8::HandleScope scope;
813 char* non_ascii = NewArray<char>(3 * length + 1);
814 char* ascii = NewArray<char>(length + 1);
815 non_ascii[3 * length] = 0;
816 ascii[length] = 0;
817 for (int i = 0; i < length; i++) {
818 ascii[i] = 'a';
819 non_ascii[3 * i] = chars[0];
820 non_ascii[3 * i + 1] = chars[1];
821 non_ascii[3 * i + 2] = chars[2];
822 }
823 Handle<String> non_ascii_sym =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000824 FACTORY->InternalizeUtf8String(
825 Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000826 CHECK_EQ(length, non_ascii_sym->length());
827 Handle<String> ascii_sym =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000828 FACTORY->InternalizeOneByteString(OneByteVector(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000829 CHECK_EQ(length, ascii_sym->length());
830 Handle<String> non_ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000831 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000832 non_ascii_str->Hash();
833 CHECK_EQ(length, non_ascii_str->length());
834 Handle<String> ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000835 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000836 ascii_str->Hash();
837 CHECK_EQ(length, ascii_str->length());
838 DeleteArray(non_ascii);
839 DeleteArray(ascii);
840 }
841}
842
843
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000844static int ObjectsFoundInHeap(Heap* heap, Handle<Object> objs[], int size) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000845 // Count the number of objects found in the heap.
846 int found_count = 0;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000847 HeapIterator iterator(heap);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000848 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000849 for (int i = 0; i < size; i++) {
850 if (*objs[i] == obj) {
851 found_count++;
852 }
853 }
854 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000855 return found_count;
856}
857
858
859TEST(Iteration) {
860 InitializeVM();
861 v8::HandleScope scope;
862
863 // Array of objects to scan haep for.
864 const int objs_count = 6;
865 Handle<Object> objs[objs_count];
866 int next_objs_index = 0;
867
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000868 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000869 objs[next_objs_index++] = FACTORY->NewJSArray(10);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000870 objs[next_objs_index++] = FACTORY->NewJSArray(10,
871 FAST_HOLEY_ELEMENTS,
872 TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000873
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000874 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000875 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000876 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000877 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000878 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000879
880 // Allocate a large string (for large object space).
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000881 int large_size = Page::kMaxNonCodeHeapObjectSize + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000882 char* str = new char[large_size];
883 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
884 str[large_size - 1] = '\0';
885 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000886 FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000887 delete[] str;
888
889 // Add a Map object to look for.
890 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
891
892 CHECK_EQ(objs_count, next_objs_index);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000893 CHECK_EQ(objs_count, ObjectsFoundInHeap(HEAP, objs, objs_count));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000894}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000895
896
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000897TEST(EmptyHandleEscapeFrom) {
898 InitializeVM();
899
900 v8::HandleScope scope;
901 Handle<JSObject> runaway;
902
903 {
904 v8::HandleScope nested;
905 Handle<JSObject> empty;
906 runaway = empty.EscapeFrom(&nested);
907 }
908
909 CHECK(runaway.is_null());
910}
911
912
913static int LenFromSize(int size) {
914 return (size - FixedArray::kHeaderSize) / kPointerSize;
915}
916
917
918TEST(Regression39128) {
919 // Test case for crbug.com/39128.
920 InitializeVM();
921
922 // Increase the chance of 'bump-the-pointer' allocation in old space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000923 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000924
925 v8::HandleScope scope;
926
927 // The plan: create JSObject which references objects in new space.
928 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000929 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000930
931 // Step 1: prepare a map for the object. We add 1 inobject property to it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 Handle<JSFunction> object_ctor(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000933 Isolate::Current()->native_context()->object_function());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000934 CHECK(object_ctor->has_initial_map());
935 Handle<Map> object_map(object_ctor->initial_map());
936 // Create a map with single inobject property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000937 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000938 int n_properties = my_map->inobject_properties();
939 CHECK_GT(n_properties, 0);
940
941 int object_size = my_map->instance_size();
942
943 // Step 2: allocate a lot of objects so to almost fill new space: we need
944 // just enough room to allocate JSObject and thus fill the newspace.
945
946 int allocation_amount = Min(FixedArray::kMaxSize,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000947 HEAP->MaxObjectSizeInNewSpace());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000948 int allocation_len = LenFromSize(allocation_amount);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000949 NewSpace* new_space = HEAP->new_space();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000950 Address* top_addr = new_space->allocation_top_address();
951 Address* limit_addr = new_space->allocation_limit_address();
952 while ((*limit_addr - *top_addr) > allocation_amount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000953 CHECK(!HEAP->always_allocate());
954 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
955 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000956 CHECK(new_space->Contains(array));
957 }
958
959 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000960 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000961 int fixed_array_len = LenFromSize(to_fill);
962 CHECK(fixed_array_len < FixedArray::kMaxLength);
963
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000964 CHECK(!HEAP->always_allocate());
965 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
966 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000967 CHECK(new_space->Contains(array));
968
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000970 CHECK(new_space->Contains(object));
971 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000972 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000973 CHECK_EQ(0, jsobject->properties()->length());
974 // Create a reference to object in new space in jsobject.
975 jsobject->FastPropertyAtPut(-1, array);
976
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000977 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000978
979 // Step 4: clone jsobject, but force always allocate first to create a clone
980 // in old pointer space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000981 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000982 AlwaysAllocateScope aa_scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000984 JSObject* clone = JSObject::cast(clone_obj);
985 if (clone->address() != old_pointer_space_top) {
986 // Alas, got allocated from free list, we cannot do checks.
987 return;
988 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000989 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000990}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000991
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000992
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000993TEST(TestCodeFlushing) {
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +0000994 // If we do not flush code this test is invalid.
995 if (!FLAG_flush_code) return;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000996 i::FLAG_allow_natives_syntax = true;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000997 InitializeVM();
998 v8::HandleScope scope;
999 const char* source = "function foo() {"
1000 " var x = 42;"
1001 " var y = 42;"
1002 " var z = x + y;"
1003 "};"
1004 "foo()";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001005 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001006
1007 // This compile will add the code to the compilation cache.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001008 { v8::HandleScope scope;
1009 CompileRun(source);
1010 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001011
1012 // Check function is compiled.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001013 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001014 GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001015 CHECK(func_value->IsJSFunction());
1016 Handle<JSFunction> function(JSFunction::cast(func_value));
1017 CHECK(function->shared()->is_compiled());
1018
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001019 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001020 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1021 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001022 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001023
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001024 // Simulate several GCs that use full marking.
1025 const int kAgingThreshold = 6;
1026 for (int i = 0; i < kAgingThreshold; i++) {
1027 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1028 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001029
1030 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001031 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1032 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001033 // Call foo to get it recompiled.
1034 CompileRun("foo()");
1035 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001036 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001037}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001038
1039
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001040TEST(TestCodeFlushingIncremental) {
1041 // If we do not flush code this test is invalid.
1042 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1043 i::FLAG_allow_natives_syntax = true;
1044 InitializeVM();
1045 v8::HandleScope scope;
1046 const char* source = "function foo() {"
1047 " var x = 42;"
1048 " var y = 42;"
1049 " var z = x + y;"
1050 "};"
1051 "foo()";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001052 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001053
1054 // This compile will add the code to the compilation cache.
1055 { v8::HandleScope scope;
1056 CompileRun(source);
1057 }
1058
1059 // Check function is compiled.
1060 Object* func_value = Isolate::Current()->context()->global_object()->
1061 GetProperty(*foo_name)->ToObjectChecked();
1062 CHECK(func_value->IsJSFunction());
1063 Handle<JSFunction> function(JSFunction::cast(func_value));
1064 CHECK(function->shared()->is_compiled());
1065
1066 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001067 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1068 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001069 CHECK(function->shared()->is_compiled());
1070
1071 // Simulate several GCs that use incremental marking.
1072 const int kAgingThreshold = 6;
1073 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001074 SimulateIncrementalMarking();
1075 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1076 }
1077 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1078 CHECK(!function->is_compiled() || function->IsOptimized());
1079
1080 // This compile will compile the function again.
1081 { v8::HandleScope scope;
1082 CompileRun("foo();");
1083 }
1084
1085 // Simulate several GCs that use incremental marking but make sure
1086 // the loop breaks once the function is enqueued as a candidate.
1087 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001088 SimulateIncrementalMarking();
1089 if (!function->next_function_link()->IsUndefined()) break;
1090 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1091 }
1092
1093 // Force optimization while incremental marking is active and while
1094 // the function is enqueued as a candidate.
1095 { v8::HandleScope scope;
1096 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1097 }
1098
1099 // Simulate one final GC to make sure the candidate queue is sane.
1100 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1101 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1102 CHECK(function->is_compiled() || !function->IsOptimized());
1103}
1104
1105
1106TEST(TestCodeFlushingIncrementalScavenge) {
1107 // If we do not flush code this test is invalid.
1108 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1109 i::FLAG_allow_natives_syntax = true;
1110 InitializeVM();
1111 v8::HandleScope scope;
1112 const char* source = "var foo = function() {"
1113 " var x = 42;"
1114 " var y = 42;"
1115 " var z = x + y;"
1116 "};"
1117 "foo();"
1118 "var bar = function() {"
1119 " var x = 23;"
1120 "};"
1121 "bar();";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001122 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
1123 Handle<String> bar_name = FACTORY->InternalizeUtf8String("bar");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001124
1125 // Perfrom one initial GC to enable code flushing.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001126 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001127
1128 // This compile will add the code to the compilation cache.
1129 { v8::HandleScope scope;
1130 CompileRun(source);
1131 }
1132
1133 // Check functions are compiled.
1134 Object* func_value = Isolate::Current()->context()->global_object()->
1135 GetProperty(*foo_name)->ToObjectChecked();
1136 CHECK(func_value->IsJSFunction());
1137 Handle<JSFunction> function(JSFunction::cast(func_value));
1138 CHECK(function->shared()->is_compiled());
1139 Object* func_value2 = Isolate::Current()->context()->global_object()->
1140 GetProperty(*bar_name)->ToObjectChecked();
1141 CHECK(func_value2->IsJSFunction());
1142 Handle<JSFunction> function2(JSFunction::cast(func_value2));
1143 CHECK(function2->shared()->is_compiled());
1144
1145 // Clear references to functions so that one of them can die.
1146 { v8::HandleScope scope;
1147 CompileRun("foo = 0; bar = 0;");
1148 }
1149
1150 // Bump the code age so that flushing is triggered while the function
1151 // object is still located in new-space.
1152 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001153 for (int i = 0; i < kAgingThreshold; i++) {
1154 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1155 function2->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1156 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001157
1158 // Simulate incremental marking so that the functions are enqueued as
1159 // code flushing candidates. Then kill one of the functions. Finally
1160 // perform a scavenge while incremental marking is still running.
1161 SimulateIncrementalMarking();
1162 *function2.location() = NULL;
1163 HEAP->CollectGarbage(NEW_SPACE, "test scavenge while marking");
1164
1165 // Simulate one final GC to make sure the candidate queue is sane.
1166 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1167 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1168 CHECK(!function->is_compiled() || function->IsOptimized());
1169}
1170
1171
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001172TEST(TestCodeFlushingIncrementalAbort) {
1173 // If we do not flush code this test is invalid.
1174 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1175 i::FLAG_allow_natives_syntax = true;
1176 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001177 Isolate* isolate = Isolate::Current();
1178 Heap* heap = isolate->heap();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001179 v8::HandleScope scope;
1180 const char* source = "function foo() {"
1181 " var x = 42;"
1182 " var y = 42;"
1183 " var z = x + y;"
1184 "};"
1185 "foo()";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001186 Handle<String> foo_name = FACTORY->InternalizeUtf8String("foo");
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001187
1188 // This compile will add the code to the compilation cache.
1189 { v8::HandleScope scope;
1190 CompileRun(source);
1191 }
1192
1193 // Check function is compiled.
1194 Object* func_value = Isolate::Current()->context()->global_object()->
1195 GetProperty(*foo_name)->ToObjectChecked();
1196 CHECK(func_value->IsJSFunction());
1197 Handle<JSFunction> function(JSFunction::cast(func_value));
1198 CHECK(function->shared()->is_compiled());
1199
1200 // The code will survive at least two GCs.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001201 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1202 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001203 CHECK(function->shared()->is_compiled());
1204
1205 // Bump the code age so that flushing is triggered.
1206 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001207 for (int i = 0; i < kAgingThreshold; i++) {
1208 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1209 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001210
1211 // Simulate incremental marking so that the function is enqueued as
1212 // code flushing candidate.
1213 SimulateIncrementalMarking();
1214
1215 // Enable the debugger and add a breakpoint while incremental marking
1216 // is running so that incremental marking aborts and code flushing is
1217 // disabled.
1218 int position = 0;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001219 Handle<Object> breakpoint_object(Smi::FromInt(0), isolate);
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001220 isolate->debug()->SetBreakPoint(function, breakpoint_object, &position);
1221 isolate->debug()->ClearAllBreakPoints();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001222
1223 // Force optimization now that code flushing is disabled.
1224 { v8::HandleScope scope;
1225 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1226 }
1227
1228 // Simulate one final GC to make sure the candidate queue is sane.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001229 heap->CollectAllGarbage(Heap::kNoGCFlags);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001230 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1231 CHECK(function->is_compiled() || !function->IsOptimized());
1232}
1233
1234
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001235// Count the number of native contexts in the weak list of native contexts.
1236int CountNativeContexts() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001237 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001238 Object* object = HEAP->native_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001239 while (!object->IsUndefined()) {
1240 count++;
1241 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1242 }
1243 return count;
1244}
1245
1246
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001247// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001248// functions attached to a native context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001249static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1250 int count = 0;
1251 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1252 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1253 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1254 count++;
1255 object = JSFunction::cast(object)->next_function_link();
1256 }
1257 return count;
1258}
1259
1260
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001261TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001262 v8::V8::Initialize();
1263
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001264 // Some flags turn Scavenge collections into Mark-sweep collections
1265 // and hence are incompatible with this test case.
1266 if (FLAG_gc_global || FLAG_stress_compaction) return;
1267
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001268 static const int kNumTestContexts = 10;
1269
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001270 Isolate* isolate = Isolate::Current();
1271 Heap* heap = isolate->heap();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001272 v8::HandleScope scope;
1273 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1274
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001275 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001276
1277 // Create a number of global contests which gets linked together.
1278 for (int i = 0; i < kNumTestContexts; i++) {
1279 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001280
1281 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1282
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001283 CHECK_EQ(i + 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001284
1285 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001286
1287 // Create a handle scope so no function objects get stuch in the outer
1288 // handle scope
1289 v8::HandleScope scope;
1290 const char* source = "function f1() { };"
1291 "function f2() { };"
1292 "function f3() { };"
1293 "function f4() { };"
1294 "function f5() { };";
1295 CompileRun(source);
1296 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1297 CompileRun("f1()");
1298 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1299 CompileRun("f2()");
1300 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1301 CompileRun("f3()");
1302 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1303 CompileRun("f4()");
1304 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1305 CompileRun("f5()");
1306 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1307
1308 // Remove function f1, and
1309 CompileRun("f1=null");
1310
1311 // Scavenge treats these references as strong.
1312 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001313 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001314 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1315 }
1316
1317 // Mark compact handles the weak references.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001318 isolate->compilation_cache()->Clear();
1319 heap->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001320 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1321
1322 // Get rid of f3 and f5 in the same way.
1323 CompileRun("f3=null");
1324 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001325 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001326 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1327 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001328 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001329 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1330 CompileRun("f5=null");
1331 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001332 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001333 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1334 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001335 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001336 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1337
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001338 ctx[i]->Exit();
1339 }
1340
1341 // Force compilation cache cleanup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001342 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001343
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001344 // Dispose the native contexts one by one.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001345 for (int i = 0; i < kNumTestContexts; i++) {
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001346 ctx[i].Dispose(ctx[i]->GetIsolate());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001347 ctx[i].Clear();
1348
1349 // Scavenge treats these references as strong.
1350 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001351 HEAP->PerformScavenge();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001352 CHECK_EQ(kNumTestContexts - i, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001353 }
1354
1355 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001356 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001357 CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001358 }
1359
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001360 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001361}
1362
1363
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001364// Count the number of native contexts in the weak list of native contexts
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001365// causing a GC after the specified number of elements.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001366static int CountNativeContextsWithGC(Isolate* isolate, int n) {
1367 Heap* heap = isolate->heap();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001368 int count = 0;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001369 Handle<Object> object(heap->native_contexts_list(), isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001370 while (!object->IsUndefined()) {
1371 count++;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001372 if (count == n) heap->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001373 object =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001374 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK),
1375 isolate);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001376 }
1377 return count;
1378}
1379
1380
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001381// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001382// functions attached to a native context causing a GC after the
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001383// specified number of elements.
1384static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1385 int n) {
1386 int count = 0;
1387 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001388 Isolate* isolate = icontext->GetIsolate();
1389 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST),
1390 isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001391 while (object->IsJSFunction() &&
1392 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1393 count++;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001394 if (count == n) isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001395 object = Handle<Object>(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001396 Object::cast(JSFunction::cast(*object)->next_function_link()),
1397 isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001398 }
1399 return count;
1400}
1401
1402
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001403TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001404 v8::V8::Initialize();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001405 Isolate* isolate = Isolate::Current();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001406
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001407 static const int kNumTestContexts = 10;
1408
1409 v8::HandleScope scope;
1410 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1411
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001412 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001413
1414 // Create an number of contexts and check the length of the weak list both
1415 // with and without GCs while iterating the list.
1416 for (int i = 0; i < kNumTestContexts; i++) {
1417 ctx[i] = v8::Context::New();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001418 CHECK_EQ(i + 1, CountNativeContexts());
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001419 CHECK_EQ(i + 1, CountNativeContextsWithGC(isolate, i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001420 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001421
1422 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1423
1424 // Compile a number of functions the length of the weak list of optimized
1425 // functions both with and without GCs while iterating the list.
1426 ctx[0]->Enter();
1427 const char* source = "function f1() { };"
1428 "function f2() { };"
1429 "function f3() { };"
1430 "function f4() { };"
1431 "function f5() { };";
1432 CompileRun(source);
1433 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1434 CompileRun("f1()");
1435 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1436 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1437 CompileRun("f2()");
1438 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1439 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1440 CompileRun("f3()");
1441 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1442 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1443 CompileRun("f4()");
1444 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1445 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1446 CompileRun("f5()");
1447 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1448 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1449
1450 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001451}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001452
1453
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001454TEST(TestSizeOfObjects) {
1455 v8::V8::Initialize();
1456
1457 // Get initial heap size after several full GCs, which will stabilize
1458 // the heap size and return with sweeping finished completely.
1459 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1460 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1461 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1462 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001463 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001464 CHECK(HEAP->old_pointer_space()->IsLazySweepingComplete());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001465 int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1466
1467 {
1468 // Allocate objects on several different old-space pages so that
1469 // lazy sweeping kicks in for subsequent GC runs.
1470 AlwaysAllocateScope always_allocate;
1471 int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1472 for (int i = 1; i <= 100; i++) {
1473 HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1474 CHECK_EQ(initial_size + i * filler_size,
1475 static_cast<int>(HEAP->SizeOfObjects()));
1476 }
1477 }
1478
1479 // The heap size should go back to initial size after a full GC, even
1480 // though sweeping didn't finish yet.
1481 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001482
1483 // Normally sweeping would not be complete here, but no guarantees.
1484
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001485 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1486
1487 // Advancing the sweeper step-wise should not change the heap size.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001488 while (!HEAP->old_pointer_space()->IsLazySweepingComplete()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001489 HEAP->old_pointer_space()->AdvanceSweeper(KB);
1490 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1491 }
1492}
1493
1494
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001495TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1496 InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001497 HEAP->EnsureHeapIsIterable();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001498 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001499 HeapIterator iterator(HEAP);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001500 intptr_t size_of_objects_2 = 0;
1501 for (HeapObject* obj = iterator.next();
1502 obj != NULL;
1503 obj = iterator.next()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001504 if (!obj->IsFreeSpace()) {
1505 size_of_objects_2 += obj->Size();
1506 }
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001507 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001508 // Delta must be within 5% of the larger result.
1509 // TODO(gc): Tighten this up by distinguishing between byte
1510 // arrays that are real and those that merely mark free space
1511 // on the heap.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001512 if (size_of_objects_1 > size_of_objects_2) {
1513 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1514 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1515 "Iterator: %" V8_PTR_PREFIX "d, "
1516 "delta: %" V8_PTR_PREFIX "d\n",
1517 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001518 CHECK_GT(size_of_objects_1 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001519 } else {
1520 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1521 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1522 "Iterator: %" V8_PTR_PREFIX "d, "
1523 "delta: %" V8_PTR_PREFIX "d\n",
1524 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001525 CHECK_GT(size_of_objects_2 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001526 }
1527}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001528
1529
danno@chromium.orgc612e022011-11-10 11:38:15 +00001530static void FillUpNewSpace(NewSpace* new_space) {
1531 // Fill up new space to the point that it is completely full. Make sure
1532 // that the scavenger does not undo the filling.
1533 v8::HandleScope scope;
1534 AlwaysAllocateScope always_allocate;
1535 intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001536 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001537 for (intptr_t i = 0; i < number_of_fillers; i++) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001538 CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001539 }
1540}
1541
1542
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001543TEST(GrowAndShrinkNewSpace) {
1544 InitializeVM();
1545 NewSpace* new_space = HEAP->new_space();
1546
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001547 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1548 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001549 // The max size cannot exceed the reserved size, since semispaces must be
1550 // always within the reserved space. We can't test new space growing and
1551 // shrinking if the reserved size is the same as the minimum (initial) size.
1552 return;
1553 }
1554
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001555 // Explicitly growing should double the space capacity.
1556 intptr_t old_capacity, new_capacity;
1557 old_capacity = new_space->Capacity();
1558 new_space->Grow();
1559 new_capacity = new_space->Capacity();
1560 CHECK(2 * old_capacity == new_capacity);
1561
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001562 old_capacity = new_space->Capacity();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001563 FillUpNewSpace(new_space);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001564 new_capacity = new_space->Capacity();
1565 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001566
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001567 // Explicitly shrinking should not affect space capacity.
1568 old_capacity = new_space->Capacity();
1569 new_space->Shrink();
1570 new_capacity = new_space->Capacity();
1571 CHECK(old_capacity == new_capacity);
1572
1573 // Let the scavenger empty the new space.
1574 HEAP->CollectGarbage(NEW_SPACE);
1575 CHECK_LE(new_space->Size(), old_capacity);
1576
1577 // Explicitly shrinking should halve the space capacity.
1578 old_capacity = new_space->Capacity();
1579 new_space->Shrink();
1580 new_capacity = new_space->Capacity();
1581 CHECK(old_capacity == 2 * new_capacity);
1582
1583 // Consecutive shrinking should not affect space capacity.
1584 old_capacity = new_space->Capacity();
1585 new_space->Shrink();
1586 new_space->Shrink();
1587 new_space->Shrink();
1588 new_capacity = new_space->Capacity();
1589 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001590}
danno@chromium.orgc612e022011-11-10 11:38:15 +00001591
1592
1593TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1594 InitializeVM();
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001595
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001596 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1597 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001598 // The max size cannot exceed the reserved size, since semispaces must be
1599 // always within the reserved space. We can't test new space growing and
1600 // shrinking if the reserved size is the same as the minimum (initial) size.
1601 return;
1602 }
1603
danno@chromium.orgc612e022011-11-10 11:38:15 +00001604 v8::HandleScope scope;
1605 NewSpace* new_space = HEAP->new_space();
1606 intptr_t old_capacity, new_capacity;
1607 old_capacity = new_space->Capacity();
1608 new_space->Grow();
1609 new_capacity = new_space->Capacity();
1610 CHECK(2 * old_capacity == new_capacity);
1611 FillUpNewSpace(new_space);
1612 HEAP->CollectAllAvailableGarbage();
1613 new_capacity = new_space->Capacity();
1614 CHECK(old_capacity == new_capacity);
1615}
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001616
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001617
1618static int NumberOfGlobalObjects() {
1619 int count = 0;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001620 HeapIterator iterator(HEAP);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001621 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1622 if (obj->IsGlobalObject()) count++;
1623 }
1624 return count;
1625}
1626
1627
1628// Test that we don't embed maps from foreign contexts into
1629// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001630TEST(LeakNativeContextViaMap) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001631 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001632 v8::HandleScope outer_scope;
1633 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1634 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1635 ctx1->Enter();
1636
1637 HEAP->CollectAllAvailableGarbage();
1638 CHECK_EQ(4, NumberOfGlobalObjects());
1639
1640 {
1641 v8::HandleScope inner_scope;
1642 CompileRun("var v = {x: 42}");
1643 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1644 ctx2->Enter();
1645 ctx2->Global()->Set(v8_str("o"), v);
1646 v8::Local<v8::Value> res = CompileRun(
1647 "function f() { return o.x; }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001648 "for (var i = 0; i < 10; ++i) f();"
1649 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001650 "f();");
1651 CHECK_EQ(42, res->Int32Value());
1652 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1653 ctx2->Exit();
1654 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001655 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001656 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001657 }
1658 HEAP->CollectAllAvailableGarbage();
1659 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001660 ctx2.Dispose(ctx2->GetIsolate());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001661 HEAP->CollectAllAvailableGarbage();
1662 CHECK_EQ(0, NumberOfGlobalObjects());
1663}
1664
1665
1666// Test that we don't embed functions from foreign contexts into
1667// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001668TEST(LeakNativeContextViaFunction) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001669 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001670 v8::HandleScope outer_scope;
1671 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1672 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1673 ctx1->Enter();
1674
1675 HEAP->CollectAllAvailableGarbage();
1676 CHECK_EQ(4, NumberOfGlobalObjects());
1677
1678 {
1679 v8::HandleScope inner_scope;
1680 CompileRun("var v = function() { return 42; }");
1681 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1682 ctx2->Enter();
1683 ctx2->Global()->Set(v8_str("o"), v);
1684 v8::Local<v8::Value> res = CompileRun(
1685 "function f(x) { return x(); }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001686 "for (var i = 0; i < 10; ++i) f(o);"
1687 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001688 "f(o);");
1689 CHECK_EQ(42, res->Int32Value());
1690 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1691 ctx2->Exit();
1692 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001693 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001694 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001695 }
1696 HEAP->CollectAllAvailableGarbage();
1697 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001698 ctx2.Dispose(ctx2->GetIsolate());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001699 HEAP->CollectAllAvailableGarbage();
1700 CHECK_EQ(0, NumberOfGlobalObjects());
1701}
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001702
1703
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001704TEST(LeakNativeContextViaMapKeyed) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001705 i::FLAG_allow_natives_syntax = true;
1706 v8::HandleScope outer_scope;
1707 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1708 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1709 ctx1->Enter();
1710
1711 HEAP->CollectAllAvailableGarbage();
1712 CHECK_EQ(4, NumberOfGlobalObjects());
1713
1714 {
1715 v8::HandleScope inner_scope;
1716 CompileRun("var v = [42, 43]");
1717 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1718 ctx2->Enter();
1719 ctx2->Global()->Set(v8_str("o"), v);
1720 v8::Local<v8::Value> res = CompileRun(
1721 "function f() { return o[0]; }"
1722 "for (var i = 0; i < 10; ++i) f();"
1723 "%OptimizeFunctionOnNextCall(f);"
1724 "f();");
1725 CHECK_EQ(42, res->Int32Value());
1726 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1727 ctx2->Exit();
1728 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001729 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001730 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001731 }
1732 HEAP->CollectAllAvailableGarbage();
1733 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001734 ctx2.Dispose(ctx2->GetIsolate());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001735 HEAP->CollectAllAvailableGarbage();
1736 CHECK_EQ(0, NumberOfGlobalObjects());
1737}
1738
1739
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001740TEST(LeakNativeContextViaMapProto) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001741 i::FLAG_allow_natives_syntax = true;
1742 v8::HandleScope outer_scope;
1743 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1744 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1745 ctx1->Enter();
1746
1747 HEAP->CollectAllAvailableGarbage();
1748 CHECK_EQ(4, NumberOfGlobalObjects());
1749
1750 {
1751 v8::HandleScope inner_scope;
1752 CompileRun("var v = { y: 42}");
1753 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1754 ctx2->Enter();
1755 ctx2->Global()->Set(v8_str("o"), v);
1756 v8::Local<v8::Value> res = CompileRun(
1757 "function f() {"
1758 " var p = {x: 42};"
1759 " p.__proto__ = o;"
1760 " return p.x;"
1761 "}"
1762 "for (var i = 0; i < 10; ++i) f();"
1763 "%OptimizeFunctionOnNextCall(f);"
1764 "f();");
1765 CHECK_EQ(42, res->Int32Value());
1766 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1767 ctx2->Exit();
1768 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001769 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001770 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001771 }
1772 HEAP->CollectAllAvailableGarbage();
1773 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001774 ctx2.Dispose(ctx2->GetIsolate());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001775 HEAP->CollectAllAvailableGarbage();
1776 CHECK_EQ(0, NumberOfGlobalObjects());
1777}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001778
1779
1780TEST(InstanceOfStubWriteBarrier) {
1781 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001782#ifdef VERIFY_HEAP
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001783 i::FLAG_verify_heap = true;
1784#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001785
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001786 InitializeVM();
1787 if (!i::V8::UseCrankshaft()) return;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001788 if (i::FLAG_force_marking_deque_overflows) return;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001789 v8::HandleScope outer_scope;
1790
1791 {
1792 v8::HandleScope scope;
1793 CompileRun(
1794 "function foo () { }"
1795 "function mkbar () { return new (new Function(\"\")) (); }"
1796 "function f (x) { return (x instanceof foo); }"
1797 "function g () { f(mkbar()); }"
1798 "f(new foo()); f(new foo());"
1799 "%OptimizeFunctionOnNextCall(f);"
1800 "f(new foo()); g();");
1801 }
1802
1803 IncrementalMarking* marking = HEAP->incremental_marking();
1804 marking->Abort();
1805 marking->Start();
1806
1807 Handle<JSFunction> f =
1808 v8::Utils::OpenHandle(
1809 *v8::Handle<v8::Function>::Cast(
1810 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1811
1812 CHECK(f->IsOptimized());
1813
1814 while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1815 !marking->IsStopped()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001816 // Discard any pending GC requests otherwise we will get GC when we enter
1817 // code below.
1818 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001819 }
1820
1821 CHECK(marking->IsMarking());
1822
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001823 {
1824 v8::HandleScope scope;
1825 v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1826 v8::Handle<v8::Function> g =
1827 v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1828 g->Call(global, 0, NULL);
1829 }
1830
1831 HEAP->incremental_marking()->set_should_hurry(true);
1832 HEAP->CollectGarbage(OLD_POINTER_SPACE);
1833}
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001834
1835
1836TEST(PrototypeTransitionClearing) {
1837 InitializeVM();
1838 v8::HandleScope scope;
1839
1840 CompileRun(
1841 "var base = {};"
1842 "var live = [];"
1843 "for (var i = 0; i < 10; i++) {"
1844 " var object = {};"
1845 " var prototype = {};"
1846 " object.__proto__ = prototype;"
1847 " if (i >= 3) live.push(object, prototype);"
1848 "}");
1849
1850 Handle<JSObject> baseObject =
1851 v8::Utils::OpenHandle(
1852 *v8::Handle<v8::Object>::Cast(
1853 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1854
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001855 // Verify that only dead prototype transitions are cleared.
1856 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001857 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001858 const int transitions = 10 - 3;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001859 CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001860
1861 // Verify that prototype transitions array was compacted.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001862 FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001863 for (int i = 0; i < transitions; i++) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001864 int j = Map::kProtoTransitionHeaderSize +
1865 i * Map::kProtoTransitionElementsPerEntry;
1866 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001867 Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
1868 CHECK(proto->IsTheHole() || proto->IsJSObject());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001869 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001870
1871 // Make sure next prototype is placed on an old-space evacuation candidate.
1872 Handle<JSObject> prototype;
1873 PagedSpace* space = HEAP->old_pointer_space();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001874 {
1875 AlwaysAllocateScope always_allocate;
1876 SimulateFullSpace(space);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001877 prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001878 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001879
1880 // Add a prototype on an evacuation candidate and verify that transition
1881 // clearing correctly records slots in prototype transition array.
1882 i::FLAG_always_compact = true;
1883 Handle<Map> map(baseObject->map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001884 CHECK(!space->LastPage()->Contains(
1885 map->GetPrototypeTransitions()->address()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001886 CHECK(space->LastPage()->Contains(prototype->address()));
1887 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1888 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1889 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1890 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001891}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001892
1893
1894TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1895 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001896#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001897 i::FLAG_verify_heap = true;
1898#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001899
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001900 InitializeVM();
1901 if (!i::V8::UseCrankshaft()) return;
1902 v8::HandleScope outer_scope;
1903
1904 {
1905 v8::HandleScope scope;
1906 CompileRun(
1907 "function f () {"
1908 " var s = 0;"
1909 " for (var i = 0; i < 100; i++) s += i;"
1910 " return s;"
1911 "}"
1912 "f(); f();"
1913 "%OptimizeFunctionOnNextCall(f);"
1914 "f();");
1915 }
1916 Handle<JSFunction> f =
1917 v8::Utils::OpenHandle(
1918 *v8::Handle<v8::Function>::Cast(
1919 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1920 CHECK(f->IsOptimized());
1921
1922 IncrementalMarking* marking = HEAP->incremental_marking();
1923 marking->Abort();
1924 marking->Start();
1925
1926 // The following two calls will increment HEAP->global_ic_age().
1927 const int kLongIdlePauseInMs = 1000;
1928 v8::V8::ContextDisposedNotification();
1929 v8::V8::IdleNotification(kLongIdlePauseInMs);
1930
1931 while (!marking->IsStopped() && !marking->IsComplete()) {
1932 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1933 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001934 if (!marking->IsStopped() || marking->should_hurry()) {
1935 // We don't normally finish a GC via Step(), we normally finish by
1936 // setting the stack guard and then do the final steps in the stack
1937 // guard interrupt. But here we didn't ask for that, and there is no
1938 // JS code running to trigger the interrupt, so we explicitly finalize
1939 // here.
1940 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1941 "Test finalizing incremental mark-sweep");
1942 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001943
1944 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1945 CHECK_EQ(0, f->shared()->opt_count());
1946 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1947}
1948
1949
1950TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1951 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001952#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001953 i::FLAG_verify_heap = true;
1954#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001955
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001956 InitializeVM();
1957 if (!i::V8::UseCrankshaft()) return;
1958 v8::HandleScope outer_scope;
1959
1960 {
1961 v8::HandleScope scope;
1962 CompileRun(
1963 "function f () {"
1964 " var s = 0;"
1965 " for (var i = 0; i < 100; i++) s += i;"
1966 " return s;"
1967 "}"
1968 "f(); f();"
1969 "%OptimizeFunctionOnNextCall(f);"
1970 "f();");
1971 }
1972 Handle<JSFunction> f =
1973 v8::Utils::OpenHandle(
1974 *v8::Handle<v8::Function>::Cast(
1975 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1976 CHECK(f->IsOptimized());
1977
1978 HEAP->incremental_marking()->Abort();
1979
1980 // The following two calls will increment HEAP->global_ic_age().
1981 // Since incremental marking is off, IdleNotification will do full GC.
1982 const int kLongIdlePauseInMs = 1000;
1983 v8::V8::ContextDisposedNotification();
1984 v8::V8::IdleNotification(kLongIdlePauseInMs);
1985
1986 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1987 CHECK_EQ(0, f->shared()->opt_count());
1988 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1989}
1990
1991
1992// Test that HAllocateObject will always return an object in new-space.
1993TEST(OptimizedAllocationAlwaysInNewSpace) {
1994 i::FLAG_allow_natives_syntax = true;
1995 InitializeVM();
1996 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001997 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001998 v8::HandleScope scope;
1999
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002000 SimulateFullSpace(HEAP->new_space());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00002001 AlwaysAllocateScope always_allocate;
2002 v8::Local<v8::Value> res = CompileRun(
2003 "function c(x) {"
2004 " this.x = x;"
2005 " for (var i = 0; i < 32; i++) {"
2006 " this['x' + i] = x;"
2007 " }"
2008 "}"
2009 "function f(x) { return new c(x); };"
2010 "f(1); f(2); f(3);"
2011 "%OptimizeFunctionOnNextCall(f);"
2012 "f(4);");
2013 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
2014
2015 Handle<JSObject> o =
2016 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2017
2018 CHECK(HEAP->InNewSpace(*o));
2019}
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002020
2021
2022static int CountMapTransitions(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002023 return map->transitions()->number_of_transitions();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002024}
2025
2026
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002027// Test that map transitions are cleared and maps are collected with
2028// incremental marking as well.
2029TEST(Regress1465) {
2030 i::FLAG_allow_natives_syntax = true;
2031 i::FLAG_trace_incremental_marking = true;
2032 InitializeVM();
2033 v8::HandleScope scope;
2034 static const int transitions_count = 256;
2035
2036 {
2037 AlwaysAllocateScope always_allocate;
2038 for (int i = 0; i < transitions_count; i++) {
2039 EmbeddedVector<char, 64> buffer;
2040 OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
2041 CompileRun(buffer.start());
2042 }
2043 CompileRun("var root = new Object;");
2044 }
2045
2046 Handle<JSObject> root =
2047 v8::Utils::OpenHandle(
2048 *v8::Handle<v8::Object>::Cast(
2049 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2050
2051 // Count number of live transitions before marking.
2052 int transitions_before = CountMapTransitions(root->map());
2053 CompileRun("%DebugPrint(root);");
2054 CHECK_EQ(transitions_count, transitions_before);
2055
2056 SimulateIncrementalMarking();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002057 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002058
2059 // Count number of live transitions after marking. Note that one transition
2060 // is left, because 'o' still holds an instance of one transition target.
2061 int transitions_after = CountMapTransitions(root->map());
2062 CompileRun("%DebugPrint(root);");
2063 CHECK_EQ(1, transitions_after);
2064}
verwaest@chromium.org37141392012-05-31 13:27:02 +00002065
2066
2067TEST(Regress2143a) {
2068 i::FLAG_collect_maps = true;
2069 i::FLAG_incremental_marking = true;
2070 InitializeVM();
2071 v8::HandleScope scope;
2072
2073 // Prepare a map transition from the root object together with a yet
2074 // untransitioned root object.
2075 CompileRun("var root = new Object;"
2076 "root.foo = 0;"
2077 "root = new Object;");
2078
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002079 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002080
2081 // Compile a StoreIC that performs the prepared map transition. This
2082 // will restart incremental marking and should make sure the root is
2083 // marked grey again.
2084 CompileRun("function f(o) {"
2085 " o.foo = 0;"
2086 "}"
2087 "f(new Object);"
2088 "f(root);");
2089
2090 // This bug only triggers with aggressive IC clearing.
2091 HEAP->AgeInlineCaches();
2092
2093 // Explicitly request GC to perform final marking step and sweeping.
2094 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002095
2096 Handle<JSObject> root =
2097 v8::Utils::OpenHandle(
2098 *v8::Handle<v8::Object>::Cast(
2099 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2100
2101 // The root object should be in a sane state.
2102 CHECK(root->IsJSObject());
2103 CHECK(root->map()->IsMap());
2104}
2105
2106
2107TEST(Regress2143b) {
2108 i::FLAG_collect_maps = true;
2109 i::FLAG_incremental_marking = true;
2110 i::FLAG_allow_natives_syntax = true;
2111 InitializeVM();
2112 v8::HandleScope scope;
2113
2114 // Prepare a map transition from the root object together with a yet
2115 // untransitioned root object.
2116 CompileRun("var root = new Object;"
2117 "root.foo = 0;"
2118 "root = new Object;");
2119
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002120 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002121
2122 // Compile an optimized LStoreNamedField that performs the prepared
2123 // map transition. This will restart incremental marking and should
2124 // make sure the root is marked grey again.
2125 CompileRun("function f(o) {"
2126 " o.foo = 0;"
2127 "}"
2128 "f(new Object);"
2129 "f(new Object);"
2130 "%OptimizeFunctionOnNextCall(f);"
2131 "f(root);"
2132 "%DeoptimizeFunction(f);");
2133
2134 // This bug only triggers with aggressive IC clearing.
2135 HEAP->AgeInlineCaches();
2136
2137 // Explicitly request GC to perform final marking step and sweeping.
2138 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002139
2140 Handle<JSObject> root =
2141 v8::Utils::OpenHandle(
2142 *v8::Handle<v8::Object>::Cast(
2143 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2144
2145 // The root object should be in a sane state.
2146 CHECK(root->IsJSObject());
2147 CHECK(root->map()->IsMap());
2148}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002149
2150
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002151TEST(ReleaseOverReservedPages) {
2152 i::FLAG_trace_gc = true;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002153 // The optimizer can allocate stuff, messing up the test.
2154 i::FLAG_crankshaft = false;
2155 i::FLAG_always_opt = false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002156 InitializeVM();
2157 v8::HandleScope scope;
2158 static const int number_of_test_pages = 20;
2159
2160 // Prepare many pages with low live-bytes count.
2161 PagedSpace* old_pointer_space = HEAP->old_pointer_space();
2162 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2163 for (int i = 0; i < number_of_test_pages; i++) {
2164 AlwaysAllocateScope always_allocate;
2165 SimulateFullSpace(old_pointer_space);
2166 FACTORY->NewFixedArray(1, TENURED);
2167 }
2168 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2169
2170 // Triggering one GC will cause a lot of garbage to be discovered but
2171 // even spread across all allocated pages.
2172 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00002173 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002174
2175 // Triggering subsequent GCs should cause at least half of the pages
2176 // to be released to the OS after at most two cycles.
2177 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
2178 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2179 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
2180 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
2181
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002182 // Triggering a last-resort GC should cause all pages to be released to the
2183 // OS so that other processes can seize the memory. If we get a failure here
2184 // where there are 2 pages left instead of 1, then we should increase the
2185 // size of the first page a little in SizeOfFirstPage in spaces.cc. The
2186 // first page should be small in order to reduce memory used when the VM
2187 // boots, but if the 20 small arrays don't fit on the first page then that's
2188 // an indication that it is too small.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002189 HEAP->CollectAllAvailableGarbage("triggered really hard");
2190 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2191}
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002192
2193
2194TEST(Regress2237) {
2195 InitializeVM();
2196 v8::HandleScope scope;
2197 Handle<String> slice(HEAP->empty_string());
2198
2199 {
2200 // Generate a parent that lives in new-space.
2201 v8::HandleScope inner_scope;
2202 const char* c = "This text is long enough to trigger sliced strings.";
2203 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002204 CHECK(s->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002205 CHECK(HEAP->InNewSpace(*s));
2206
2207 // Generate a sliced string that is based on the above parent and
2208 // lives in old-space.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002209 SimulateFullSpace(HEAP->new_space());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002210 AlwaysAllocateScope always_allocate;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002211 Handle<String> t = FACTORY->NewProperSubString(s, 5, 35);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002212 CHECK(t->IsSlicedString());
2213 CHECK(!HEAP->InNewSpace(*t));
2214 *slice.location() = *t.location();
2215 }
2216
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002217 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002218 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002219 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002220}
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00002221
2222
2223#ifdef OBJECT_PRINT
2224TEST(PrintSharedFunctionInfo) {
2225 InitializeVM();
2226 v8::HandleScope scope;
2227 const char* source = "f = function() { return 987654321; }\n"
2228 "g = function() { return 123456789; }\n";
2229 CompileRun(source);
2230 Handle<JSFunction> g =
2231 v8::Utils::OpenHandle(
2232 *v8::Handle<v8::Function>::Cast(
2233 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2234
2235 AssertNoAllocation no_alloc;
2236 g->shared()->PrintLn();
2237}
2238#endif // OBJECT_PRINT
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002239
2240
2241TEST(Regress2211) {
2242 InitializeVM();
2243 v8::HandleScope scope;
2244
2245 v8::Handle<v8::String> value = v8_str("val string");
2246 Smi* hash = Smi::FromInt(321);
2247 Heap* heap = Isolate::Current()->heap();
2248
2249 for (int i = 0; i < 2; i++) {
2250 // Store identity hash first and common hidden property second.
2251 v8::Handle<v8::Object> obj = v8::Object::New();
2252 Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
2253 CHECK(internal_obj->HasFastProperties());
2254
2255 // In the first iteration, set hidden value first and identity hash second.
2256 // In the second iteration, reverse the order.
2257 if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
2258 MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
2259 ALLOW_CREATION);
2260 CHECK(!maybe_obj->IsFailure());
2261 if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
2262
2263 // Check values.
2264 CHECK_EQ(hash,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002265 internal_obj->GetHiddenProperty(heap->identity_hash_string()));
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002266 CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
2267
2268 // Check size.
2269 DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
2270 ObjectHashTable* hashtable = ObjectHashTable::cast(
2271 internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
2272 // HashTable header (5) and 4 initial entries (8).
2273 CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
2274 }
2275}
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002276
2277
2278TEST(IncrementalMarkingClearsTypeFeedbackCells) {
2279 if (i::FLAG_always_opt) return;
2280 InitializeVM();
2281 v8::HandleScope scope;
2282 v8::Local<v8::Value> fun1, fun2;
2283
2284 {
2285 LocalContext env;
2286 CompileRun("function fun() {};");
2287 fun1 = env->Global()->Get(v8_str("fun"));
2288 }
2289
2290 {
2291 LocalContext env;
2292 CompileRun("function fun() {};");
2293 fun2 = env->Global()->Get(v8_str("fun"));
2294 }
2295
2296 // Prepare function f that contains type feedback for closures
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002297 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002298 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1);
2299 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2);
2300 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
2301 Handle<JSFunction> f =
2302 v8::Utils::OpenHandle(
2303 *v8::Handle<v8::Function>::Cast(
2304 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2305 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast(
2306 f->shared()->code()->type_feedback_info())->type_feedback_cells());
2307
2308 CHECK_EQ(2, cells->CellCount());
2309 CHECK(cells->Cell(0)->value()->IsJSFunction());
2310 CHECK(cells->Cell(1)->value()->IsJSFunction());
2311
2312 SimulateIncrementalMarking();
2313 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2314
2315 CHECK_EQ(2, cells->CellCount());
2316 CHECK(cells->Cell(0)->value()->IsTheHole());
2317 CHECK(cells->Cell(1)->value()->IsTheHole());
2318}
2319
2320
2321static Code* FindFirstIC(Code* code, Code::Kind kind) {
2322 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
2323 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
2324 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
2325 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
2326 for (RelocIterator it(code, mask); !it.done(); it.next()) {
2327 RelocInfo* info = it.rinfo();
2328 Code* target = Code::GetCodeFromTargetAddress(info->target_address());
2329 if (target->is_inline_cache_stub() && target->kind() == kind) {
2330 return target;
2331 }
2332 }
2333 return NULL;
2334}
2335
2336
2337TEST(IncrementalMarkingPreservesMonomorhpicIC) {
2338 if (i::FLAG_always_opt) return;
2339 InitializeVM();
2340 v8::HandleScope scope;
2341
2342 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002343 // originating from the same native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002344 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
2345 "function f(o) { return o.x; } f(obj); f(obj);");
2346 Handle<JSFunction> f =
2347 v8::Utils::OpenHandle(
2348 *v8::Handle<v8::Function>::Cast(
2349 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2350
2351 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2352 CHECK(ic_before->ic_state() == MONOMORPHIC);
2353
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002354 SimulateIncrementalMarking();
2355 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2356
2357 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2358 CHECK(ic_after->ic_state() == MONOMORPHIC);
2359}
2360
2361
2362TEST(IncrementalMarkingClearsMonomorhpicIC) {
2363 if (i::FLAG_always_opt) return;
2364 InitializeVM();
2365 v8::HandleScope scope;
2366 v8::Local<v8::Value> obj1;
2367
2368 {
2369 LocalContext env;
2370 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2371 obj1 = env->Global()->Get(v8_str("obj"));
2372 }
2373
2374 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002375 // originating from a different native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002376 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2377 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
2378 Handle<JSFunction> f =
2379 v8::Utils::OpenHandle(
2380 *v8::Handle<v8::Function>::Cast(
2381 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2382
2383 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2384 CHECK(ic_before->ic_state() == MONOMORPHIC);
2385
2386 // Fire context dispose notification.
2387 v8::V8::ContextDisposedNotification();
2388 SimulateIncrementalMarking();
2389 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2390
2391 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2392 CHECK(ic_after->ic_state() == UNINITIALIZED);
2393}
2394
2395
2396TEST(IncrementalMarkingClearsPolymorhpicIC) {
2397 if (i::FLAG_always_opt) return;
2398 InitializeVM();
2399 v8::HandleScope scope;
2400 v8::Local<v8::Value> obj1, obj2;
2401
2402 {
2403 LocalContext env;
2404 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2405 obj1 = env->Global()->Get(v8_str("obj"));
2406 }
2407
2408 {
2409 LocalContext env;
2410 CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
2411 obj2 = env->Global()->Get(v8_str("obj"));
2412 }
2413
2414 // Prepare function f that contains a polymorphic IC for objects
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002415 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002416 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2417 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2);
2418 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
2419 Handle<JSFunction> f =
2420 v8::Utils::OpenHandle(
2421 *v8::Handle<v8::Function>::Cast(
2422 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2423
2424 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002425 CHECK(ic_before->ic_state() == POLYMORPHIC);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002426
2427 // Fire context dispose notification.
2428 v8::V8::ContextDisposedNotification();
2429 SimulateIncrementalMarking();
2430 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2431
2432 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2433 CHECK(ic_after->ic_state() == UNINITIALIZED);
2434}
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002435
2436
2437class SourceResource: public v8::String::ExternalAsciiStringResource {
2438 public:
2439 explicit SourceResource(const char* data)
2440 : data_(data), length_(strlen(data)) { }
2441
2442 virtual void Dispose() {
2443 i::DeleteArray(data_);
2444 data_ = NULL;
2445 }
2446
2447 const char* data() const { return data_; }
2448
2449 size_t length() const { return length_; }
2450
2451 bool IsDisposed() { return data_ == NULL; }
2452
2453 private:
2454 const char* data_;
2455 size_t length_;
2456};
2457
2458
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002459void ReleaseStackTraceDataTest(const char* source) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002460 // Test that the data retained by the Error.stack accessor is released
2461 // after the first time the accessor is fired. We use external string
2462 // to check whether the data is being released since the external string
2463 // resource's callback is fired when the external string is GC'ed.
2464 InitializeVM();
2465 v8::HandleScope scope;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002466 SourceResource* resource = new SourceResource(i::StrDup(source));
2467 {
2468 v8::HandleScope scope;
2469 v8::Handle<v8::String> source_string = v8::String::NewExternal(resource);
2470 v8::Script::Compile(source_string)->Run();
2471 CHECK(!resource->IsDisposed());
2472 }
2473 HEAP->CollectAllAvailableGarbage();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002474
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002475 // External source has been released.
2476 CHECK(resource->IsDisposed());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002477 delete resource;
2478}
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002479
2480
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002481TEST(ReleaseStackTraceData) {
2482 static const char* source1 = "var error = null; "
2483 /* Normal Error */ "try { "
2484 " throw new Error(); "
2485 "} catch (e) { "
2486 " error = e; "
2487 "} ";
2488 static const char* source2 = "var error = null; "
2489 /* Stack overflow */ "try { "
2490 " (function f() { f(); })(); "
2491 "} catch (e) { "
2492 " error = e; "
2493 "} ";
2494 ReleaseStackTraceDataTest(source1);
2495 ReleaseStackTraceDataTest(source2);
2496}
2497
2498
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002499TEST(Regression144230) {
2500 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002501 Isolate* isolate = Isolate::Current();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002502 Heap* heap = isolate->heap();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002503 v8::HandleScope scope;
2504
2505 // First make sure that the uninitialized CallIC stub is on a single page
2506 // that will later be selected as an evacuation candidate.
2507 {
2508 v8::HandleScope inner_scope;
2509 AlwaysAllocateScope always_allocate;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002510 SimulateFullSpace(heap->code_space());
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002511 isolate->stub_cache()->ComputeCallInitialize(9, RelocInfo::CODE_TARGET);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002512 }
2513
2514 // Second compile a CallIC and execute it once so that it gets patched to
2515 // the pre-monomorphic stub. These code objects are on yet another page.
2516 {
2517 v8::HandleScope inner_scope;
2518 AlwaysAllocateScope always_allocate;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002519 SimulateFullSpace(heap->code_space());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002520 CompileRun("var o = { f:function(a,b,c,d,e,f,g,h,i) {}};"
2521 "function call() { o.f(1,2,3,4,5,6,7,8,9); };"
2522 "call();");
2523 }
2524
2525 // Third we fill up the last page of the code space so that it does not get
2526 // chosen as an evacuation candidate.
2527 {
2528 v8::HandleScope inner_scope;
2529 AlwaysAllocateScope always_allocate;
2530 CompileRun("for (var i = 0; i < 2000; i++) {"
2531 " eval('function f' + i + '() { return ' + i +'; };' +"
2532 " 'f' + i + '();');"
2533 "}");
2534 }
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002535 heap->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002536
2537 // Fourth is the tricky part. Make sure the code containing the CallIC is
2538 // visited first without clearing the IC. The shared function info is then
2539 // visited later, causing the CallIC to be cleared.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002540 Handle<String> name = isolate->factory()->InternalizeUtf8String("call");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002541 Handle<GlobalObject> global(isolate->context()->global_object());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002542 MaybeObject* maybe_call = global->GetProperty(*name);
2543 JSFunction* call = JSFunction::cast(maybe_call->ToObjectChecked());
2544 USE(global->SetProperty(*name, Smi::FromInt(0), NONE, kNonStrictMode));
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002545 isolate->compilation_cache()->Clear();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002546 call->shared()->set_ic_age(heap->global_ic_age() + 1);
2547 Handle<Object> call_code(call->code(), isolate);
2548 Handle<Object> call_function(call, isolate);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002549
2550 // Now we are ready to mess up the heap.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002551 heap->CollectAllGarbage(Heap::kReduceMemoryFootprintMask);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002552
2553 // Either heap verification caught the problem already or we go kaboom once
2554 // the CallIC is executed the next time.
2555 USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode));
2556 CompileRun("call();");
2557}
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002558
2559
2560TEST(Regress159140) {
2561 i::FLAG_allow_natives_syntax = true;
2562 i::FLAG_flush_code_incrementally = true;
2563 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002564 Isolate* isolate = Isolate::Current();
2565 Heap* heap = isolate->heap();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002566 v8::HandleScope scope;
2567
2568 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002569 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002570
2571 // Prepare several closures that are all eligible for code flushing
2572 // because all reachable ones are not optimized. Make sure that the
2573 // optimized code object is directly reachable through a handle so
2574 // that it is marked black during incremental marking.
2575 Handle<Code> code;
2576 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002577 HandleScope inner_scope(isolate);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002578 CompileRun("function h(x) {}"
2579 "function mkClosure() {"
2580 " return function(x) { return x + 1; };"
2581 "}"
2582 "var f = mkClosure();"
2583 "var g = mkClosure();"
2584 "f(1); f(2);"
2585 "g(1); g(2);"
2586 "h(1); h(2);"
2587 "%OptimizeFunctionOnNextCall(f); f(3);"
2588 "%OptimizeFunctionOnNextCall(h); h(3);");
2589
2590 Handle<JSFunction> f =
2591 v8::Utils::OpenHandle(
2592 *v8::Handle<v8::Function>::Cast(
2593 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2594 CHECK(f->is_compiled());
2595 CompileRun("f = null;");
2596
2597 Handle<JSFunction> g =
2598 v8::Utils::OpenHandle(
2599 *v8::Handle<v8::Function>::Cast(
2600 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2601 CHECK(g->is_compiled());
2602 const int kAgingThreshold = 6;
2603 for (int i = 0; i < kAgingThreshold; i++) {
2604 g->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2605 }
2606
2607 code = inner_scope.CloseAndEscape(Handle<Code>(f->code()));
2608 }
2609
2610 // Simulate incremental marking so that the functions are enqueued as
2611 // code flushing candidates. Then optimize one function. Finally
2612 // finish the GC to complete code flushing.
2613 SimulateIncrementalMarking();
2614 CompileRun("%OptimizeFunctionOnNextCall(g); g(3);");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002615 heap->CollectAllGarbage(Heap::kNoGCFlags);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002616
2617 // Unoptimized code is missing and the deoptimizer will go ballistic.
2618 CompileRun("g('bozo');");
2619}
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002620
2621
2622TEST(Regress165495) {
2623 i::FLAG_allow_natives_syntax = true;
2624 i::FLAG_flush_code_incrementally = true;
2625 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002626 Isolate* isolate = Isolate::Current();
2627 Heap* heap = isolate->heap();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002628 v8::HandleScope scope;
2629
2630 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002631 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002632
2633 // Prepare an optimized closure that the optimized code map will get
2634 // populated. Then age the unoptimized code to trigger code flushing
2635 // but make sure the optimized code is unreachable.
2636 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002637 HandleScope inner_scope(isolate);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002638 CompileRun("function mkClosure() {"
2639 " return function(x) { return x + 1; };"
2640 "}"
2641 "var f = mkClosure();"
2642 "f(1); f(2);"
2643 "%OptimizeFunctionOnNextCall(f); f(3);");
2644
2645 Handle<JSFunction> f =
2646 v8::Utils::OpenHandle(
2647 *v8::Handle<v8::Function>::Cast(
2648 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2649 CHECK(f->is_compiled());
2650 const int kAgingThreshold = 6;
2651 for (int i = 0; i < kAgingThreshold; i++) {
2652 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2653 }
2654
2655 CompileRun("f = null;");
2656 }
2657
2658 // Simulate incremental marking so that unoptimized code is flushed
2659 // even though it still is cached in the optimized code map.
2660 SimulateIncrementalMarking();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002661 heap->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002662
2663 // Make a new closure that will get code installed from the code map.
2664 // Unoptimized code is missing and the deoptimizer will go ballistic.
2665 CompileRun("var g = mkClosure(); g('bozo');");
2666}
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002667
2668
2669TEST(Regress169209) {
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002670 i::FLAG_stress_compaction = false;
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002671 i::FLAG_allow_natives_syntax = true;
2672 i::FLAG_flush_code_incrementally = true;
2673 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002674 Isolate* isolate = Isolate::Current();
2675 Heap* heap = isolate->heap();
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002676 v8::HandleScope scope;
2677
2678 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002679 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002680
2681 // Prepare a shared function info eligible for code flushing for which
2682 // the unoptimized code will be replaced during optimization.
2683 Handle<SharedFunctionInfo> shared1;
2684 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002685 HandleScope inner_scope(isolate);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002686 CompileRun("function f() { return 'foobar'; }"
2687 "function g(x) { if (x) f(); }"
2688 "f();"
2689 "g(false);"
2690 "g(false);");
2691
2692 Handle<JSFunction> f =
2693 v8::Utils::OpenHandle(
2694 *v8::Handle<v8::Function>::Cast(
2695 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2696 CHECK(f->is_compiled());
2697 const int kAgingThreshold = 6;
2698 for (int i = 0; i < kAgingThreshold; i++) {
2699 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2700 }
2701
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002702 shared1 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002703 }
2704
2705 // Prepare a shared function info eligible for code flushing that will
2706 // represent the dangling tail of the candidate list.
2707 Handle<SharedFunctionInfo> shared2;
2708 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002709 HandleScope inner_scope(isolate);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002710 CompileRun("function flushMe() { return 0; }"
2711 "flushMe(1);");
2712
2713 Handle<JSFunction> f =
2714 v8::Utils::OpenHandle(
2715 *v8::Handle<v8::Function>::Cast(
2716 v8::Context::GetCurrent()->Global()->Get(v8_str("flushMe"))));
2717 CHECK(f->is_compiled());
2718 const int kAgingThreshold = 6;
2719 for (int i = 0; i < kAgingThreshold; i++) {
2720 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2721 }
2722
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002723 shared2 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002724 }
2725
2726 // Simulate incremental marking and collect code flushing candidates.
2727 SimulateIncrementalMarking();
2728 CHECK(shared1->code()->gc_metadata() != NULL);
2729
2730 // Optimize function and make sure the unoptimized code is replaced.
2731#ifdef DEBUG
2732 FLAG_stop_at = "f";
2733#endif
2734 CompileRun("%OptimizeFunctionOnNextCall(g);"
2735 "g(false);");
2736
2737 // Finish garbage collection cycle.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002738 heap->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002739 CHECK(shared1->code()->gc_metadata() == NULL);
2740}
yangguo@chromium.org28381b42013-01-21 14:39:38 +00002741
2742
2743// Helper function that simulates a fill new-space in the heap.
2744static inline void AllocateAllButNBytes(v8::internal::NewSpace* space,
2745 int extra_bytes) {
2746 int space_remaining = static_cast<int>(
2747 *space->allocation_limit_address() - *space->allocation_top_address());
2748 CHECK(space_remaining >= extra_bytes);
2749 int new_linear_size = space_remaining - extra_bytes;
2750 v8::internal::MaybeObject* maybe = space->AllocateRaw(new_linear_size);
2751 v8::internal::FreeListNode* node = v8::internal::FreeListNode::cast(maybe);
2752 node->set_size(space->heap(), new_linear_size);
2753}
2754
2755
2756TEST(Regress169928) {
2757 i::FLAG_allow_natives_syntax = true;
2758 i::FLAG_crankshaft = false;
2759 InitializeVM();
2760 v8::HandleScope scope;
2761
2762 // Some flags turn Scavenge collections into Mark-sweep collections
2763 // and hence are incompatible with this test case.
2764 if (FLAG_gc_global || FLAG_stress_compaction) return;
2765
2766 // Prepare the environment
2767 CompileRun("function fastliteralcase(literal, value) {"
2768 " literal[0] = value;"
2769 " return literal;"
2770 "}"
2771 "function get_standard_literal() {"
2772 " var literal = [1, 2, 3];"
2773 " return literal;"
2774 "}"
2775 "obj = fastliteralcase(get_standard_literal(), 1);"
2776 "obj = fastliteralcase(get_standard_literal(), 1.5);"
2777 "obj = fastliteralcase(get_standard_literal(), 2);");
2778
2779 // prepare the heap
2780 v8::Local<v8::String> mote_code_string =
2781 v8_str("fastliteralcase(mote, 2.5);");
2782
2783 v8::Local<v8::String> array_name = v8_str("mote");
2784 v8::Context::GetCurrent()->Global()->Set(array_name, v8::Int32::New(0));
2785
2786 // First make sure we flip spaces
2787 HEAP->CollectGarbage(NEW_SPACE);
2788
2789 // Allocate the object.
2790 Handle<FixedArray> array_data = FACTORY->NewFixedArray(2, NOT_TENURED);
2791 array_data->set(0, Smi::FromInt(1));
2792 array_data->set(1, Smi::FromInt(2));
2793
2794 AllocateAllButNBytes(HEAP->new_space(),
2795 JSArray::kSize + AllocationSiteInfo::kSize +
2796 kPointerSize);
2797
2798 Handle<JSArray> array = FACTORY->NewJSArrayWithElements(array_data,
2799 FAST_SMI_ELEMENTS,
2800 NOT_TENURED);
2801
2802 CHECK_EQ(Smi::FromInt(2), array->length());
2803 CHECK(array->HasFastSmiOrObjectElements());
2804
2805 // We need filler the size of AllocationSiteInfo object, plus an extra
2806 // fill pointer value.
2807 MaybeObject* maybe_object = HEAP->AllocateRaw(
2808 AllocationSiteInfo::kSize + kPointerSize, NEW_SPACE, OLD_POINTER_SPACE);
2809 Object* obj = NULL;
2810 CHECK(maybe_object->ToObject(&obj));
2811 Address addr_obj = reinterpret_cast<Address>(
2812 reinterpret_cast<byte*>(obj - kHeapObjectTag));
2813 HEAP->CreateFillerObjectAt(addr_obj,
2814 AllocationSiteInfo::kSize + kPointerSize);
2815
2816 // Give the array a name, making sure not to allocate strings.
2817 v8::Handle<v8::Object> array_obj = v8::Utils::ToLocal(array);
2818 v8::Context::GetCurrent()->Global()->Set(array_name, array_obj);
2819
2820 // This should crash with a protection violation if we are running a build
2821 // with the bug.
2822 AlwaysAllocateScope aa_scope;
2823 v8::Script::Compile(mote_code_string)->Run();
2824}
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002825
2826
2827TEST(Regress168801) {
2828 i::FLAG_always_compact = true;
2829 i::FLAG_cache_optimized_code = false;
2830 i::FLAG_allow_natives_syntax = true;
2831 i::FLAG_flush_code_incrementally = true;
2832 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002833 Isolate* isolate = Isolate::Current();
2834 Heap* heap = isolate->heap();
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002835 v8::HandleScope scope;
2836
2837 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002838 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002839
2840 // Ensure the code ends up on an evacuation candidate.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002841 SimulateFullSpace(heap->code_space());
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002842
2843 // Prepare an unoptimized function that is eligible for code flushing.
2844 Handle<JSFunction> function;
2845 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002846 HandleScope inner_scope(isolate);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002847 CompileRun("function mkClosure() {"
2848 " return function(x) { return x + 1; };"
2849 "}"
2850 "var f = mkClosure();"
2851 "f(1); f(2);");
2852
2853 Handle<JSFunction> f =
2854 v8::Utils::OpenHandle(
2855 *v8::Handle<v8::Function>::Cast(
2856 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2857 CHECK(f->is_compiled());
2858 const int kAgingThreshold = 6;
2859 for (int i = 0; i < kAgingThreshold; i++) {
2860 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2861 }
2862
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002863 function = inner_scope.CloseAndEscape(handle(*f, isolate));
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002864 }
2865
2866 // Simulate incremental marking so that unoptimized function is enqueued as a
2867 // candidate for code flushing. The shared function info however will not be
2868 // explicitly enqueued.
2869 SimulateIncrementalMarking();
2870
2871 // Now optimize the function so that it is taken off the candidate list.
2872 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002873 HandleScope inner_scope(isolate);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002874 CompileRun("%OptimizeFunctionOnNextCall(f); f(3);");
2875 }
2876
2877 // This cycle will bust the heap and subsequent cycles will go ballistic.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002878 heap->CollectAllGarbage(Heap::kNoGCFlags);
2879 heap->CollectAllGarbage(Heap::kNoGCFlags);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002880}
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002881
2882
2883TEST(Regress173458) {
2884 i::FLAG_always_compact = true;
2885 i::FLAG_cache_optimized_code = false;
2886 i::FLAG_allow_natives_syntax = true;
2887 i::FLAG_flush_code_incrementally = true;
2888 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002889 Isolate* isolate = Isolate::Current();
2890 Heap* heap = isolate->heap();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002891 v8::HandleScope scope;
2892
2893 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002894 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002895
2896 // Ensure the code ends up on an evacuation candidate.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002897 SimulateFullSpace(heap->code_space());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002898
2899 // Prepare an unoptimized function that is eligible for code flushing.
2900 Handle<JSFunction> function;
2901 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002902 HandleScope inner_scope(isolate);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002903 CompileRun("function mkClosure() {"
2904 " return function(x) { return x + 1; };"
2905 "}"
2906 "var f = mkClosure();"
2907 "f(1); f(2);");
2908
2909 Handle<JSFunction> f =
2910 v8::Utils::OpenHandle(
2911 *v8::Handle<v8::Function>::Cast(
2912 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2913 CHECK(f->is_compiled());
2914 const int kAgingThreshold = 6;
2915 for (int i = 0; i < kAgingThreshold; i++) {
2916 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2917 }
2918
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002919 function = inner_scope.CloseAndEscape(handle(*f, isolate));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002920 }
2921
2922 // Simulate incremental marking so that unoptimized function is enqueued as a
2923 // candidate for code flushing. The shared function info however will not be
2924 // explicitly enqueued.
2925 SimulateIncrementalMarking();
2926
2927 // Now enable the debugger which in turn will disable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002928 CHECK(isolate->debug()->Load());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002929
2930 // This cycle will bust the heap and subsequent cycles will go ballistic.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002931 heap->CollectAllGarbage(Heap::kNoGCFlags);
2932 heap->CollectAllGarbage(Heap::kNoGCFlags);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002933}