📄 test-heap.cc
字号:
// 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, Array::kHeaderSize); CheckMap(Heap::long_string_map(), LONG_STRING_TYPE, TwoByteString::kHeaderSize);}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)); 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)); 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()); value = Heap::NumberFromInt32(Smi::kMinValue - 1); CHECK(value->IsHeapNumber()); CHECK(value->IsNumber()); CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number()); value = Heap::NumberFromInt32(Smi::kMaxValue + 1); CHECK(value->IsHeapNumber()); CHECK(value->IsNumber()); CHECK_EQ(static_cast<double>(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(); CHECK(Smi::FromInt(42)->IsSmi()); CHECK(Failure::RetryAfterGC(12, NEW_SPACE)->IsFailure()); CHECK_EQ(12, Failure::RetryAfterGC(12, NEW_SPACE)->requested()); CHECK_EQ(NEW_SPACE, Failure::RetryAfterGC(12, NEW_SPACE)->allocation_space()); CHECK_EQ(OLD_POINTER_SPACE, Failure::RetryAfterGC(12, 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::MaxHeapObjectSize(); 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(static_cast<int>(strlen(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(static_cast<int>(strlen(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::Object> handle, void* id) { USE(handle); if (1234 == reinterpret_cast<int>(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::Object> handle, void* id) { if (1234 == reinterpret_cast<int>(id)) WeakPointerCleared = true; handle.Dispose();}TEST(DeleteWeakGlobalHandle) { InitializeVM(); WeakPointerCleared = false;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -