| // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #include "platform/assert.h" |
| #include "vm/dart.h" |
| #include "vm/isolate.h" |
| #include "vm/unit_test.h" |
| #include "vm/zone.h" |
| |
| namespace dart { |
| |
| VM_UNIT_TEST_CASE(AllocateZone) { |
| #if defined(DEBUG) |
| FLAG_trace_zones = true; |
| #endif |
| Dart_CreateIsolate(NULL, NULL, bin::core_isolate_snapshot_data, |
| bin::core_isolate_snapshot_instructions, NULL, NULL, NULL); |
| Thread* thread = Thread::Current(); |
| EXPECT(thread->zone() == NULL); |
| { |
| StackZone stack_zone(thread); |
| EXPECT(thread->zone() != NULL); |
| Zone* zone = stack_zone.GetZone(); |
| intptr_t allocated_size = 0; |
| |
| // The loop is to make sure we overflow one segment and go on |
| // to the next segment. |
| for (int i = 0; i < 1000; i++) { |
| uword first = zone->AllocUnsafe(2 * kWordSize); |
| uword second = zone->AllocUnsafe(3 * kWordSize); |
| EXPECT(first != second); |
| allocated_size = ((2 + 3) * kWordSize); |
| } |
| EXPECT_LE(allocated_size, zone->SizeInBytes()); |
| |
| // Test for allocation of large segments. |
| const uword kLargeSize = 1 * MB; |
| const uword kSegmentSize = 64 * KB; |
| ASSERT(kLargeSize > kSegmentSize); |
| for (int i = 0; i < 10; i++) { |
| EXPECT(zone->AllocUnsafe(kLargeSize) != 0); |
| allocated_size += kLargeSize; |
| } |
| EXPECT_LE(allocated_size, zone->SizeInBytes()); |
| |
| // Test corner cases of kSegmentSize. |
| uint8_t* buffer = NULL; |
| buffer = |
| reinterpret_cast<uint8_t*>(zone->AllocUnsafe(kSegmentSize - kWordSize)); |
| EXPECT(buffer != NULL); |
| buffer[(kSegmentSize - kWordSize) - 1] = 0; |
| allocated_size += (kSegmentSize - kWordSize); |
| EXPECT_LE(allocated_size, zone->SizeInBytes()); |
| |
| buffer = reinterpret_cast<uint8_t*>( |
| zone->AllocUnsafe(kSegmentSize - (2 * kWordSize))); |
| EXPECT(buffer != NULL); |
| buffer[(kSegmentSize - (2 * kWordSize)) - 1] = 0; |
| allocated_size += (kSegmentSize - (2 * kWordSize)); |
| EXPECT_LE(allocated_size, zone->SizeInBytes()); |
| |
| buffer = |
| reinterpret_cast<uint8_t*>(zone->AllocUnsafe(kSegmentSize + kWordSize)); |
| EXPECT(buffer != NULL); |
| buffer[(kSegmentSize + kWordSize) - 1] = 0; |
| allocated_size += (kSegmentSize + kWordSize); |
| EXPECT_LE(allocated_size, zone->SizeInBytes()); |
| } |
| EXPECT(thread->zone() == NULL); |
| Dart_ShutdownIsolate(); |
| } |
| |
| |
| VM_UNIT_TEST_CASE(AllocGeneric_Success) { |
| #if defined(DEBUG) |
| FLAG_trace_zones = true; |
| #endif |
| Dart_CreateIsolate(NULL, NULL, bin::core_isolate_snapshot_data, |
| bin::core_isolate_snapshot_instructions, NULL, NULL, NULL); |
| Thread* thread = Thread::Current(); |
| EXPECT(thread->zone() == NULL); |
| { |
| StackZone zone(thread); |
| EXPECT(thread->zone() != NULL); |
| intptr_t allocated_size = 0; |
| |
| const intptr_t kNumElements = 1000; |
| zone.GetZone()->Alloc<uint32_t>(kNumElements); |
| allocated_size += sizeof(uint32_t) * kNumElements; |
| EXPECT_LE(allocated_size, zone.SizeInBytes()); |
| } |
| EXPECT(thread->zone() == NULL); |
| Dart_ShutdownIsolate(); |
| } |
| |
| |
| // This test is expected to crash. |
| VM_UNIT_TEST_CASE(AllocGeneric_Overflow) { |
| #if defined(DEBUG) |
| FLAG_trace_zones = true; |
| #endif |
| Dart_CreateIsolate(NULL, NULL, bin::core_isolate_snapshot_data, |
| bin::core_isolate_snapshot_instructions, NULL, NULL, NULL); |
| Thread* thread = Thread::Current(); |
| EXPECT(thread->zone() == NULL); |
| { |
| StackZone zone(thread); |
| EXPECT(thread->zone() != NULL); |
| |
| const intptr_t kNumElements = (kIntptrMax / sizeof(uint32_t)) + 1; |
| zone.GetZone()->Alloc<uint32_t>(kNumElements); |
| } |
| Dart_ShutdownIsolate(); |
| } |
| |
| |
| VM_UNIT_TEST_CASE(ZoneAllocated) { |
| #if defined(DEBUG) |
| FLAG_trace_zones = true; |
| #endif |
| Dart_CreateIsolate(NULL, NULL, bin::core_isolate_snapshot_data, |
| bin::core_isolate_snapshot_instructions, NULL, NULL, NULL); |
| Thread* thread = Thread::Current(); |
| EXPECT(thread->zone() == NULL); |
| static int marker; |
| |
| class SimpleZoneObject : public ZoneAllocated { |
| public: |
| SimpleZoneObject() : slot(marker++) {} |
| virtual ~SimpleZoneObject() {} |
| virtual int GetSlot() { return slot; } |
| int slot; |
| }; |
| |
| // Reset the marker. |
| marker = 0; |
| |
| // Create a few zone allocated objects. |
| { |
| StackZone zone(thread); |
| EXPECT_EQ(0, zone.SizeInBytes()); |
| SimpleZoneObject* first = new SimpleZoneObject(); |
| EXPECT(first != NULL); |
| SimpleZoneObject* second = new SimpleZoneObject(); |
| EXPECT(second != NULL); |
| EXPECT(first != second); |
| intptr_t expected_size = (2 * sizeof(SimpleZoneObject)); |
| EXPECT_LE(expected_size, zone.SizeInBytes()); |
| |
| // Make sure the constructors were invoked. |
| EXPECT_EQ(0, first->slot); |
| EXPECT_EQ(1, second->slot); |
| |
| // Make sure we can write to the members of the zone objects. |
| first->slot = 42; |
| second->slot = 87; |
| EXPECT_EQ(42, first->slot); |
| EXPECT_EQ(87, second->slot); |
| } |
| EXPECT(thread->zone() == NULL); |
| Dart_ShutdownIsolate(); |
| } |
| |
| |
| TEST_CASE(PrintToString) { |
| StackZone zone(Thread::Current()); |
| const char* result = zone.GetZone()->PrintToString("Hello %s!", "World"); |
| EXPECT_STREQ("Hello World!", result); |
| } |
| |
| |
| #ifndef PRODUCT |
| VM_UNIT_TEST_CASE(PrintZoneMemoryInfoToJSON) { |
| #if defined(DEBUG) |
| FLAG_trace_zones = true; |
| #endif |
| Dart_CreateIsolate(NULL, NULL, bin::core_isolate_snapshot_data, |
| bin::core_isolate_snapshot_instructions, NULL, NULL, NULL); |
| Thread* thread = Thread::Current(); |
| EXPECT(thread->zone() == NULL); |
| { |
| StackZone zone(thread); |
| StackZone string_stack_zone(thread); |
| EXPECT(thread->zone() != NULL); |
| |
| intptr_t allocated_size = 0; |
| const intptr_t kNumElements = 1000; |
| |
| zone.GetZone()->Alloc<uint32_t>(kNumElements); |
| allocated_size += sizeof(uint32_t) * kNumElements; |
| |
| EXPECT_LE(allocated_size, zone.SizeInBytes()); |
| { |
| JSONStream stream; |
| // Get the JSON formated zone information. |
| zone.GetZone()->PrintJSON(&stream); |
| const char* json = stream.ToCString(); |
| // Ensure that matches actual values. |
| char* size_buf = |
| OS::SCreate(string_stack_zone.GetZone(), "\"capacity\":%" Pd |
| "," |
| "\"used\":%" Pd "", |
| zone.CapacityInBytes(), zone.SizeInBytes()); |
| EXPECT_LE(zone.SizeInBytes(), zone.CapacityInBytes()); |
| EXPECT_SUBSTRING(size_buf, json); |
| } |
| |
| // Expand the zone to ensure that JSON is updated accordingly. |
| zone.GetZone()->Alloc<uint32_t>(kNumElements); |
| allocated_size += sizeof(uint32_t) * kNumElements; |
| EXPECT_LE(allocated_size, zone.SizeInBytes()); |
| { |
| JSONStream stream; |
| zone.GetZone()->PrintJSON(&stream); |
| const char* json = stream.ToCString(); |
| char* size_buf = |
| OS::SCreate(string_stack_zone.GetZone(), "\"capacity\":%" Pd |
| "," |
| "\"used\":%" Pd "", |
| zone.CapacityInBytes(), zone.SizeInBytes()); |
| EXPECT_LE(zone.SizeInBytes(), zone.CapacityInBytes()); |
| EXPECT_SUBSTRING(size_buf, json); |
| } |
| } |
| EXPECT(thread->zone() == NULL); |
| Dart_ShutdownIsolate(); |
| } |
| #endif |
| |
| |
| VM_UNIT_TEST_CASE(NativeScopeZoneAllocation) { |
| ASSERT(ApiNativeScope::Current() == NULL); |
| ASSERT(Thread::Current() == NULL); |
| EXPECT_EQ(0, ApiNativeScope::current_memory_usage()); |
| { |
| ApiNativeScope scope; |
| EXPECT_EQ(scope.zone()->CapacityInBytes(), |
| ApiNativeScope::current_memory_usage()); |
| (void)Dart_ScopeAllocate(2048); |
| EXPECT_EQ(scope.zone()->CapacityInBytes(), |
| ApiNativeScope::current_memory_usage()); |
| } |
| EXPECT_EQ(0, ApiNativeScope::current_memory_usage()); |
| } |
| |
| } // namespace dart |