The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.
Please select the desired protocol below to get the URL.
This URL has Read-Only access.
main_repo / deps / v8 / test / cctest / test-heap.cc @ 40c0f755
History | View | Annotate | Download (23 KB)
1 |
// Copyright 2006-2008 the V8 project authors. All rights reserved.
|
---|---|
2 |
|
3 |
#include <stdlib.h> |
4 |
|
5 |
#include "v8.h" |
6 |
|
7 |
#include "execution.h" |
8 |
#include "factory.h" |
9 |
#include "macro-assembler.h" |
10 |
#include "global-handles.h" |
11 |
#include "cctest.h" |
12 |
|
13 |
using namespace v8::internal; |
14 |
|
15 |
static v8::Persistent<v8::Context> env;
|
16 |
|
17 |
static void InitializeVM() { |
18 |
if (env.IsEmpty()) env = v8::Context::New();
|
19 |
v8::HandleScope scope; |
20 |
env->Enter(); |
21 |
} |
22 |
|
23 |
|
24 |
static void CheckMap(Map* map, int type, int instance_size) { |
25 |
CHECK(map->IsHeapObject()); |
26 |
#ifdef DEBUG
|
27 |
CHECK(Heap::Contains(map)); |
28 |
#endif
|
29 |
CHECK_EQ(Heap::meta_map(), map->map()); |
30 |
CHECK_EQ(type, map->instance_type()); |
31 |
CHECK_EQ(instance_size, map->instance_size()); |
32 |
} |
33 |
|
34 |
|
35 |
TEST(HeapMaps) { |
36 |
InitializeVM(); |
37 |
CheckMap(Heap::meta_map(), MAP_TYPE, Map::kSize); |
38 |
CheckMap(Heap::heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize); |
39 |
CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, Array::kHeaderSize); |
40 |
CheckMap(Heap::long_string_map(), LONG_STRING_TYPE, |
41 |
SeqTwoByteString::kHeaderSize); |
42 |
} |
43 |
|
44 |
|
45 |
static void CheckOddball(Object* obj, const char* string) { |
46 |
CHECK(obj->IsOddball()); |
47 |
bool exc;
|
48 |
Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc); |
49 |
CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
|
50 |
} |
51 |
|
52 |
|
53 |
static void CheckSmi(int value, const char* string) { |
54 |
bool exc;
|
55 |
Object* print_string = |
56 |
*Execution::ToString(Handle<Object>(Smi::FromInt(value)), &exc); |
57 |
CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
|
58 |
} |
59 |
|
60 |
|
61 |
static void CheckNumber(double value, const char* string) { |
62 |
Object* obj = Heap::NumberFromDouble(value); |
63 |
CHECK(obj->IsNumber()); |
64 |
bool exc;
|
65 |
Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc); |
66 |
CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
|
67 |
} |
68 |
|
69 |
|
70 |
static void CheckFindCodeObject() { |
71 |
// Test FindCodeObject
|
72 |
#define __ assm.
|
73 |
|
74 |
Assembler assm(NULL, 0); |
75 |
|
76 |
__ nop(); // supported on all architectures
|
77 |
|
78 |
CodeDesc desc; |
79 |
assm.GetCode(&desc); |
80 |
Object* code = Heap::CreateCode(desc, |
81 |
NULL,
|
82 |
Code::ComputeFlags(Code::STUB), |
83 |
Handle<Object>(Heap::undefined_value())); |
84 |
CHECK(code->IsCode()); |
85 |
|
86 |
HeapObject* obj = HeapObject::cast(code); |
87 |
Address obj_addr = obj->address(); |
88 |
|
89 |
for (int i = 0; i < obj->Size(); i += kPointerSize) { |
90 |
Object* found = Heap::FindCodeObject(obj_addr + i); |
91 |
CHECK_EQ(code, found); |
92 |
} |
93 |
|
94 |
Object* copy = Heap::CreateCode(desc, |
95 |
NULL,
|
96 |
Code::ComputeFlags(Code::STUB), |
97 |
Handle<Object>(Heap::undefined_value())); |
98 |
CHECK(copy->IsCode()); |
99 |
HeapObject* obj_copy = HeapObject::cast(copy); |
100 |
Object* not_right = Heap::FindCodeObject(obj_copy->address() + |
101 |
obj_copy->Size() / 2);
|
102 |
CHECK(not_right != code); |
103 |
} |
104 |
|
105 |
|
106 |
TEST(HeapObjects) { |
107 |
InitializeVM(); |
108 |
|
109 |
v8::HandleScope sc; |
110 |
Object* value = Heap::NumberFromDouble(1.000123); |
111 |
CHECK(value->IsHeapNumber()); |
112 |
CHECK(value->IsNumber()); |
113 |
CHECK_EQ(1.000123, value->Number()); |
114 |
|
115 |
value = Heap::NumberFromDouble(1.0); |
116 |
CHECK(value->IsSmi()); |
117 |
CHECK(value->IsNumber()); |
118 |
CHECK_EQ(1.0, value->Number()); |
119 |
|
120 |
value = Heap::NumberFromInt32(1024);
|
121 |
CHECK(value->IsSmi()); |
122 |
CHECK(value->IsNumber()); |
123 |
CHECK_EQ(1024.0, value->Number()); |
124 |
|
125 |
value = Heap::NumberFromInt32(Smi::kMinValue); |
126 |
CHECK(value->IsSmi()); |
127 |
CHECK(value->IsNumber()); |
128 |
CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value()); |
129 |
|
130 |
value = Heap::NumberFromInt32(Smi::kMaxValue); |
131 |
CHECK(value->IsSmi()); |
132 |
CHECK(value->IsNumber()); |
133 |
CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value()); |
134 |
|
135 |
value = Heap::NumberFromInt32(Smi::kMinValue - 1);
|
136 |
CHECK(value->IsHeapNumber()); |
137 |
CHECK(value->IsNumber()); |
138 |
CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number()); |
139 |
|
140 |
value = Heap::NumberFromInt32(Smi::kMaxValue + 1);
|
141 |
CHECK(value->IsHeapNumber()); |
142 |
CHECK(value->IsNumber()); |
143 |
CHECK_EQ(static_cast<double>(Smi::kMaxValue + 1), value->Number()); |
144 |
|
145 |
// nan oddball checks
|
146 |
CHECK(Heap::nan_value()->IsNumber()); |
147 |
CHECK(isnan(Heap::nan_value()->Number())); |
148 |
|
149 |
Object* str = Heap::AllocateStringFromAscii(CStrVector("fisk hest "));
|
150 |
if (!str->IsFailure()) {
|
151 |
String* s = String::cast(str); |
152 |
CHECK(s->IsString()); |
153 |
CHECK_EQ(10, s->length());
|
154 |
} else {
|
155 |
CHECK(false);
|
156 |
} |
157 |
|
158 |
String* object_symbol = String::cast(Heap::Object_symbol()); |
159 |
CHECK(Top::context()->global()->HasLocalProperty(object_symbol)); |
160 |
|
161 |
// Check ToString for oddballs
|
162 |
CheckOddball(Heap::true_value(), "true");
|
163 |
CheckOddball(Heap::false_value(), "false");
|
164 |
CheckOddball(Heap::null_value(), "null");
|
165 |
CheckOddball(Heap::undefined_value(), "undefined");
|
166 |
|
167 |
// Check ToString for Smis
|
168 |
CheckSmi(0, "0"); |
169 |
CheckSmi(42, "42"); |
170 |
CheckSmi(-42, "-42"); |
171 |
|
172 |
// Check ToString for Numbers
|
173 |
CheckNumber(1.1, "1.1"); |
174 |
|
175 |
CheckFindCodeObject(); |
176 |
} |
177 |
|
178 |
|
179 |
TEST(Tagging) { |
180 |
InitializeVM(); |
181 |
CHECK(Smi::FromInt(42)->IsSmi());
|
182 |
CHECK(Failure::RetryAfterGC(12, NEW_SPACE)->IsFailure());
|
183 |
CHECK_EQ(12, Failure::RetryAfterGC(12, NEW_SPACE)->requested()); |
184 |
CHECK_EQ(NEW_SPACE, Failure::RetryAfterGC(12, NEW_SPACE)->allocation_space());
|
185 |
CHECK_EQ(OLD_POINTER_SPACE, |
186 |
Failure::RetryAfterGC(12, OLD_POINTER_SPACE)->allocation_space());
|
187 |
CHECK(Failure::Exception()->IsFailure()); |
188 |
CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi()); |
189 |
CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi()); |
190 |
} |
191 |
|
192 |
|
193 |
TEST(GarbageCollection) { |
194 |
InitializeVM(); |
195 |
|
196 |
v8::HandleScope sc; |
197 |
// check GC when heap is empty
|
198 |
int free_bytes = Heap::MaxHeapObjectSize();
|
199 |
CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE)); |
200 |
|
201 |
// allocate a function and keep it in global object's property
|
202 |
String* func_name = String::cast(Heap::LookupAsciiSymbol("theFunction"));
|
203 |
SharedFunctionInfo* function_share = |
204 |
SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(func_name)); |
205 |
JSFunction* function = |
206 |
JSFunction::cast(Heap::AllocateFunction(*Top::function_map(), |
207 |
function_share, |
208 |
Heap::undefined_value())); |
209 |
Map* initial_map = |
210 |
Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize)); |
211 |
function->set_initial_map(initial_map); |
212 |
Top::context()->global()->SetProperty(func_name, function, NONE); |
213 |
|
214 |
// allocate an object, but it is unrooted
|
215 |
String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
|
216 |
String* prop_namex = String::cast(Heap::LookupAsciiSymbol("theSlotx"));
|
217 |
JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function)); |
218 |
obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
|
219 |
obj->SetProperty(prop_namex, Smi::FromInt(24), NONE);
|
220 |
|
221 |
CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
|
222 |
CHECK_EQ(Smi::FromInt(24), obj->GetProperty(prop_namex));
|
223 |
|
224 |
CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE)); |
225 |
|
226 |
// function should be alive, func_name might be invalid after GC
|
227 |
func_name = String::cast(Heap::LookupAsciiSymbol("theFunction"));
|
228 |
CHECK(Top::context()->global()->HasLocalProperty(func_name)); |
229 |
// check function is retained
|
230 |
Object* func_value = Top::context()->global()->GetProperty(func_name); |
231 |
CHECK(func_value->IsJSFunction()); |
232 |
// old function pointer may not be valid
|
233 |
function = JSFunction::cast(func_value); |
234 |
|
235 |
// allocate another object, make it reachable from global
|
236 |
obj = JSObject::cast(Heap::AllocateJSObject(function)); |
237 |
String* obj_name = String::cast(Heap::LookupAsciiSymbol("theObject"));
|
238 |
Top::context()->global()->SetProperty(obj_name, obj, NONE); |
239 |
// set property
|
240 |
prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
|
241 |
obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
|
242 |
|
243 |
// after gc, it should survive
|
244 |
CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE)); |
245 |
|
246 |
obj_name = String::cast(Heap::LookupAsciiSymbol("theObject"));
|
247 |
CHECK(Top::context()->global()->HasLocalProperty(obj_name)); |
248 |
CHECK(Top::context()->global()->GetProperty(obj_name)->IsJSObject()); |
249 |
obj = JSObject::cast(Top::context()->global()->GetProperty(obj_name)); |
250 |
prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
|
251 |
CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
|
252 |
} |
253 |
|
254 |
|
255 |
static void VerifyStringAllocation(const char* string) { |
256 |
String* s = String::cast(Heap::AllocateStringFromUtf8(CStrVector(string)));
|
257 |
CHECK_EQ(static_cast<int>(strlen(string)), s->length()); |
258 |
for (int index = 0; index < s->length(); index++) { |
259 |
CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index)); } |
260 |
} |
261 |
|
262 |
|
263 |
TEST(String) { |
264 |
InitializeVM(); |
265 |
|
266 |
VerifyStringAllocation("a");
|
267 |
VerifyStringAllocation("ab");
|
268 |
VerifyStringAllocation("abc");
|
269 |
VerifyStringAllocation("abcd");
|
270 |
VerifyStringAllocation("fiskerdrengen er paa havet");
|
271 |
} |
272 |
|
273 |
|
274 |
TEST(LocalHandles) { |
275 |
InitializeVM(); |
276 |
|
277 |
v8::HandleScope scope; |
278 |
const char* name = "Kasper the spunky"; |
279 |
Handle<String> string = Factory::NewStringFromAscii(CStrVector(name));
|
280 |
CHECK_EQ(static_cast<int>(strlen(name)), string->length()); |
281 |
} |
282 |
|
283 |
|
284 |
TEST(GlobalHandles) { |
285 |
InitializeVM(); |
286 |
|
287 |
Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
|
288 |
Object* u = Heap::AllocateHeapNumber(1.12344); |
289 |
|
290 |
Handle<Object> h1 = GlobalHandles::Create(i); |
291 |
Handle<Object> h2 = GlobalHandles::Create(u); |
292 |
Handle<Object> h3 = GlobalHandles::Create(i); |
293 |
Handle<Object> h4 = GlobalHandles::Create(u); |
294 |
|
295 |
// after gc, it should survive
|
296 |
CHECK(Heap::CollectGarbage(0, NEW_SPACE));
|
297 |
|
298 |
CHECK((*h1)->IsString()); |
299 |
CHECK((*h2)->IsHeapNumber()); |
300 |
CHECK((*h3)->IsString()); |
301 |
CHECK((*h4)->IsHeapNumber()); |
302 |
|
303 |
CHECK_EQ(*h3, *h1); |
304 |
GlobalHandles::Destroy(h1.location()); |
305 |
GlobalHandles::Destroy(h3.location()); |
306 |
|
307 |
CHECK_EQ(*h4, *h2); |
308 |
GlobalHandles::Destroy(h2.location()); |
309 |
GlobalHandles::Destroy(h4.location()); |
310 |
} |
311 |
|
312 |
|
313 |
static bool WeakPointerCleared = false; |
314 |
|
315 |
static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle, |
316 |
void* id) {
|
317 |
USE(handle); |
318 |
if (1234 == reinterpret_cast<int>(id)) WeakPointerCleared = true; |
319 |
} |
320 |
|
321 |
|
322 |
TEST(WeakGlobalHandlesScavenge) { |
323 |
InitializeVM(); |
324 |
|
325 |
WeakPointerCleared = false;
|
326 |
|
327 |
Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
|
328 |
Object* u = Heap::AllocateHeapNumber(1.12344); |
329 |
|
330 |
Handle<Object> h1 = GlobalHandles::Create(i); |
331 |
Handle<Object> h2 = GlobalHandles::Create(u); |
332 |
|
333 |
GlobalHandles::MakeWeak(h2.location(), |
334 |
reinterpret_cast<void*>(1234), |
335 |
&TestWeakGlobalHandleCallback); |
336 |
|
337 |
// Scavenge treats weak pointers as normal roots.
|
338 |
Heap::PerformScavenge(); |
339 |
|
340 |
CHECK((*h1)->IsString()); |
341 |
CHECK((*h2)->IsHeapNumber()); |
342 |
|
343 |
CHECK(!WeakPointerCleared); |
344 |
CHECK(!GlobalHandles::IsNearDeath(h2.location())); |
345 |
CHECK(!GlobalHandles::IsNearDeath(h1.location())); |
346 |
|
347 |
GlobalHandles::Destroy(h1.location()); |
348 |
GlobalHandles::Destroy(h2.location()); |
349 |
} |
350 |
|
351 |
|
352 |
TEST(WeakGlobalHandlesMark) { |
353 |
InitializeVM(); |
354 |
|
355 |
WeakPointerCleared = false;
|
356 |
|
357 |
Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
|
358 |
Object* u = Heap::AllocateHeapNumber(1.12344); |
359 |
|
360 |
Handle<Object> h1 = GlobalHandles::Create(i); |
361 |
Handle<Object> h2 = GlobalHandles::Create(u); |
362 |
|
363 |
CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
|
364 |
CHECK(Heap::CollectGarbage(0, NEW_SPACE));
|
365 |
// Make sure the object is promoted.
|
366 |
|
367 |
GlobalHandles::MakeWeak(h2.location(), |
368 |
reinterpret_cast<void*>(1234), |
369 |
&TestWeakGlobalHandleCallback); |
370 |
CHECK(!GlobalHandles::IsNearDeath(h1.location())); |
371 |
CHECK(!GlobalHandles::IsNearDeath(h2.location())); |
372 |
|
373 |
CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
|
374 |
|
375 |
CHECK((*h1)->IsString()); |
376 |
|
377 |
CHECK(WeakPointerCleared); |
378 |
CHECK(!GlobalHandles::IsNearDeath(h1.location())); |
379 |
CHECK(GlobalHandles::IsNearDeath(h2.location())); |
380 |
|
381 |
GlobalHandles::Destroy(h1.location()); |
382 |
GlobalHandles::Destroy(h2.location()); |
383 |
} |
384 |
|
385 |
static void TestDeleteWeakGlobalHandleCallback( |
386 |
v8::Persistent<v8::Value> handle, |
387 |
void* id) {
|
388 |
if (1234 == reinterpret_cast<int>(id)) WeakPointerCleared = true; |
389 |
handle.Dispose(); |
390 |
} |
391 |
|
392 |
TEST(DeleteWeakGlobalHandle) { |
393 |
InitializeVM(); |
394 |
|
395 |
WeakPointerCleared = false;
|
396 |
|
397 |
Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
|
398 |
Handle<Object> h = GlobalHandles::Create(i); |
399 |
|
400 |
GlobalHandles::MakeWeak(h.location(), |
401 |
reinterpret_cast<void*>(1234), |
402 |
&TestDeleteWeakGlobalHandleCallback); |
403 |
|
404 |
// Scanvenge does not recognize weak reference.
|
405 |
Heap::PerformScavenge(); |
406 |
|
407 |
CHECK(!WeakPointerCleared); |
408 |
|
409 |
// Mark-compact treats weak reference properly.
|
410 |
CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
|
411 |
|
412 |
CHECK(WeakPointerCleared); |
413 |
} |
414 |
|
415 |
static const char* not_so_random_string_table[] = { |
416 |
"abstract",
|
417 |
"boolean",
|
418 |
"break",
|
419 |
"byte",
|
420 |
"case",
|
421 |
"catch",
|
422 |
"char",
|
423 |
"class",
|
424 |
"const",
|
425 |
"continue",
|
426 |
"debugger",
|
427 |
"default",
|
428 |
"delete",
|
429 |
"do",
|
430 |
"double",
|
431 |
"else",
|
432 |
"enum",
|
433 |
"export",
|
434 |
"extends",
|
435 |
"false",
|
436 |
"final",
|
437 |
"finally",
|
438 |
"float",
|
439 |
"for",
|
440 |
"function",
|
441 |
"goto",
|
442 |
"if",
|
443 |
"implements",
|
444 |
"import",
|
445 |
"in",
|
446 |
"instanceof",
|
447 |
"int",
|
448 |
"interface",
|
449 |
"long",
|
450 |
"native",
|
451 |
"new",
|
452 |
"null",
|
453 |
"package",
|
454 |
"private",
|
455 |
"protected",
|
456 |
"public",
|
457 |
"return",
|
458 |
"short",
|
459 |
"static",
|
460 |
"super",
|
461 |
"switch",
|
462 |
"synchronized",
|
463 |
"this",
|
464 |
"throw",
|
465 |
"throws",
|
466 |
"transient",
|
467 |
"true",
|
468 |
"try",
|
469 |
"typeof",
|
470 |
"var",
|
471 |
"void",
|
472 |
"volatile",
|
473 |
"while",
|
474 |
"with",
|
475 |
0
|
476 |
}; |
477 |
|
478 |
|
479 |
static void CheckSymbols(const char** strings) { |
480 |
for (const char* string = *strings; *strings != 0; string = *strings++) { |
481 |
Object* a = Heap::LookupAsciiSymbol(string);
|
482 |
CHECK(a->IsSymbol()); |
483 |
Object* b = Heap::LookupAsciiSymbol(string);
|
484 |
CHECK_EQ(b, a); |
485 |
CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
|
486 |
} |
487 |
} |
488 |
|
489 |
|
490 |
TEST(SymbolTable) { |
491 |
InitializeVM(); |
492 |
|
493 |
CheckSymbols(not_so_random_string_table); |
494 |
CheckSymbols(not_so_random_string_table); |
495 |
} |
496 |
|
497 |
|
498 |
TEST(FunctionAllocation) { |
499 |
InitializeVM(); |
500 |
|
501 |
v8::HandleScope sc; |
502 |
String* name = String::cast(Heap::LookupAsciiSymbol("theFunction"));
|
503 |
SharedFunctionInfo* function_share = |
504 |
SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(name)); |
505 |
JSFunction* function = |
506 |
JSFunction::cast(Heap::AllocateFunction(*Top::function_map(), |
507 |
function_share, |
508 |
Heap::undefined_value())); |
509 |
Map* initial_map = |
510 |
Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize)); |
511 |
function->set_initial_map(initial_map); |
512 |
|
513 |
String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
|
514 |
JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function)); |
515 |
obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
|
516 |
CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
|
517 |
// Check that we can add properties to function objects.
|
518 |
function->SetProperty(prop_name, Smi::FromInt(24), NONE);
|
519 |
CHECK_EQ(Smi::FromInt(24), function->GetProperty(prop_name));
|
520 |
} |
521 |
|
522 |
|
523 |
TEST(ObjectProperties) { |
524 |
InitializeVM(); |
525 |
|
526 |
v8::HandleScope sc; |
527 |
JSFunction* constructor = |
528 |
JSFunction::cast( |
529 |
Top::context()->global()->GetProperty(String::cast( |
530 |
Heap::Object_symbol()))); |
531 |
JSObject* obj = JSObject::cast(Heap::AllocateJSObject(constructor)); |
532 |
String* first = String::cast(Heap::LookupAsciiSymbol("first"));
|
533 |
String* second = String::cast(Heap::LookupAsciiSymbol("second"));
|
534 |
|
535 |
// check for empty
|
536 |
CHECK(!obj->HasLocalProperty(first)); |
537 |
|
538 |
// add first
|
539 |
obj->SetProperty(first, Smi::FromInt(1), NONE);
|
540 |
CHECK(obj->HasLocalProperty(first)); |
541 |
|
542 |
// delete first
|
543 |
CHECK(obj->DeleteProperty(first)); |
544 |
CHECK(!obj->HasLocalProperty(first)); |
545 |
|
546 |
// add first and then second
|
547 |
obj->SetProperty(first, Smi::FromInt(1), NONE);
|
548 |
obj->SetProperty(second, Smi::FromInt(2), NONE);
|
549 |
CHECK(obj->HasLocalProperty(first)); |
550 |
CHECK(obj->HasLocalProperty(second)); |
551 |
|
552 |
// delete first and then second
|
553 |
CHECK(obj->DeleteProperty(first)); |
554 |
CHECK(obj->HasLocalProperty(second)); |
555 |
CHECK(obj->DeleteProperty(second)); |
556 |
CHECK(!obj->HasLocalProperty(first)); |
557 |
CHECK(!obj->HasLocalProperty(second)); |
558 |
|
559 |
// add first and then second
|
560 |
obj->SetProperty(first, Smi::FromInt(1), NONE);
|
561 |
obj->SetProperty(second, Smi::FromInt(2), NONE);
|
562 |
CHECK(obj->HasLocalProperty(first)); |
563 |
CHECK(obj->HasLocalProperty(second)); |
564 |
|
565 |
// delete second and then first
|
566 |
CHECK(obj->DeleteProperty(second)); |
567 |
CHECK(obj->HasLocalProperty(first)); |
568 |
CHECK(obj->DeleteProperty(first)); |
569 |
CHECK(!obj->HasLocalProperty(first)); |
570 |
CHECK(!obj->HasLocalProperty(second)); |
571 |
|
572 |
// check string and symbol match
|
573 |
static const char* string1 = "fisk"; |
574 |
String* s1 = |
575 |
String::cast(Heap::AllocateStringFromAscii(CStrVector(string1))); |
576 |
obj->SetProperty(s1, Smi::FromInt(1), NONE);
|
577 |
CHECK(obj->HasLocalProperty(String::cast(Heap::LookupAsciiSymbol(string1)))); |
578 |
|
579 |
// check symbol and string match
|
580 |
static const char* string2 = "fugl"; |
581 |
String* s2 = String::cast(Heap::LookupAsciiSymbol(string2)); |
582 |
obj->SetProperty(s2, Smi::FromInt(1), NONE);
|
583 |
CHECK(obj->HasLocalProperty( |
584 |
String::cast(Heap::AllocateStringFromAscii(CStrVector(string2))))); |
585 |
} |
586 |
|
587 |
|
588 |
TEST(JSObjectMaps) { |
589 |
InitializeVM(); |
590 |
|
591 |
v8::HandleScope sc; |
592 |
String* name = String::cast(Heap::LookupAsciiSymbol("theFunction"));
|
593 |
SharedFunctionInfo* function_share = |
594 |
SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(name)); |
595 |
JSFunction* function = |
596 |
JSFunction::cast(Heap::AllocateFunction(*Top::function_map(), |
597 |
function_share, |
598 |
Heap::undefined_value())); |
599 |
Map* initial_map = |
600 |
Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize)); |
601 |
function->set_initial_map(initial_map); |
602 |
String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
|
603 |
JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function)); |
604 |
|
605 |
// Set a propery
|
606 |
obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
|
607 |
CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
|
608 |
|
609 |
// Check the map has changed
|
610 |
CHECK(initial_map != obj->map()); |
611 |
} |
612 |
|
613 |
|
614 |
TEST(JSArray) { |
615 |
InitializeVM(); |
616 |
|
617 |
v8::HandleScope sc; |
618 |
String* name = String::cast(Heap::LookupAsciiSymbol("Array"));
|
619 |
JSFunction* function = |
620 |
JSFunction::cast(Top::context()->global()->GetProperty(name)); |
621 |
|
622 |
// Allocate the object.
|
623 |
JSArray* array = JSArray::cast(Heap::AllocateJSObject(function)); |
624 |
array->Initialize(0);
|
625 |
|
626 |
// Set array length to 0.
|
627 |
array->SetElementsLength(Smi::FromInt(0));
|
628 |
CHECK_EQ(Smi::FromInt(0), array->length());
|
629 |
CHECK(array->HasFastElements()); // Must be in fast mode.
|
630 |
|
631 |
// array[length] = name.
|
632 |
array->SetElement(0, name);
|
633 |
CHECK_EQ(Smi::FromInt(1), array->length());
|
634 |
CHECK_EQ(array->GetElement(0), name);
|
635 |
|
636 |
// Set array length with larger than smi value.
|
637 |
Object* length = Heap::NumberFromInt32(Smi::kMaxValue + 1);
|
638 |
array->SetElementsLength(length); |
639 |
|
640 |
uint32_t int_length = 0;
|
641 |
CHECK(Array::IndexFromObject(length, &int_length)); |
642 |
CHECK_EQ(length, array->length()); |
643 |
CHECK(!array->HasFastElements()); // Must be in slow mode.
|
644 |
|
645 |
// array[length] = name.
|
646 |
array->SetElement(int_length, name); |
647 |
uint32_t new_int_length = 0;
|
648 |
CHECK(Array::IndexFromObject(array->length(), &new_int_length)); |
649 |
CHECK_EQ(static_cast<double>(int_length), new_int_length - 1); |
650 |
CHECK_EQ(array->GetElement(int_length), name); |
651 |
CHECK_EQ(array->GetElement(0), name);
|
652 |
} |
653 |
|
654 |
|
655 |
TEST(JSObjectCopy) { |
656 |
InitializeVM(); |
657 |
|
658 |
v8::HandleScope sc; |
659 |
String* name = String::cast(Heap::Object_symbol()); |
660 |
JSFunction* constructor = |
661 |
JSFunction::cast(Top::context()->global()->GetProperty(name)); |
662 |
JSObject* obj = JSObject::cast(Heap::AllocateJSObject(constructor)); |
663 |
String* first = String::cast(Heap::LookupAsciiSymbol("first"));
|
664 |
String* second = String::cast(Heap::LookupAsciiSymbol("second"));
|
665 |
|
666 |
obj->SetProperty(first, Smi::FromInt(1), NONE);
|
667 |
obj->SetProperty(second, Smi::FromInt(2), NONE);
|
668 |
|
669 |
obj->SetElement(0, first);
|
670 |
obj->SetElement(1, second);
|
671 |
|
672 |
// Make the clone.
|
673 |
JSObject* clone = JSObject::cast(Heap::CopyJSObject(obj)); |
674 |
CHECK(clone != obj); |
675 |
|
676 |
CHECK_EQ(obj->GetElement(0), clone->GetElement(0)); |
677 |
CHECK_EQ(obj->GetElement(1), clone->GetElement(1)); |
678 |
|
679 |
CHECK_EQ(obj->GetProperty(first), clone->GetProperty(first)); |
680 |
CHECK_EQ(obj->GetProperty(second), clone->GetProperty(second)); |
681 |
|
682 |
// Flip the values.
|
683 |
clone->SetProperty(first, Smi::FromInt(2), NONE);
|
684 |
clone->SetProperty(second, Smi::FromInt(1), NONE);
|
685 |
|
686 |
clone->SetElement(0, second);
|
687 |
clone->SetElement(1, first);
|
688 |
|
689 |
CHECK_EQ(obj->GetElement(1), clone->GetElement(0)); |
690 |
CHECK_EQ(obj->GetElement(0), clone->GetElement(1)); |
691 |
|
692 |
CHECK_EQ(obj->GetProperty(second), clone->GetProperty(first)); |
693 |
CHECK_EQ(obj->GetProperty(first), clone->GetProperty(second)); |
694 |
} |
695 |
|
696 |
|
697 |
TEST(StringAllocation) { |
698 |
InitializeVM(); |
699 |
|
700 |
|
701 |
const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 }; |
702 |
for (int length = 0; length < 100; length++) { |
703 |
v8::HandleScope scope; |
704 |
char* non_ascii = NewArray<char>(3 * length + 1); |
705 |
char* ascii = NewArray<char>(length + 1); |
706 |
non_ascii[3 * length] = 0; |
707 |
ascii[length] = 0;
|
708 |
for (int i = 0; i < length; i++) { |
709 |
ascii[i] = 'a';
|
710 |
non_ascii[3 * i] = chars[0]; |
711 |
non_ascii[3 * i + 1] = chars[1]; |
712 |
non_ascii[3 * i + 2] = chars[2]; |
713 |
} |
714 |
Handle<String> non_ascii_sym = |
715 |
Factory::LookupSymbol(Vector<const char>(non_ascii, 3 * length)); |
716 |
CHECK_EQ(length, non_ascii_sym->length()); |
717 |
Handle<String> ascii_sym = |
718 |
Factory::LookupSymbol(Vector<const char>(ascii, length)); |
719 |
CHECK_EQ(length, ascii_sym->length()); |
720 |
Handle<String> non_ascii_str = |
721 |
Factory::NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length)); |
722 |
non_ascii_str->Hash(); |
723 |
CHECK_EQ(length, non_ascii_str->length()); |
724 |
Handle<String> ascii_str = |
725 |
Factory::NewStringFromUtf8(Vector<const char>(ascii, length)); |
726 |
ascii_str->Hash(); |
727 |
CHECK_EQ(length, ascii_str->length()); |
728 |
DeleteArray(non_ascii); |
729 |
DeleteArray(ascii); |
730 |
} |
731 |
} |
732 |
|
733 |
|
734 |
static int ObjectsFoundInHeap(Handle<Object> objs[], int size) { |
735 |
// Count the number of objects found in the heap.
|
736 |
int found_count = 0; |
737 |
HeapIterator iterator; |
738 |
while (iterator.has_next()) {
|
739 |
HeapObject* obj = iterator.next(); |
740 |
CHECK(obj != NULL);
|
741 |
for (int i = 0; i < size; i++) { |
742 |
if (*objs[i] == obj) {
|
743 |
found_count++; |
744 |
} |
745 |
} |
746 |
} |
747 |
CHECK(!iterator.has_next()); |
748 |
return found_count;
|
749 |
} |
750 |
|
751 |
|
752 |
TEST(Iteration) { |
753 |
InitializeVM(); |
754 |
v8::HandleScope scope; |
755 |
|
756 |
// Array of objects to scan haep for.
|
757 |
const int objs_count = 6; |
758 |
Handle<Object> objs[objs_count]; |
759 |
int next_objs_index = 0; |
760 |
|
761 |
// Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
|
762 |
objs[next_objs_index++] = Factory::NewJSArray(10);
|
763 |
objs[next_objs_index++] = Factory::NewJSArray(10, TENURED);
|
764 |
|
765 |
// Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
|
766 |
objs[next_objs_index++] = |
767 |
Factory::NewStringFromAscii(CStrVector("abcdefghij"));
|
768 |
objs[next_objs_index++] = |
769 |
Factory::NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
|
770 |
|
771 |
// Allocate a large string (for large object space).
|
772 |
int large_size = Heap::MaxHeapObjectSize() + 1; |
773 |
char* str = new char[large_size]; |
774 |
for (int i = 0; i < large_size - 1; ++i) str[i] = 'a'; |
775 |
str[large_size - 1] = '\0'; |
776 |
objs[next_objs_index++] = |
777 |
Factory::NewStringFromAscii(CStrVector(str), TENURED); |
778 |
delete[] str;
|
779 |
|
780 |
// Add a Map object to look for.
|
781 |
objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
|
782 |
|
783 |
CHECK_EQ(objs_count, next_objs_index); |
784 |
CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count)); |
785 |
} |