v8/test/cctest/test-heap.cc
sgjesse@chromium.org eb4d261e24 Remove the different length string types
The different length string types was used to encode the string length and the hash in one field. This is now split into two fields one for length and one for hash. The hash field still encodes the array index of the string if it has one. If an array index is encoded in the hash field the string length is added to the top bits of the hash field to avoid a hash value of zero.

On 32-bit this causes an additional 4 bytes to be used for all string objects. On 64-bit this will be half on average dur to pointer alignment.
Review URL: http://codereview.chromium.org/436001

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3350 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2009-11-24 14:10:06 +00:00

797 lines
24 KiB
C++

// Copyright 2006-2008 the V8 project authors. All rights reserved.
#include <stdlib.h>
#include "v8.h"
#include "execution.h"
#include "factory.h"
#include "macro-assembler.h"
#include "global-handles.h"
#include "cctest.h"
using namespace v8::internal;
static v8::Persistent<v8::Context> env;
static void InitializeVM() {
if (env.IsEmpty()) env = v8::Context::New();
v8::HandleScope scope;
env->Enter();
}
static void CheckMap(Map* map, int type, int instance_size) {
CHECK(map->IsHeapObject());
#ifdef DEBUG
CHECK(Heap::Contains(map));
#endif
CHECK_EQ(Heap::meta_map(), map->map());
CHECK_EQ(type, map->instance_type());
CHECK_EQ(instance_size, map->instance_size());
}
TEST(HeapMaps) {
InitializeVM();
CheckMap(Heap::meta_map(), MAP_TYPE, Map::kSize);
CheckMap(Heap::heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, FixedArray::kHeaderSize);
CheckMap(Heap::string_map(), STRING_TYPE, SeqTwoByteString::kAlignedSize);
}
static void CheckOddball(Object* obj, const char* string) {
CHECK(obj->IsOddball());
bool exc;
Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
}
static void CheckSmi(int value, const char* string) {
bool exc;
Object* print_string =
*Execution::ToString(Handle<Object>(Smi::FromInt(value)), &exc);
CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
}
static void CheckNumber(double value, const char* string) {
Object* obj = Heap::NumberFromDouble(value);
CHECK(obj->IsNumber());
bool exc;
Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
}
static void CheckFindCodeObject() {
// Test FindCodeObject
#define __ assm.
Assembler assm(NULL, 0);
__ nop(); // supported on all architectures
CodeDesc desc;
assm.GetCode(&desc);
Object* code = Heap::CreateCode(desc,
NULL,
Code::ComputeFlags(Code::STUB),
Handle<Object>(Heap::undefined_value()));
CHECK(code->IsCode());
HeapObject* obj = HeapObject::cast(code);
Address obj_addr = obj->address();
for (int i = 0; i < obj->Size(); i += kPointerSize) {
Object* found = Heap::FindCodeObject(obj_addr + i);
CHECK_EQ(code, found);
}
Object* copy = Heap::CreateCode(desc,
NULL,
Code::ComputeFlags(Code::STUB),
Handle<Object>(Heap::undefined_value()));
CHECK(copy->IsCode());
HeapObject* obj_copy = HeapObject::cast(copy);
Object* not_right = Heap::FindCodeObject(obj_copy->address() +
obj_copy->Size() / 2);
CHECK(not_right != code);
}
TEST(HeapObjects) {
InitializeVM();
v8::HandleScope sc;
Object* value = Heap::NumberFromDouble(1.000123);
CHECK(value->IsHeapNumber());
CHECK(value->IsNumber());
CHECK_EQ(1.000123, value->Number());
value = Heap::NumberFromDouble(1.0);
CHECK(value->IsSmi());
CHECK(value->IsNumber());
CHECK_EQ(1.0, value->Number());
value = Heap::NumberFromInt32(1024);
CHECK(value->IsSmi());
CHECK(value->IsNumber());
CHECK_EQ(1024.0, value->Number());
value = Heap::NumberFromInt32(Smi::kMinValue);
CHECK(value->IsSmi());
CHECK(value->IsNumber());
CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
value = Heap::NumberFromInt32(Smi::kMaxValue);
CHECK(value->IsSmi());
CHECK(value->IsNumber());
CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value());
#ifndef V8_TARGET_ARCH_X64
// TODO(lrn): We need a NumberFromIntptr function in order to test this.
value = Heap::NumberFromInt32(Smi::kMinValue - 1);
CHECK(value->IsHeapNumber());
CHECK(value->IsNumber());
CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
#endif
value = Heap::NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
CHECK(value->IsHeapNumber());
CHECK(value->IsNumber());
CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
value->Number());
// nan oddball checks
CHECK(Heap::nan_value()->IsNumber());
CHECK(isnan(Heap::nan_value()->Number()));
Object* str = Heap::AllocateStringFromAscii(CStrVector("fisk hest "));
if (!str->IsFailure()) {
String* s = String::cast(str);
CHECK(s->IsString());
CHECK_EQ(10, s->length());
} else {
CHECK(false);
}
String* object_symbol = String::cast(Heap::Object_symbol());
CHECK(Top::context()->global()->HasLocalProperty(object_symbol));
// Check ToString for oddballs
CheckOddball(Heap::true_value(), "true");
CheckOddball(Heap::false_value(), "false");
CheckOddball(Heap::null_value(), "null");
CheckOddball(Heap::undefined_value(), "undefined");
// Check ToString for Smis
CheckSmi(0, "0");
CheckSmi(42, "42");
CheckSmi(-42, "-42");
// Check ToString for Numbers
CheckNumber(1.1, "1.1");
CheckFindCodeObject();
}
TEST(Tagging) {
InitializeVM();
int request = 24;
CHECK_EQ(request, static_cast<int>(OBJECT_SIZE_ALIGN(request)));
CHECK(Smi::FromInt(42)->IsSmi());
CHECK(Failure::RetryAfterGC(request, NEW_SPACE)->IsFailure());
CHECK_EQ(request, Failure::RetryAfterGC(request, NEW_SPACE)->requested());
CHECK_EQ(NEW_SPACE,
Failure::RetryAfterGC(request, NEW_SPACE)->allocation_space());
CHECK_EQ(OLD_POINTER_SPACE,
Failure::RetryAfterGC(request,
OLD_POINTER_SPACE)->allocation_space());
CHECK(Failure::Exception()->IsFailure());
CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
}
TEST(GarbageCollection) {
InitializeVM();
v8::HandleScope sc;
// check GC when heap is empty
int free_bytes = Heap::MaxObjectSizeInPagedSpace();
CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE));
// allocate a function and keep it in global object's property
String* func_name = String::cast(Heap::LookupAsciiSymbol("theFunction"));
SharedFunctionInfo* function_share =
SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(func_name));
JSFunction* function =
JSFunction::cast(Heap::AllocateFunction(*Top::function_map(),
function_share,
Heap::undefined_value()));
Map* initial_map =
Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize));
function->set_initial_map(initial_map);
Top::context()->global()->SetProperty(func_name, function, NONE);
// allocate an object, but it is unrooted
String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
String* prop_namex = String::cast(Heap::LookupAsciiSymbol("theSlotx"));
JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function));
obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
obj->SetProperty(prop_namex, Smi::FromInt(24), NONE);
CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
CHECK_EQ(Smi::FromInt(24), obj->GetProperty(prop_namex));
CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE));
// function should be alive, func_name might be invalid after GC
func_name = String::cast(Heap::LookupAsciiSymbol("theFunction"));
CHECK(Top::context()->global()->HasLocalProperty(func_name));
// check function is retained
Object* func_value = Top::context()->global()->GetProperty(func_name);
CHECK(func_value->IsJSFunction());
// old function pointer may not be valid
function = JSFunction::cast(func_value);
// allocate another object, make it reachable from global
obj = JSObject::cast(Heap::AllocateJSObject(function));
String* obj_name = String::cast(Heap::LookupAsciiSymbol("theObject"));
Top::context()->global()->SetProperty(obj_name, obj, NONE);
// set property
prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
// after gc, it should survive
CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE));
obj_name = String::cast(Heap::LookupAsciiSymbol("theObject"));
CHECK(Top::context()->global()->HasLocalProperty(obj_name));
CHECK(Top::context()->global()->GetProperty(obj_name)->IsJSObject());
obj = JSObject::cast(Top::context()->global()->GetProperty(obj_name));
prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
}
static void VerifyStringAllocation(const char* string) {
String* s = String::cast(Heap::AllocateStringFromUtf8(CStrVector(string)));
CHECK_EQ(StrLength(string), s->length());
for (int index = 0; index < s->length(); index++) {
CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index)); }
}
TEST(String) {
InitializeVM();
VerifyStringAllocation("a");
VerifyStringAllocation("ab");
VerifyStringAllocation("abc");
VerifyStringAllocation("abcd");
VerifyStringAllocation("fiskerdrengen er paa havet");
}
TEST(LocalHandles) {
InitializeVM();
v8::HandleScope scope;
const char* name = "Kasper the spunky";
Handle<String> string = Factory::NewStringFromAscii(CStrVector(name));
CHECK_EQ(StrLength(name), string->length());
}
TEST(GlobalHandles) {
InitializeVM();
Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
Object* u = Heap::AllocateHeapNumber(1.12344);
Handle<Object> h1 = GlobalHandles::Create(i);
Handle<Object> h2 = GlobalHandles::Create(u);
Handle<Object> h3 = GlobalHandles::Create(i);
Handle<Object> h4 = GlobalHandles::Create(u);
// after gc, it should survive
CHECK(Heap::CollectGarbage(0, NEW_SPACE));
CHECK((*h1)->IsString());
CHECK((*h2)->IsHeapNumber());
CHECK((*h3)->IsString());
CHECK((*h4)->IsHeapNumber());
CHECK_EQ(*h3, *h1);
GlobalHandles::Destroy(h1.location());
GlobalHandles::Destroy(h3.location());
CHECK_EQ(*h4, *h2);
GlobalHandles::Destroy(h2.location());
GlobalHandles::Destroy(h4.location());
}
static bool WeakPointerCleared = false;
static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
void* id) {
USE(handle);
if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
}
TEST(WeakGlobalHandlesScavenge) {
InitializeVM();
WeakPointerCleared = false;
Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
Object* u = Heap::AllocateHeapNumber(1.12344);
Handle<Object> h1 = GlobalHandles::Create(i);
Handle<Object> h2 = GlobalHandles::Create(u);
GlobalHandles::MakeWeak(h2.location(),
reinterpret_cast<void*>(1234),
&TestWeakGlobalHandleCallback);
// Scavenge treats weak pointers as normal roots.
Heap::PerformScavenge();
CHECK((*h1)->IsString());
CHECK((*h2)->IsHeapNumber());
CHECK(!WeakPointerCleared);
CHECK(!GlobalHandles::IsNearDeath(h2.location()));
CHECK(!GlobalHandles::IsNearDeath(h1.location()));
GlobalHandles::Destroy(h1.location());
GlobalHandles::Destroy(h2.location());
}
TEST(WeakGlobalHandlesMark) {
InitializeVM();
WeakPointerCleared = false;
Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
Object* u = Heap::AllocateHeapNumber(1.12344);
Handle<Object> h1 = GlobalHandles::Create(i);
Handle<Object> h2 = GlobalHandles::Create(u);
CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
CHECK(Heap::CollectGarbage(0, NEW_SPACE));
// Make sure the object is promoted.
GlobalHandles::MakeWeak(h2.location(),
reinterpret_cast<void*>(1234),
&TestWeakGlobalHandleCallback);
CHECK(!GlobalHandles::IsNearDeath(h1.location()));
CHECK(!GlobalHandles::IsNearDeath(h2.location()));
CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
CHECK((*h1)->IsString());
CHECK(WeakPointerCleared);
CHECK(!GlobalHandles::IsNearDeath(h1.location()));
CHECK(GlobalHandles::IsNearDeath(h2.location()));
GlobalHandles::Destroy(h1.location());
GlobalHandles::Destroy(h2.location());
}
static void TestDeleteWeakGlobalHandleCallback(
v8::Persistent<v8::Value> handle,
void* id) {
if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
handle.Dispose();
}
TEST(DeleteWeakGlobalHandle) {
InitializeVM();
WeakPointerCleared = false;
Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
Handle<Object> h = GlobalHandles::Create(i);
GlobalHandles::MakeWeak(h.location(),
reinterpret_cast<void*>(1234),
&TestDeleteWeakGlobalHandleCallback);
// Scanvenge does not recognize weak reference.
Heap::PerformScavenge();
CHECK(!WeakPointerCleared);
// Mark-compact treats weak reference properly.
CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
CHECK(WeakPointerCleared);
}
static const char* not_so_random_string_table[] = {
"abstract",
"boolean",
"break",
"byte",
"case",
"catch",
"char",
"class",
"const",
"continue",
"debugger",
"default",
"delete",
"do",
"double",
"else",
"enum",
"export",
"extends",
"false",
"final",
"finally",
"float",
"for",
"function",
"goto",
"if",
"implements",
"import",
"in",
"instanceof",
"int",
"interface",
"long",
"native",
"new",
"null",
"package",
"private",
"protected",
"public",
"return",
"short",
"static",
"super",
"switch",
"synchronized",
"this",
"throw",
"throws",
"transient",
"true",
"try",
"typeof",
"var",
"void",
"volatile",
"while",
"with",
0
};
static void CheckSymbols(const char** strings) {
for (const char* string = *strings; *strings != 0; string = *strings++) {
Object* a = Heap::LookupAsciiSymbol(string);
// LookupAsciiSymbol may return a failure if a GC is needed.
if (a->IsFailure()) continue;
CHECK(a->IsSymbol());
Object* b = Heap::LookupAsciiSymbol(string);
if (b->IsFailure()) continue;
CHECK_EQ(b, a);
CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
}
}
TEST(SymbolTable) {
InitializeVM();
CheckSymbols(not_so_random_string_table);
CheckSymbols(not_so_random_string_table);
}
TEST(FunctionAllocation) {
InitializeVM();
v8::HandleScope sc;
String* name = String::cast(Heap::LookupAsciiSymbol("theFunction"));
SharedFunctionInfo* function_share =
SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(name));
JSFunction* function =
JSFunction::cast(Heap::AllocateFunction(*Top::function_map(),
function_share,
Heap::undefined_value()));
Map* initial_map =
Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize));
function->set_initial_map(initial_map);
String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function));
obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
// Check that we can add properties to function objects.
function->SetProperty(prop_name, Smi::FromInt(24), NONE);
CHECK_EQ(Smi::FromInt(24), function->GetProperty(prop_name));
}
TEST(ObjectProperties) {
InitializeVM();
v8::HandleScope sc;
JSFunction* constructor =
JSFunction::cast(
Top::context()->global()->GetProperty(String::cast(
Heap::Object_symbol())));
JSObject* obj = JSObject::cast(Heap::AllocateJSObject(constructor));
String* first = String::cast(Heap::LookupAsciiSymbol("first"));
String* second = String::cast(Heap::LookupAsciiSymbol("second"));
// check for empty
CHECK(!obj->HasLocalProperty(first));
// add first
obj->SetProperty(first, Smi::FromInt(1), NONE);
CHECK(obj->HasLocalProperty(first));
// delete first
CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION));
CHECK(!obj->HasLocalProperty(first));
// add first and then second
obj->SetProperty(first, Smi::FromInt(1), NONE);
obj->SetProperty(second, Smi::FromInt(2), NONE);
CHECK(obj->HasLocalProperty(first));
CHECK(obj->HasLocalProperty(second));
// delete first and then second
CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION));
CHECK(obj->HasLocalProperty(second));
CHECK(obj->DeleteProperty(second, JSObject::NORMAL_DELETION));
CHECK(!obj->HasLocalProperty(first));
CHECK(!obj->HasLocalProperty(second));
// add first and then second
obj->SetProperty(first, Smi::FromInt(1), NONE);
obj->SetProperty(second, Smi::FromInt(2), NONE);
CHECK(obj->HasLocalProperty(first));
CHECK(obj->HasLocalProperty(second));
// delete second and then first
CHECK(obj->DeleteProperty(second, JSObject::NORMAL_DELETION));
CHECK(obj->HasLocalProperty(first));
CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION));
CHECK(!obj->HasLocalProperty(first));
CHECK(!obj->HasLocalProperty(second));
// check string and symbol match
static const char* string1 = "fisk";
String* s1 =
String::cast(Heap::AllocateStringFromAscii(CStrVector(string1)));
obj->SetProperty(s1, Smi::FromInt(1), NONE);
CHECK(obj->HasLocalProperty(String::cast(Heap::LookupAsciiSymbol(string1))));
// check symbol and string match
static const char* string2 = "fugl";
String* s2 = String::cast(Heap::LookupAsciiSymbol(string2));
obj->SetProperty(s2, Smi::FromInt(1), NONE);
CHECK(obj->HasLocalProperty(
String::cast(Heap::AllocateStringFromAscii(CStrVector(string2)))));
}
TEST(JSObjectMaps) {
InitializeVM();
v8::HandleScope sc;
String* name = String::cast(Heap::LookupAsciiSymbol("theFunction"));
SharedFunctionInfo* function_share =
SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(name));
JSFunction* function =
JSFunction::cast(Heap::AllocateFunction(*Top::function_map(),
function_share,
Heap::undefined_value()));
Map* initial_map =
Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize));
function->set_initial_map(initial_map);
String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function));
// Set a propery
obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
// Check the map has changed
CHECK(initial_map != obj->map());
}
TEST(JSArray) {
InitializeVM();
v8::HandleScope sc;
String* name = String::cast(Heap::LookupAsciiSymbol("Array"));
JSFunction* function =
JSFunction::cast(Top::context()->global()->GetProperty(name));
// Allocate the object.
JSArray* array = JSArray::cast(Heap::AllocateJSObject(function));
array->Initialize(0);
// Set array length to 0.
array->SetElementsLength(Smi::FromInt(0));
CHECK_EQ(Smi::FromInt(0), array->length());
CHECK(array->HasFastElements()); // Must be in fast mode.
// array[length] = name.
array->SetElement(0, name);
CHECK_EQ(Smi::FromInt(1), array->length());
CHECK_EQ(array->GetElement(0), name);
// Set array length with larger than smi value.
Object* length =
Heap::NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
array->SetElementsLength(length);
uint32_t int_length = 0;
CHECK(Array::IndexFromObject(length, &int_length));
CHECK_EQ(length, array->length());
CHECK(array->HasDictionaryElements()); // Must be in slow mode.
// array[length] = name.
array->SetElement(int_length, name);
uint32_t new_int_length = 0;
CHECK(Array::IndexFromObject(array->length(), &new_int_length));
CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
CHECK_EQ(array->GetElement(int_length), name);
CHECK_EQ(array->GetElement(0), name);
}
TEST(JSObjectCopy) {
InitializeVM();
v8::HandleScope sc;
String* name = String::cast(Heap::Object_symbol());
JSFunction* constructor =
JSFunction::cast(Top::context()->global()->GetProperty(name));
JSObject* obj = JSObject::cast(Heap::AllocateJSObject(constructor));
String* first = String::cast(Heap::LookupAsciiSymbol("first"));
String* second = String::cast(Heap::LookupAsciiSymbol("second"));
obj->SetProperty(first, Smi::FromInt(1), NONE);
obj->SetProperty(second, Smi::FromInt(2), NONE);
obj->SetElement(0, first);
obj->SetElement(1, second);
// Make the clone.
JSObject* clone = JSObject::cast(Heap::CopyJSObject(obj));
CHECK(clone != obj);
CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
CHECK_EQ(obj->GetProperty(first), clone->GetProperty(first));
CHECK_EQ(obj->GetProperty(second), clone->GetProperty(second));
// Flip the values.
clone->SetProperty(first, Smi::FromInt(2), NONE);
clone->SetProperty(second, Smi::FromInt(1), NONE);
clone->SetElement(0, second);
clone->SetElement(1, first);
CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
CHECK_EQ(obj->GetProperty(second), clone->GetProperty(first));
CHECK_EQ(obj->GetProperty(first), clone->GetProperty(second));
}
TEST(StringAllocation) {
InitializeVM();
const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
for (int length = 0; length < 100; length++) {
v8::HandleScope scope;
char* non_ascii = NewArray<char>(3 * length + 1);
char* ascii = NewArray<char>(length + 1);
non_ascii[3 * length] = 0;
ascii[length] = 0;
for (int i = 0; i < length; i++) {
ascii[i] = 'a';
non_ascii[3 * i] = chars[0];
non_ascii[3 * i + 1] = chars[1];
non_ascii[3 * i + 2] = chars[2];
}
Handle<String> non_ascii_sym =
Factory::LookupSymbol(Vector<const char>(non_ascii, 3 * length));
CHECK_EQ(length, non_ascii_sym->length());
Handle<String> ascii_sym =
Factory::LookupSymbol(Vector<const char>(ascii, length));
CHECK_EQ(length, ascii_sym->length());
Handle<String> non_ascii_str =
Factory::NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
non_ascii_str->Hash();
CHECK_EQ(length, non_ascii_str->length());
Handle<String> ascii_str =
Factory::NewStringFromUtf8(Vector<const char>(ascii, length));
ascii_str->Hash();
CHECK_EQ(length, ascii_str->length());
DeleteArray(non_ascii);
DeleteArray(ascii);
}
}
static int ObjectsFoundInHeap(Handle<Object> objs[], int size) {
// Count the number of objects found in the heap.
int found_count = 0;
HeapIterator iterator;
while (iterator.has_next()) {
HeapObject* obj = iterator.next();
CHECK(obj != NULL);
for (int i = 0; i < size; i++) {
if (*objs[i] == obj) {
found_count++;
}
}
}
CHECK(!iterator.has_next());
return found_count;
}
TEST(Iteration) {
InitializeVM();
v8::HandleScope scope;
// Array of objects to scan haep for.
const int objs_count = 6;
Handle<Object> objs[objs_count];
int next_objs_index = 0;
// Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
objs[next_objs_index++] = Factory::NewJSArray(10);
objs[next_objs_index++] = Factory::NewJSArray(10, TENURED);
// Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
objs[next_objs_index++] =
Factory::NewStringFromAscii(CStrVector("abcdefghij"));
objs[next_objs_index++] =
Factory::NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
// Allocate a large string (for large object space).
int large_size = Heap::MaxObjectSizeInPagedSpace() + 1;
char* str = new char[large_size];
for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
str[large_size - 1] = '\0';
objs[next_objs_index++] =
Factory::NewStringFromAscii(CStrVector(str), TENURED);
delete[] str;
// Add a Map object to look for.
objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
CHECK_EQ(objs_count, next_objs_index);
CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count));
}